Allow underscores in hex strings.

This commit is contained in:
Daniel Kirchner 2019-09-06 15:29:51 +02:00
parent ea0a952a69
commit 6f3341a204
9 changed files with 56 additions and 5 deletions

View File

@ -7,6 +7,7 @@ Breaking changes:
Language Features:
* Allow global enums and structs.
* Allow underscores as delimiters in hex strings.
Compiler Features:

View File

@ -499,7 +499,7 @@ terminate the string literal. Newline only terminates the string literal if it i
Hexadecimal Literals
--------------------
Hexadecimal literals are prefixed with the keyword ``hex`` and are enclosed in double or single-quotes (``hex"001122FF"``). Their content must be a hexadecimal string and their value will be the binary representation of those values.
Hexadecimal literals are prefixed with the keyword ``hex`` and are enclosed in double or single-quotes (``hex"001122FF"``, ``hex'0011_22_FF'``). Their content must be hexadecimal digits which can optionally use a single underscore as separator between byte boundaries. The value of the literal will be the binary representation of the hexadecimal sequence.
Hexadecimal literals behave like :ref:`string literals <string_literals>` and have the same convertibility restrictions.

View File

@ -67,7 +67,7 @@ string langutil::to_string(ScannerError _errorCode)
{
case ScannerError::NoError: return "No error.";
case ScannerError::IllegalToken: return "Invalid token.";
case ScannerError::IllegalHexString: return "Expected even number of hex-nibbles within double-quotes.";
case ScannerError::IllegalHexString: return "Expected even number of hex-nibbles.";
case ScannerError::IllegalHexDigit: return "Hexadecimal digit missing or invalid.";
case ScannerError::IllegalCommentTerminator: return "Expected multi-line comment-terminator.";
case ScannerError::IllegalEscapeSequence: return "Invalid escape sequence.";
@ -759,13 +759,25 @@ Token Scanner::scanHexString()
char const quote = m_char;
advance(); // consume quote
LiteralScope literal(this, LITERAL_TYPE_STRING);
bool allowUnderscore = false;
while (m_char != quote && !isSourcePastEndOfInput())
{
char c = m_char;
if (!scanHexByte(c))
// can only return false if hex-byte is incomplete (only one hex digit instead of two)
if (scanHexByte(c))
{
addLiteralChar(c);
allowUnderscore = true;
}
else if (c == '_')
{
advance();
if (!allowUnderscore || m_char == quote)
return setError(ScannerError::IllegalNumberSeparator);
allowUnderscore = false;
}
else
return setError(ScannerError::IllegalHexString);
addLiteralChar(c);
}
if (m_char != quote)

View File

@ -0,0 +1,7 @@
contract C {
function f() public pure returns(bytes memory) {
return hex"12_34_5678_9A";
}
}
// ----
// f() -> 32, 5, left(0x123456789A)

View File

@ -0,0 +1,7 @@
contract C {
function f() public pure {
hex"12__34";
}
}
// ----
// ParserError: (52-60): Invalid use of number separator '_'.

View File

@ -0,0 +1,7 @@
contract C {
function f() public pure {
hex"_1234";
}
}
// ----
// ParserError: (52-57): Invalid use of number separator '_'.

View File

@ -0,0 +1,7 @@
contract C {
function f() public pure {
hex"1_234";
}
}
// ----
// ParserError: (52-56): Expected even number of hex-nibbles.

View File

@ -0,0 +1,7 @@
contract C {
function f() public pure {
hex"1234_";
}
}
// ----
// ParserError: (52-61): Invalid use of number separator '_'.

View File

@ -0,0 +1,3 @@
contract C {
bytes constant c = hex"12_3456_789012";
}