Introduce hex literals (#832)

* Introduce hex keyword token

* Support hex literals

* Include tests for hex literals

* Document hex literals
This commit is contained in:
Alex Beregszaszi 2016-08-16 15:31:23 +01:00 committed by chriseth
parent 970260bf0f
commit ec3298535e
5 changed files with 82 additions and 0 deletions

View File

@ -218,6 +218,15 @@ String literals are written with either double or single-quotes (``"foo"`` or ``
String literals support escape characters, such as ``\n``, ``\xNN`` and ``\uNNNN``. ``\xNN`` takes a hex value and inserts the appropriate byte, while ``\uNNNN`` takes a Unicode codepoint and inserts an UTF-8 sequence.
.. index:: literal, bytes
Hexadecimal Literals
--------------------
Hexademical 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.
Hexademical Literals behave like String Literals and have the same convertibility restrictions.
.. index:: enum
.. _enums:

View File

@ -591,7 +591,23 @@ void Scanner::scanToken()
break;
default:
if (isIdentifierStart(m_char))
{
tie(token, m, n) = scanIdentifierOrKeyword();
// Special case for hexademical literals
if (token == Token::Hex)
{
// reset
m = 0;
n = 0;
// Special quoted hex string must follow
if (m_char == '"' || m_char == '\'')
token = scanHexString();
else
token = Token::Illegal;
}
}
else if (isDecimalDigit(m_char))
token = scanNumber();
else if (skipWhitespace())
@ -684,6 +700,25 @@ Token::Value Scanner::scanString()
return Token::StringLiteral;
}
Token::Value Scanner::scanHexString()
{
char const quote = m_char;
advance(); // consume quote
LiteralScope literal(this, LITERAL_TYPE_STRING);
while (m_char != quote && !isSourcePastEndOfInput() && !isLineTerminator(m_char))
{
char c = m_char;
if (!scanHexByte(c))
return Token::Illegal;
addLiteralChar(c);
}
if (m_char != quote)
return Token::Illegal;
literal.complete();
advance(); // consume quote
return Token::StringLiteral;
}
void Scanner::scanDecimalDigits()
{
while (isDecimalDigit(m_char))

View File

@ -203,6 +203,7 @@ private:
std::tuple<Token::Value, unsigned, unsigned> scanIdentifierOrKeyword();
Token::Value scanString();
Token::Value scanHexString();
Token::Value scanSingleLineDocComment();
Token::Value scanMultiLineDocComment();
/// Scans a slash '/' and depending on the characters returns the appropriate token

View File

@ -155,6 +155,7 @@ namespace solidity
K(External, "external", 0) \
K(For, "for", 0) \
K(Function, "function", 0) \
K(Hex, "hex", 0) \
K(If, "if", 0) \
K(Indexed, "indexed", 0) \
K(Internal, "internal", 0) \

View File

@ -324,6 +324,42 @@ BOOST_AUTO_TEST_CASE(invalid_short_unicode_string_escape)
BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal);
}
BOOST_AUTO_TEST_CASE(valid_hex_literal)
{
Scanner scanner(CharStream("{ hex\"00112233FF\""));
BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace);
BOOST_CHECK_EQUAL(scanner.next(), Token::StringLiteral);
BOOST_CHECK_EQUAL(scanner.currentLiteral(), std::string("\x00\x11\x22\x33\xFF", 5));
}
BOOST_AUTO_TEST_CASE(invalid_short_hex_literal)
{
Scanner scanner(CharStream("{ hex\"00112233F\""));
BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace);
BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal);
}
BOOST_AUTO_TEST_CASE(invalid_hex_literal_with_space)
{
Scanner scanner(CharStream("{ hex\"00112233FF \""));
BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace);
BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal);
}
BOOST_AUTO_TEST_CASE(invalid_hex_literal_with_wrong_quotes)
{
Scanner scanner(CharStream("{ hex\"00112233FF'"));
BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace);
BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal);
}
BOOST_AUTO_TEST_CASE(invalid_hex_literal_nonhex_string)
{
Scanner scanner(CharStream("{ hex\"hello\""));
BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace);
BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal);
}
BOOST_AUTO_TEST_SUITE_END()