From 6f3341a2047b3b0c806340df057254b0743e3579 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 6 Sep 2019 15:29:51 +0200 Subject: [PATCH] Allow underscores in hex strings. --- Changelog.md | 1 + docs/types/value-types.rst | 2 +- liblangutil/Scanner.cpp | 20 +++++++++++++++---- .../literals/hex_string_with_underscore.sol | 7 +++++++ .../hex_string_duplicate_underscore.sol | 7 +++++++ .../hex_string_leading_underscore.sol | 7 +++++++ .../hex_string_misaligned_underscore.sol | 7 +++++++ .../hex_string_trailing_underscore.sol | 7 +++++++ .../literals/hex_string_underscores_valid.sol | 3 +++ 9 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol create mode 100644 test/libsolidity/syntaxTests/literals/hex_string_duplicate_underscore.sol create mode 100644 test/libsolidity/syntaxTests/literals/hex_string_leading_underscore.sol create mode 100644 test/libsolidity/syntaxTests/literals/hex_string_misaligned_underscore.sol create mode 100644 test/libsolidity/syntaxTests/literals/hex_string_trailing_underscore.sol create mode 100644 test/libsolidity/syntaxTests/literals/hex_string_underscores_valid.sol diff --git a/Changelog.md b/Changelog.md index 224a8331c..246bd074e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Breaking changes: Language Features: * Allow global enums and structs. + * Allow underscores as delimiters in hex strings. Compiler Features: diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index d03a4c55f..68782027d 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -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 ` and have the same convertibility restrictions. diff --git a/liblangutil/Scanner.cpp b/liblangutil/Scanner.cpp index a317c79b6..82b19d8cf 100644 --- a/liblangutil/Scanner.cpp +++ b/liblangutil/Scanner.cpp @@ -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) diff --git a/test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol b/test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol new file mode 100644 index 000000000..db7f70f83 --- /dev/null +++ b/test/libsolidity/semanticTests/literals/hex_string_with_underscore.sol @@ -0,0 +1,7 @@ +contract C { + function f() public pure returns(bytes memory) { + return hex"12_34_5678_9A"; + } +} +// ---- +// f() -> 32, 5, left(0x123456789A) diff --git a/test/libsolidity/syntaxTests/literals/hex_string_duplicate_underscore.sol b/test/libsolidity/syntaxTests/literals/hex_string_duplicate_underscore.sol new file mode 100644 index 000000000..822cd826f --- /dev/null +++ b/test/libsolidity/syntaxTests/literals/hex_string_duplicate_underscore.sol @@ -0,0 +1,7 @@ +contract C { + function f() public pure { + hex"12__34"; + } +} +// ---- +// ParserError: (52-60): Invalid use of number separator '_'. diff --git a/test/libsolidity/syntaxTests/literals/hex_string_leading_underscore.sol b/test/libsolidity/syntaxTests/literals/hex_string_leading_underscore.sol new file mode 100644 index 000000000..320b181b8 --- /dev/null +++ b/test/libsolidity/syntaxTests/literals/hex_string_leading_underscore.sol @@ -0,0 +1,7 @@ +contract C { + function f() public pure { + hex"_1234"; + } +} +// ---- +// ParserError: (52-57): Invalid use of number separator '_'. diff --git a/test/libsolidity/syntaxTests/literals/hex_string_misaligned_underscore.sol b/test/libsolidity/syntaxTests/literals/hex_string_misaligned_underscore.sol new file mode 100644 index 000000000..d0b945530 --- /dev/null +++ b/test/libsolidity/syntaxTests/literals/hex_string_misaligned_underscore.sol @@ -0,0 +1,7 @@ +contract C { + function f() public pure { + hex"1_234"; + } +} +// ---- +// ParserError: (52-56): Expected even number of hex-nibbles. diff --git a/test/libsolidity/syntaxTests/literals/hex_string_trailing_underscore.sol b/test/libsolidity/syntaxTests/literals/hex_string_trailing_underscore.sol new file mode 100644 index 000000000..c098587ac --- /dev/null +++ b/test/libsolidity/syntaxTests/literals/hex_string_trailing_underscore.sol @@ -0,0 +1,7 @@ +contract C { + function f() public pure { + hex"1234_"; + } +} +// ---- +// ParserError: (52-61): Invalid use of number separator '_'. diff --git a/test/libsolidity/syntaxTests/literals/hex_string_underscores_valid.sol b/test/libsolidity/syntaxTests/literals/hex_string_underscores_valid.sol new file mode 100644 index 000000000..64ece5a40 --- /dev/null +++ b/test/libsolidity/syntaxTests/literals/hex_string_underscores_valid.sol @@ -0,0 +1,3 @@ +contract C { + bytes constant c = hex"12_3456_789012"; +}