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.