/* This file is part of cpp-ethereum. cpp-ethereum is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. */ /** * @author Christian <c@ethdev.com> * @date 2014 * Solidity parser. */ #include <vector> #include <libdevcore/Log.h> #include <libevmcore/SourceLocation.h> #include <libsolidity/Parser.h> #include <libsolidity/Scanner.h> #include <libsolidity/Exceptions.h> using namespace std; namespace dev { namespace solidity { /// AST node factory that also tracks the begin and end position of an AST node /// while it is being parsed class Parser::ASTNodeFactory { public: ASTNodeFactory(Parser const& _parser): m_parser(_parser), m_location(_parser.getPosition(), -1, _parser.getSourceName()) {} ASTNodeFactory(Parser const& _parser, ASTPointer<ASTNode> const& _childNode): m_parser(_parser), m_location(_childNode->getLocation()) {} void markEndPosition() { m_location.end = m_parser.getEndPosition(); } void setLocation(SourceLocation const& _location) { m_location = _location; } void setLocationEmpty() { m_location.end = m_location.start; } /// Set the end position to the one of the given node. void setEndPositionFromNode(ASTPointer<ASTNode> const& _node) { m_location.end = _node->getLocation().end; } template <class NodeType, typename... Args> ASTPointer<NodeType> createNode(Args&& ... _args) { if (m_location.end < 0) markEndPosition(); return make_shared<NodeType>(m_location, forward<Args>(_args)...); } private: Parser const& m_parser; SourceLocation m_location; }; ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner) { m_scanner = _scanner; ASTNodeFactory nodeFactory(*this); vector<ASTPointer<ASTNode>> nodes; while (_scanner->getCurrentToken() != Token::EOS) { switch (m_scanner->getCurrentToken()) { case Token::Import: nodes.push_back(parseImportDirective()); break; case Token::Contract: nodes.push_back(parseContractDefinition()); break; default: BOOST_THROW_EXCEPTION(createParserError(std::string("Expected import directive or contract definition."))); } } return nodeFactory.createNode<SourceUnit>(nodes); } std::shared_ptr<const string> const& Parser::getSourceName() const { return m_scanner->getSourceName(); } int Parser::getPosition() const { return m_scanner->getCurrentLocation().start; } int Parser::getEndPosition() const { return m_scanner->getCurrentLocation().end; } ASTPointer<ImportDirective> Parser::parseImportDirective() { ASTNodeFactory nodeFactory(*this); expectToken(Token::Import); if (m_scanner->getCurrentToken() != Token::StringLiteral) BOOST_THROW_EXCEPTION(createParserError("Expected string literal (URL).")); ASTPointer<ASTString> url = getLiteralAndAdvance(); nodeFactory.markEndPosition(); expectToken(Token::Semicolon); return nodeFactory.createNode<ImportDirective>(url); } ASTPointer<ContractDefinition> Parser::parseContractDefinition() { ASTNodeFactory nodeFactory(*this); ASTPointer<ASTString> docString; if (m_scanner->getCurrentCommentLiteral() != "") docString = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral()); expectToken(Token::Contract); ASTPointer<ASTString> name = expectIdentifierToken(); vector<ASTPointer<InheritanceSpecifier>> baseContracts; vector<ASTPointer<StructDefinition>> structs; vector<ASTPointer<EnumDefinition>> enums; vector<ASTPointer<VariableDeclaration>> stateVariables; vector<ASTPointer<FunctionDefinition>> functions; vector<ASTPointer<ModifierDefinition>> modifiers; vector<ASTPointer<EventDefinition>> events; if (m_scanner->getCurrentToken() == Token::Is) do { m_scanner->next(); baseContracts.push_back(parseInheritanceSpecifier()); } while (m_scanner->getCurrentToken() == Token::Comma); expectToken(Token::LBrace); while (true) { Token::Value currentToken = m_scanner->getCurrentToken(); if (currentToken == Token::RBrace) break; else if (currentToken == Token::Function) functions.push_back(parseFunctionDefinition(name.get())); else if (currentToken == Token::Struct) structs.push_back(parseStructDefinition()); else if (currentToken == Token::Enum) enums.push_back(parseEnumDefinition()); else if (currentToken == Token::Identifier || currentToken == Token::Mapping || Token::isElementaryTypeName(currentToken)) { VarDeclParserOptions options; options.isStateVariable = true; options.allowInitialValue = true; stateVariables.push_back(parseVariableDeclaration(options)); expectToken(Token::Semicolon); } else if (currentToken == Token::Modifier) modifiers.push_back(parseModifierDefinition()); else if (currentToken == Token::Event) events.push_back(parseEventDefinition()); else BOOST_THROW_EXCEPTION(createParserError("Function, variable, struct or modifier declaration expected.")); } nodeFactory.markEndPosition(); expectToken(Token::RBrace); return nodeFactory.createNode<ContractDefinition>(name, docString, baseContracts, structs, enums, stateVariables, functions, modifiers, events); } ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier() { ASTNodeFactory nodeFactory(*this); ASTPointer<Identifier> name(parseIdentifier()); vector<ASTPointer<Expression>> arguments; if (m_scanner->getCurrentToken() == Token::LParen) { m_scanner->next(); arguments = parseFunctionCallListArguments(); nodeFactory.markEndPosition(); expectToken(Token::RParen); } else nodeFactory.setEndPositionFromNode(name); return nodeFactory.createNode<InheritanceSpecifier>(name, arguments); } Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token) { Declaration::Visibility visibility(Declaration::Visibility::Default); if (_token == Token::Public) visibility = Declaration::Visibility::Public; else if (_token == Token::Internal) visibility = Declaration::Visibility::Internal; else if (_token == Token::Private) visibility = Declaration::Visibility::Private; else if (_token == Token::External) visibility = Declaration::Visibility::External; else solAssert(false, "Invalid visibility specifier."); m_scanner->next(); return visibility; } ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* _contractName) { ASTNodeFactory nodeFactory(*this); ASTPointer<ASTString> docstring; if (m_scanner->getCurrentCommentLiteral() != "") docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral()); expectToken(Token::Function); ASTPointer<ASTString> name; if (m_scanner->getCurrentToken() == Token::LParen) name = make_shared<ASTString>(); // anonymous function else name = expectIdentifierToken(); ASTPointer<ParameterList> parameters(parseParameterList()); bool isDeclaredConst = false; Declaration::Visibility visibility(Declaration::Visibility::Default); vector<ASTPointer<ModifierInvocation>> modifiers; while (true) { Token::Value token = m_scanner->getCurrentToken(); if (token == Token::Const) { isDeclaredConst = true; m_scanner->next(); } else if (token == Token::Identifier) modifiers.push_back(parseModifierInvocation()); else if (Token::isVisibilitySpecifier(token)) { if (visibility != Declaration::Visibility::Default) BOOST_THROW_EXCEPTION(createParserError("Multiple visibility specifiers.")); visibility = parseVisibilitySpecifier(token); } else break; } ASTPointer<ParameterList> returnParameters; if (m_scanner->getCurrentToken() == Token::Returns) { bool const permitEmptyParameterList = false; m_scanner->next(); returnParameters = parseParameterList(permitEmptyParameterList); } else returnParameters = createEmptyParameterList(); ASTPointer<Block> block = parseBlock(); nodeFactory.setEndPositionFromNode(block); bool const c_isConstructor = (_contractName && *name == *_contractName); return nodeFactory.createNode<FunctionDefinition>(name, visibility, c_isConstructor, docstring, parameters, isDeclaredConst, modifiers, returnParameters, block); } ASTPointer<StructDefinition> Parser::parseStructDefinition() { ASTNodeFactory nodeFactory(*this); expectToken(Token::Struct); ASTPointer<ASTString> name = expectIdentifierToken(); vector<ASTPointer<VariableDeclaration>> members; expectToken(Token::LBrace); while (m_scanner->getCurrentToken() != Token::RBrace) { members.push_back(parseVariableDeclaration()); expectToken(Token::Semicolon); } nodeFactory.markEndPosition(); expectToken(Token::RBrace); return nodeFactory.createNode<StructDefinition>(name, members); } ASTPointer<EnumValue> Parser::parseEnumValue() { ASTNodeFactory nodeFactory(*this); nodeFactory.markEndPosition(); return nodeFactory.createNode<EnumValue>(expectIdentifierToken()); } ASTPointer<EnumDefinition> Parser::parseEnumDefinition() { ASTNodeFactory nodeFactory(*this); expectToken(Token::Enum); ASTPointer<ASTString> name = expectIdentifierToken(); vector<ASTPointer<EnumValue>> members; expectToken(Token::LBrace); while (m_scanner->getCurrentToken() != Token::RBrace) { members.push_back(parseEnumValue()); if (m_scanner->getCurrentToken() == Token::RBrace) break; expectToken(Token::Comma); if (m_scanner->getCurrentToken() != Token::Identifier) BOOST_THROW_EXCEPTION(createParserError("Expected Identifier after ','")); } nodeFactory.markEndPosition(); expectToken(Token::RBrace); return nodeFactory.createNode<EnumDefinition>(name, members); } ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( VarDeclParserOptions const& _options, ASTPointer<TypeName> const& _lookAheadArrayType) { ASTNodeFactory nodeFactory = _lookAheadArrayType ? ASTNodeFactory(*this, _lookAheadArrayType) : ASTNodeFactory(*this); ASTPointer<TypeName> type; if (_lookAheadArrayType) type = _lookAheadArrayType; else { type = parseTypeName(_options.allowVar); if (type != nullptr) nodeFactory.setEndPositionFromNode(type); } bool isIndexed = false; ASTPointer<ASTString> identifier; Token::Value token = m_scanner->getCurrentToken(); Declaration::Visibility visibility(Declaration::Visibility::Default); if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token)) visibility = parseVisibilitySpecifier(token); if (_options.allowIndexed && token == Token::Indexed) { isIndexed = true; m_scanner->next(); } nodeFactory.markEndPosition(); if (_options.allowEmptyName && m_scanner->getCurrentToken() != Token::Identifier) { identifier = make_shared<ASTString>(""); solAssert(type != nullptr, ""); nodeFactory.setEndPositionFromNode(type); } else identifier = expectIdentifierToken(); ASTPointer<Expression> value; if (_options.allowInitialValue) { if (m_scanner->getCurrentToken() == Token::Assign) { m_scanner->next(); value = parseExpression(); nodeFactory.setEndPositionFromNode(value); } } return nodeFactory.createNode<VariableDeclaration>(type, identifier, value, visibility, _options.isStateVariable, isIndexed); } ASTPointer<ModifierDefinition> Parser::parseModifierDefinition() { ScopeGuard resetModifierFlag([this]() { m_insideModifier = false; }); m_insideModifier = true; ASTNodeFactory nodeFactory(*this); ASTPointer<ASTString> docstring; if (m_scanner->getCurrentCommentLiteral() != "") docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral()); expectToken(Token::Modifier); ASTPointer<ASTString> name(expectIdentifierToken()); ASTPointer<ParameterList> parameters; if (m_scanner->getCurrentToken() == Token::LParen) parameters = parseParameterList(); else parameters = createEmptyParameterList(); ASTPointer<Block> block = parseBlock(); nodeFactory.setEndPositionFromNode(block); return nodeFactory.createNode<ModifierDefinition>(name, docstring, parameters, block); } ASTPointer<EventDefinition> Parser::parseEventDefinition() { ASTNodeFactory nodeFactory(*this); ASTPointer<ASTString> docstring; if (m_scanner->getCurrentCommentLiteral() != "") docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral()); expectToken(Token::Event); ASTPointer<ASTString> name(expectIdentifierToken()); ASTPointer<ParameterList> parameters; if (m_scanner->getCurrentToken() == Token::LParen) parameters = parseParameterList(true, true); else parameters = createEmptyParameterList(); nodeFactory.markEndPosition(); expectToken(Token::Semicolon); return nodeFactory.createNode<EventDefinition>(name, docstring, parameters); } ASTPointer<ModifierInvocation> Parser::parseModifierInvocation() { ASTNodeFactory nodeFactory(*this); ASTPointer<Identifier> name(parseIdentifier()); vector<ASTPointer<Expression>> arguments; if (m_scanner->getCurrentToken() == Token::LParen) { m_scanner->next(); arguments = parseFunctionCallListArguments(); nodeFactory.markEndPosition(); expectToken(Token::RParen); } else nodeFactory.setEndPositionFromNode(name); return nodeFactory.createNode<ModifierInvocation>(name, arguments); } ASTPointer<Identifier> Parser::parseIdentifier() { ASTNodeFactory nodeFactory(*this); nodeFactory.markEndPosition(); return nodeFactory.createNode<Identifier>(expectIdentifierToken()); } ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) { ASTNodeFactory nodeFactory(*this); ASTPointer<TypeName> type; Token::Value token = m_scanner->getCurrentToken(); if (Token::isElementaryTypeName(token)) { type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(token); m_scanner->next(); } else if (token == Token::Var) { if (!_allowVar) BOOST_THROW_EXCEPTION(createParserError("Expected explicit type name.")); m_scanner->next(); } else if (token == Token::Mapping) type = parseMapping(); else if (token == Token::Identifier) { ASTNodeFactory nodeFactory(*this); nodeFactory.markEndPosition(); type = nodeFactory.createNode<UserDefinedTypeName>(expectIdentifierToken()); } else BOOST_THROW_EXCEPTION(createParserError("Expected type name")); // Parse "[...]" postfixes for arrays. while (m_scanner->getCurrentToken() == Token::LBrack) { m_scanner->next(); ASTPointer<Expression> length; if (m_scanner->getCurrentToken() != Token::RBrack) length = parseExpression(); nodeFactory.markEndPosition(); expectToken(Token::RBrack); type = nodeFactory.createNode<ArrayTypeName>(type, length); } return type; } ASTPointer<Mapping> Parser::parseMapping() { ASTNodeFactory nodeFactory(*this); expectToken(Token::Mapping); expectToken(Token::LParen); if (!Token::isElementaryTypeName(m_scanner->getCurrentToken())) BOOST_THROW_EXCEPTION(createParserError("Expected elementary type name for mapping key type")); ASTPointer<ElementaryTypeName> keyType; keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(m_scanner->getCurrentToken()); m_scanner->next(); expectToken(Token::Arrow); bool const allowVar = false; ASTPointer<TypeName> valueType = parseTypeName(allowVar); nodeFactory.markEndPosition(); expectToken(Token::RParen); return nodeFactory.createNode<Mapping>(keyType, valueType); } ASTPointer<ParameterList> Parser::parseParameterList(bool _allowEmpty, bool _allowIndexed) { ASTNodeFactory nodeFactory(*this); vector<ASTPointer<VariableDeclaration>> parameters; VarDeclParserOptions options; options.allowIndexed = _allowIndexed; options.allowEmptyName = true; expectToken(Token::LParen); if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RParen) { parameters.push_back(parseVariableDeclaration(options)); while (m_scanner->getCurrentToken() != Token::RParen) { expectToken(Token::Comma); parameters.push_back(parseVariableDeclaration(options)); } } nodeFactory.markEndPosition(); m_scanner->next(); return nodeFactory.createNode<ParameterList>(parameters); } ASTPointer<Block> Parser::parseBlock() { ASTNodeFactory nodeFactory(*this); expectToken(Token::LBrace); vector<ASTPointer<Statement>> statements; while (m_scanner->getCurrentToken() != Token::RBrace) statements.push_back(parseStatement()); nodeFactory.markEndPosition(); expectToken(Token::RBrace); return nodeFactory.createNode<Block>(statements); } ASTPointer<Statement> Parser::parseStatement() { ASTPointer<Statement> statement; switch (m_scanner->getCurrentToken()) { case Token::If: return parseIfStatement(); case Token::While: return parseWhileStatement(); case Token::For: return parseForStatement(); case Token::LBrace: return parseBlock(); // starting from here, all statements must be terminated by a semicolon case Token::Continue: statement = ASTNodeFactory(*this).createNode<Continue>(); m_scanner->next(); break; case Token::Break: statement = ASTNodeFactory(*this).createNode<Break>(); m_scanner->next(); break; case Token::Return: { ASTNodeFactory nodeFactory(*this); ASTPointer<Expression> expression; if (m_scanner->next() != Token::Semicolon) { expression = parseExpression(); nodeFactory.setEndPositionFromNode(expression); } statement = nodeFactory.createNode<Return>(expression); break; } case Token::Identifier: if (m_insideModifier && m_scanner->getCurrentLiteral() == "_") { statement = ASTNodeFactory(*this).createNode<PlaceholderStatement>(); m_scanner->next(); return statement; } // fall-through default: statement = parseSimpleStatement(); } expectToken(Token::Semicolon); return statement; } ASTPointer<IfStatement> Parser::parseIfStatement() { ASTNodeFactory nodeFactory(*this); expectToken(Token::If); expectToken(Token::LParen); ASTPointer<Expression> condition = parseExpression(); expectToken(Token::RParen); ASTPointer<Statement> trueBody = parseStatement(); ASTPointer<Statement> falseBody; if (m_scanner->getCurrentToken() == Token::Else) { m_scanner->next(); falseBody = parseStatement(); nodeFactory.setEndPositionFromNode(falseBody); } else nodeFactory.setEndPositionFromNode(trueBody); return nodeFactory.createNode<IfStatement>(condition, trueBody, falseBody); } ASTPointer<WhileStatement> Parser::parseWhileStatement() { ASTNodeFactory nodeFactory(*this); expectToken(Token::While); expectToken(Token::LParen); ASTPointer<Expression> condition = parseExpression(); expectToken(Token::RParen); ASTPointer<Statement> body = parseStatement(); nodeFactory.setEndPositionFromNode(body); return nodeFactory.createNode<WhileStatement>(condition, body); } ASTPointer<ForStatement> Parser::parseForStatement() { ASTNodeFactory nodeFactory(*this); ASTPointer<Statement> initExpression; ASTPointer<Expression> conditionExpression; ASTPointer<ExpressionStatement> loopExpression; expectToken(Token::For); expectToken(Token::LParen); // LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen? if (m_scanner->getCurrentToken() != Token::Semicolon) initExpression = parseSimpleStatement(); expectToken(Token::Semicolon); if (m_scanner->getCurrentToken() != Token::Semicolon) conditionExpression = parseExpression(); expectToken(Token::Semicolon); if (m_scanner->getCurrentToken() != Token::RParen) loopExpression = parseExpressionStatement(); expectToken(Token::RParen); ASTPointer<Statement> body = parseStatement(); nodeFactory.setEndPositionFromNode(body); return nodeFactory.createNode<ForStatement>(initExpression, conditionExpression, loopExpression, body); } ASTPointer<Statement> Parser::parseSimpleStatement() { // These two cases are very hard to distinguish: // x[7 * 20 + 3] a; - x[7 * 20 + 3] = 9; // In the first case, x is a type name, in the second it is the name of a variable. switch (peekStatementType()) { case LookAheadInfo::VariableDeclarationStatement: return parseVariableDeclarationStatement(); case LookAheadInfo::ExpressionStatement: return parseExpressionStatement(); default: break; } // At this point, we have '(Identifier|ElementaryTypeName) "["'. // We parse '(Identifier|ElementaryTypeName) ( "[" Expression "]" )+' and then decide whether to hand this over // to ExpressionStatement or create a VariableDeclarationStatement out of it. ASTPointer<PrimaryExpression> primary; if (m_scanner->getCurrentToken() == Token::Identifier) primary = parseIdentifier(); else { primary = ASTNodeFactory(*this).createNode<ElementaryTypeNameExpression>(m_scanner->getCurrentToken()); m_scanner->next(); } vector<pair<ASTPointer<Expression>, SourceLocation>> indices; solAssert(m_scanner->getCurrentToken() == Token::LBrack, ""); SourceLocation indexLocation = primary->getLocation(); do { expectToken(Token::LBrack); ASTPointer<Expression> index; if (m_scanner->getCurrentToken() != Token::RBrack) index = parseExpression(); indexLocation.end = getEndPosition(); indices.push_back(make_pair(index, indexLocation)); expectToken(Token::RBrack); } while (m_scanner->getCurrentToken() == Token::LBrack); if (m_scanner->getCurrentToken() == Token::Identifier) return parseVariableDeclarationStatement(typeNameIndexAccessStructure(primary, indices)); else return parseExpressionStatement(expressionFromIndexAccessStructure(primary, indices)); } ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStatement( ASTPointer<TypeName> const& _lookAheadArrayType) { VarDeclParserOptions options; options.allowVar = true; options.allowInitialValue = true; ASTPointer<VariableDeclaration> variable = parseVariableDeclaration(options, _lookAheadArrayType); ASTNodeFactory nodeFactory(*this, variable); return nodeFactory.createNode<VariableDeclarationStatement>(variable); } ASTPointer<ExpressionStatement> Parser::parseExpressionStatement( ASTPointer<Expression> const& _lookAheadIndexAccessStructure) { ASTPointer<Expression> expression = parseExpression(_lookAheadIndexAccessStructure); return ASTNodeFactory(*this, expression).createNode<ExpressionStatement>(expression); } ASTPointer<Expression> Parser::parseExpression( ASTPointer<Expression> const& _lookAheadIndexAccessStructure) { ASTPointer<Expression> expression = parseBinaryExpression(4, _lookAheadIndexAccessStructure); if (!Token::isAssignmentOp(m_scanner->getCurrentToken())) return expression; Token::Value assignmentOperator = expectAssignmentOperator(); ASTPointer<Expression> rightHandSide = parseExpression(); ASTNodeFactory nodeFactory(*this, expression); nodeFactory.setEndPositionFromNode(rightHandSide); return nodeFactory.createNode<Assignment>(expression, assignmentOperator, rightHandSide); } ASTPointer<Expression> Parser::parseBinaryExpression(int _minPrecedence, ASTPointer<Expression> const& _lookAheadIndexAccessStructure) { ASTPointer<Expression> expression = parseUnaryExpression(_lookAheadIndexAccessStructure); ASTNodeFactory nodeFactory(*this, expression); int precedence = Token::precedence(m_scanner->getCurrentToken()); for (; precedence >= _minPrecedence; --precedence) while (Token::precedence(m_scanner->getCurrentToken()) == precedence) { Token::Value op = m_scanner->getCurrentToken(); m_scanner->next(); ASTPointer<Expression> right = parseBinaryExpression(precedence + 1); nodeFactory.setEndPositionFromNode(right); expression = nodeFactory.createNode<BinaryOperation>(expression, op, right); } return expression; } ASTPointer<Expression> Parser::parseUnaryExpression( ASTPointer<Expression> const& _lookAheadIndexAccessStructure) { ASTNodeFactory nodeFactory = _lookAheadIndexAccessStructure ? ASTNodeFactory(*this, _lookAheadIndexAccessStructure) : ASTNodeFactory(*this); Token::Value token = m_scanner->getCurrentToken(); if (!_lookAheadIndexAccessStructure && (Token::isUnaryOp(token) || Token::isCountOp(token))) { // prefix expression m_scanner->next(); ASTPointer<Expression> subExpression = parseUnaryExpression(); nodeFactory.setEndPositionFromNode(subExpression); return nodeFactory.createNode<UnaryOperation>(token, subExpression, true); } else { // potential postfix expression ASTPointer<Expression> subExpression = parseLeftHandSideExpression(_lookAheadIndexAccessStructure); token = m_scanner->getCurrentToken(); if (!Token::isCountOp(token)) return subExpression; nodeFactory.markEndPosition(); m_scanner->next(); return nodeFactory.createNode<UnaryOperation>(token, subExpression, false); } } ASTPointer<Expression> Parser::parseLeftHandSideExpression( ASTPointer<Expression> const& _lookAheadIndexAccessStructure) { ASTNodeFactory nodeFactory = _lookAheadIndexAccessStructure ? ASTNodeFactory(*this, _lookAheadIndexAccessStructure) : ASTNodeFactory(*this); ASTPointer<Expression> expression; if (_lookAheadIndexAccessStructure) expression = _lookAheadIndexAccessStructure; else if (m_scanner->getCurrentToken() == Token::New) { expectToken(Token::New); ASTPointer<Identifier> contractName(parseIdentifier()); nodeFactory.setEndPositionFromNode(contractName); expression = nodeFactory.createNode<NewExpression>(contractName); } else expression = parsePrimaryExpression(); while (true) { switch (m_scanner->getCurrentToken()) { case Token::LBrack: { m_scanner->next(); ASTPointer<Expression> index; if (m_scanner->getCurrentToken() != Token::RBrack) index = parseExpression(); nodeFactory.markEndPosition(); expectToken(Token::RBrack); expression = nodeFactory.createNode<IndexAccess>(expression, index); } break; case Token::Period: { m_scanner->next(); nodeFactory.markEndPosition(); expression = nodeFactory.createNode<MemberAccess>(expression, expectIdentifierToken()); } break; case Token::LParen: { m_scanner->next(); vector<ASTPointer<Expression>> arguments; vector<ASTPointer<ASTString>> names; std::tie(arguments, names) = parseFunctionCallArguments(); nodeFactory.markEndPosition(); expectToken(Token::RParen); expression = nodeFactory.createNode<FunctionCall>(expression, arguments, names); } break; default: return expression; } } } ASTPointer<Expression> Parser::parsePrimaryExpression() { ASTNodeFactory nodeFactory(*this); Token::Value token = m_scanner->getCurrentToken(); ASTPointer<Expression> expression; switch (token) { case Token::TrueLiteral: case Token::FalseLiteral: expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance()); break; case Token::Number: if (Token::isEtherSubdenomination(m_scanner->peekNextToken())) { ASTPointer<ASTString> literal = getLiteralAndAdvance(); nodeFactory.markEndPosition(); Literal::SubDenomination subdenomination = static_cast<Literal::SubDenomination>(m_scanner->getCurrentToken()); m_scanner->next(); expression = nodeFactory.createNode<Literal>(token, literal, subdenomination); break; } // fall-through case Token::StringLiteral: nodeFactory.markEndPosition(); expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance()); break; case Token::Identifier: nodeFactory.markEndPosition(); expression = nodeFactory.createNode<Identifier>(getLiteralAndAdvance()); break; case Token::LParen: { m_scanner->next(); ASTPointer<Expression> expression = parseExpression(); expectToken(Token::RParen); return expression; } default: if (Token::isElementaryTypeName(token)) { // used for casts expression = nodeFactory.createNode<ElementaryTypeNameExpression>(token); m_scanner->next(); } else BOOST_THROW_EXCEPTION(createParserError("Expected primary expression.")); break; } return expression; } vector<ASTPointer<Expression>> Parser::parseFunctionCallListArguments() { vector<ASTPointer<Expression>> arguments; if (m_scanner->getCurrentToken() != Token::RParen) { arguments.push_back(parseExpression()); while (m_scanner->getCurrentToken() != Token::RParen) { expectToken(Token::Comma); arguments.push_back(parseExpression()); } } return arguments; } pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> Parser::parseFunctionCallArguments() { pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> ret; Token::Value token = m_scanner->getCurrentToken(); if (token == Token::LBrace) { // call({arg1 : 1, arg2 : 2 }) expectToken(Token::LBrace); while (m_scanner->getCurrentToken() != Token::RBrace) { ret.second.push_back(expectIdentifierToken()); expectToken(Token::Colon); ret.first.push_back(parseExpression()); if (m_scanner->getCurrentToken() == Token::Comma) expectToken(Token::Comma); else break; } expectToken(Token::RBrace); } else ret.first = parseFunctionCallListArguments(); return ret; } Parser::LookAheadInfo Parser::peekStatementType() const { // Distinguish between variable declaration (and potentially assignment) and expression statement // (which include assignments to other expressions and pre-declared variables). // We have a variable declaration if we get a keyword that specifies a type name. // If it is an identifier or an elementary type name followed by an identifier, we also have // a variable declaration. // If we get an identifier followed by a "[", it can be both ("type[9] a;" or "arr[9] = 7;"). // In all other cases, we have an expression statement. Token::Value token(m_scanner->getCurrentToken()); bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier); if (token == Token::Mapping || token == Token::Var || (mightBeTypeName && m_scanner->peekNextToken() == Token::Identifier)) return LookAheadInfo::VariableDeclarationStatement; if (mightBeTypeName && m_scanner->peekNextToken() == Token::LBrack) return LookAheadInfo::IndexAccessStructure; return LookAheadInfo::ExpressionStatement; } ASTPointer<TypeName> Parser::typeNameIndexAccessStructure( ASTPointer<PrimaryExpression> const& _primary, vector<pair<ASTPointer<Expression>, SourceLocation>> const& _indices) { ASTNodeFactory nodeFactory(*this, _primary); ASTPointer<TypeName> type; if (auto identifier = dynamic_cast<Identifier const*>(_primary.get())) type = nodeFactory.createNode<UserDefinedTypeName>(make_shared<ASTString>(identifier->getName())); else if (auto typeName = dynamic_cast<ElementaryTypeNameExpression const*>(_primary.get())) type = nodeFactory.createNode<ElementaryTypeName>(typeName->getTypeToken()); else solAssert(false, "Invalid type name for array look-ahead."); for (auto const& lengthExpression: _indices) { nodeFactory.setLocation(lengthExpression.second); type = nodeFactory.createNode<ArrayTypeName>(type, lengthExpression.first); } return type; } ASTPointer<Expression> Parser::expressionFromIndexAccessStructure( ASTPointer<PrimaryExpression> const& _primary, vector<pair<ASTPointer<Expression>, SourceLocation>> const& _indices) { ASTNodeFactory nodeFactory(*this, _primary); ASTPointer<Expression> expression(_primary); for (auto const& index: _indices) { nodeFactory.setLocation(index.second); expression = nodeFactory.createNode<IndexAccess>(expression, index.first); } return expression; } void Parser::expectToken(Token::Value _value) { if (m_scanner->getCurrentToken() != _value) BOOST_THROW_EXCEPTION(createParserError(string("Expected token ") + string(Token::getName(_value)))); m_scanner->next(); } Token::Value Parser::expectAssignmentOperator() { Token::Value op = m_scanner->getCurrentToken(); if (!Token::isAssignmentOp(op)) BOOST_THROW_EXCEPTION(createParserError("Expected assignment operator")); m_scanner->next(); return op; } ASTPointer<ASTString> Parser::expectIdentifierToken() { if (m_scanner->getCurrentToken() != Token::Identifier) BOOST_THROW_EXCEPTION(createParserError("Expected identifier")); return getLiteralAndAdvance(); } ASTPointer<ASTString> Parser::getLiteralAndAdvance() { ASTPointer<ASTString> identifier = make_shared<ASTString>(m_scanner->getCurrentLiteral()); m_scanner->next(); return identifier; } ASTPointer<ParameterList> Parser::createEmptyParameterList() { ASTNodeFactory nodeFactory(*this); nodeFactory.setLocationEmpty(); return nodeFactory.createNode<ParameterList>(vector<ASTPointer<VariableDeclaration>>()); } ParserError Parser::createParserError(string const& _description) const { return ParserError() << errinfo_sourceLocation(SourceLocation(getPosition(), getPosition(), getSourceName())) << errinfo_comment(_description); } } }