Language feature: Binary Literals/Strings/Numbers

Motivation

Hello! I thought it would be cool to have binary literals, strings, numbers for solidity. There is already hexadecimal support for both solidity and yul, so why not binaries? As mentioned at here, there is clear use case of binary representation is beneficial, such as expressing bitmasks.

Design Proposal

Lexer Rules

Most of the rules follow how hexadecimal works. Let me explain ANTLR definition of binary digits:

Define BinCharactor as

fragment BinCharacter: [01];

Define BinDigits as

fragment BinDigits: BinCharacter ('_'? BinCharacter)*;

Valid BinDigits may contain underscore, but underscores must not be consecutive, which behavior is identical to HexDigits.

Define BinNumber as

BinNumber: '0' 'b' BinDigits;

So we can declare binary digits as 0b0, 0b1, 0b1010101, 0b1_010101_1, but not 0b10__01.

Define BinOctet, BinOctets as

fragment BinOctets: BinOctet ('_'? BinOctet)*;
fragment BinOctet: BinCharacter BinCharacter BinCharacter BinCharacter BinCharacter BinCharacter BinCharacter BinCharacter;

These are for building blocks of binary literals, which are prefixed with bin.

Define BinString as

BinString: 'bin' (('"' BinOctets? '"') | ('\'' BinOctets? '\''));

So when prefixed with bin like bin"11110000", bin'0000111100001111', bin"00001111_00001111 will be valid bin literals, but when each chunk length is not multiple of 8, such as bin'101', it is invalid. This behavior follows the behavior of hex literals, where hex'12' is valid but hex'123' is invalid because it has odd number of digits.

We may also use binaries in yul by defining

YulBinNumber: '0' 'b' [01]+;
YulBinStringLiteral: BinString;

Conversion

Binary conversion to other types follow same rule what hex representation does.

Binary literals can be implicitly converted to any integer type(uint8, uint16 etc) that is large enough the represent it without truncation.

Binary literals can be implicitly converted to fixed-size byte arrays(bytes2, bytes4 etc) if their numbers are less or equal to the size of byte type.

Max Size

Binary string(BinString) is first viewed as a byte sequence, by viewing each pair of octuple bin digits as a byte. The byte sequence must not exceed 32 bytes (i.e. 256 bin digits), and is treated as above.

Example Usage

contract Test {
    bytes constant c_ = bin"11110000_0000111100001111";
    function binaryTest() public {
        bytes32 a = bin"11111111";
        // bytes4 b_ = bin"11"; // error, must be multiple of 8
        uint b = 0b101;
        uint c = 0b10101_101_10101;
        bytes memory d = bin'1111111100000000';
        uint256 e = 0b1011 * 1 days;
        bytes4 f = 0b0;
        // bytes2 g_ = 0b000011110000111100001111; // error, rvalue too big
        bytes3 g = 0b1111000011111111_000_00000;
        assembly {
            mstore(0b1001, 1)
            mstore(0b10, bin'10101010')
            let h := 0b1110
            mstore(bin"11001111", bin'11110000_11010111')
            switch h
            case 0b1 { }
            case bin"00010011" { }
            default { }
        }
    }
}

Implementation

I implemented an initial version of this feature at Add binary {string|literal|number} to solidity and yul by pcw109550 · Pull Request #15003 · ethereum/solidity · GitHub.

1 Like

Thanks for doing this!