diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 618a0896921c..a9ee90160375 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -1057,16 +1057,16 @@ ASTPointer Parser::parseEmitStatement(ASTPointer const if (m_scanner->currentToken() != Token::Identifier) fatalParserError("Expected event name or path."); - vector> path; + IndexAccessedPath iap; while (true) { - path.push_back(parseIdentifier()); + iap.path.push_back(parseIdentifier()); if (m_scanner->currentToken() != Token::Period) break; m_scanner->next(); }; - auto eventName = expressionFromIndexAccessStructure(path, {}); + auto eventName = expressionFromIndexAccessStructure(iap); expectToken(Token::LParen); vector> arguments; @@ -1098,46 +1098,17 @@ ASTPointer Parser::parseSimpleStatement(ASTPointer const& default: break; } + // At this point, we have 'Identifier "["' or 'Identifier "." Identifier' or 'ElementoryTypeName "["'. - // We parse '(Identifier ("." Identifier)* |ElementaryTypeName) ( "[" Expression "]" )+' + // We parse '(Identifier ("." Identifier)* |ElementaryTypeName) ( "[" Expression "]" )*' // until we can decide whether to hand this over to ExpressionStatement or create a // VariableDeclarationStatement out of it. - vector> path; - bool startedWithElementary = false; - if (m_scanner->currentToken() == Token::Identifier) - path.push_back(parseIdentifier()); - else - { - startedWithElementary = true; - unsigned firstNum; - unsigned secondNum; - tie(firstNum, secondNum) = m_scanner->currentTokenInfo(); - ElementaryTypeNameToken elemToken(m_scanner->currentToken(), firstNum, secondNum); - path.push_back(ASTNodeFactory(*this).createNode(elemToken)); - m_scanner->next(); - } - while (!startedWithElementary && m_scanner->currentToken() == Token::Period) - { - m_scanner->next(); - path.push_back(parseIdentifier()); - } - vector, SourceLocation>> indices; - while (m_scanner->currentToken() == Token::LBrack) - { - expectToken(Token::LBrack); - ASTPointer index; - if (m_scanner->currentToken() != Token::RBrack) - index = parseExpression(); - SourceLocation indexLocation = path.front()->location(); - indexLocation.end = endPosition(); - indices.push_back(make_pair(index, indexLocation)); - expectToken(Token::RBrack); - } + IndexAccessedPath iap = parseIndexAccessedPath(); if (m_scanner->currentToken() == Token::Identifier || Token::isLocationSpecifier(m_scanner->currentToken())) - return parseVariableDeclarationStatement(_docString, typeNameIndexAccessStructure(path, indices)); + return parseVariableDeclarationStatement(_docString, typeNameFromIndexAccessStructure(iap)); else - return parseExpressionStatement(_docString, expressionFromIndexAccessStructure(path, indices)); + return parseExpressionStatement(_docString, expressionFromIndexAccessStructure(iap)); } ASTPointer Parser::parseVariableDeclarationStatement( @@ -1529,32 +1500,65 @@ Parser::LookAheadInfo Parser::peekStatementType() const return LookAheadInfo::ExpressionStatement; } -ASTPointer Parser::typeNameIndexAccessStructure( - vector> const& _path, - vector, SourceLocation>> const& _indices -) +Parser::IndexAccessedPath Parser::parseIndexAccessedPath() +{ + IndexAccessedPath iap; + if (m_scanner->currentToken() == Token::Identifier) + { + iap.path.push_back(parseIdentifier()); + while (m_scanner->currentToken() == Token::Period) + { + m_scanner->next(); + iap.path.push_back(parseIdentifier()); + } + } + else + { + unsigned firstNum; + unsigned secondNum; + tie(firstNum, secondNum) = m_scanner->currentTokenInfo(); + ElementaryTypeNameToken elemToken(m_scanner->currentToken(), firstNum, secondNum); + iap.path.push_back(ASTNodeFactory(*this).createNode(elemToken)); + m_scanner->next(); + } + while (m_scanner->currentToken() == Token::LBrack) + { + expectToken(Token::LBrack); + ASTPointer index; + if (m_scanner->currentToken() != Token::RBrack) + index = parseExpression(); + SourceLocation indexLocation = iap.path.front()->location(); + indexLocation.end = endPosition(); + iap.indices.push_back(make_pair(index, indexLocation)); + expectToken(Token::RBrack); + } + + return iap; +} + +ASTPointer Parser::typeNameFromIndexAccessStructure(Parser::IndexAccessedPath const& _iap) { - solAssert(!_path.empty(), ""); + solAssert(!_iap.path.empty(), ""); RecursionGuard recursionGuard(*this); ASTNodeFactory nodeFactory(*this); - SourceLocation location = _path.front()->location(); - location.end = _path.back()->location().end; + SourceLocation location = _iap.path.front()->location(); + location.end = _iap.path.back()->location().end; nodeFactory.setLocation(location); ASTPointer type; - if (auto typeName = dynamic_cast(_path.front().get())) + if (auto typeName = dynamic_cast(_iap.path.front().get())) { - solAssert(_path.size() == 1, ""); + solAssert(_iap.path.size() == 1, ""); type = nodeFactory.createNode(typeName->typeName()); } else { vector path; - for (auto const& el: _path) + for (auto const& el: _iap.path) path.push_back(dynamic_cast(*el).name()); type = nodeFactory.createNode(path); } - for (auto const& lengthExpression: _indices) + for (auto const& lengthExpression: _iap.indices) { nodeFactory.setLocation(lengthExpression.second); type = nodeFactory.createNode(type, lengthExpression.first); @@ -1563,26 +1567,25 @@ ASTPointer Parser::typeNameIndexAccessStructure( } ASTPointer Parser::expressionFromIndexAccessStructure( - vector> const& _path, - vector, SourceLocation>> const& _indices + Parser::IndexAccessedPath const& _iap ) { - solAssert(!_path.empty(), ""); + solAssert(!_iap.path.empty(), ""); RecursionGuard recursionGuard(*this); - ASTNodeFactory nodeFactory(*this, _path.front()); - ASTPointer expression(_path.front()); - for (size_t i = 1; i < _path.size(); ++i) + ASTNodeFactory nodeFactory(*this, _iap.path.front()); + ASTPointer expression(_iap.path.front()); + for (size_t i = 1; i < _iap.path.size(); ++i) { - SourceLocation location(_path.front()->location()); - location.end = _path[i]->location().end; + SourceLocation location(_iap.path.front()->location()); + location.end = _iap.path[i]->location().end; nodeFactory.setLocation(location); - Identifier const& identifier = dynamic_cast(*_path[i]); + Identifier const& identifier = dynamic_cast(*_iap.path[i]); expression = nodeFactory.createNode( expression, make_shared(identifier.name()) ); } - for (auto const& index: _indices) + for (auto const& index: _iap.indices) { nodeFactory.setLocation(index.second); expression = nodeFactory.createNode(expression, index.first); diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index eb120a6149ef..c425423124f4 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -145,21 +145,25 @@ class Parser: public ParserBase { IndexAccessStructure, VariableDeclarationStatement, ExpressionStatement }; + /// Structure that represents a.b.c[x][y][z]. Can be converted either to an expression + /// or to a type name. Path cannot be empty, but indices can be empty. + struct IndexAccessedPath + { + std::vector> path; + std::vector, SourceLocation>> indices; + }; /// Performs limited look-ahead to distinguish between variable declaration and expression statement. /// For source code of the form "a[][8]" ("IndexAccessStructure"), this is not possible to /// decide with constant look-ahead. LookAheadInfo peekStatementType() const; + /// @returns an IndexAccessedPath as a prestage to parsing a variable declaration (type name) + /// or an expression; + IndexAccessedPath parseIndexAccessedPath(); /// @returns a typename parsed in look-ahead fashion from something like "a.b[8][2**70]". - ASTPointer typeNameIndexAccessStructure( - std::vector> const& _path, - std::vector, SourceLocation>> const& _indices - ); + ASTPointer typeNameFromIndexAccessStructure(IndexAccessedPath const& _pathAndIndices); /// @returns an expression parsed in look-ahead fashion from something like "a.b[8][2**70]". - ASTPointer expressionFromIndexAccessStructure( - std::vector> const& _path, - std::vector, SourceLocation>> const& _indices - ); + ASTPointer expressionFromIndexAccessStructure(IndexAccessedPath const& _pathAndIndices); std::string currentTokenName(); Token::Value expectAssignmentOperator();