From fda86c21f867ab1cd29ca633a035db36f5f5030a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 24 Feb 2023 19:49:42 +0100 Subject: [PATCH] User-defined literal suffixes: Parsing and grammar --- libsolidity/parsing/Parser.cpp | 122 ++++++++++++------ libsolidity/parsing/Parser.h | 1 + .../denominations/finney_invalid.sol | 8 +- .../denominations/szabo_invalid.sol | 8 +- 4 files changed, 91 insertions(+), 48 deletions(-) diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index d791fff03..0c7f561b7 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -36,10 +36,12 @@ #include #include #include + #include -#include +#include #include #include +#include using namespace std; using namespace solidity::langutil; @@ -2000,6 +2002,84 @@ ASTPointer Parser::parseLeftHandSideExpression( } } +ASTPointer Parser::parseLiteral() +{ + RecursionGuard recursionGuard(*this); + ASTNodeFactory nodeFactory(*this); + Token initialToken = m_scanner->currentToken(); + ASTPointer value = make_shared(m_scanner->currentLiteral()); + Literal::Suffix suffix = Literal::SubDenomination::None; + + switch (initialToken) + { + case Token::TrueLiteral: + case Token::FalseLiteral: + case Token::Number: + { + nodeFactory.markEndPosition(); + advance(); + break; + } + case Token::StringLiteral: + case Token::UnicodeStringLiteral: + case Token::HexStringLiteral: + { + while (m_scanner->peekNextToken() == initialToken) + { + advance(); + *value += m_scanner->currentLiteral(); + } + nodeFactory.markEndPosition(); + advance(); + if (m_scanner->currentToken() == Token::Illegal) + fatalParserError(5428_error, to_string(m_scanner->currentError())); + break; + } + default: + solAssert(false); + break; + } + + if (initialToken == Token::Number && ( + TokenTraits::isEtherSubdenomination(m_scanner->currentToken()) || + TokenTraits::isTimeSubdenomination(m_scanner->currentToken()) + )) + { + nodeFactory.markEndPosition(); + suffix = static_cast(m_scanner->currentToken()); + advance(); + } + else if (m_scanner->currentToken() == Token::Identifier) + { + // TODO: Make sure locations are set correctly + ASTPointer suffixName = make_shared(m_scanner->currentLiteral()); + nodeFactory.markEndPosition(); + ASTPointer identifier = nodeFactory.createNode(suffixName); + + advance(); + + if (m_scanner->currentToken() != Token::Period) + suffix = identifier; + else + { + ASTPointer memberAccess = identifier; + do + { + // FIXME: This grabs the semicolon + advance(); + nodeFactory.markEndPosition(); + SourceLocation memberLocation = currentLocation(); + ASTPointer memberName = expectIdentifierToken(); + memberAccess = nodeFactory.createNode(memberAccess, std::move(memberName), std::move(memberLocation)); + } + while (m_scanner->currentToken() == Token::Period); + + suffix = dynamic_pointer_cast(memberAccess); + } + } + return nodeFactory.createNode(initialToken, std::move(value), std::move(suffix)); +} + ASTPointer Parser::parsePrimaryExpression() { RecursionGuard recursionGuard(*this); @@ -2011,50 +2091,12 @@ ASTPointer Parser::parsePrimaryExpression() { case Token::TrueLiteral: case Token::FalseLiteral: - nodeFactory.markEndPosition(); - expression = nodeFactory.createNode(token, getLiteralAndAdvance()); - break; case Token::Number: - if (TokenTraits::isEtherSubdenomination(m_scanner->peekNextToken())) - { - ASTPointer literal = getLiteralAndAdvance(); - nodeFactory.markEndPosition(); - Literal::SubDenomination subdenomination = static_cast(m_scanner->currentToken()); - advance(); - expression = nodeFactory.createNode(token, literal, subdenomination); - } - else if (TokenTraits::isTimeSubdenomination(m_scanner->peekNextToken())) - { - ASTPointer literal = getLiteralAndAdvance(); - nodeFactory.markEndPosition(); - Literal::SubDenomination subdenomination = static_cast(m_scanner->currentToken()); - advance(); - expression = nodeFactory.createNode(token, literal, subdenomination); - } - else - { - nodeFactory.markEndPosition(); - expression = nodeFactory.createNode(token, getLiteralAndAdvance()); - } - break; case Token::StringLiteral: case Token::UnicodeStringLiteral: case Token::HexStringLiteral: - { - string literal = m_scanner->currentLiteral(); - Token firstToken = m_scanner->currentToken(); - while (m_scanner->peekNextToken() == firstToken) - { - advance(); - literal += m_scanner->currentLiteral(); - } - nodeFactory.markEndPosition(); - advance(); - if (m_scanner->currentToken() == Token::Illegal) - fatalParserError(5428_error, to_string(m_scanner->currentError())); - expression = nodeFactory.createNode(token, make_shared(literal)); + expression = parseLiteral(); break; - } case Token::Identifier: nodeFactory.markEndPosition(); expression = nodeFactory.createNode(getLiteralAndAdvance()); diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 02f06c447..f967ea38a 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -160,6 +160,7 @@ private: ASTPointer parseLeftHandSideExpression( ASTPointer const& _partiallyParsedExpression = ASTPointer() ); + ASTPointer parseLiteral(); ASTPointer parsePrimaryExpression(); std::vector> parseFunctionCallListArguments(); diff --git a/test/libsolidity/syntaxTests/denominations/finney_invalid.sol b/test/libsolidity/syntaxTests/denominations/finney_invalid.sol index b7bae7fa7..7641b4584 100644 --- a/test/libsolidity/syntaxTests/denominations/finney_invalid.sol +++ b/test/libsolidity/syntaxTests/denominations/finney_invalid.sol @@ -1,7 +1,7 @@ contract C { - function f() { - uint x = 1 finney; - } + function f() public { + uint x = 1 finney; + } } // ---- -// ParserError 2314: (45-51): Expected ';' but got identifier +// DeclarationError 7576: (56-64): Undeclared identifier. diff --git a/test/libsolidity/syntaxTests/denominations/szabo_invalid.sol b/test/libsolidity/syntaxTests/denominations/szabo_invalid.sol index d206830d5..dd7b760be 100644 --- a/test/libsolidity/syntaxTests/denominations/szabo_invalid.sol +++ b/test/libsolidity/syntaxTests/denominations/szabo_invalid.sol @@ -1,7 +1,7 @@ contract C { - function f() { - uint x = 1 szabo; - } + function f() public { + uint x = 1 szabo; + } } // ---- -// ParserError 2314: (45-50): Expected ';' but got identifier +// DeclarationError 7576: (56-63): Undeclared identifier.