/src/solidity/libsolidity/parsing/Parser.cpp
Line | Count | Source |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | /** |
19 | | * @author Christian <c@ethdev.com> |
20 | | * @date 2014 |
21 | | * Solidity parser. |
22 | | */ |
23 | | |
24 | | #include <libsolidity/parsing/Parser.h> |
25 | | |
26 | | #include <libsolidity/ast/UserDefinableOperators.h> |
27 | | #include <libsolidity/interface/Version.h> |
28 | | #include <libyul/AST.h> |
29 | | #include <libyul/AsmParser.h> |
30 | | #include <libyul/backends/evm/EVMDialect.h> |
31 | | #include <liblangutil/ErrorReporter.h> |
32 | | #include <liblangutil/Scanner.h> |
33 | | #include <liblangutil/SemVerHandler.h> |
34 | | #include <liblangutil/SourceLocation.h> |
35 | | #include <libyul/backends/evm/EVMDialect.h> |
36 | | #include <boost/algorithm/string/trim.hpp> |
37 | | #include <boost/algorithm/string/replace.hpp> |
38 | | #include <boost/algorithm/string/predicate.hpp> |
39 | | |
40 | | #include <cctype> |
41 | | #include <memory> |
42 | | #include <regex> |
43 | | #include <tuple> |
44 | | #include <vector> |
45 | | |
46 | | using namespace solidity::langutil; |
47 | | using namespace std::string_literals; |
48 | | |
49 | | namespace solidity::frontend |
50 | | { |
51 | | |
52 | | /// AST node factory that also tracks the begin and end position of an AST node |
53 | | /// while it is being parsed |
54 | | class Parser::ASTNodeFactory |
55 | | { |
56 | | public: |
57 | | explicit ASTNodeFactory(Parser& _parser): |
58 | 2.62M | m_parser(_parser), m_location{ |
59 | 2.62M | _parser.currentLocation().start, |
60 | 2.62M | -1, |
61 | 2.62M | _parser.currentLocation().sourceName |
62 | 2.62M | } |
63 | 2.62M | {} |
64 | | ASTNodeFactory(Parser& _parser, ASTPointer<ASTNode> const& _childNode): |
65 | 697k | m_parser(_parser), m_location{_childNode->location()} {} |
66 | | |
67 | 1.29M | void markEndPosition() { m_location.end = m_parser.currentLocation().end; } |
68 | 82.7k | void setLocation(SourceLocation const& _location) { m_location = _location; } |
69 | 23.0k | void setLocationEmpty() { m_location.end = m_location.start; } |
70 | | /// Set the end position to the one of the given node. |
71 | 464k | void setEndPositionFromNode(ASTPointer<ASTNode> const& _node) { m_location.end = _node->location().end; } |
72 | | |
73 | | template <class NodeType, typename... Args> |
74 | | ASTPointer<NodeType> createNode(Args&& ... _args) |
75 | 1.78M | { |
76 | 1.78M | solAssert(m_location.sourceName, ""); |
77 | 1.78M | if (m_location.end < 0) |
78 | 46.7k | markEndPosition(); |
79 | 1.78M | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); |
80 | 1.78M | } std::__1::shared_ptr<solidity::frontend::SourceUnit> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::SourceUnit, std::__1::optional<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::vector<std::__1::shared_ptr<solidity::frontend::ASTNode>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::ASTNode> > >&, bool&>(std::__1::optional<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::ASTNode>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::ASTNode> > >&, bool&) Line | Count | Source | 75 | 27.9k | { | 76 | 27.9k | solAssert(m_location.sourceName, ""); | 77 | 27.9k | if (m_location.end < 0) | 78 | 27.9k | markEndPosition(); | 79 | 27.9k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 27.9k | } |
std::__1::shared_ptr<solidity::frontend::StructuredDocumentation> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::StructuredDocumentation, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&) Line | Count | Source | 75 | 2.37k | { | 76 | 2.37k | solAssert(m_location.sourceName, ""); | 77 | 2.37k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 2.37k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 2.37k | } |
std::__1::shared_ptr<solidity::frontend::PragmaDirective> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::PragmaDirective, std::__1::vector<solidity::langutil::Token, std::__1::allocator<solidity::langutil::Token> >&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&>(std::__1::vector<solidity::langutil::Token, std::__1::allocator<solidity::langutil::Token> >&, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&) Line | Count | Source | 75 | 33.2k | { | 76 | 33.2k | solAssert(m_location.sourceName, ""); | 77 | 33.2k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 33.2k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 33.2k | } |
std::__1::shared_ptr<solidity::frontend::ImportDirective> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ImportDirective, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::vector<solidity::frontend::ImportDirective::SymbolAlias, std::__1::allocator<solidity::frontend::ImportDirective::SymbolAlias> > >(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::vector<solidity::frontend::ImportDirective::SymbolAlias, std::__1::allocator<solidity::frontend::ImportDirective::SymbolAlias> >&&) Line | Count | Source | 75 | 1.76k | { | 76 | 1.76k | solAssert(m_location.sourceName, ""); | 77 | 1.76k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 1.76k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 1.76k | } |
std::__1::shared_ptr<solidity::frontend::StorageLayoutSpecifier> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::StorageLayoutSpecifier, std::__1::shared_ptr<solidity::frontend::Expression>&>(std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 55 | { | 76 | 55 | solAssert(m_location.sourceName, ""); | 77 | 55 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 55 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 55 | } |
std::__1::shared_ptr<solidity::frontend::ContractDefinition> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ContractDefinition, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::InheritanceSpecifier>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::InheritanceSpecifier> > >&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::ASTNode>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::ASTNode> > >&, solidity::frontend::ContractKind&, bool&, std::__1::shared_ptr<solidity::frontend::StorageLayoutSpecifier>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::InheritanceSpecifier>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::InheritanceSpecifier> > >&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::ASTNode>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::ASTNode> > >&, solidity::frontend::ContractKind&, bool&, std::__1::shared_ptr<solidity::frontend::StorageLayoutSpecifier>&) Line | Count | Source | 75 | 27.9k | { | 76 | 27.9k | solAssert(m_location.sourceName, ""); | 77 | 27.9k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 27.9k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 27.9k | } |
std::__1::shared_ptr<solidity::frontend::InheritanceSpecifier> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::InheritanceSpecifier, std::__1::shared_ptr<solidity::frontend::IdentifierPath>&, std::__1::unique_ptr<std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >, std::__1::default_delete<std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > > > > >(std::__1::shared_ptr<solidity::frontend::IdentifierPath>&, std::__1::unique_ptr<std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >, std::__1::default_delete<std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > > > >&&) Line | Count | Source | 75 | 5.37k | { | 76 | 5.37k | solAssert(m_location.sourceName, ""); | 77 | 5.37k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 5.37k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 5.37k | } |
std::__1::shared_ptr<solidity::frontend::OverrideSpecifier> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::OverrideSpecifier, std::__1::vector<std::__1::shared_ptr<solidity::frontend::IdentifierPath>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::IdentifierPath> > > >(std::__1::vector<std::__1::shared_ptr<solidity::frontend::IdentifierPath>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::IdentifierPath> > >&&) Line | Count | Source | 75 | 1.17k | { | 76 | 1.17k | solAssert(m_location.sourceName, ""); | 77 | 1.17k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 1.17k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 1.17k | } |
std::__1::shared_ptr<solidity::frontend::ForAllQuantifier> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ForAllQuantifier, std::__1::shared_ptr<solidity::frontend::ParameterList>, std::__1::shared_ptr<solidity::frontend::FunctionDefinition> >(std::__1::shared_ptr<solidity::frontend::ParameterList>&&, std::__1::shared_ptr<solidity::frontend::FunctionDefinition>&&) Line | Count | Source | 75 | 14 | { | 76 | 14 | solAssert(m_location.sourceName, ""); | 77 | 14 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 14 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 14 | } |
std::__1::shared_ptr<solidity::frontend::FunctionDefinition> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::FunctionDefinition, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, solidity::frontend::Visibility&, solidity::frontend::StateMutability&, bool&, solidity::langutil::Token&, bool&, std::__1::shared_ptr<solidity::frontend::OverrideSpecifier>&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::ModifierInvocation>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::ModifierInvocation> > >&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::shared_ptr<solidity::frontend::Block>&, std::__1::shared_ptr<solidity::frontend::Expression>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, solidity::frontend::Visibility&, solidity::frontend::StateMutability&, bool&, solidity::langutil::Token&, bool&, std::__1::shared_ptr<solidity::frontend::OverrideSpecifier>&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::ModifierInvocation>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::ModifierInvocation> > >&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::shared_ptr<solidity::frontend::Block>&, std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 29.4k | { | 76 | 29.4k | solAssert(m_location.sourceName, ""); | 77 | 29.4k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 29.4k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 29.4k | } |
std::__1::shared_ptr<solidity::frontend::StructDefinition> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::StructDefinition, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, solidity::langutil::SourceLocation, std::__1::vector<std::__1::shared_ptr<solidity::frontend::VariableDeclaration>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::VariableDeclaration> > >, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation> >(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&, solidity::langutil::SourceLocation&&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::VariableDeclaration>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::VariableDeclaration> > >&&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&&) Line | Count | Source | 75 | 9.75k | { | 76 | 9.75k | solAssert(m_location.sourceName, ""); | 77 | 9.75k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 9.75k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 9.75k | } |
std::__1::shared_ptr<solidity::frontend::EnumValue> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::EnumValue, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&) Line | Count | Source | 75 | 2.69k | { | 76 | 2.69k | solAssert(m_location.sourceName, ""); | 77 | 2.69k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 2.69k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 2.69k | } |
std::__1::shared_ptr<solidity::frontend::EnumDefinition> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::EnumDefinition, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::EnumValue>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::EnumValue> > >&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::EnumValue>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::EnumValue> > >&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&) Line | Count | Source | 75 | 632 | { | 76 | 632 | solAssert(m_location.sourceName, ""); | 77 | 632 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 632 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 632 | } |
std::__1::shared_ptr<solidity::frontend::VariableDeclaration> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::VariableDeclaration, std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::Expression>&, solidity::frontend::Visibility&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation> const&, bool&, solidity::frontend::VariableDeclaration::Mutability&, std::__1::shared_ptr<solidity::frontend::OverrideSpecifier>&, solidity::frontend::VariableDeclaration::Location&>(std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::Expression>&, solidity::frontend::Visibility&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation> const&, bool&, solidity::frontend::VariableDeclaration::Mutability&, std::__1::shared_ptr<solidity::frontend::OverrideSpecifier>&, solidity::frontend::VariableDeclaration::Location&) Line | Count | Source | 75 | 96.0k | { | 76 | 96.0k | solAssert(m_location.sourceName, ""); | 77 | 96.0k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 96.0k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 96.0k | } |
std::__1::shared_ptr<solidity::frontend::ModifierDefinition> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ModifierDefinition, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, bool&, std::__1::shared_ptr<solidity::frontend::OverrideSpecifier>&, std::__1::shared_ptr<solidity::frontend::Block>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, bool&, std::__1::shared_ptr<solidity::frontend::OverrideSpecifier>&, std::__1::shared_ptr<solidity::frontend::Block>&) Line | Count | Source | 75 | 3.39k | { | 76 | 3.39k | solAssert(m_location.sourceName, ""); | 77 | 3.39k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 3.39k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 3.39k | } |
std::__1::shared_ptr<solidity::frontend::EventDefinition> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::EventDefinition, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, bool&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, bool&) Line | Count | Source | 75 | 3.83k | { | 76 | 3.83k | solAssert(m_location.sourceName, ""); | 77 | 3.83k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 3.83k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 3.83k | } |
std::__1::shared_ptr<solidity::frontend::ErrorDefinition> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ErrorDefinition, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&) Line | Count | Source | 75 | 1.07k | { | 76 | 1.07k | solAssert(m_location.sourceName, ""); | 77 | 1.07k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 1.07k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 1.07k | } |
std::__1::shared_ptr<solidity::frontend::UsingForDirective> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::UsingForDirective, std::__1::vector<std::__1::shared_ptr<solidity::frontend::IdentifierPath>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::IdentifierPath> > >, std::__1::vector<std::__1::optional<solidity::langutil::Token>, std::__1::allocator<std::__1::optional<solidity::langutil::Token> > >, bool const&, std::__1::shared_ptr<solidity::frontend::TypeName>&, bool&>(std::__1::vector<std::__1::shared_ptr<solidity::frontend::IdentifierPath>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::IdentifierPath> > >&&, std::__1::vector<std::__1::optional<solidity::langutil::Token>, std::__1::allocator<std::__1::optional<solidity::langutil::Token> > >&&, bool const&, std::__1::shared_ptr<solidity::frontend::TypeName>&, bool&) Line | Count | Source | 75 | 825 | { | 76 | 825 | solAssert(m_location.sourceName, ""); | 77 | 825 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 825 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 825 | } |
std::__1::shared_ptr<solidity::frontend::ModifierInvocation> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ModifierInvocation, std::__1::shared_ptr<solidity::frontend::IdentifierPath>&, std::__1::unique_ptr<std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >, std::__1::default_delete<std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > > > > >(std::__1::shared_ptr<solidity::frontend::IdentifierPath>&, std::__1::unique_ptr<std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >, std::__1::default_delete<std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > > > >&&) Line | Count | Source | 75 | 4.19k | { | 76 | 4.19k | solAssert(m_location.sourceName, ""); | 77 | 4.19k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 4.19k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 4.19k | } |
std::__1::shared_ptr<solidity::frontend::Identifier> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Identifier, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&) Line | Count | Source | 75 | 206k | { | 76 | 206k | solAssert(m_location.sourceName, ""); | 77 | 206k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 206k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 206k | } |
std::__1::shared_ptr<solidity::frontend::UserDefinedTypeName> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::UserDefinedTypeName, std::__1::shared_ptr<solidity::frontend::IdentifierPath>&>(std::__1::shared_ptr<solidity::frontend::IdentifierPath>&) Line | Count | Source | 75 | 26.1k | { | 76 | 26.1k | solAssert(m_location.sourceName, ""); | 77 | 26.1k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 26.1k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 26.1k | } |
std::__1::shared_ptr<solidity::frontend::UserDefinedValueTypeDefinition> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::UserDefinedValueTypeDefinition, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation, std::__1::shared_ptr<solidity::frontend::TypeName>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&&, std::__1::shared_ptr<solidity::frontend::TypeName>&) Line | Count | Source | 75 | 735 | { | 76 | 735 | solAssert(m_location.sourceName, ""); | 77 | 735 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 735 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 735 | } |
std::__1::shared_ptr<solidity::frontend::IdentifierPath> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::IdentifierPath, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, std::__1::vector<solidity::langutil::SourceLocation, std::__1::allocator<solidity::langutil::SourceLocation> >&>(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, std::__1::vector<solidity::langutil::SourceLocation, std::__1::allocator<solidity::langutil::SourceLocation> >&) Line | Count | Source | 75 | 39.9k | { | 76 | 39.9k | solAssert(m_location.sourceName, ""); | 77 | 39.9k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 39.9k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 39.9k | } |
std::__1::shared_ptr<solidity::frontend::ArrayTypeName> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ArrayTypeName, std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<solidity::frontend::Expression>&>(std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 24.0k | { | 76 | 24.0k | solAssert(m_location.sourceName, ""); | 77 | 24.0k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 24.0k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 24.0k | } |
std::__1::shared_ptr<solidity::frontend::ElementaryTypeName> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ElementaryTypeName, solidity::langutil::ElementaryTypeNameToken&, std::__1::optional<solidity::frontend::StateMutability>&>(solidity::langutil::ElementaryTypeNameToken&, std::__1::optional<solidity::frontend::StateMutability>&) Line | Count | Source | 75 | 72.6k | { | 76 | 72.6k | solAssert(m_location.sourceName, ""); | 77 | 72.6k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 72.6k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 72.6k | } |
std::__1::shared_ptr<solidity::frontend::FunctionTypeName> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::FunctionTypeName, std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, solidity::frontend::Visibility&, solidity::frontend::StateMutability&>(std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, solidity::frontend::Visibility&, solidity::frontend::StateMutability&) Line | Count | Source | 75 | 1.32k | { | 76 | 1.32k | solAssert(m_location.sourceName, ""); | 77 | 1.32k | if (m_location.end < 0) | 78 | 1.32k | markEndPosition(); | 79 | 1.32k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 1.32k | } |
std::__1::shared_ptr<solidity::frontend::ElementaryTypeName> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ElementaryTypeName, solidity::langutil::ElementaryTypeNameToken>(solidity::langutil::ElementaryTypeNameToken&&) Line | Count | Source | 75 | 13.9k | { | 76 | 13.9k | solAssert(m_location.sourceName, ""); | 77 | 13.9k | if (m_location.end < 0) | 78 | 13.9k | markEndPosition(); | 79 | 13.9k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 13.9k | } |
std::__1::shared_ptr<solidity::frontend::Mapping> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Mapping, std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&>(std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&) Line | Count | Source | 75 | 1.15k | { | 76 | 1.15k | solAssert(m_location.sourceName, ""); | 77 | 1.15k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 1.15k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 1.15k | } |
std::__1::shared_ptr<solidity::frontend::ParameterList> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ParameterList, std::__1::vector<std::__1::shared_ptr<solidity::frontend::VariableDeclaration>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::VariableDeclaration> > >&>(std::__1::vector<std::__1::shared_ptr<solidity::frontend::VariableDeclaration>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::VariableDeclaration> > >&) Line | Count | Source | 75 | 49.5k | { | 76 | 49.5k | solAssert(m_location.sourceName, ""); | 77 | 49.5k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 49.5k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 49.5k | } |
std::__1::shared_ptr<solidity::frontend::Block> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Block, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, bool const&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::Statement>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Statement> > >&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, bool const&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::Statement>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Statement> > >&) Line | Count | Source | 75 | 30.2k | { | 76 | 30.2k | solAssert(m_location.sourceName, ""); | 77 | 30.2k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 30.2k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 30.2k | } |
std::__1::shared_ptr<solidity::frontend::Continue> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Continue, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&) Line | Count | Source | 75 | 105 | { | 76 | 105 | solAssert(m_location.sourceName, ""); | 77 | 105 | if (m_location.end < 0) | 78 | 105 | markEndPosition(); | 79 | 105 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 105 | } |
std::__1::shared_ptr<solidity::frontend::Break> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Break, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&) Line | Count | Source | 75 | 123 | { | 76 | 123 | solAssert(m_location.sourceName, ""); | 77 | 123 | if (m_location.end < 0) | 78 | 123 | markEndPosition(); | 79 | 123 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 123 | } |
std::__1::shared_ptr<solidity::frontend::Return> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Return, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, std::__1::shared_ptr<solidity::frontend::Expression>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 46.9k | { | 76 | 46.9k | solAssert(m_location.sourceName, ""); | 77 | 46.9k | if (m_location.end < 0) | 78 | 407 | markEndPosition(); | 79 | 46.9k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 46.9k | } |
std::__1::shared_ptr<solidity::frontend::Throw> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Throw, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&) Line | Count | Source | 75 | 4 | { | 76 | 4 | solAssert(m_location.sourceName, ""); | 77 | 4 | if (m_location.end < 0) | 78 | 4 | markEndPosition(); | 79 | 4 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 4 | } |
std::__1::shared_ptr<solidity::frontend::PlaceholderStatement> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::PlaceholderStatement, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&) Line | Count | Source | 75 | 1.00k | { | 76 | 1.00k | solAssert(m_location.sourceName, ""); | 77 | 1.00k | if (m_location.end < 0) | 78 | 1.00k | markEndPosition(); | 79 | 1.00k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 1.00k | } |
std::__1::shared_ptr<solidity::frontend::IfStatement> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::IfStatement, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Statement>&, std::__1::shared_ptr<solidity::frontend::Statement>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Statement>&, std::__1::shared_ptr<solidity::frontend::Statement>&) Line | Count | Source | 75 | 38.9k | { | 76 | 38.9k | solAssert(m_location.sourceName, ""); | 77 | 38.9k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 38.9k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 38.9k | } |
std::__1::shared_ptr<solidity::frontend::TryCatchClause> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::TryCatchClause, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::shared_ptr<solidity::frontend::Block>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::shared_ptr<solidity::frontend::Block>&) Line | Count | Source | 75 | 411 | { | 76 | 411 | solAssert(m_location.sourceName, ""); | 77 | 411 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 411 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 411 | } |
std::__1::shared_ptr<solidity::frontend::TryStatement> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::TryStatement, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::TryCatchClause>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::TryCatchClause> > >&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::TryCatchClause>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::TryCatchClause> > >&) Line | Count | Source | 75 | 311 | { | 76 | 311 | solAssert(m_location.sourceName, ""); | 77 | 311 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 311 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 311 | } |
std::__1::shared_ptr<solidity::frontend::TryCatchClause> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::TryCatchClause, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::shared_ptr<solidity::frontend::Block>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::shared_ptr<solidity::frontend::Block>&) Line | Count | Source | 75 | 587 | { | 76 | 587 | solAssert(m_location.sourceName, ""); | 77 | 587 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 587 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 587 | } |
std::__1::shared_ptr<solidity::frontend::WhileStatement> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::WhileStatement, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Statement>&, bool>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Statement>&, bool&&) Line | Count | Source | 75 | 271 | { | 76 | 271 | solAssert(m_location.sourceName, ""); | 77 | 271 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 271 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 271 | } |
std::__1::shared_ptr<solidity::frontend::ForStatement> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ForStatement, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::Statement>&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::ExpressionStatement>&, std::__1::shared_ptr<solidity::frontend::Statement>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::Statement>&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::ExpressionStatement>&, std::__1::shared_ptr<solidity::frontend::Statement>&) Line | Count | Source | 75 | 3.23k | { | 76 | 3.23k | solAssert(m_location.sourceName, ""); | 77 | 3.23k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 3.23k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 3.23k | } |
std::__1::shared_ptr<solidity::frontend::FunctionCall> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::FunctionCall, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >&, std::__1::vector<std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >&, std::__1::vector<solidity::langutil::SourceLocation, std::__1::allocator<solidity::langutil::SourceLocation> >&>(std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >&, std::__1::vector<std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >&, std::__1::vector<solidity::langutil::SourceLocation, std::__1::allocator<solidity::langutil::SourceLocation> >&) Line | Count | Source | 75 | 39.7k | { | 76 | 39.7k | solAssert(m_location.sourceName, ""); | 77 | 39.7k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 39.7k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 39.7k | } |
std::__1::shared_ptr<solidity::frontend::EmitStatement> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::EmitStatement, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::FunctionCall>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::FunctionCall>&) Line | Count | Source | 75 | 1.57k | { | 76 | 1.57k | solAssert(m_location.sourceName, ""); | 77 | 1.57k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 1.57k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 1.57k | } |
std::__1::shared_ptr<solidity::frontend::RevertStatement> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::RevertStatement, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::FunctionCall>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::FunctionCall>&) Line | Count | Source | 75 | 87 | { | 76 | 87 | solAssert(m_location.sourceName, ""); | 77 | 87 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 87 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 87 | } |
std::__1::shared_ptr<solidity::frontend::VariableDeclarationStatement> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::VariableDeclarationStatement, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::VariableDeclaration>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::VariableDeclaration> > >&, std::__1::shared_ptr<solidity::frontend::Expression>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::VariableDeclaration>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::VariableDeclaration> > >&, std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 12.5k | { | 76 | 12.5k | solAssert(m_location.sourceName, ""); | 77 | 12.5k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 12.5k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 12.5k | } |
std::__1::shared_ptr<solidity::frontend::VariableDeclaration> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::VariableDeclaration, decltype(nullptr), std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, decltype(nullptr), solidity::frontend::Visibility, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation> const&, bool, solidity::frontend::VariableDeclaration::Mutability, decltype(nullptr), solidity::frontend::VariableDeclaration::Location, std::__1::shared_ptr<solidity::frontend::Expression>&>(decltype(nullptr)&&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, decltype(nullptr)&&, solidity::frontend::Visibility&&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation> const&, bool&&, solidity::frontend::VariableDeclaration::Mutability&&, decltype(nullptr)&&, solidity::frontend::VariableDeclaration::Location&&, std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 260 | { | 76 | 260 | solAssert(m_location.sourceName, ""); | 77 | 260 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 260 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 260 | } |
std::__1::shared_ptr<solidity::frontend::VariableDeclaration> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::VariableDeclaration, decltype(nullptr), std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, decltype(nullptr), solidity::frontend::Visibility, decltype(nullptr)>(decltype(nullptr)&&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, decltype(nullptr)&&, solidity::frontend::Visibility&&, decltype(nullptr)&&) Line | Count | Source | 75 | 60 | { | 76 | 60 | solAssert(m_location.sourceName, ""); | 77 | 60 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 60 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 60 | } |
std::__1::shared_ptr<solidity::frontend::TypeClassDefinition> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::TypeClassDefinition, std::__1::shared_ptr<solidity::frontend::VariableDeclaration>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation> const&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::ASTNode>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::ASTNode> > >&>(std::__1::shared_ptr<solidity::frontend::VariableDeclaration>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&, solidity::langutil::SourceLocation&, std::__1::shared_ptr<solidity::frontend::StructuredDocumentation> const&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::ASTNode>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::ASTNode> > >&) Line | Count | Source | 75 | 48 | { | 76 | 48 | solAssert(m_location.sourceName, ""); | 77 | 48 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 48 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 48 | } |
std::__1::shared_ptr<solidity::frontend::TypeClassName> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::TypeClassName, std::__1::variant<solidity::langutil::Token, std::__1::shared_ptr<solidity::frontend::IdentifierPath> >&>(std::__1::variant<solidity::langutil::Token, std::__1::shared_ptr<solidity::frontend::IdentifierPath> >&) Line | Count | Source | 75 | 54 | { | 76 | 54 | solAssert(m_location.sourceName, ""); | 77 | 54 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 54 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 54 | } |
std::__1::shared_ptr<solidity::frontend::TypeClassInstantiation> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::TypeClassInstantiation, std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::shared_ptr<solidity::frontend::TypeClassName>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::ASTNode>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::ASTNode> > >&>(std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<solidity::frontend::ParameterList>&, std::__1::shared_ptr<solidity::frontend::TypeClassName>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::ASTNode>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::ASTNode> > >&) Line | Count | Source | 75 | 38 | { | 76 | 38 | solAssert(m_location.sourceName, ""); | 77 | 38 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 38 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 38 | } |
std::__1::shared_ptr<solidity::frontend::Builtin> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Builtin, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, solidity::langutil::SourceLocation>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&, solidity::langutil::SourceLocation&&) Line | Count | Source | 75 | 26 | { | 76 | 26 | solAssert(m_location.sourceName, ""); | 77 | 26 | if (m_location.end < 0) | 78 | 26 | markEndPosition(); | 79 | 26 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 26 | } |
std::__1::shared_ptr<solidity::frontend::TypeDefinition> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::TypeDefinition, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, solidity::langutil::SourceLocation, std::__1::shared_ptr<solidity::frontend::ParameterList>, std::__1::shared_ptr<solidity::frontend::Expression> >(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&, solidity::langutil::SourceLocation&&, std::__1::shared_ptr<solidity::frontend::ParameterList>&&, std::__1::shared_ptr<solidity::frontend::Expression>&&) Line | Count | Source | 75 | 195 | { | 76 | 195 | solAssert(m_location.sourceName, ""); | 77 | 195 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 195 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 195 | } |
std::__1::shared_ptr<solidity::frontend::TupleExpression> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::TupleExpression, std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >&, bool>(std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >&, bool&&) Line | Count | Source | 75 | 1.86k | { | 76 | 1.86k | solAssert(m_location.sourceName, ""); | 77 | 1.86k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 1.86k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 1.86k | } |
std::__1::shared_ptr<solidity::frontend::ExpressionStatement> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ExpressionStatement, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::Expression>&>(std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&, std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 55.0k | { | 76 | 55.0k | solAssert(m_location.sourceName, ""); | 77 | 55.0k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 55.0k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 55.0k | } |
std::__1::shared_ptr<solidity::frontend::Assignment> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Assignment, std::__1::shared_ptr<solidity::frontend::Expression>&, solidity::langutil::Token&, std::__1::shared_ptr<solidity::frontend::Expression>&>(std::__1::shared_ptr<solidity::frontend::Expression>&, solidity::langutil::Token&, std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 38.3k | { | 76 | 38.3k | solAssert(m_location.sourceName, ""); | 77 | 38.3k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 38.3k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 38.3k | } |
std::__1::shared_ptr<solidity::frontend::Conditional> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Conditional, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression>&>(std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 1.36k | { | 76 | 1.36k | solAssert(m_location.sourceName, ""); | 77 | 1.36k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 1.36k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 1.36k | } |
std::__1::shared_ptr<solidity::frontend::BinaryOperation> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::BinaryOperation, std::__1::shared_ptr<solidity::frontend::Expression>&, solidity::langutil::Token&, std::__1::shared_ptr<solidity::frontend::Expression>&>(std::__1::shared_ptr<solidity::frontend::Expression>&, solidity::langutil::Token&, std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 102k | { | 76 | 102k | solAssert(m_location.sourceName, ""); | 77 | 102k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 102k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 102k | } |
std::__1::shared_ptr<solidity::frontend::UnaryOperation> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::UnaryOperation, solidity::langutil::Token&, std::__1::shared_ptr<solidity::frontend::Expression>&, bool>(solidity::langutil::Token&, std::__1::shared_ptr<solidity::frontend::Expression>&, bool&&) Line | Count | Source | 75 | 47.2k | { | 76 | 47.2k | solAssert(m_location.sourceName, ""); | 77 | 47.2k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 47.2k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 47.2k | } |
std::__1::shared_ptr<solidity::frontend::NewExpression> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::NewExpression, std::__1::shared_ptr<solidity::frontend::TypeName>&>(std::__1::shared_ptr<solidity::frontend::TypeName>&) Line | Count | Source | 75 | 3.26k | { | 76 | 3.26k | solAssert(m_location.sourceName, ""); | 77 | 3.26k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 3.26k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 3.26k | } |
std::__1::shared_ptr<solidity::frontend::ElementaryTypeName> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ElementaryTypeName, solidity::langutil::ElementaryTypeNameToken, std::__1::optional<solidity::frontend::StateMutability> >(solidity::langutil::ElementaryTypeNameToken&&, std::__1::optional<solidity::frontend::StateMutability>&&) Line | Count | Source | 75 | 275 | { | 76 | 275 | solAssert(m_location.sourceName, ""); | 77 | 275 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 275 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 275 | } |
std::__1::shared_ptr<solidity::frontend::ElementaryTypeNameExpression> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ElementaryTypeNameExpression, std::__1::shared_ptr<solidity::frontend::ElementaryTypeName>&>(std::__1::shared_ptr<solidity::frontend::ElementaryTypeName>&) Line | Count | Source | 75 | 13.1k | { | 76 | 13.1k | solAssert(m_location.sourceName, ""); | 77 | 13.1k | if (m_location.end < 0) | 78 | 1.76k | markEndPosition(); | 79 | 13.1k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 13.1k | } |
std::__1::shared_ptr<solidity::frontend::IndexRangeAccess> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::IndexRangeAccess, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression>&>(std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 750 | { | 76 | 750 | solAssert(m_location.sourceName, ""); | 77 | 750 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 750 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 750 | } |
std::__1::shared_ptr<solidity::frontend::IndexAccess> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::IndexAccess, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression>&>(std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression>&) Line | Count | Source | 75 | 97.1k | { | 76 | 97.1k | solAssert(m_location.sourceName, ""); | 77 | 97.1k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 97.1k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 97.1k | } |
std::__1::shared_ptr<solidity::frontend::MemberAccess> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::MemberAccess, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, solidity::langutil::SourceLocation>(std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&, solidity::langutil::SourceLocation&&) Line | Count | Source | 75 | 127k | { | 76 | 127k | solAssert(m_location.sourceName, ""); | 77 | 127k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 127k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 127k | } |
std::__1::shared_ptr<solidity::frontend::FunctionCallOptions> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::FunctionCallOptions, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >&, std::__1::vector<std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >&>(std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >&, std::__1::vector<std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > >&) Line | Count | Source | 75 | 412 | { | 76 | 412 | solAssert(m_location.sourceName, ""); | 77 | 412 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 412 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 412 | } |
std::__1::shared_ptr<solidity::frontend::Literal> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Literal, solidity::langutil::Token&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, solidity::frontend::Literal::SubDenomination&>(solidity::langutil::Token&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&, solidity::frontend::Literal::SubDenomination&) Line | Count | Source | 75 | 475 | { | 76 | 475 | solAssert(m_location.sourceName, ""); | 77 | 475 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 475 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 475 | } |
std::__1::shared_ptr<solidity::frontend::Literal> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::Literal, solidity::langutil::Token&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, solidity::frontend::Literal::SubDenomination>(solidity::langutil::Token&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&, solidity::frontend::Literal::SubDenomination&&) Line | Count | Source | 75 | 323k | { | 76 | 323k | solAssert(m_location.sourceName, ""); | 77 | 323k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 323k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 323k | } |
std::__1::shared_ptr<solidity::frontend::TupleExpression> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::TupleExpression, std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >&, bool&>(std::__1::vector<std::__1::shared_ptr<solidity::frontend::Expression>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::Expression> > >&, bool&) Line | Count | Source | 75 | 9.29k | { | 76 | 9.29k | solAssert(m_location.sourceName, ""); | 77 | 9.29k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 9.29k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 9.29k | } |
std::__1::shared_ptr<solidity::frontend::ElementaryTypeName> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ElementaryTypeName, solidity::langutil::ElementaryTypeNameToken const&>(solidity::langutil::ElementaryTypeNameToken const&) Line | Count | Source | 75 | 1.66k | { | 76 | 1.66k | solAssert(m_location.sourceName, ""); | 77 | 1.66k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 1.66k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 1.66k | } |
std::__1::shared_ptr<solidity::frontend::UserDefinedTypeName> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::UserDefinedTypeName, std::__1::shared_ptr<solidity::frontend::IdentifierPath> >(std::__1::shared_ptr<solidity::frontend::IdentifierPath>&&) Line | Count | Source | 75 | 290 | { | 76 | 290 | solAssert(m_location.sourceName, ""); | 77 | 290 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 290 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 290 | } |
std::__1::shared_ptr<solidity::frontend::ArrayTypeName> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ArrayTypeName, std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<solidity::frontend::Expression> const&>(std::__1::shared_ptr<solidity::frontend::TypeName>&, std::__1::shared_ptr<solidity::frontend::Expression> const&) Line | Count | Source | 75 | 3.38k | { | 76 | 3.38k | solAssert(m_location.sourceName, ""); | 77 | 3.38k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 3.38k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 3.38k | } |
std::__1::shared_ptr<solidity::frontend::MemberAccess> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::MemberAccess, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, solidity::langutil::SourceLocation const&>(std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >&&, solidity::langutil::SourceLocation const&) Line | Count | Source | 75 | 40.2k | { | 76 | 40.2k | solAssert(m_location.sourceName, ""); | 77 | 40.2k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 40.2k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 40.2k | } |
std::__1::shared_ptr<solidity::frontend::IndexRangeAccess> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::IndexRangeAccess, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression> const&, std::__1::shared_ptr<solidity::frontend::Expression> const&>(std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression> const&, std::__1::shared_ptr<solidity::frontend::Expression> const&) Line | Count | Source | 75 | 881 | { | 76 | 881 | solAssert(m_location.sourceName, ""); | 77 | 881 | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 881 | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 881 | } |
std::__1::shared_ptr<solidity::frontend::IndexAccess> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::IndexAccess, std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression> const&>(std::__1::shared_ptr<solidity::frontend::Expression>&, std::__1::shared_ptr<solidity::frontend::Expression> const&) Line | Count | Source | 75 | 31.9k | { | 76 | 31.9k | solAssert(m_location.sourceName, ""); | 77 | 31.9k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 31.9k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 31.9k | } |
std::__1::shared_ptr<solidity::frontend::ParameterList> solidity::frontend::Parser::ASTNodeFactory::createNode<solidity::frontend::ParameterList, std::__1::vector<std::__1::shared_ptr<solidity::frontend::VariableDeclaration>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::VariableDeclaration> > > >(std::__1::vector<std::__1::shared_ptr<solidity::frontend::VariableDeclaration>, std::__1::allocator<std::__1::shared_ptr<solidity::frontend::VariableDeclaration> > >&&) Line | Count | Source | 75 | 23.0k | { | 76 | 23.0k | solAssert(m_location.sourceName, ""); | 77 | 23.0k | if (m_location.end < 0) | 78 | 0 | markEndPosition(); | 79 | 23.0k | return std::make_shared<NodeType>(m_parser.nextID(), m_location, std::forward<Args>(_args)...); | 80 | 23.0k | } |
|
81 | | |
82 | 2.14k | SourceLocation const& location() const noexcept { return m_location; } |
83 | | |
84 | | private: |
85 | | Parser& m_parser; |
86 | | SourceLocation m_location; |
87 | | }; |
88 | | |
89 | | ASTPointer<SourceUnit> Parser::parse(CharStream& _charStream) |
90 | 32.8k | { |
91 | 32.8k | solAssert(!m_insideModifier, ""); |
92 | 32.8k | try |
93 | 32.8k | { |
94 | 32.8k | m_recursionDepth = 0; |
95 | 32.8k | m_scanner = std::make_shared<Scanner>(_charStream); |
96 | 32.8k | ASTNodeFactory nodeFactory(*this); |
97 | 32.8k | m_experimentalSolidityEnabledInCurrentSourceUnit = false; |
98 | | |
99 | 32.8k | std::vector<ASTPointer<ASTNode>> nodes; |
100 | 40.8k | while (m_scanner->currentToken() == Token::Pragma) |
101 | 7.95k | nodes.push_back(parsePragmaDirective(false)); |
102 | | |
103 | 32.8k | if (m_experimentalSolidityEnabledInCurrentSourceUnit) |
104 | 186 | m_scanner->setScannerMode(ScannerKind::ExperimentalSolidity); |
105 | | |
106 | 105k | while (m_scanner->currentToken() != Token::EOS) |
107 | 77.0k | { |
108 | 77.0k | switch (m_scanner->currentToken()) |
109 | 77.0k | { |
110 | 25.5k | case Token::Pragma: |
111 | 25.5k | nodes.push_back(parsePragmaDirective(true)); |
112 | 25.5k | break; |
113 | 1.87k | case Token::Import: |
114 | 1.87k | nodes.push_back(parseImportDirective()); |
115 | 1.87k | break; |
116 | 835 | case Token::Abstract: |
117 | 1.62k | case Token::Interface: |
118 | 28.1k | case Token::Contract: |
119 | 29.5k | case Token::Library: |
120 | 29.5k | nodes.push_back(parseContractDefinition()); |
121 | 29.5k | break; |
122 | 501 | case Token::Struct: |
123 | 501 | nodes.push_back(parseStructDefinition()); |
124 | 501 | break; |
125 | 426 | case Token::Enum: |
126 | 426 | nodes.push_back(parseEnumDefinition()); |
127 | 426 | break; |
128 | 809 | case Token::Type: |
129 | 809 | if (m_experimentalSolidityEnabledInCurrentSourceUnit) |
130 | 205 | nodes.push_back(parseTypeDefinition()); |
131 | 604 | else |
132 | 604 | nodes.push_back(parseUserDefinedValueTypeDefinition()); |
133 | 809 | break; |
134 | 523 | case Token::Using: |
135 | 523 | nodes.push_back(parseUsingDirective()); |
136 | 523 | break; |
137 | 3.51k | case Token::Function: |
138 | 3.51k | nodes.push_back(parseFunctionDefinition(true)); |
139 | 3.51k | break; |
140 | 22 | case Token::ForAll: |
141 | 22 | nodes.push_back(parseQuantifiedFunctionDefinition()); |
142 | 22 | break; |
143 | 740 | case Token::Event: |
144 | 740 | nodes.push_back(parseEventDefinition()); |
145 | 740 | break; |
146 | 61 | case Token::Class: |
147 | 61 | solAssert(m_experimentalSolidityEnabledInCurrentSourceUnit); |
148 | 61 | nodes.push_back(parseTypeClassDefinition()); |
149 | 61 | break; |
150 | 59 | case Token::Instantiation: |
151 | 59 | solAssert(m_experimentalSolidityEnabledInCurrentSourceUnit); |
152 | 59 | nodes.push_back(parseTypeClassInstantiation()); |
153 | 59 | break; |
154 | 13.3k | default: |
155 | 13.3k | if ( |
156 | | // Workaround because `error` is not a keyword. |
157 | 13.3k | m_scanner->currentToken() == Token::Identifier && |
158 | 7.19k | currentLiteral() == "error" && |
159 | 742 | m_scanner->peekNextToken() == Token::Identifier && |
160 | 739 | m_scanner->peekNextNextToken() == Token::LParen |
161 | 13.3k | ) |
162 | 703 | nodes.push_back(parseErrorDefinition()); |
163 | | // Constant variable. |
164 | 12.6k | else if (variableDeclarationStart() && m_scanner->peekNextToken() != Token::EOS) |
165 | 11.6k | { |
166 | 11.6k | VarDeclParserOptions options; |
167 | 11.6k | options.kind = VarDeclKind::FileLevel; |
168 | 11.6k | options.allowInitialValue = true; |
169 | 11.6k | nodes.push_back(parseVariableDeclaration(options)); |
170 | 11.6k | expectToken(Token::Semicolon); |
171 | 11.6k | } |
172 | 1.02k | else |
173 | 1.02k | fatalParserError(7858_error, "Expected pragma, import directive or contract/interface/library/user-defined type/constant/function/error/event definition."); |
174 | 77.0k | } |
175 | 77.0k | } |
176 | 28.2k | solAssert(m_recursionDepth == 0, ""); |
177 | 28.2k | return nodeFactory.createNode<SourceUnit>(findLicenseString(nodes), nodes, m_experimentalSolidityEnabledInCurrentSourceUnit); |
178 | 32.8k | } |
179 | 32.8k | catch (FatalError const&) |
180 | 32.8k | { |
181 | 4.87k | if (!m_errorReporter.hasErrors()) |
182 | 0 | { |
183 | 0 | std::cerr << "Unreported fatal error:" << std::endl; |
184 | 0 | std::cerr << boost::current_exception_diagnostic_information() << std::endl; |
185 | 0 | solAssert(false, "Unreported fatal error."); |
186 | 0 | } |
187 | 4.87k | return nullptr; |
188 | 4.87k | } |
189 | 32.8k | } |
190 | | |
191 | | void Parser::parsePragmaVersion(SourceLocation const& _location, std::vector<Token> const& _tokens, std::vector<std::string> const& _literals) |
192 | 2.14k | { |
193 | 2.14k | SemVerMatchExpressionParser parser(_tokens, _literals); |
194 | 2.14k | try |
195 | 2.14k | { |
196 | 2.14k | SemVerMatchExpression matchExpression = parser.parse(); |
197 | 2.14k | static SemVerVersion const currentVersion{std::string(VersionString)}; |
198 | | // FIXME: only match for major version incompatibility |
199 | 2.14k | if (!matchExpression.matches(currentVersion)) |
200 | 50 | m_errorReporter.fatalParserError( |
201 | 50 | 5333_error, |
202 | 50 | _location, |
203 | 50 | "Source file requires different compiler version (current compiler is " + |
204 | 50 | std::string(VersionString) + ") - note that nightly builds are considered to be " |
205 | 50 | "strictly less than the released version" |
206 | 50 | ); |
207 | 2.14k | } |
208 | 2.14k | catch (SemVerError const& matchError) |
209 | 2.14k | { |
210 | 206 | m_errorReporter.fatalParserError( |
211 | 206 | 1684_error, |
212 | 206 | _location, |
213 | 206 | "Invalid version pragma. "s + matchError.what() |
214 | 206 | ); |
215 | 206 | } |
216 | 2.14k | } |
217 | | |
218 | | ASTPointer<StructuredDocumentation> Parser::parseStructuredDocumentation() |
219 | 179k | { |
220 | 179k | if (!m_scanner->currentCommentLiteral().empty()) |
221 | 2.37k | { |
222 | 2.37k | ASTNodeFactory nodeFactory{*this}; |
223 | 2.37k | nodeFactory.setLocation(m_scanner->currentCommentLocation()); |
224 | 2.37k | return nodeFactory.createNode<StructuredDocumentation>( |
225 | 2.37k | std::make_shared<ASTString>(m_scanner->currentCommentLiteral()) |
226 | 2.37k | ); |
227 | 2.37k | } |
228 | 177k | return nullptr; |
229 | 179k | } |
230 | | |
231 | | ASTPointer<PragmaDirective> Parser::parsePragmaDirective(bool const _finishedParsingTopLevelPragmas) |
232 | 33.5k | { |
233 | 33.5k | RecursionGuard recursionGuard(*this); |
234 | | // pragma anything* ; |
235 | | // Currently supported: |
236 | | // pragma solidity ^0.4.0 || ^0.3.0; |
237 | 33.5k | ASTNodeFactory nodeFactory(*this); |
238 | 33.5k | expectToken(Token::Pragma); |
239 | 33.5k | std::vector<std::string> literals; |
240 | 33.5k | std::vector<Token> tokens; |
241 | | |
242 | 33.5k | do |
243 | 125k | { |
244 | 125k | Token token = m_scanner->currentToken(); |
245 | 125k | if (token == Token::Illegal) |
246 | 26.6k | parserError(6281_error, "Token incompatible with Solidity parser as part of pragma directive."); |
247 | 98.9k | else |
248 | 98.9k | { |
249 | 98.9k | std::string literal = m_scanner->currentLiteral(); |
250 | 98.9k | if (literal.empty() && TokenTraits::toString(token)) |
251 | 19.9k | literal = TokenTraits::toString(token); |
252 | 98.9k | literals.push_back(literal); |
253 | 98.9k | tokens.push_back(token); |
254 | 98.9k | } |
255 | 125k | advance(); |
256 | 125k | } |
257 | 125k | while (m_scanner->currentToken() != Token::Semicolon && m_scanner->currentToken() != Token::EOS); |
258 | 33.5k | nodeFactory.markEndPosition(); |
259 | 33.5k | expectToken(Token::Semicolon); |
260 | | |
261 | 33.5k | if (literals.size() >= 1 && literals[0] == "solidity") |
262 | 2.14k | { |
263 | 2.14k | parsePragmaVersion( |
264 | 2.14k | nodeFactory.location(), |
265 | 2.14k | std::vector<Token>(tokens.begin() + 1, tokens.end()), |
266 | 2.14k | std::vector<std::string>(literals.begin() + 1, literals.end()) |
267 | 2.14k | ); |
268 | 2.14k | } |
269 | | |
270 | 33.5k | if (literals.size() >= 2 && literals[0] == "experimental" && literals[1] == "solidity") |
271 | 219 | { |
272 | 219 | if (m_evmVersion < EVMVersion::constantinople()) |
273 | 7 | fatalParserError(7637_error, "Experimental solidity requires Constantinople EVM version at the minimum."); |
274 | 219 | if (_finishedParsingTopLevelPragmas) |
275 | 2 | fatalParserError(8185_error, "Experimental pragma \"solidity\" can only be set at the beginning of the source unit."); |
276 | 219 | m_experimentalSolidityEnabledInCurrentSourceUnit = true; |
277 | 219 | } |
278 | | |
279 | 33.5k | return nodeFactory.createNode<PragmaDirective>(tokens, literals); |
280 | 33.5k | } |
281 | | |
282 | | ASTPointer<ImportDirective> Parser::parseImportDirective() |
283 | 1.87k | { |
284 | 1.87k | RecursionGuard recursionGuard(*this); |
285 | | // import "abc" [as x]; |
286 | | // import * as x from "abc"; |
287 | | // import {a as b, c} from "abc"; |
288 | 1.87k | ASTNodeFactory nodeFactory(*this); |
289 | 1.87k | expectToken(Token::Import); |
290 | 1.87k | ASTPointer<ASTString> path; |
291 | 1.87k | ASTPointer<ASTString> unitAlias = std::make_shared<std::string>(); |
292 | 1.87k | SourceLocation unitAliasLocation{}; |
293 | 1.87k | ImportDirective::SymbolAliasList symbolAliases; |
294 | | |
295 | 1.87k | if (isQuotedPath() || isStdlibPath()) |
296 | 1.29k | { |
297 | 1.29k | path = isQuotedPath() ? getLiteralAndAdvance() : getStdlibImportPathAndAdvance(); |
298 | 1.29k | if (m_scanner->currentToken() == Token::As) |
299 | 176 | { |
300 | 176 | advance(); |
301 | 176 | tie(unitAlias, unitAliasLocation) = expectIdentifierWithLocation(); |
302 | 176 | } |
303 | 1.29k | } |
304 | 574 | else |
305 | 574 | { |
306 | 574 | if (m_scanner->currentToken() == Token::LBrace) |
307 | 456 | { |
308 | 456 | advance(); |
309 | 1.45k | while (true) |
310 | 1.43k | { |
311 | 1.43k | ASTPointer<ASTString> alias; |
312 | 1.43k | SourceLocation aliasLocation = currentLocation(); |
313 | 1.43k | ASTPointer<Identifier> id = parseIdentifier(); |
314 | 1.43k | if (m_scanner->currentToken() == Token::As) |
315 | 286 | { |
316 | 286 | expectToken(Token::As); |
317 | 286 | tie(alias, aliasLocation) = expectIdentifierWithLocation(); |
318 | 286 | } |
319 | 1.43k | symbolAliases.emplace_back(ImportDirective::SymbolAlias{std::move(id), std::move(alias), aliasLocation}); |
320 | 1.43k | if (m_scanner->currentToken() != Token::Comma) |
321 | 437 | break; |
322 | 996 | advance(); |
323 | 996 | } |
324 | 456 | expectToken(Token::RBrace); |
325 | 456 | } |
326 | 118 | else if (m_scanner->currentToken() == Token::Mul) |
327 | 91 | { |
328 | 91 | advance(); |
329 | 91 | expectToken(Token::As); |
330 | 91 | tie(unitAlias, unitAliasLocation) = expectIdentifierWithLocation(); |
331 | 91 | } |
332 | 27 | else |
333 | 27 | fatalParserError(9478_error, "Expected string literal (path), \"*\" or alias list."); |
334 | | // "from" is not a keyword but parsed as an identifier because of backwards |
335 | | // compatibility and because it is a really common word. |
336 | 574 | if (m_scanner->currentToken() != Token::Identifier || m_scanner->currentLiteral() != "from") |
337 | 24 | fatalParserError(8208_error, "Expected \"from\"."); |
338 | 574 | advance(); |
339 | 574 | if (!isQuotedPath() && !isStdlibPath()) |
340 | 12 | fatalParserError(6845_error, "Expected import path."); |
341 | 574 | path = isQuotedPath() ? getLiteralAndAdvance() : getStdlibImportPathAndAdvance(); |
342 | 574 | } |
343 | 1.87k | if (path->empty()) |
344 | 1 | fatalParserError(6326_error, "Import path cannot be empty."); |
345 | 1.87k | nodeFactory.markEndPosition(); |
346 | 1.87k | expectToken(Token::Semicolon); |
347 | 1.87k | return nodeFactory.createNode<ImportDirective>(path, unitAlias, unitAliasLocation, std::move(symbolAliases)); |
348 | 1.87k | } |
349 | | |
350 | | std::pair<ContractKind, bool> Parser::parseContractKind() |
351 | 29.5k | { |
352 | 29.5k | ContractKind kind; |
353 | 29.5k | bool abstract = false; |
354 | 29.5k | if (m_scanner->currentToken() == Token::Abstract) |
355 | 835 | { |
356 | 835 | abstract = true; |
357 | 835 | advance(); |
358 | 835 | } |
359 | 29.5k | switch (m_scanner->currentToken()) |
360 | 29.5k | { |
361 | 801 | case Token::Interface: |
362 | 801 | kind = ContractKind::Interface; |
363 | 801 | break; |
364 | 27.3k | case Token::Contract: |
365 | 27.3k | kind = ContractKind::Contract; |
366 | 27.3k | break; |
367 | 1.38k | case Token::Library: |
368 | 1.38k | kind = ContractKind::Library; |
369 | 1.38k | break; |
370 | 18 | default: |
371 | 18 | parserError(3515_error, "Expected keyword \"contract\", \"interface\" or \"library\"."); |
372 | 18 | return std::make_pair(ContractKind::Contract, abstract); |
373 | 29.5k | } |
374 | 29.5k | advance(); |
375 | 29.5k | return std::make_pair(kind, abstract); |
376 | 29.5k | } |
377 | | |
378 | | ASTPointer<StorageLayoutSpecifier> Parser::parseStorageLayoutSpecifier() |
379 | 62 | { |
380 | 62 | RecursionGuard recursionGuard(*this); |
381 | 62 | ASTNodeFactory nodeFactory(*this); |
382 | 62 | ASTPointer<ASTString> layoutIdentifier = expectIdentifierToken(); |
383 | 62 | solAssert(layoutIdentifier && *layoutIdentifier == "layout"); |
384 | 62 | if ( |
385 | 62 | m_scanner->currentToken() != Token::Identifier || |
386 | 59 | m_scanner->currentLiteral() != "at" |
387 | 62 | ) |
388 | 62 | m_errorReporter.parserError( |
389 | 62 | 1994_error, |
390 | 62 | m_scanner->currentLocation(), |
391 | 62 | "Expected \'at\' but got " + tokenName(m_scanner->currentToken()) |
392 | 62 | ); |
393 | | |
394 | 62 | advance(); |
395 | 62 | ASTPointer<Expression> baseSlotExpression = parseExpression(); |
396 | 62 | solAssert(baseSlotExpression); |
397 | 62 | nodeFactory.setEndPositionFromNode(baseSlotExpression); |
398 | 62 | return nodeFactory.createNode<StorageLayoutSpecifier>( |
399 | 62 | baseSlotExpression |
400 | 62 | ); |
401 | 62 | } |
402 | | |
403 | | ASTPointer<ContractDefinition> Parser::parseContractDefinition() |
404 | 29.5k | { |
405 | 29.5k | RecursionGuard recursionGuard(*this); |
406 | 29.5k | ASTNodeFactory nodeFactory(*this); |
407 | 29.5k | ASTPointer<ASTString> name = nullptr; |
408 | 29.5k | SourceLocation nameLocation{}; |
409 | 29.5k | ASTPointer<StructuredDocumentation> documentation; |
410 | 29.5k | std::vector<ASTPointer<InheritanceSpecifier>> baseContracts; |
411 | 29.5k | std::vector<ASTPointer<ASTNode>> subNodes; |
412 | 29.5k | std::pair<ContractKind, bool> contractKind{}; |
413 | 29.5k | ASTPointer<StorageLayoutSpecifier> storageLayoutSpecifier; |
414 | 29.5k | documentation = parseStructuredDocumentation(); |
415 | 29.5k | contractKind = parseContractKind(); |
416 | 29.5k | std::tie(name, nameLocation) = expectIdentifierWithLocation(); |
417 | 33.6k | while (true) |
418 | 33.6k | { |
419 | 33.6k | if (m_scanner->currentToken() == Token::Is) |
420 | 4.06k | { |
421 | 4.06k | if (baseContracts.size() != 0) |
422 | 15 | m_errorReporter.parserError( |
423 | 15 | 6668_error, |
424 | 15 | m_scanner->currentLocation(), |
425 | 15 | SecondarySourceLocation().append("Previous list:", baseContracts[0]->location()), |
426 | 15 | "More than one inheritance list." |
427 | 15 | ); |
428 | 4.06k | do |
429 | 5.39k | { |
430 | 5.39k | advance(); |
431 | 5.39k | baseContracts.push_back(parseInheritanceSpecifier()); |
432 | 5.39k | } |
433 | 5.39k | while (m_scanner->currentToken() == Token::Comma); |
434 | 4.06k | } |
435 | 29.5k | else if ( |
436 | 29.5k | m_scanner->currentToken() == Token::Identifier && |
437 | 75 | m_scanner->currentLiteral() == "layout" && |
438 | 62 | contractKind.first == ContractKind::Contract |
439 | 29.5k | ) |
440 | 62 | { |
441 | 62 | if (storageLayoutSpecifier) |
442 | 50 | m_errorReporter.parserError( |
443 | 50 | 8714_error, |
444 | 50 | m_scanner->currentLocation(), |
445 | 50 | SecondarySourceLocation().append("Previous definition:", storageLayoutSpecifier->location()), |
446 | 50 | "More than one storage layout definition." |
447 | 50 | ); |
448 | | |
449 | 62 | storageLayoutSpecifier = parseStorageLayoutSpecifier(); |
450 | 62 | } |
451 | 29.5k | else |
452 | 29.5k | break; |
453 | 33.6k | } |
454 | | |
455 | 29.5k | if (storageLayoutSpecifier && baseContracts.size() > 0) |
456 | 0 | { |
457 | 0 | solAssert(!storageLayoutSpecifier->location().intersects(baseContracts[0]->location())); |
458 | 0 | solAssert(!baseContracts[0]->location().intersects(storageLayoutSpecifier->location())); |
459 | 0 | } |
460 | | |
461 | 29.5k | expectToken(Token::LBrace); |
462 | 87.6k | while (true) |
463 | 86.0k | { |
464 | 86.0k | Token currentTokenValue = m_scanner->currentToken(); |
465 | 86.0k | if (currentTokenValue == Token::RBrace) |
466 | 27.9k | break; |
467 | 58.1k | else if ( |
468 | 58.1k | (currentTokenValue == Token::Function && m_scanner->peekNextToken() != Token::LParen) || |
469 | 34.2k | currentTokenValue == Token::Constructor || |
470 | 31.7k | currentTokenValue == Token::Receive || |
471 | 31.5k | currentTokenValue == Token::Fallback |
472 | 58.1k | ) |
473 | 27.0k | subNodes.push_back(parseFunctionDefinition()); |
474 | 31.0k | else if (currentTokenValue == Token::Struct) |
475 | 9.34k | subNodes.push_back(parseStructDefinition()); |
476 | 21.6k | else if (currentTokenValue == Token::Enum) |
477 | 255 | subNodes.push_back(parseEnumDefinition()); |
478 | 21.4k | else if (currentTokenValue == Token::Type) |
479 | 176 | subNodes.push_back(parseUserDefinedValueTypeDefinition()); |
480 | 21.2k | else if ( |
481 | | // Workaround because `error` is not a keyword. |
482 | 21.2k | currentTokenValue == Token::Identifier && |
483 | 2.07k | currentLiteral() == "error" && |
484 | 456 | m_scanner->peekNextToken() == Token::Identifier && |
485 | 454 | m_scanner->peekNextNextToken() == Token::LParen |
486 | 21.2k | ) |
487 | 417 | subNodes.push_back(parseErrorDefinition()); |
488 | 20.8k | else if (variableDeclarationStart()) |
489 | 13.7k | { |
490 | 13.7k | VarDeclParserOptions options; |
491 | 13.7k | options.kind = VarDeclKind::State; |
492 | 13.7k | options.allowInitialValue = true; |
493 | 13.7k | subNodes.push_back(parseVariableDeclaration(options)); |
494 | 13.7k | expectToken(Token::Semicolon); |
495 | 13.7k | } |
496 | 7.13k | else if (currentTokenValue == Token::Modifier) |
497 | 3.47k | subNodes.push_back(parseModifierDefinition()); |
498 | 3.66k | else if (currentTokenValue == Token::Event) |
499 | 3.14k | subNodes.push_back(parseEventDefinition()); |
500 | 518 | else if (currentTokenValue == Token::Using) |
501 | 390 | subNodes.push_back(parseUsingDirective()); |
502 | 128 | else |
503 | 128 | fatalParserError(9182_error, "Function, variable, struct or modifier declaration expected."); |
504 | 86.0k | } |
505 | 29.5k | nodeFactory.markEndPosition(); |
506 | 29.5k | expectToken(Token::RBrace); |
507 | 29.5k | return nodeFactory.createNode<ContractDefinition>( |
508 | 29.5k | name, |
509 | 29.5k | nameLocation, |
510 | 29.5k | documentation, |
511 | 29.5k | baseContracts, |
512 | 29.5k | subNodes, |
513 | 29.5k | contractKind.first, |
514 | 29.5k | contractKind.second, |
515 | 29.5k | storageLayoutSpecifier |
516 | 29.5k | ); |
517 | 29.5k | } |
518 | | |
519 | | ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier() |
520 | 5.39k | { |
521 | 5.39k | RecursionGuard recursionGuard(*this); |
522 | 5.39k | ASTNodeFactory nodeFactory(*this); |
523 | 5.39k | ASTPointer<IdentifierPath> name(parseIdentifierPath()); |
524 | 5.39k | std::unique_ptr<std::vector<ASTPointer<Expression>>> arguments; |
525 | 5.39k | if (m_scanner->currentToken() == Token::LParen) |
526 | 193 | { |
527 | 193 | advance(); |
528 | 193 | arguments = std::make_unique<std::vector<ASTPointer<Expression>>>(parseFunctionCallListArguments()); |
529 | 193 | nodeFactory.markEndPosition(); |
530 | 193 | expectToken(Token::RParen); |
531 | 193 | } |
532 | 5.19k | else |
533 | 5.19k | nodeFactory.setEndPositionFromNode(name); |
534 | 5.39k | return nodeFactory.createNode<InheritanceSpecifier>(name, std::move(arguments)); |
535 | 5.39k | } |
536 | | |
537 | | Visibility Parser::parseVisibilitySpecifier() |
538 | 28.7k | { |
539 | 28.7k | Visibility visibility(Visibility::Default); |
540 | 28.7k | Token token = m_scanner->currentToken(); |
541 | 28.7k | switch (token) |
542 | 28.7k | { |
543 | 19.5k | case Token::Public: |
544 | 19.5k | visibility = Visibility::Public; |
545 | 19.5k | break; |
546 | 2.75k | case Token::Internal: |
547 | 2.75k | visibility = Visibility::Internal; |
548 | 2.75k | break; |
549 | 159 | case Token::Private: |
550 | 159 | visibility = Visibility::Private; |
551 | 159 | break; |
552 | 6.35k | case Token::External: |
553 | 6.35k | visibility = Visibility::External; |
554 | 6.35k | break; |
555 | 0 | default: |
556 | 0 | solAssert(false, "Invalid visibility specifier."); |
557 | 28.7k | } |
558 | 28.7k | advance(); |
559 | 28.7k | return visibility; |
560 | 28.7k | } |
561 | | |
562 | | ASTPointer<OverrideSpecifier> Parser::parseOverrideSpecifier() |
563 | 1.19k | { |
564 | 1.19k | solAssert(m_scanner->currentToken() == Token::Override, ""); |
565 | | |
566 | 1.19k | ASTNodeFactory nodeFactory(*this); |
567 | 1.19k | std::vector<ASTPointer<IdentifierPath>> overrides; |
568 | | |
569 | 1.19k | nodeFactory.markEndPosition(); |
570 | 1.19k | advance(); |
571 | | |
572 | 1.19k | if (m_scanner->currentToken() == Token::LParen) |
573 | 503 | { |
574 | 503 | advance(); |
575 | 2.43k | while (true) |
576 | 2.41k | { |
577 | 2.41k | overrides.push_back(parseIdentifierPath()); |
578 | | |
579 | 2.41k | if (m_scanner->currentToken() == Token::RParen) |
580 | 488 | break; |
581 | | |
582 | 1.93k | expectToken(Token::Comma); |
583 | 1.93k | } |
584 | | |
585 | 503 | nodeFactory.markEndPosition(); |
586 | 503 | expectToken(Token::RParen); |
587 | 503 | } |
588 | | |
589 | 1.19k | return nodeFactory.createNode<OverrideSpecifier>(std::move(overrides)); |
590 | 1.19k | } |
591 | | |
592 | | StateMutability Parser::parseStateMutability() |
593 | 10.3k | { |
594 | 10.3k | StateMutability stateMutability(StateMutability::NonPayable); |
595 | 10.3k | Token token = m_scanner->currentToken(); |
596 | 10.3k | switch (token) |
597 | 10.3k | { |
598 | 1.60k | case Token::Payable: |
599 | 1.60k | stateMutability = StateMutability::Payable; |
600 | 1.60k | break; |
601 | 2.36k | case Token::View: |
602 | 2.36k | stateMutability = StateMutability::View; |
603 | 2.36k | break; |
604 | 6.33k | case Token::Pure: |
605 | 6.33k | stateMutability = StateMutability::Pure; |
606 | 6.33k | break; |
607 | 0 | default: |
608 | 0 | solAssert(false, "Invalid state mutability specifier."); |
609 | 10.3k | } |
610 | 10.3k | advance(); |
611 | 10.3k | return stateMutability; |
612 | 10.3k | } |
613 | | |
614 | | Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVariable) |
615 | 32.0k | { |
616 | 32.0k | RecursionGuard recursionGuard(*this); |
617 | 32.0k | FunctionHeaderParserResult result; |
618 | | |
619 | 32.0k | VarDeclParserOptions options; |
620 | 32.0k | options.allowLocationSpecifier = true; |
621 | 32.0k | result.parameters = parseParameterList(options); |
622 | 72.1k | while (true) |
623 | 71.9k | { |
624 | 71.9k | Token token = m_scanner->currentToken(); |
625 | 71.9k | if (!_isStateVariable && token == Token::Identifier) |
626 | 4.21k | result.modifiers.push_back(parseModifierInvocation()); |
627 | 67.7k | else if (TokenTraits::isVisibilitySpecifier(token)) |
628 | 24.4k | { |
629 | 24.4k | if (result.visibility != Visibility::Default) |
630 | 207 | { |
631 | | // There is the special case of a public state variable of function type. |
632 | | // Detect this and return early. |
633 | 207 | if (_isStateVariable && (result.visibility == Visibility::External || result.visibility == Visibility::Internal)) |
634 | 67 | break; |
635 | 140 | parserError( |
636 | 140 | 9439_error, |
637 | 140 | "Visibility already specified as \"" + |
638 | 140 | Declaration::visibilityToString(result.visibility) + |
639 | 140 | "\"." |
640 | 140 | ); |
641 | 140 | advance(); |
642 | 140 | } |
643 | 24.1k | else |
644 | 24.1k | result.visibility = parseVisibilitySpecifier(); |
645 | 24.4k | } |
646 | 43.3k | else if (TokenTraits::isStateMutabilitySpecifier(token)) |
647 | 9.85k | { |
648 | 9.85k | if (result.stateMutability != StateMutability::NonPayable) |
649 | 37 | { |
650 | 37 | parserError( |
651 | 37 | 9680_error, |
652 | 37 | "State mutability already specified as \"" + |
653 | 37 | stateMutabilityToString(result.stateMutability) + |
654 | 37 | "\"." |
655 | 37 | ); |
656 | 37 | advance(); |
657 | 37 | } |
658 | 9.81k | else |
659 | 9.81k | result.stateMutability = parseStateMutability(); |
660 | 9.85k | } |
661 | 33.5k | else if (!_isStateVariable && token == Token::Override) |
662 | 707 | { |
663 | 707 | if (result.overrides) |
664 | 33 | parserError(1827_error, "Override already specified."); |
665 | | |
666 | 707 | result.overrides = parseOverrideSpecifier(); |
667 | 707 | } |
668 | 32.8k | else if (!_isStateVariable && token == Token::Virtual) |
669 | 914 | { |
670 | 914 | if (result.isVirtual) |
671 | 125 | parserError(6879_error, "Virtual already specified."); |
672 | | |
673 | 914 | result.isVirtual = true; |
674 | 914 | advance(); |
675 | 914 | } |
676 | 31.8k | else |
677 | 31.8k | break; |
678 | 71.9k | } |
679 | 32.0k | if (m_experimentalSolidityEnabledInCurrentSourceUnit) |
680 | 212 | { |
681 | 212 | if (m_scanner->currentToken() == Token::RightArrow) |
682 | 10 | { |
683 | 10 | advance(); |
684 | 10 | result.experimentalReturnExpression = parseBinaryExpression(); |
685 | 10 | } |
686 | 212 | } |
687 | 31.8k | else |
688 | 31.8k | { |
689 | 31.8k | if (m_scanner->currentToken() == Token::Returns) |
690 | 11.4k | { |
691 | 11.4k | bool const permitEmptyParameterList = m_experimentalSolidityEnabledInCurrentSourceUnit; |
692 | 11.4k | advance(); |
693 | 11.4k | result.returnParameters = parseParameterList(options, permitEmptyParameterList); |
694 | 11.4k | } |
695 | 20.4k | else |
696 | 20.4k | result.returnParameters = createEmptyParameterList(); |
697 | 31.8k | } |
698 | 32.0k | return result; |
699 | 32.0k | } |
700 | | |
701 | | ASTPointer<ForAllQuantifier> Parser::parseQuantifiedFunctionDefinition() |
702 | 22 | { |
703 | 22 | solAssert(m_experimentalSolidityEnabledInCurrentSourceUnit); |
704 | 22 | RecursionGuard recursionGuard(*this); |
705 | 22 | ASTNodeFactory nodeFactory(*this); |
706 | | |
707 | 22 | expectToken(Token::ForAll); |
708 | 22 | ASTPointer<ParameterList> typeVariableDeclarations = parseParameterList(); |
709 | 22 | nodeFactory.markEndPosition(); |
710 | | |
711 | 22 | if (m_scanner->currentToken() != Token::Function) |
712 | 4 | fatalParserError(5709_error, "Expected a function definition."); |
713 | | |
714 | 22 | ASTPointer<FunctionDefinition> quantifiedFunction = parseFunctionDefinition(true /* _freeFunction */, true /* _allowBody */); |
715 | | |
716 | 22 | return nodeFactory.createNode<ForAllQuantifier>( |
717 | 22 | std::move(typeVariableDeclarations), |
718 | 22 | std::move(quantifiedFunction) |
719 | 22 | ); |
720 | 22 | } |
721 | | |
722 | | ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(bool _freeFunction, bool _allowBody) |
723 | 30.7k | { |
724 | 30.7k | RecursionGuard recursionGuard(*this); |
725 | 30.7k | ASTNodeFactory nodeFactory(*this); |
726 | 30.7k | ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation(); |
727 | | |
728 | 30.7k | Token kind = m_scanner->currentToken(); |
729 | 30.7k | ASTPointer<ASTString> name; |
730 | 30.7k | SourceLocation nameLocation; |
731 | 30.7k | if (kind == Token::Function) |
732 | 27.5k | { |
733 | 27.5k | advance(); |
734 | 27.5k | if ( |
735 | 27.5k | m_scanner->currentToken() == Token::Constructor || |
736 | 27.5k | m_scanner->currentToken() == Token::Fallback || |
737 | 27.4k | m_scanner->currentToken() == Token::Receive |
738 | 27.5k | ) |
739 | 39 | { |
740 | 39 | std::string expected = std::map<Token, std::string>{ |
741 | 39 | {Token::Constructor, "constructor"}, |
742 | 39 | {Token::Fallback, "fallback function"}, |
743 | 39 | {Token::Receive, "receive function"}, |
744 | 39 | }.at(m_scanner->currentToken()); |
745 | 39 | nameLocation = currentLocation(); |
746 | 39 | name = std::make_shared<ASTString>(TokenTraits::toString(m_scanner->currentToken())); |
747 | 39 | std::string message{ |
748 | 39 | "This function is named \"" + *name + "\" but is not the " + expected + " of the contract. " |
749 | 39 | "If you intend this to be a " + expected + ", use \"" + *name + "(...) { ... }\" without " |
750 | 39 | "the \"function\" keyword to define it." |
751 | 39 | }; |
752 | 39 | if (m_scanner->currentToken() == Token::Constructor) |
753 | 6 | parserError(3323_error, message); |
754 | 33 | else |
755 | 33 | parserWarning(3445_error, message); |
756 | 39 | advance(); |
757 | 39 | } |
758 | 27.4k | else |
759 | 27.4k | tie(name, nameLocation) = expectIdentifierWithLocation(); |
760 | 27.5k | } |
761 | 3.20k | else |
762 | 3.20k | { |
763 | 3.20k | solAssert(kind == Token::Constructor || kind == Token::Fallback || kind == Token::Receive, ""); |
764 | 3.20k | advance(); |
765 | 3.20k | name = std::make_shared<ASTString>(); |
766 | 3.20k | } |
767 | | |
768 | 30.7k | FunctionHeaderParserResult header = parseFunctionHeader(false); |
769 | | |
770 | 30.7k | if (m_experimentalSolidityEnabledInCurrentSourceUnit) |
771 | 30.7k | solAssert(!header.returnParameters); |
772 | 30.5k | else |
773 | 30.7k | solAssert(!header.experimentalReturnExpression); |
774 | | |
775 | 30.7k | ASTPointer<Block> block; |
776 | 30.7k | nodeFactory.markEndPosition(); |
777 | 30.7k | if (!_allowBody) |
778 | 32 | expectToken(Token::Semicolon); |
779 | 30.6k | else if (m_scanner->currentToken() == Token::Semicolon) |
780 | 2.40k | advance(); |
781 | 28.2k | else |
782 | 28.2k | { |
783 | 28.2k | block = parseBlock(); |
784 | 28.2k | nodeFactory.setEndPositionFromNode(block); |
785 | 28.2k | } |
786 | 30.7k | return nodeFactory.createNode<FunctionDefinition>( |
787 | 30.7k | name, |
788 | 30.7k | nameLocation, |
789 | 30.7k | header.visibility, |
790 | 30.7k | header.stateMutability, |
791 | 30.7k | _freeFunction, |
792 | 30.7k | kind, |
793 | 30.7k | header.isVirtual, |
794 | 30.7k | header.overrides, |
795 | 30.7k | documentation, |
796 | 30.7k | header.parameters, |
797 | 30.7k | header.modifiers, |
798 | 30.7k | header.returnParameters, |
799 | 30.7k | block, |
800 | 30.7k | header.experimentalReturnExpression |
801 | 30.7k | ); |
802 | 30.7k | } |
803 | | |
804 | | ASTPointer<StructDefinition> Parser::parseStructDefinition() |
805 | 9.84k | { |
806 | 9.84k | RecursionGuard recursionGuard(*this); |
807 | 9.84k | ASTNodeFactory nodeFactory(*this); |
808 | 9.84k | ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation(); |
809 | 9.84k | expectToken(Token::Struct); |
810 | 9.84k | auto [name, nameLocation] = expectIdentifierWithLocation(); |
811 | 9.84k | std::vector<ASTPointer<VariableDeclaration>> members; |
812 | 9.84k | expectToken(Token::LBrace); |
813 | 30.7k | while (m_scanner->currentToken() != Token::RBrace) |
814 | 20.8k | { |
815 | 20.8k | members.push_back(parseVariableDeclaration()); |
816 | 20.8k | expectToken(Token::Semicolon); |
817 | 20.8k | } |
818 | 9.84k | nodeFactory.markEndPosition(); |
819 | 9.84k | expectToken(Token::RBrace); |
820 | 9.84k | return nodeFactory.createNode<StructDefinition>(std::move(name), std::move(nameLocation), std::move(members), std::move(documentation)); |
821 | 9.84k | } |
822 | | |
823 | | ASTPointer<EnumValue> Parser::parseEnumValue() |
824 | 2.69k | { |
825 | 2.69k | RecursionGuard recursionGuard(*this); |
826 | 2.69k | ASTNodeFactory nodeFactory(*this); |
827 | 2.69k | ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation(); |
828 | 2.69k | nodeFactory.markEndPosition(); |
829 | 2.69k | return nodeFactory.createNode<EnumValue>(expectIdentifierToken(), documentation); |
830 | 2.69k | } |
831 | | |
832 | | ASTPointer<EnumDefinition> Parser::parseEnumDefinition() |
833 | 681 | { |
834 | 681 | RecursionGuard recursionGuard(*this); |
835 | 681 | ASTNodeFactory nodeFactory(*this); |
836 | 681 | ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation(); |
837 | 681 | expectToken(Token::Enum); |
838 | 681 | auto [name, nameLocation] = expectIdentifierWithLocation(); |
839 | 681 | std::vector<ASTPointer<EnumValue>> members; |
840 | 681 | expectToken(Token::LBrace); |
841 | | |
842 | 2.83k | while (m_scanner->currentToken() != Token::RBrace) |
843 | 2.69k | { |
844 | 2.69k | members.push_back(parseEnumValue()); |
845 | 2.69k | if (m_scanner->currentToken() == Token::RBrace) |
846 | 543 | break; |
847 | 2.15k | expectToken(Token::Comma); |
848 | 2.15k | if (m_scanner->currentToken() != Token::Identifier) |
849 | 6 | fatalParserError(1612_error, "Expected identifier after ','"); |
850 | 2.15k | } |
851 | 681 | if (members.empty()) |
852 | 89 | parserError(3147_error, "Enum with no members is not allowed."); |
853 | | |
854 | 681 | nodeFactory.markEndPosition(); |
855 | 681 | expectToken(Token::RBrace); |
856 | 681 | return nodeFactory.createNode<EnumDefinition>(name, nameLocation, members, documentation); |
857 | 681 | } |
858 | | |
859 | | ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( |
860 | | VarDeclParserOptions const& _options, |
861 | | ASTPointer<TypeName> const& _lookAheadArrayType |
862 | | ) |
863 | 97.4k | { |
864 | 97.4k | RecursionGuard recursionGuard(*this); |
865 | 97.4k | ASTNodeFactory nodeFactory = _lookAheadArrayType ? |
866 | 95.4k | ASTNodeFactory(*this, _lookAheadArrayType) : ASTNodeFactory(*this); |
867 | | |
868 | 97.4k | ASTPointer<StructuredDocumentation> const documentation = parseStructuredDocumentation(); |
869 | 97.4k | ASTPointer<TypeName> type = _lookAheadArrayType ? _lookAheadArrayType : parseTypeName(); |
870 | 97.4k | nodeFactory.setEndPositionFromNode(type); |
871 | | |
872 | 97.4k | if (dynamic_cast<FunctionTypeName*>(type.get()) && _options.kind == VarDeclKind::State && m_scanner->currentToken() == Token::LBrace) |
873 | 1 | fatalParserError( |
874 | 1 | 2915_error, |
875 | 1 | "Expected a state variable declaration. If you intended this as a fallback function " |
876 | 1 | "or a function to handle plain ether transactions, use the \"fallback\" keyword " |
877 | 1 | "or the \"receive\" keyword instead." |
878 | 1 | ); |
879 | | |
880 | 97.4k | bool isIndexed = false; |
881 | 97.4k | VariableDeclaration::Mutability mutability = VariableDeclaration::Mutability::Mutable; |
882 | 97.4k | ASTPointer<OverrideSpecifier> overrides = nullptr; |
883 | 97.4k | Visibility visibility(Visibility::Default); |
884 | 97.4k | VariableDeclaration::Location location = VariableDeclaration::Location::Unspecified; |
885 | 97.4k | ASTPointer<ASTString> identifier; |
886 | 97.4k | SourceLocation nameLocation{}; |
887 | | |
888 | 117k | while (true) |
889 | 117k | { |
890 | 117k | Token token = m_scanner->currentToken(); |
891 | 117k | if (_options.kind == VarDeclKind::State && TokenTraits::isVariableVisibilitySpecifier(token)) |
892 | 4.60k | { |
893 | 4.60k | nodeFactory.markEndPosition(); |
894 | 4.60k | if (visibility != Visibility::Default) |
895 | 7 | { |
896 | 7 | parserError( |
897 | 7 | 4110_error, |
898 | 7 | "Visibility already specified as \"" + |
899 | 7 | Declaration::visibilityToString(visibility) + |
900 | 7 | "\"." |
901 | 7 | ); |
902 | 7 | advance(); |
903 | 7 | } |
904 | 4.59k | else |
905 | 4.59k | visibility = parseVisibilitySpecifier(); |
906 | 4.60k | } |
907 | 112k | else if (_options.kind == VarDeclKind::State && token == Token::Override) |
908 | 217 | { |
909 | 217 | if (overrides) |
910 | 13 | parserError(9125_error, "Override already specified."); |
911 | | |
912 | 217 | overrides = parseOverrideSpecifier(); |
913 | 217 | } |
914 | 112k | else |
915 | 112k | { |
916 | 112k | if (_options.allowIndexed && token == Token::Indexed) |
917 | 240 | { |
918 | 240 | if (isIndexed) |
919 | 16 | parserError(5399_error, "Indexed already specified."); |
920 | | |
921 | 240 | isIndexed = true; |
922 | 240 | } |
923 | 112k | else if (token == Token::Constant || token == Token::Immutable) |
924 | 3.22k | { |
925 | 3.22k | if (mutability != VariableDeclaration::Mutability::Mutable) |
926 | 39 | parserError( |
927 | 39 | 3109_error, |
928 | 39 | std::string("Mutability already set to ") + |
929 | 39 | (mutability == VariableDeclaration::Mutability::Constant ? "\"constant\"" : "\"immutable\"") |
930 | 39 | ); |
931 | 3.18k | else if (token == Token::Constant) |
932 | 2.67k | mutability = VariableDeclaration::Mutability::Constant; |
933 | 514 | else if (token == Token::Immutable) |
934 | 514 | mutability = VariableDeclaration::Mutability::Immutable; |
935 | 3.22k | } |
936 | 108k | else if (_options.allowLocationSpecifier && TokenTraits::isLocationSpecifier(token)) |
937 | 12.2k | { |
938 | 12.2k | if (location != VariableDeclaration::Location::Unspecified) |
939 | 2 | parserError(3548_error, "Location already specified."); |
940 | 12.2k | else |
941 | 12.2k | { |
942 | 12.2k | switch (token) |
943 | 12.2k | { |
944 | 698 | case Token::Storage: |
945 | 698 | location = VariableDeclaration::Location::Storage; |
946 | 698 | break; |
947 | 9.74k | case Token::Memory: |
948 | 9.74k | location = VariableDeclaration::Location::Memory; |
949 | 9.74k | break; |
950 | 1.80k | case Token::CallData: |
951 | 1.80k | location = VariableDeclaration::Location::CallData; |
952 | 1.80k | break; |
953 | 0 | default: |
954 | 0 | solAssert(false, "Unknown data location."); |
955 | 12.2k | } |
956 | 12.2k | } |
957 | 12.2k | } |
958 | 96.7k | else if ( |
959 | 96.7k | _options.kind == VarDeclKind::State && |
960 | 13.6k | token == Token::Identifier && |
961 | 13.5k | m_scanner->currentLiteral() == "transient" && |
962 | 1 | m_scanner->peekNextToken() != Token::Assign && |
963 | 1 | m_scanner->peekNextToken() != Token::Semicolon |
964 | 96.7k | ) |
965 | 0 | { |
966 | 0 | if (location != VariableDeclaration::Location::Unspecified) |
967 | 0 | parserError(ErrorId{3548}, "Location already specified."); |
968 | 0 | else |
969 | 0 | location = VariableDeclaration::Location::Transient; |
970 | 0 | } |
971 | 96.7k | else |
972 | 96.7k | break; |
973 | 15.7k | nodeFactory.markEndPosition(); |
974 | 15.7k | advance(); |
975 | 15.7k | } |
976 | 117k | } |
977 | | |
978 | 97.4k | if (_options.allowEmptyName && m_scanner->currentToken() != Token::Identifier) |
979 | 18.3k | identifier = std::make_shared<ASTString>(""); |
980 | 79.1k | else |
981 | 79.1k | { |
982 | 79.1k | nodeFactory.markEndPosition(); |
983 | 79.1k | tie(identifier, nameLocation) = expectIdentifierWithLocation(); |
984 | 79.1k | } |
985 | 97.4k | ASTPointer<Expression> value; |
986 | 97.4k | if (_options.allowInitialValue) |
987 | 24.1k | { |
988 | 24.1k | if (m_scanner->currentToken() == Token::Assign) |
989 | 5.88k | { |
990 | 5.88k | advance(); |
991 | 5.88k | value = parseExpression(); |
992 | 5.88k | nodeFactory.setEndPositionFromNode(value); |
993 | 5.88k | } |
994 | 24.1k | } |
995 | 97.4k | return nodeFactory.createNode<VariableDeclaration>( |
996 | 97.4k | type, |
997 | 97.4k | identifier, |
998 | 97.4k | nameLocation, |
999 | 97.4k | value, |
1000 | 97.4k | visibility, |
1001 | 97.4k | documentation, |
1002 | 97.4k | isIndexed, |
1003 | 97.4k | mutability, |
1004 | 97.4k | overrides, |
1005 | 97.4k | location |
1006 | 97.4k | ); |
1007 | 97.4k | } |
1008 | | |
1009 | | ASTPointer<ModifierDefinition> Parser::parseModifierDefinition() |
1010 | 3.47k | { |
1011 | 3.47k | RecursionGuard recursionGuard(*this); |
1012 | 3.47k | ScopeGuard resetModifierFlag([this]() { m_insideModifier = false; }); |
1013 | 3.47k | m_insideModifier = true; |
1014 | | |
1015 | 3.47k | ASTNodeFactory nodeFactory(*this); |
1016 | 3.47k | ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation(); |
1017 | | |
1018 | 3.47k | expectToken(Token::Modifier); |
1019 | 3.47k | auto [name, nameLocation] = expectIdentifierWithLocation(); |
1020 | 3.47k | ASTPointer<ParameterList> parameters; |
1021 | 3.47k | if (m_scanner->currentToken() == Token::LParen) |
1022 | 693 | { |
1023 | 693 | VarDeclParserOptions options; |
1024 | 693 | options.allowLocationSpecifier = true; |
1025 | 693 | parameters = parseParameterList(options); |
1026 | 693 | } |
1027 | 2.77k | else |
1028 | 2.77k | parameters = createEmptyParameterList(); |
1029 | | |
1030 | 3.47k | ASTPointer<OverrideSpecifier> overrides; |
1031 | 3.47k | bool isVirtual = false; |
1032 | | |
1033 | 3.99k | while (true) |
1034 | 3.96k | { |
1035 | 3.96k | if (m_scanner->currentToken() == Token::Override) |
1036 | 268 | { |
1037 | 268 | if (overrides) |
1038 | 6 | parserError(9102_error, "Override already specified."); |
1039 | 268 | overrides = parseOverrideSpecifier(); |
1040 | 268 | } |
1041 | 3.69k | else if (m_scanner->currentToken() == Token::Virtual) |
1042 | 255 | { |
1043 | 255 | if (isVirtual) |
1044 | 10 | parserError(2662_error, "Virtual already specified."); |
1045 | | |
1046 | 255 | isVirtual = true; |
1047 | 255 | advance(); |
1048 | 255 | } |
1049 | 3.44k | else |
1050 | 3.44k | break; |
1051 | 3.96k | } |
1052 | | |
1053 | 3.47k | ASTPointer<Block> block; |
1054 | 3.47k | nodeFactory.markEndPosition(); |
1055 | 3.47k | if (m_scanner->currentToken() != Token::Semicolon) |
1056 | 1.00k | { |
1057 | 1.00k | block = parseBlock(); |
1058 | 1.00k | nodeFactory.setEndPositionFromNode(block); |
1059 | 1.00k | } |
1060 | 2.47k | else |
1061 | 2.47k | advance(); // just consume the ';' |
1062 | | |
1063 | 3.47k | return nodeFactory.createNode<ModifierDefinition>(name, nameLocation, documentation, parameters, isVirtual, overrides, block); |
1064 | 3.47k | } |
1065 | | |
1066 | | std::pair<ASTPointer<ASTString>, SourceLocation> Parser::expectIdentifierWithLocation() |
1067 | 200k | { |
1068 | 200k | SourceLocation nameLocation = currentLocation(); |
1069 | 200k | ASTPointer<ASTString> name = expectIdentifierToken(); |
1070 | | |
1071 | 200k | return {std::move(name), std::move(nameLocation)}; |
1072 | 200k | } |
1073 | | |
1074 | | ASTPointer<EventDefinition> Parser::parseEventDefinition() |
1075 | 3.88k | { |
1076 | 3.88k | RecursionGuard recursionGuard(*this); |
1077 | 3.88k | ASTNodeFactory nodeFactory(*this); |
1078 | 3.88k | ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation(); |
1079 | | |
1080 | 3.88k | expectToken(Token::Event); |
1081 | 3.88k | auto [name, nameLocation] = expectIdentifierWithLocation(); |
1082 | | |
1083 | 3.88k | VarDeclParserOptions options; |
1084 | 3.88k | options.allowIndexed = true; |
1085 | 3.88k | ASTPointer<ParameterList> parameters = parseParameterList(options); |
1086 | | |
1087 | 3.88k | bool anonymous = false; |
1088 | 3.88k | if (m_scanner->currentToken() == Token::Anonymous) |
1089 | 106 | { |
1090 | 106 | anonymous = true; |
1091 | 106 | advance(); |
1092 | 106 | } |
1093 | 3.88k | nodeFactory.markEndPosition(); |
1094 | 3.88k | expectToken(Token::Semicolon); |
1095 | 3.88k | return nodeFactory.createNode<EventDefinition>(name, nameLocation, documentation, parameters, anonymous); |
1096 | 3.88k | } |
1097 | | |
1098 | | ASTPointer<ErrorDefinition> Parser::parseErrorDefinition() |
1099 | 1.12k | { |
1100 | 1.12k | RecursionGuard recursionGuard(*this); |
1101 | 1.12k | ASTNodeFactory nodeFactory(*this); |
1102 | 1.12k | ASTPointer<StructuredDocumentation> documentation = parseStructuredDocumentation(); |
1103 | | |
1104 | 1.12k | solAssert(*expectIdentifierToken() == "error", ""); |
1105 | 1.12k | auto&& [name, nameLocation] = expectIdentifierWithLocation(); |
1106 | | |
1107 | 1.12k | ASTPointer<ParameterList> parameters = parseParameterList({}); |
1108 | 1.12k | nodeFactory.markEndPosition(); |
1109 | 1.12k | expectToken(Token::Semicolon); |
1110 | 1.12k | return nodeFactory.createNode<ErrorDefinition>(name, std::move(nameLocation), documentation, parameters); |
1111 | 1.12k | } |
1112 | | |
1113 | | ASTPointer<UsingForDirective> Parser::parseUsingDirective() |
1114 | 913 | { |
1115 | 913 | RecursionGuard recursionGuard(*this); |
1116 | 913 | ASTNodeFactory nodeFactory(*this); |
1117 | | |
1118 | 913 | expectToken(Token::Using); |
1119 | | |
1120 | 913 | std::vector<ASTPointer<IdentifierPath>> functions; |
1121 | 913 | std::vector<std::optional<Token>> operators; |
1122 | 913 | bool const usesBraces = m_scanner->currentToken() == Token::LBrace; |
1123 | 913 | if (usesBraces) |
1124 | 465 | { |
1125 | 465 | do |
1126 | 962 | { |
1127 | 962 | advance(); |
1128 | 962 | functions.emplace_back(parseIdentifierPath()); |
1129 | 962 | if (m_scanner->currentToken() == Token::As) |
1130 | 462 | { |
1131 | 462 | advance(); |
1132 | 462 | Token operator_ = m_scanner->currentToken(); |
1133 | 462 | if (!util::contains(userDefinableOperators, operator_)) |
1134 | 114 | { |
1135 | 114 | std::string operatorName; |
1136 | 114 | if (!m_scanner->currentLiteral().empty()) |
1137 | 80 | operatorName = m_scanner->currentLiteral(); |
1138 | 34 | else if (char const* tokenString = TokenTraits::toString(operator_)) |
1139 | 11 | operatorName = std::string(tokenString); |
1140 | | |
1141 | 114 | parserError( |
1142 | 114 | 4403_error, |
1143 | 114 | fmt::format( |
1144 | 114 | "Not a user-definable operator: {}. Only the following operators can be user-defined: {}", |
1145 | 114 | operatorName, |
1146 | 1.71k | util::joinHumanReadable(userDefinableOperators | ranges::views::transform([](Token _t) { return std::string{TokenTraits::toString(_t)}; })) |
1147 | 114 | ) |
1148 | 114 | ); |
1149 | 114 | } |
1150 | 462 | operators.emplace_back(operator_); |
1151 | 462 | advance(); |
1152 | 462 | } |
1153 | 500 | else |
1154 | 500 | operators.emplace_back(std::nullopt); |
1155 | 962 | } |
1156 | 962 | while (m_scanner->currentToken() == Token::Comma); |
1157 | 465 | expectToken(Token::RBrace); |
1158 | 465 | } |
1159 | 448 | else |
1160 | 448 | { |
1161 | 448 | functions.emplace_back(parseIdentifierPath()); |
1162 | 448 | operators.emplace_back(std::nullopt); |
1163 | 448 | } |
1164 | | |
1165 | 913 | ASTPointer<TypeName> typeName; |
1166 | 913 | expectToken(Token::For); |
1167 | 913 | if (m_scanner->currentToken() == Token::Mul) |
1168 | 152 | advance(); |
1169 | 761 | else |
1170 | 761 | typeName = parseTypeName(); |
1171 | 913 | bool global = false; |
1172 | 913 | if (m_scanner->currentToken() == Token::Identifier && currentLiteral() == "global") |
1173 | 287 | { |
1174 | 287 | global = true; |
1175 | 287 | advance(); |
1176 | 287 | } |
1177 | 913 | nodeFactory.markEndPosition(); |
1178 | 913 | expectToken(Token::Semicolon); |
1179 | 913 | return nodeFactory.createNode<UsingForDirective>(std::move(functions), std::move(operators), usesBraces, typeName, global); |
1180 | 913 | } |
1181 | | |
1182 | | ASTPointer<ModifierInvocation> Parser::parseModifierInvocation() |
1183 | 4.21k | { |
1184 | 4.21k | RecursionGuard recursionGuard(*this); |
1185 | 4.21k | ASTNodeFactory nodeFactory(*this); |
1186 | 4.21k | ASTPointer<IdentifierPath> name(parseIdentifierPath()); |
1187 | 4.21k | std::unique_ptr<std::vector<ASTPointer<Expression>>> arguments; |
1188 | 4.21k | if (m_scanner->currentToken() == Token::LParen) |
1189 | 1.32k | { |
1190 | 1.32k | advance(); |
1191 | 1.32k | arguments = std::make_unique<std::vector<ASTPointer<Expression>>>(parseFunctionCallListArguments()); |
1192 | 1.32k | nodeFactory.markEndPosition(); |
1193 | 1.32k | expectToken(Token::RParen); |
1194 | 1.32k | } |
1195 | 2.89k | else |
1196 | 2.89k | nodeFactory.setEndPositionFromNode(name); |
1197 | 4.21k | return nodeFactory.createNode<ModifierInvocation>(name, std::move(arguments)); |
1198 | 4.21k | } |
1199 | | |
1200 | | ASTPointer<Identifier> Parser::parseIdentifier() |
1201 | 32.5k | { |
1202 | 32.5k | RecursionGuard recursionGuard(*this); |
1203 | 32.5k | ASTNodeFactory nodeFactory(*this); |
1204 | 32.5k | nodeFactory.markEndPosition(); |
1205 | 32.5k | return nodeFactory.createNode<Identifier>(expectIdentifierToken()); |
1206 | 32.5k | } |
1207 | | |
1208 | | ASTPointer<Identifier> Parser::parseIdentifierOrAddress() |
1209 | 40.4k | { |
1210 | 40.4k | RecursionGuard recursionGuard(*this); |
1211 | 40.4k | ASTNodeFactory nodeFactory(*this); |
1212 | 40.4k | nodeFactory.markEndPosition(); |
1213 | 40.4k | return nodeFactory.createNode<Identifier>(expectIdentifierTokenOrAddress()); |
1214 | 40.4k | } |
1215 | | |
1216 | | ASTPointer<UserDefinedTypeName> Parser::parseUserDefinedTypeName() |
1217 | 26.2k | { |
1218 | 26.2k | ASTNodeFactory nodeFactory(*this); |
1219 | 26.2k | ASTPointer<IdentifierPath> identifierPath = parseIdentifierPath(); |
1220 | 26.2k | nodeFactory.setEndPositionFromNode(identifierPath); |
1221 | 26.2k | return nodeFactory.createNode<UserDefinedTypeName>(identifierPath); |
1222 | 26.2k | } |
1223 | | |
1224 | | ASTPointer<UserDefinedValueTypeDefinition> Parser::parseUserDefinedValueTypeDefinition() |
1225 | 780 | { |
1226 | 780 | ASTNodeFactory nodeFactory(*this); |
1227 | 780 | expectToken(Token::Type); |
1228 | 780 | auto&& [name, nameLocation] = expectIdentifierWithLocation(); |
1229 | 780 | expectToken(Token::Is); |
1230 | 780 | ASTPointer<TypeName> typeName = parseTypeName(); |
1231 | 780 | nodeFactory.markEndPosition(); |
1232 | 780 | expectToken(Token::Semicolon); |
1233 | 780 | return nodeFactory.createNode<UserDefinedValueTypeDefinition>( |
1234 | 780 | name, |
1235 | 780 | std::move(nameLocation), |
1236 | 780 | typeName |
1237 | 780 | ); |
1238 | 780 | } |
1239 | | |
1240 | | ASTPointer<IdentifierPath> Parser::parseIdentifierPath() |
1241 | 39.6k | { |
1242 | 39.6k | RecursionGuard recursionGuard(*this); |
1243 | 39.6k | ASTNodeFactory nodeFactory(*this); |
1244 | 39.6k | nodeFactory.markEndPosition(); |
1245 | | |
1246 | 39.6k | auto [name, nameLocation] = expectIdentifierWithLocation(); |
1247 | | |
1248 | 39.6k | std::vector<ASTString> identifierPath{*name}; |
1249 | 39.6k | std::vector<SourceLocation> identifierPathLocations{nameLocation}; |
1250 | | |
1251 | 41.9k | while (m_scanner->currentToken() == Token::Period) |
1252 | 2.28k | { |
1253 | 2.28k | advance(); |
1254 | | |
1255 | 2.28k | nodeFactory.markEndPosition(); |
1256 | | |
1257 | 2.28k | tie(name, nameLocation) = expectIdentifierWithLocation(); |
1258 | | |
1259 | 2.28k | identifierPath.push_back(*name); |
1260 | 2.28k | identifierPathLocations.push_back(nameLocation); |
1261 | 2.28k | } |
1262 | 39.6k | return nodeFactory.createNode<IdentifierPath>(identifierPath, identifierPathLocations); |
1263 | 39.6k | } |
1264 | | |
1265 | | ASTPointer<TypeName> Parser::parseTypeNameSuffix(ASTPointer<TypeName> type, ASTNodeFactory& nodeFactory) |
1266 | 101k | { |
1267 | 101k | RecursionGuard recursionGuard(*this); |
1268 | 125k | while (m_scanner->currentToken() == Token::LBrack) |
1269 | 24.5k | { |
1270 | 24.5k | advance(); |
1271 | 24.5k | ASTPointer<Expression> length; |
1272 | 24.5k | if (m_scanner->currentToken() != Token::RBrack) |
1273 | 9.69k | length = parseExpression(); |
1274 | 24.5k | nodeFactory.markEndPosition(); |
1275 | 24.5k | expectToken(Token::RBrack); |
1276 | 24.5k | type = nodeFactory.createNode<ArrayTypeName>(type, length); |
1277 | 24.5k | } |
1278 | 101k | return type; |
1279 | 101k | } |
1280 | | |
1281 | | ASTPointer<TypeName> Parser::parseTypeName() |
1282 | 101k | { |
1283 | 101k | RecursionGuard recursionGuard(*this); |
1284 | 101k | ASTNodeFactory nodeFactory(*this); |
1285 | 101k | ASTPointer<TypeName> type; |
1286 | 101k | Token token = m_scanner->currentToken(); |
1287 | 101k | if (TokenTraits::isElementaryTypeName(token)) |
1288 | 72.6k | { |
1289 | 72.6k | unsigned firstSize; |
1290 | 72.6k | unsigned secondSize; |
1291 | 72.6k | std::tie(firstSize, secondSize) = m_scanner->currentTokenInfo(); |
1292 | 72.6k | ElementaryTypeNameToken elemTypeName(token, firstSize, secondSize); |
1293 | 72.6k | ASTNodeFactory nodeFactory(*this); |
1294 | 72.6k | nodeFactory.markEndPosition(); |
1295 | 72.6k | advance(); |
1296 | 72.6k | auto stateMutability = elemTypeName.token() == Token::Address |
1297 | 72.6k | ? std::optional<StateMutability>{StateMutability::NonPayable} |
1298 | 72.6k | : std::nullopt; |
1299 | 72.6k | if (TokenTraits::isStateMutabilitySpecifier(m_scanner->currentToken())) |
1300 | 490 | { |
1301 | 490 | if (elemTypeName.token() == Token::Address) |
1302 | 485 | { |
1303 | 485 | nodeFactory.markEndPosition(); |
1304 | 485 | stateMutability = parseStateMutability(); |
1305 | 485 | } |
1306 | 5 | else |
1307 | 5 | { |
1308 | 5 | parserError(9106_error, "State mutability can only be specified for address types."); |
1309 | 5 | advance(); |
1310 | 5 | } |
1311 | 490 | } |
1312 | 72.6k | type = nodeFactory.createNode<ElementaryTypeName>(elemTypeName, stateMutability); |
1313 | 72.6k | } |
1314 | 28.8k | else if (token == Token::Function) |
1315 | 1.39k | type = parseFunctionType(); |
1316 | 27.4k | else if (token == Token::Mapping) |
1317 | 1.25k | type = parseMapping(); |
1318 | 26.1k | else if (token == Token::Identifier) |
1319 | 26.1k | type = parseUserDefinedTypeName(); |
1320 | 83 | else |
1321 | 83 | fatalParserError(3546_error, "Expected type name"); |
1322 | | |
1323 | 101k | solAssert(type, ""); |
1324 | | // Parse "[...]" postfixes for arrays. |
1325 | 101k | type = parseTypeNameSuffix(type, nodeFactory); |
1326 | | |
1327 | 101k | return type; |
1328 | 101k | } |
1329 | | |
1330 | | ASTPointer<FunctionTypeName> Parser::parseFunctionType() |
1331 | 1.39k | { |
1332 | 1.39k | solAssert(!m_experimentalSolidityEnabledInCurrentSourceUnit); |
1333 | 1.39k | RecursionGuard recursionGuard(*this); |
1334 | 1.39k | ASTNodeFactory nodeFactory(*this); |
1335 | 1.39k | expectToken(Token::Function); |
1336 | 1.39k | FunctionHeaderParserResult header = parseFunctionHeader(true); |
1337 | 1.39k | solAssert(!header.experimentalReturnExpression); |
1338 | 1.39k | return nodeFactory.createNode<FunctionTypeName>( |
1339 | 1.39k | header.parameters, |
1340 | 1.39k | header.returnParameters, |
1341 | 1.39k | header.visibility, |
1342 | 1.39k | header.stateMutability |
1343 | 1.39k | ); |
1344 | 1.39k | } |
1345 | | |
1346 | | ASTPointer<Mapping> Parser::parseMapping() |
1347 | 1.25k | { |
1348 | 1.25k | RecursionGuard recursionGuard(*this); |
1349 | 1.25k | ASTNodeFactory nodeFactory(*this); |
1350 | 1.25k | expectToken(Token::Mapping); |
1351 | 1.25k | expectToken(Token::LParen); |
1352 | 1.25k | ASTPointer<TypeName> keyType; |
1353 | 1.25k | Token token = m_scanner->currentToken(); |
1354 | 1.25k | unsigned firstSize; |
1355 | 1.25k | unsigned secondSize; |
1356 | 1.25k | std::tie(firstSize, secondSize) = m_scanner->currentTokenInfo(); |
1357 | 1.25k | if (token == Token::Identifier) |
1358 | 95 | keyType = parseUserDefinedTypeName(); |
1359 | 1.16k | else if (TokenTraits::isElementaryTypeName(token)) |
1360 | 1.15k | { |
1361 | 1.15k | keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>( |
1362 | 1.15k | ElementaryTypeNameToken{token, firstSize, secondSize} |
1363 | 1.15k | ); |
1364 | 1.15k | advance(); |
1365 | 1.15k | } |
1366 | 8 | else |
1367 | 8 | fatalParserError(1005_error, "Expected elementary type name or identifier for mapping key type"); |
1368 | 1.25k | ASTPointer<ASTString> keyName = std::make_shared<ASTString>(""); |
1369 | 1.25k | SourceLocation keyNameLocation{}; |
1370 | 1.25k | if (m_scanner->currentToken() == Token::Identifier) |
1371 | 214 | tie(keyName, keyNameLocation) = expectIdentifierWithLocation(); |
1372 | 1.25k | expectToken(Token::DoubleArrow); |
1373 | 1.25k | ASTPointer<TypeName> valueType = parseTypeName(); |
1374 | 1.25k | ASTPointer<ASTString> valueName = std::make_shared<ASTString>(""); |
1375 | 1.25k | SourceLocation valueNameLocation{}; |
1376 | 1.25k | if (m_scanner->currentToken() == Token::Identifier) |
1377 | 152 | tie(valueName, valueNameLocation) = expectIdentifierWithLocation(); |
1378 | 1.25k | nodeFactory.markEndPosition(); |
1379 | 1.25k | expectToken(Token::RParen); |
1380 | 1.25k | return nodeFactory.createNode<Mapping>(keyType, keyName, keyNameLocation, valueType, valueName, valueNameLocation); |
1381 | 1.25k | } |
1382 | | |
1383 | | ASTPointer<ParameterList> Parser::parseParameterList( |
1384 | | VarDeclParserOptions const& _options, |
1385 | | bool _allowEmpty |
1386 | | ) |
1387 | 49.8k | { |
1388 | 49.8k | RecursionGuard recursionGuard(*this); |
1389 | 49.8k | ASTNodeFactory nodeFactory(*this); |
1390 | 49.8k | std::vector<ASTPointer<VariableDeclaration>> parameters; |
1391 | 49.8k | VarDeclParserOptions options(_options); |
1392 | 49.8k | options.allowEmptyName = true; |
1393 | 49.8k | if (m_experimentalSolidityEnabledInCurrentSourceUnit && m_scanner->currentToken() == Token::Identifier) |
1394 | 24 | { |
1395 | | // Parses unary parameter lists without parentheses. TODO: is this a good idea in all cases? Including arguments? |
1396 | 24 | parameters = {parsePostfixVariableDeclaration()}; |
1397 | 24 | nodeFactory.setEndPositionFromNode(parameters.front()); |
1398 | 24 | return nodeFactory.createNode<ParameterList>(parameters); |
1399 | 24 | } |
1400 | 49.8k | expectToken(Token::LParen); |
1401 | 49.8k | auto parseSingleVariableDeclaration = [&]() { |
1402 | 37.9k | if (m_experimentalSolidityEnabledInCurrentSourceUnit) |
1403 | 214 | return parsePostfixVariableDeclaration(); |
1404 | 37.7k | else |
1405 | 37.7k | return parseVariableDeclaration(options); |
1406 | 37.9k | }; |
1407 | 49.8k | if (!_allowEmpty || m_scanner->currentToken() != Token::RParen) |
1408 | 26.5k | { |
1409 | 26.5k | parameters.push_back(parseSingleVariableDeclaration()); |
1410 | 38.0k | while (m_scanner->currentToken() != Token::RParen) |
1411 | 11.5k | { |
1412 | 11.5k | if (m_scanner->currentToken() == Token::Comma && m_scanner->peekNextToken() == Token::RParen) |
1413 | 2 | fatalParserError(7591_error, "Unexpected trailing comma in parameter list."); |
1414 | 11.5k | expectToken(Token::Comma); |
1415 | 11.5k | parameters.push_back(parseSingleVariableDeclaration()); |
1416 | 11.5k | } |
1417 | 26.5k | } |
1418 | 49.8k | nodeFactory.markEndPosition(); |
1419 | 49.8k | advance(); |
1420 | 49.8k | return nodeFactory.createNode<ParameterList>(parameters); |
1421 | 49.8k | } |
1422 | | |
1423 | | ASTPointer<Block> Parser::parseBlock(bool _allowUnchecked, ASTPointer<ASTString> const& _docString) |
1424 | 32.2k | { |
1425 | 32.2k | RecursionGuard recursionGuard(*this); |
1426 | 32.2k | ASTNodeFactory nodeFactory(*this); |
1427 | 32.2k | bool const unchecked = m_scanner->currentToken() == Token::Unchecked; |
1428 | 32.2k | if (unchecked) |
1429 | 196 | { |
1430 | 196 | if (!_allowUnchecked) |
1431 | 1 | parserError(5296_error, "\"unchecked\" blocks can only be used inside regular blocks."); |
1432 | 196 | advance(); |
1433 | 196 | } |
1434 | 32.2k | expectToken(Token::LBrace); |
1435 | 32.2k | std::vector<ASTPointer<Statement>> statements; |
1436 | 149k | while (m_scanner->currentToken() != Token::RBrace) |
1437 | 117k | statements.push_back(parseStatement(true)); |
1438 | 32.2k | nodeFactory.markEndPosition(); |
1439 | 32.2k | expectToken(Token::RBrace); |
1440 | 32.2k | return nodeFactory.createNode<Block>(_docString, unchecked, statements); |
1441 | 32.2k | } |
1442 | | |
1443 | | ASTPointer<Statement> Parser::parseStatement(bool _allowUnchecked) |
1444 | 160k | { |
1445 | 160k | RecursionGuard recursionGuard(*this); |
1446 | 160k | ASTPointer<ASTString> docString; |
1447 | 160k | ASTPointer<Statement> statement; |
1448 | 160k | if (!m_scanner->currentCommentLiteral().empty()) |
1449 | 550 | docString = std::make_shared<ASTString>(m_scanner->currentCommentLiteral()); |
1450 | 160k | switch (m_scanner->currentToken()) |
1451 | 160k | { |
1452 | 38.9k | case Token::If: |
1453 | 38.9k | return parseIfStatement(docString); |
1454 | 275 | case Token::While: |
1455 | 275 | return parseWhileStatement(docString); |
1456 | 94 | case Token::Do: |
1457 | 94 | return parseDoWhileStatement(docString); |
1458 | 3.38k | case Token::For: |
1459 | 3.38k | return parseForStatement(docString); |
1460 | 195 | case Token::Unchecked: |
1461 | 1.92k | case Token::LBrace: |
1462 | 1.92k | return parseBlock(_allowUnchecked, docString); |
1463 | 105 | case Token::Continue: |
1464 | 105 | statement = ASTNodeFactory(*this).createNode<Continue>(docString); |
1465 | 105 | advance(); |
1466 | 105 | break; |
1467 | 123 | case Token::Break: |
1468 | 123 | statement = ASTNodeFactory(*this).createNode<Break>(docString); |
1469 | 123 | advance(); |
1470 | 123 | break; |
1471 | 46.9k | case Token::Return: |
1472 | 46.9k | { |
1473 | 46.9k | ASTNodeFactory nodeFactory(*this); |
1474 | 46.9k | ASTPointer<Expression> expression; |
1475 | 46.9k | if (advance() != Token::Semicolon) |
1476 | 46.5k | { |
1477 | 46.5k | expression = parseExpression(); |
1478 | 46.5k | nodeFactory.setEndPositionFromNode(expression); |
1479 | 46.5k | } |
1480 | 46.9k | statement = nodeFactory.createNode<Return>(docString, expression); |
1481 | 46.9k | break; |
1482 | 195 | } |
1483 | 4 | case Token::Throw: |
1484 | 4 | { |
1485 | 4 | statement = ASTNodeFactory(*this).createNode<Throw>(docString); |
1486 | 4 | advance(); |
1487 | 4 | break; |
1488 | 195 | } |
1489 | 505 | case Token::Try: |
1490 | 505 | return parseTryStatement(docString); |
1491 | 3.92k | case Token::Assembly: |
1492 | 3.92k | return parseInlineAssembly(docString); |
1493 | 1.58k | case Token::Emit: |
1494 | 1.58k | statement = parseEmitStatement(docString); |
1495 | 1.58k | break; |
1496 | 48.6k | case Token::Identifier: |
1497 | 48.6k | if (m_scanner->currentLiteral() == "revert" && m_scanner->peekNextToken() == Token::Identifier) |
1498 | 90 | statement = parseRevertStatement(docString); |
1499 | 48.5k | else if (m_insideModifier && m_scanner->currentLiteral() == "_") |
1500 | 1.00k | { |
1501 | 1.00k | statement = ASTNodeFactory(*this).createNode<PlaceholderStatement>(docString); |
1502 | 1.00k | advance(); |
1503 | 1.00k | } |
1504 | 47.5k | else |
1505 | 47.5k | statement = parseSimpleStatement(docString); |
1506 | 48.6k | break; |
1507 | 14.2k | default: |
1508 | 14.2k | statement = parseSimpleStatement(docString); |
1509 | 14.2k | break; |
1510 | 160k | } |
1511 | 111k | expectToken(Token::Semicolon); |
1512 | 111k | return statement; |
1513 | 160k | } |
1514 | | |
1515 | | ASTPointer<InlineAssembly> Parser::parseInlineAssembly(ASTPointer<ASTString> const& _docString) |
1516 | 3.92k | { |
1517 | 3.92k | RecursionGuard recursionGuard(*this); |
1518 | 3.92k | SourceLocation location = currentLocation(); |
1519 | | |
1520 | 3.92k | expectToken(Token::Assembly); |
1521 | 3.92k | yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion); |
1522 | 3.92k | if (m_scanner->currentToken() == Token::StringLiteral) |
1523 | 19 | { |
1524 | 19 | if (m_scanner->currentLiteral() != "evmasm") |
1525 | 3 | fatalParserError(4531_error, "Only \"evmasm\" supported."); |
1526 | | // This can be used in the future to set the dialect. |
1527 | 19 | advance(); |
1528 | 19 | } |
1529 | | |
1530 | 3.92k | ASTPointer<std::vector<ASTPointer<ASTString>>> flags; |
1531 | 3.92k | if (m_scanner->currentToken() == Token::LParen) |
1532 | 51 | { |
1533 | 51 | flags = std::make_shared<std::vector<ASTPointer<ASTString>>>(); |
1534 | 51 | do |
1535 | 131 | { |
1536 | 131 | advance(); |
1537 | 131 | expectToken(Token::StringLiteral, false); |
1538 | 131 | flags->emplace_back(std::make_shared<ASTString>(m_scanner->currentLiteral())); |
1539 | 131 | advance(); |
1540 | 131 | } |
1541 | 131 | while (m_scanner->currentToken() == Token::Comma); |
1542 | 51 | expectToken(Token::RParen); |
1543 | 51 | } |
1544 | | |
1545 | 3.92k | yul::Parser asmParser(m_errorReporter, dialect); |
1546 | 3.92k | std::shared_ptr<yul::AST> ast = asmParser.parseInline(m_scanner); |
1547 | 3.92k | if (ast == nullptr) |
1548 | 350 | solThrow(FatalError, "Failed to parse inline assembly."); |
1549 | | |
1550 | 3.92k | location.end = nativeLocationOf(ast->root()).end; |
1551 | 3.92k | return std::make_shared<InlineAssembly>(nextID(), location, _docString, dialect, std::move(flags), ast); |
1552 | 3.92k | } |
1553 | | |
1554 | | ASTPointer<IfStatement> Parser::parseIfStatement(ASTPointer<ASTString> const& _docString) |
1555 | 38.9k | { |
1556 | 38.9k | RecursionGuard recursionGuard(*this); |
1557 | 38.9k | ASTNodeFactory nodeFactory(*this); |
1558 | 38.9k | expectToken(Token::If); |
1559 | 38.9k | expectToken(Token::LParen); |
1560 | 38.9k | ASTPointer<Expression> condition = parseExpression(); |
1561 | 38.9k | expectToken(Token::RParen); |
1562 | 38.9k | ASTPointer<Statement> trueBody = parseStatement(); |
1563 | 38.9k | ASTPointer<Statement> falseBody; |
1564 | 38.9k | if (m_scanner->currentToken() == Token::Else) |
1565 | 393 | { |
1566 | 393 | advance(); |
1567 | 393 | falseBody = parseStatement(); |
1568 | 393 | nodeFactory.setEndPositionFromNode(falseBody); |
1569 | 393 | } |
1570 | 38.6k | else |
1571 | 38.6k | nodeFactory.setEndPositionFromNode(trueBody); |
1572 | 38.9k | return nodeFactory.createNode<IfStatement>(_docString, condition, trueBody, falseBody); |
1573 | 38.9k | } |
1574 | | |
1575 | | ASTPointer<TryStatement> Parser::parseTryStatement(ASTPointer<ASTString> const& _docString) |
1576 | 505 | { |
1577 | 505 | RecursionGuard recursionGuard(*this); |
1578 | 505 | ASTNodeFactory nodeFactory(*this); |
1579 | 505 | expectToken(Token::Try); |
1580 | 505 | ASTPointer<Expression> externalCall = parseExpression(); |
1581 | 505 | std::vector<ASTPointer<TryCatchClause>> clauses; |
1582 | | |
1583 | 505 | ASTNodeFactory successClauseFactory(*this); |
1584 | 505 | ASTPointer<ParameterList> returnsParameters; |
1585 | 505 | if (m_scanner->currentToken() == Token::Returns) |
1586 | 115 | { |
1587 | 115 | advance(); |
1588 | 115 | VarDeclParserOptions options; |
1589 | 115 | options.allowEmptyName = true; |
1590 | 115 | options.allowLocationSpecifier = true; |
1591 | 115 | returnsParameters = parseParameterList(options, false); |
1592 | 115 | } |
1593 | 505 | ASTPointer<Block> successBlock = parseBlock(); |
1594 | 505 | successClauseFactory.setEndPositionFromNode(successBlock); |
1595 | 505 | clauses.emplace_back(successClauseFactory.createNode<TryCatchClause>( |
1596 | 505 | std::make_shared<ASTString>(), returnsParameters, successBlock |
1597 | 505 | )); |
1598 | | |
1599 | 505 | do |
1600 | 781 | { |
1601 | 781 | clauses.emplace_back(parseCatchClause()); |
1602 | 781 | } |
1603 | 781 | while (m_scanner->currentToken() == Token::Catch); |
1604 | 505 | nodeFactory.setEndPositionFromNode(clauses.back()); |
1605 | 505 | return nodeFactory.createNode<TryStatement>( |
1606 | 505 | _docString, externalCall, clauses |
1607 | 505 | ); |
1608 | 505 | } |
1609 | | |
1610 | | ASTPointer<TryCatchClause> Parser::parseCatchClause() |
1611 | 687 | { |
1612 | 687 | RecursionGuard recursionGuard(*this); |
1613 | 687 | ASTNodeFactory nodeFactory(*this); |
1614 | 687 | expectToken(Token::Catch); |
1615 | 687 | ASTPointer<ASTString> errorName = std::make_shared<std::string>(); |
1616 | 687 | ASTPointer<ParameterList> errorParameters; |
1617 | 687 | if (m_scanner->currentToken() != Token::LBrace) |
1618 | 399 | { |
1619 | 399 | if (m_scanner->currentToken() == Token::Identifier) |
1620 | 274 | errorName = expectIdentifierToken(); |
1621 | 399 | VarDeclParserOptions options; |
1622 | 399 | options.allowEmptyName = true; |
1623 | 399 | options.allowLocationSpecifier = true; |
1624 | 399 | errorParameters = parseParameterList(options, !errorName->empty()); |
1625 | 399 | } |
1626 | 687 | ASTPointer<Block> block = parseBlock(); |
1627 | 687 | nodeFactory.setEndPositionFromNode(block); |
1628 | 687 | return nodeFactory.createNode<TryCatchClause>(errorName, errorParameters, block); |
1629 | 687 | } |
1630 | | |
1631 | | ASTPointer<WhileStatement> Parser::parseWhileStatement(ASTPointer<ASTString> const& _docString) |
1632 | 275 | { |
1633 | 275 | RecursionGuard recursionGuard(*this); |
1634 | 275 | ASTNodeFactory nodeFactory(*this); |
1635 | 275 | expectToken(Token::While); |
1636 | 275 | expectToken(Token::LParen); |
1637 | 275 | ASTPointer<Expression> condition = parseExpression(); |
1638 | 275 | expectToken(Token::RParen); |
1639 | 275 | ASTPointer<Statement> body = parseStatement(); |
1640 | 275 | nodeFactory.setEndPositionFromNode(body); |
1641 | 275 | return nodeFactory.createNode<WhileStatement>(_docString, condition, body, false); |
1642 | 275 | } |
1643 | | |
1644 | | ASTPointer<WhileStatement> Parser::parseDoWhileStatement(ASTPointer<ASTString> const& _docString) |
1645 | 94 | { |
1646 | 94 | RecursionGuard recursionGuard(*this); |
1647 | 94 | ASTNodeFactory nodeFactory(*this); |
1648 | 94 | expectToken(Token::Do); |
1649 | 94 | ASTPointer<Statement> body = parseStatement(); |
1650 | 94 | expectToken(Token::While); |
1651 | 94 | expectToken(Token::LParen); |
1652 | 94 | ASTPointer<Expression> condition = parseExpression(); |
1653 | 94 | expectToken(Token::RParen); |
1654 | 94 | nodeFactory.markEndPosition(); |
1655 | 94 | expectToken(Token::Semicolon); |
1656 | 94 | return nodeFactory.createNode<WhileStatement>(_docString, condition, body, true); |
1657 | 94 | } |
1658 | | |
1659 | | |
1660 | | ASTPointer<ForStatement> Parser::parseForStatement(ASTPointer<ASTString> const& _docString) |
1661 | 3.38k | { |
1662 | 3.38k | RecursionGuard recursionGuard(*this); |
1663 | 3.38k | ASTNodeFactory nodeFactory(*this); |
1664 | 3.38k | ASTPointer<Statement> initExpression; |
1665 | 3.38k | ASTPointer<Expression> conditionExpression; |
1666 | 3.38k | ASTPointer<ExpressionStatement> loopExpression; |
1667 | 3.38k | expectToken(Token::For); |
1668 | 3.38k | expectToken(Token::LParen); |
1669 | | |
1670 | | // TODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen? |
1671 | 3.38k | if (m_scanner->currentToken() != Token::Semicolon) |
1672 | 3.18k | initExpression = parseSimpleStatement(ASTPointer<ASTString>()); |
1673 | 3.38k | expectToken(Token::Semicolon); |
1674 | | |
1675 | 3.38k | if (m_scanner->currentToken() != Token::Semicolon) |
1676 | 3.20k | conditionExpression = parseExpression(); |
1677 | 3.38k | expectToken(Token::Semicolon); |
1678 | | |
1679 | 3.38k | if (m_scanner->currentToken() != Token::RParen) |
1680 | 3.16k | loopExpression = parseExpressionStatement(ASTPointer<ASTString>()); |
1681 | 3.38k | expectToken(Token::RParen); |
1682 | | |
1683 | 3.38k | ASTPointer<Statement> body = parseStatement(); |
1684 | 3.38k | nodeFactory.setEndPositionFromNode(body); |
1685 | 3.38k | return nodeFactory.createNode<ForStatement>( |
1686 | 3.38k | _docString, |
1687 | 3.38k | initExpression, |
1688 | 3.38k | conditionExpression, |
1689 | 3.38k | loopExpression, |
1690 | 3.38k | body |
1691 | 3.38k | ); |
1692 | 3.38k | } |
1693 | | |
1694 | | ASTPointer<EmitStatement> Parser::parseEmitStatement(ASTPointer<ASTString> const& _docString) |
1695 | 1.58k | { |
1696 | 1.58k | expectToken(Token::Emit, false); |
1697 | | |
1698 | 1.58k | ASTNodeFactory nodeFactory(*this); |
1699 | 1.58k | advance(); |
1700 | 1.58k | ASTNodeFactory eventCallNodeFactory(*this); |
1701 | | |
1702 | 1.58k | if (m_scanner->currentToken() != Token::Identifier) |
1703 | 1 | fatalParserError(5620_error, "Expected event name or path."); |
1704 | | |
1705 | 1.58k | IndexAccessedPath iap; |
1706 | 1.65k | while (true) |
1707 | 1.64k | { |
1708 | 1.64k | iap.path.push_back(parseIdentifier()); |
1709 | 1.64k | if (m_scanner->currentToken() != Token::Period) |
1710 | 1.58k | break; |
1711 | 65 | advance(); |
1712 | 65 | } |
1713 | | |
1714 | 1.58k | auto eventName = expressionFromIndexAccessStructure(iap); |
1715 | 1.58k | expectToken(Token::LParen); |
1716 | | |
1717 | 1.58k | auto functionCallArguments = parseFunctionCallArguments(); |
1718 | 1.58k | eventCallNodeFactory.markEndPosition(); |
1719 | 1.58k | nodeFactory.markEndPosition(); |
1720 | 1.58k | expectToken(Token::RParen); |
1721 | 1.58k | auto eventCall = eventCallNodeFactory.createNode<FunctionCall>( |
1722 | 1.58k | eventName, |
1723 | 1.58k | functionCallArguments.arguments, |
1724 | 1.58k | functionCallArguments.parameterNames, |
1725 | 1.58k | functionCallArguments.parameterNameLocations |
1726 | 1.58k | ); |
1727 | 1.58k | return nodeFactory.createNode<EmitStatement>(_docString, eventCall); |
1728 | 1.58k | } |
1729 | | |
1730 | | ASTPointer<RevertStatement> Parser::parseRevertStatement(ASTPointer<ASTString> const& _docString) |
1731 | 90 | { |
1732 | 90 | ASTNodeFactory nodeFactory(*this); |
1733 | 90 | solAssert(*expectIdentifierToken() == "revert", ""); |
1734 | | |
1735 | 90 | ASTNodeFactory errorCallNodeFactory(*this); |
1736 | | |
1737 | 90 | solAssert(m_scanner->currentToken() == Token::Identifier, ""); |
1738 | | |
1739 | 90 | IndexAccessedPath iap; |
1740 | 127 | while (true) |
1741 | 126 | { |
1742 | 126 | iap.path.push_back(parseIdentifier()); |
1743 | 126 | if (m_scanner->currentToken() != Token::Period) |
1744 | 89 | break; |
1745 | 37 | advance(); |
1746 | 37 | } |
1747 | | |
1748 | 90 | auto errorName = expressionFromIndexAccessStructure(iap); |
1749 | 90 | expectToken(Token::LParen); |
1750 | | |
1751 | 90 | auto functionCallArguments = parseFunctionCallArguments(); |
1752 | 90 | errorCallNodeFactory.markEndPosition(); |
1753 | 90 | nodeFactory.markEndPosition(); |
1754 | 90 | expectToken(Token::RParen); |
1755 | 90 | auto errorCall = errorCallNodeFactory.createNode<FunctionCall>( |
1756 | 90 | errorName, |
1757 | 90 | functionCallArguments.arguments, |
1758 | 90 | functionCallArguments.parameterNames, |
1759 | 90 | functionCallArguments.parameterNameLocations |
1760 | 90 | ); |
1761 | 90 | return nodeFactory.createNode<RevertStatement>(_docString, errorCall); |
1762 | 90 | } |
1763 | | |
1764 | | ASTPointer<VariableDeclarationStatement> Parser::parsePostfixVariableDeclarationStatement( |
1765 | | ASTPointer<ASTString> const& _docString |
1766 | | ) |
1767 | 28 | { |
1768 | 28 | RecursionGuard recursionGuard(*this); |
1769 | 28 | ASTNodeFactory nodeFactory(*this); |
1770 | | |
1771 | 28 | expectToken(Token::Let); |
1772 | | |
1773 | 28 | std::vector<ASTPointer<VariableDeclaration>> variables; |
1774 | 28 | variables.emplace_back(parsePostfixVariableDeclaration()); |
1775 | 28 | nodeFactory.setEndPositionFromNode(variables.back()); |
1776 | | |
1777 | 28 | ASTPointer<Expression> value; |
1778 | 28 | if (m_scanner->currentToken() == Token::Assign) |
1779 | 1 | { |
1780 | 1 | advance(); |
1781 | 1 | value = parseExpression(); |
1782 | 1 | nodeFactory.setEndPositionFromNode(value); |
1783 | 1 | } |
1784 | 28 | return nodeFactory.createNode<VariableDeclarationStatement>(_docString, variables, value); |
1785 | 28 | } |
1786 | | |
1787 | | ASTPointer<VariableDeclaration> Parser::parsePostfixVariableDeclaration() |
1788 | 266 | { |
1789 | 266 | RecursionGuard recursionGuard(*this); |
1790 | 266 | ASTNodeFactory nodeFactory(*this); |
1791 | | |
1792 | 266 | ASTPointer<StructuredDocumentation> const documentation = parseStructuredDocumentation(); |
1793 | | |
1794 | 266 | nodeFactory.markEndPosition(); |
1795 | 266 | auto [identifier, nameLocation] = expectIdentifierWithLocation(); |
1796 | | |
1797 | 266 | ASTPointer<Expression> type; |
1798 | 266 | if (m_scanner->currentToken() == Token::Colon) |
1799 | 172 | { |
1800 | 172 | advance(); |
1801 | 172 | type = parseBinaryExpression(); |
1802 | 172 | nodeFactory.setEndPositionFromNode(type); |
1803 | 172 | } |
1804 | | |
1805 | 266 | return nodeFactory.createNode<VariableDeclaration>( |
1806 | 266 | nullptr, |
1807 | 266 | identifier, |
1808 | 266 | nameLocation, |
1809 | 266 | nullptr, |
1810 | 266 | Visibility::Default, |
1811 | 266 | documentation, |
1812 | 266 | false, |
1813 | 266 | VariableDeclaration::Mutability::Mutable, |
1814 | 266 | nullptr, |
1815 | 266 | VariableDeclaration::Location::Unspecified, |
1816 | 266 | type |
1817 | 266 | ); |
1818 | 266 | } |
1819 | | |
1820 | | ASTPointer<TypeClassDefinition> Parser::parseTypeClassDefinition() |
1821 | 61 | { |
1822 | 61 | solAssert(m_experimentalSolidityEnabledInCurrentSourceUnit); |
1823 | 61 | RecursionGuard recursionGuard(*this); |
1824 | 61 | ASTNodeFactory nodeFactory(*this); |
1825 | | |
1826 | 61 | std::vector<ASTPointer<ASTNode>> subNodes; |
1827 | | |
1828 | 61 | ASTPointer<StructuredDocumentation> const documentation = parseStructuredDocumentation(); |
1829 | | |
1830 | 61 | expectToken(Token::Class); |
1831 | | // TODO: parseTypeVariable()? parseTypeVariableDeclaration()? |
1832 | 61 | ASTPointer<VariableDeclaration> typeVariable; |
1833 | 61 | { |
1834 | 61 | ASTNodeFactory nodeFactory(*this); |
1835 | 61 | nodeFactory.markEndPosition(); |
1836 | 61 | auto [identifier, nameLocation] = expectIdentifierWithLocation(); |
1837 | 61 | typeVariable = nodeFactory.createNode<VariableDeclaration>( |
1838 | 61 | nullptr, |
1839 | 61 | identifier, |
1840 | 61 | nameLocation, |
1841 | 61 | nullptr, |
1842 | 61 | Visibility::Default, |
1843 | 61 | nullptr |
1844 | 61 | ); |
1845 | 61 | } |
1846 | 61 | expectToken(Token::Colon); |
1847 | 61 | auto [name, nameLocation] = expectIdentifierWithLocation(); |
1848 | 61 | expectToken(Token::LBrace); |
1849 | 97 | while (true) |
1850 | 84 | { |
1851 | 84 | Token currentTokenValue = m_scanner->currentToken(); |
1852 | 84 | if (currentTokenValue == Token::RBrace) |
1853 | 48 | break; |
1854 | 36 | expectToken(Token::Function, false); |
1855 | 36 | subNodes.push_back(parseFunctionDefinition(false, false)); |
1856 | 36 | } |
1857 | 61 | nodeFactory.markEndPosition(); |
1858 | 61 | expectToken(Token::RBrace); |
1859 | | |
1860 | 61 | return nodeFactory.createNode<TypeClassDefinition>( |
1861 | 61 | typeVariable, |
1862 | 61 | name, |
1863 | 61 | nameLocation, |
1864 | 61 | documentation, |
1865 | 61 | subNodes |
1866 | 61 | ); |
1867 | 61 | } |
1868 | | |
1869 | | ASTPointer<TypeClassName> Parser::parseTypeClassName() |
1870 | 55 | { |
1871 | 55 | RecursionGuard recursionGuard(*this); |
1872 | 55 | ASTNodeFactory nodeFactory(*this); |
1873 | 55 | std::variant<Token, ASTPointer<IdentifierPath>> name; |
1874 | 55 | if (TokenTraits::isBuiltinTypeClassName(m_scanner->currentToken())) |
1875 | 7 | { |
1876 | 7 | nodeFactory.markEndPosition(); |
1877 | 7 | name = m_scanner->currentToken(); |
1878 | 7 | advance(); |
1879 | 7 | } |
1880 | 48 | else |
1881 | 48 | { |
1882 | 48 | auto identifierPath = parseIdentifierPath(); |
1883 | 48 | name = identifierPath; |
1884 | 48 | nodeFactory.setEndPositionFromNode(identifierPath); |
1885 | 48 | } |
1886 | 55 | return nodeFactory.createNode<TypeClassName>(name); |
1887 | 55 | } |
1888 | | |
1889 | | ASTPointer<TypeClassInstantiation> Parser::parseTypeClassInstantiation() |
1890 | 59 | { |
1891 | 59 | solAssert(m_experimentalSolidityEnabledInCurrentSourceUnit); |
1892 | 59 | RecursionGuard recursionGuard(*this); |
1893 | 59 | ASTNodeFactory nodeFactory(*this); |
1894 | | |
1895 | 59 | std::vector<ASTPointer<ASTNode>> subNodes; |
1896 | | |
1897 | 59 | expectToken(Token::Instantiation); |
1898 | | // TODO: parseTypeConstructor() |
1899 | 59 | ASTPointer<TypeName> typeConstructor = parseTypeName(); |
1900 | 59 | ASTPointer<ParameterList> argumentSorts; |
1901 | 59 | if (m_scanner->currentToken() == Token::LParen) |
1902 | 9 | { |
1903 | 9 | argumentSorts = parseParameterList(); |
1904 | 9 | } |
1905 | 59 | expectToken(Token::Colon); |
1906 | 59 | ASTPointer<TypeClassName> typeClassName = parseTypeClassName(); |
1907 | 59 | expectToken(Token::LBrace); |
1908 | 144 | while (true) |
1909 | 123 | { |
1910 | 123 | Token currentTokenValue = m_scanner->currentToken(); |
1911 | 123 | if (currentTokenValue == Token::RBrace) |
1912 | 38 | break; |
1913 | 85 | expectToken(Token::Function, false); |
1914 | | // TODO: require body already during parsing? |
1915 | 85 | subNodes.push_back(parseFunctionDefinition(false, true)); |
1916 | 85 | } |
1917 | 59 | nodeFactory.markEndPosition(); |
1918 | 59 | expectToken(Token::RBrace); |
1919 | | |
1920 | 59 | return nodeFactory.createNode<TypeClassInstantiation>( |
1921 | 59 | typeConstructor, |
1922 | 59 | argumentSorts, |
1923 | 59 | typeClassName, |
1924 | 59 | subNodes |
1925 | 59 | ); |
1926 | 59 | } |
1927 | | |
1928 | | ASTPointer<TypeDefinition> Parser::parseTypeDefinition() |
1929 | 205 | { |
1930 | 205 | solAssert(m_experimentalSolidityEnabledInCurrentSourceUnit); |
1931 | 205 | ASTNodeFactory nodeFactory(*this); |
1932 | 205 | expectToken(Token::Type); |
1933 | 205 | auto&& [name, nameLocation] = expectIdentifierWithLocation(); |
1934 | | |
1935 | 205 | ASTPointer<ParameterList> arguments; |
1936 | 205 | if (m_scanner->currentToken() == Token::LParen) |
1937 | 33 | arguments = parseParameterList(); |
1938 | | |
1939 | 205 | ASTPointer<Expression> expression; |
1940 | 205 | if (m_scanner->currentToken() == Token::Assign) |
1941 | 38 | { |
1942 | 38 | expectToken(Token::Assign); |
1943 | | |
1944 | 38 | if (m_scanner->currentToken() != Token::Builtin) |
1945 | 12 | expression = parseExpression(); |
1946 | 26 | else |
1947 | 26 | { |
1948 | 26 | expectToken(Token::Builtin); |
1949 | 26 | expectToken(Token::LParen); |
1950 | | |
1951 | 26 | expression = nodeFactory.createNode<Builtin>( |
1952 | 26 | std::make_shared<std::string>(m_scanner->currentLiteral()), |
1953 | 26 | m_scanner->currentLocation() |
1954 | 26 | ); |
1955 | | |
1956 | 26 | expectToken(Token::StringLiteral); |
1957 | 26 | expectToken(Token::RParen); |
1958 | 26 | } |
1959 | 38 | } |
1960 | 205 | nodeFactory.markEndPosition(); |
1961 | 205 | expectToken(Token::Semicolon); |
1962 | 205 | return nodeFactory.createNode<TypeDefinition>( |
1963 | 205 | std::move(name), |
1964 | 205 | std::move(nameLocation), |
1965 | 205 | std::move(arguments), |
1966 | 205 | std::move(expression) |
1967 | 205 | ); |
1968 | 205 | } |
1969 | | |
1970 | | ASTPointer<Statement> Parser::parseSimpleStatement(ASTPointer<ASTString> const& _docString) |
1971 | 64.9k | { |
1972 | 64.9k | RecursionGuard recursionGuard(*this); |
1973 | 64.9k | LookAheadInfo statementType; |
1974 | 64.9k | IndexAccessedPath iap; |
1975 | | |
1976 | 64.9k | if (m_experimentalSolidityEnabledInCurrentSourceUnit && m_scanner->currentToken() == Token::Let) |
1977 | 28 | return parsePostfixVariableDeclarationStatement(_docString); |
1978 | | |
1979 | 64.9k | if (m_scanner->currentToken() == Token::LParen) |
1980 | 2.97k | { |
1981 | 2.97k | ASTNodeFactory nodeFactory(*this); |
1982 | 2.97k | size_t emptyComponents = 0; |
1983 | | // First consume all empty components. |
1984 | 2.97k | expectToken(Token::LParen); |
1985 | 3.43k | while (m_scanner->currentToken() == Token::Comma) |
1986 | 468 | { |
1987 | 468 | advance(); |
1988 | 468 | emptyComponents++; |
1989 | 468 | } |
1990 | | |
1991 | | // Now see whether we have a variable declaration or an expression. |
1992 | 2.97k | std::tie(statementType, iap) = tryParseIndexAccessedPath(); |
1993 | 2.97k | switch (statementType) |
1994 | 2.97k | { |
1995 | 1.06k | case LookAheadInfo::VariableDeclaration: |
1996 | 1.06k | { |
1997 | 1.06k | std::vector<ASTPointer<VariableDeclaration>> variables; |
1998 | 1.06k | ASTPointer<Expression> value; |
1999 | | // We have already parsed something like `(,,,,a.b.c[2][3]` |
2000 | 1.06k | VarDeclParserOptions options; |
2001 | 1.06k | options.allowLocationSpecifier = true; |
2002 | 1.06k | variables = std::vector<ASTPointer<VariableDeclaration>>(emptyComponents, nullptr); |
2003 | 1.06k | variables.push_back(parseVariableDeclaration(options, typeNameFromIndexAccessStructure(iap))); |
2004 | | |
2005 | 2.88k | while (m_scanner->currentToken() != Token::RParen) |
2006 | 1.82k | { |
2007 | 1.82k | expectToken(Token::Comma); |
2008 | 1.82k | if (m_scanner->currentToken() == Token::Comma || m_scanner->currentToken() == Token::RParen) |
2009 | 978 | variables.push_back(nullptr); |
2010 | 848 | else |
2011 | 848 | variables.push_back(parseVariableDeclaration(options)); |
2012 | 1.82k | } |
2013 | 1.06k | expectToken(Token::RParen); |
2014 | 1.06k | expectToken(Token::Assign); |
2015 | 1.06k | value = parseExpression(); |
2016 | 1.06k | nodeFactory.setEndPositionFromNode(value); |
2017 | 1.06k | return nodeFactory.createNode<VariableDeclarationStatement>(_docString, variables, value); |
2018 | 0 | } |
2019 | 1.90k | case LookAheadInfo::Expression: |
2020 | 1.90k | { |
2021 | | // Complete parsing the expression in the current component. |
2022 | 1.90k | std::vector<ASTPointer<Expression>> components(emptyComponents, nullptr); |
2023 | 1.90k | components.push_back(parseExpression(expressionFromIndexAccessStructure(iap))); |
2024 | 3.89k | while (m_scanner->currentToken() != Token::RParen) |
2025 | 1.99k | { |
2026 | 1.99k | expectToken(Token::Comma); |
2027 | 1.99k | if (m_scanner->currentToken() == Token::Comma || m_scanner->currentToken() == Token::RParen) |
2028 | 440 | components.push_back(ASTPointer<Expression>()); |
2029 | 1.55k | else |
2030 | 1.55k | components.push_back(parseExpression()); |
2031 | 1.99k | } |
2032 | 1.90k | nodeFactory.markEndPosition(); |
2033 | 1.90k | expectToken(Token::RParen); |
2034 | 1.90k | return parseExpressionStatement(_docString, nodeFactory.createNode<TupleExpression>(components, false)); |
2035 | 0 | } |
2036 | 0 | default: |
2037 | 0 | solAssert(false); |
2038 | 2.97k | } |
2039 | 2.97k | } |
2040 | 61.9k | else |
2041 | 61.9k | { |
2042 | 61.9k | std::tie(statementType, iap) = tryParseIndexAccessedPath(); |
2043 | 61.9k | switch (statementType) |
2044 | 61.9k | { |
2045 | 11.5k | case LookAheadInfo::VariableDeclaration: |
2046 | 11.5k | return parseVariableDeclarationStatement(_docString, typeNameFromIndexAccessStructure(iap)); |
2047 | 50.3k | case LookAheadInfo::Expression: |
2048 | 50.3k | return parseExpressionStatement(_docString, expressionFromIndexAccessStructure(iap)); |
2049 | 0 | default: |
2050 | 0 | solAssert(false); |
2051 | 61.9k | } |
2052 | 61.9k | } |
2053 | | |
2054 | | // FIXME: Workaround for spurious GCC 12.1 warning (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105794) |
2055 | 0 | util::unreachable(); |
2056 | 0 | } |
2057 | | |
2058 | | bool Parser::IndexAccessedPath::empty() const |
2059 | 66.5k | { |
2060 | 66.5k | if (!indices.empty()) |
2061 | 66.5k | solAssert(!path.empty()); |
2062 | | |
2063 | 66.5k | return path.empty() && indices.empty(); |
2064 | 66.5k | } |
2065 | | |
2066 | | |
2067 | | std::pair<Parser::LookAheadInfo, Parser::IndexAccessedPath> Parser::tryParseIndexAccessedPath() |
2068 | 64.9k | { |
2069 | | // These two cases are very hard to distinguish: |
2070 | | // x[7 * 20 + 3] a; and x[7 * 20 + 3] = 9; |
2071 | | // In the first case, x is a type name, in the second it is the name of a variable. |
2072 | | // As an extension, we can even have: |
2073 | | // `x.y.z[1][2] a;` and `x.y.z[1][2] = 10;` |
2074 | | // Where in the first, x.y.z leads to a type name where in the second, it accesses structs. |
2075 | | |
2076 | 64.9k | auto statementType = peekStatementType(); |
2077 | 64.9k | switch (statementType) |
2078 | 64.9k | { |
2079 | 10.6k | case LookAheadInfo::VariableDeclaration: |
2080 | 33.8k | case LookAheadInfo::Expression: |
2081 | 33.8k | return std::make_pair( |
2082 | 33.8k | m_experimentalSolidityEnabledInCurrentSourceUnit ? LookAheadInfo::Expression : statementType, |
2083 | 33.8k | IndexAccessedPath() |
2084 | 33.8k | ); |
2085 | 31.0k | default: |
2086 | 31.0k | break; |
2087 | 64.9k | } |
2088 | | |
2089 | | // At this point, we have 'Identifier "["' or 'Identifier "." Identifier' or 'ElementoryTypeName "["'. |
2090 | | // We parse '(Identifier ("." Identifier)* |ElementaryTypeName) ( "[" Expression "]" )*' |
2091 | | // until we can decide whether to hand this over to ExpressionStatement or create a |
2092 | | // VariableDeclarationStatement out of it. |
2093 | 31.0k | IndexAccessedPath iap = parseIndexAccessedPath(); |
2094 | | |
2095 | 31.0k | if (m_experimentalSolidityEnabledInCurrentSourceUnit) |
2096 | 0 | return std::make_pair(LookAheadInfo::Expression, std::move(iap)); |
2097 | | |
2098 | 31.0k | if (m_scanner->currentToken() == Token::Identifier || TokenTraits::isLocationSpecifier(m_scanner->currentToken())) |
2099 | 1.95k | return std::make_pair(LookAheadInfo::VariableDeclaration, std::move(iap)); |
2100 | 29.1k | else |
2101 | 29.1k | return std::make_pair(LookAheadInfo::Expression, std::move(iap)); |
2102 | 31.0k | } |
2103 | | |
2104 | | ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStatement( |
2105 | | ASTPointer<ASTString> const& _docString, |
2106 | | ASTPointer<TypeName> const& _lookAheadArrayType |
2107 | | ) |
2108 | 11.5k | { |
2109 | | // This does not parse multi variable declaration statements starting directly with |
2110 | | // `(`, they are parsed in parseSimpleStatement, because they are hard to distinguish |
2111 | | // from tuple expressions. |
2112 | 11.5k | RecursionGuard recursionGuard(*this); |
2113 | 11.5k | ASTNodeFactory nodeFactory(*this); |
2114 | 11.5k | if (_lookAheadArrayType) |
2115 | 1.94k | nodeFactory.setLocation(_lookAheadArrayType->location()); |
2116 | | |
2117 | 11.5k | VarDeclParserOptions options; |
2118 | 11.5k | options.allowLocationSpecifier = true; |
2119 | 11.5k | std::vector<ASTPointer<VariableDeclaration>> variables; |
2120 | 11.5k | variables.emplace_back(parseVariableDeclaration(options, _lookAheadArrayType)); |
2121 | 11.5k | nodeFactory.setEndPositionFromNode(variables.back()); |
2122 | | |
2123 | 11.5k | ASTPointer<Expression> value; |
2124 | 11.5k | if (m_scanner->currentToken() == Token::Assign) |
2125 | 7.36k | { |
2126 | 7.36k | advance(); |
2127 | 7.36k | value = parseExpression(); |
2128 | 7.36k | nodeFactory.setEndPositionFromNode(value); |
2129 | 7.36k | } |
2130 | 11.5k | return nodeFactory.createNode<VariableDeclarationStatement>(_docString, variables, value); |
2131 | 11.5k | } |
2132 | | |
2133 | | ASTPointer<ExpressionStatement> Parser::parseExpressionStatement( |
2134 | | ASTPointer<ASTString> const& _docString, |
2135 | | ASTPointer<Expression> const& _partialParserResult |
2136 | | ) |
2137 | 55.3k | { |
2138 | 55.3k | RecursionGuard recursionGuard(*this); |
2139 | 55.3k | ASTPointer<Expression> expression = parseExpression(_partialParserResult); |
2140 | 55.3k | return ASTNodeFactory(*this, expression).createNode<ExpressionStatement>(_docString, expression); |
2141 | 55.3k | } |
2142 | | |
2143 | | ASTPointer<Expression> Parser::parseExpression( |
2144 | | ASTPointer<Expression> const& _partiallyParsedExpression |
2145 | | ) |
2146 | 414k | { |
2147 | 414k | RecursionGuard recursionGuard(*this); |
2148 | 414k | ASTPointer<Expression> expression = parseBinaryExpression(4, _partiallyParsedExpression); |
2149 | 414k | if (TokenTraits::isAssignmentOp(m_scanner->currentToken())) |
2150 | 38.6k | { |
2151 | 38.6k | Token assignmentOperator = m_scanner->currentToken(); |
2152 | 38.6k | advance(); |
2153 | 38.6k | ASTPointer<Expression> rightHandSide = parseExpression(); |
2154 | 38.6k | ASTNodeFactory nodeFactory(*this, expression); |
2155 | 38.6k | nodeFactory.setEndPositionFromNode(rightHandSide); |
2156 | 38.6k | return nodeFactory.createNode<Assignment>(expression, assignmentOperator, rightHandSide); |
2157 | 38.6k | } |
2158 | 375k | else if (m_scanner->currentToken() == Token::Conditional) |
2159 | 1.75k | { |
2160 | 1.75k | advance(); |
2161 | 1.75k | ASTPointer<Expression> trueExpression = parseExpression(); |
2162 | 1.75k | expectToken(Token::Colon); |
2163 | 1.75k | ASTPointer<Expression> falseExpression = parseExpression(); |
2164 | 1.75k | ASTNodeFactory nodeFactory(*this, expression); |
2165 | 1.75k | nodeFactory.setEndPositionFromNode(falseExpression); |
2166 | 1.75k | return nodeFactory.createNode<Conditional>(expression, trueExpression, falseExpression); |
2167 | 1.75k | } |
2168 | 373k | else |
2169 | 373k | return expression; |
2170 | 414k | } |
2171 | | |
2172 | | ASTPointer<Expression> Parser::parseBinaryExpression( |
2173 | | int _minPrecedence, |
2174 | | ASTPointer<Expression> const& _partiallyParsedExpression |
2175 | | ) |
2176 | 517k | { |
2177 | 517k | RecursionGuard recursionGuard(*this); |
2178 | 517k | ASTPointer<Expression> expression = parseUnaryExpression(_partiallyParsedExpression); |
2179 | 517k | ASTNodeFactory nodeFactory(*this, expression); |
2180 | 517k | int precedence = tokenPrecedence(m_scanner->currentToken()); |
2181 | 856k | for (; precedence >= _minPrecedence; --precedence) |
2182 | 442k | while (tokenPrecedence(m_scanner->currentToken()) == precedence) |
2183 | 103k | { |
2184 | 103k | Token op = m_scanner->currentToken(); |
2185 | 103k | advance(); |
2186 | | |
2187 | 103k | static_assert(TokenTraits::hasExpHighestPrecedence(), "Exp does not have the highest precedence"); |
2188 | | |
2189 | | // Parse a**b**c as a**(b**c) |
2190 | 103k | ASTPointer<Expression> right = (op == Token::Exp) ? |
2191 | 6.33k | parseBinaryExpression(precedence) : |
2192 | 103k | parseBinaryExpression(precedence + 1); |
2193 | 103k | nodeFactory.setEndPositionFromNode(right); |
2194 | 103k | expression = nodeFactory.createNode<BinaryOperation>(expression, op, right); |
2195 | 103k | } |
2196 | 517k | return expression; |
2197 | 517k | } |
2198 | | |
2199 | | int Parser::tokenPrecedence(Token _token) const |
2200 | 950k | { |
2201 | 950k | if (m_experimentalSolidityEnabledInCurrentSourceUnit) |
2202 | 8.67k | { |
2203 | 8.67k | switch (_token) |
2204 | 8.67k | { |
2205 | 16 | case Token::Colon: |
2206 | 16 | return 1000; |
2207 | 3 | case Token::RightArrow: |
2208 | 3 | return 999; |
2209 | 8.65k | default: |
2210 | 8.65k | break; |
2211 | 8.67k | } |
2212 | 8.67k | } |
2213 | 950k | return TokenTraits::precedence(m_scanner->currentToken()); |
2214 | 950k | } |
2215 | | |
2216 | | ASTPointer<Expression> Parser::parseUnaryExpression( |
2217 | | ASTPointer<Expression> const& _partiallyParsedExpression |
2218 | | ) |
2219 | 561k | { |
2220 | 561k | RecursionGuard recursionGuard(*this); |
2221 | 561k | ASTNodeFactory nodeFactory = _partiallyParsedExpression ? |
2222 | 531k | ASTNodeFactory(*this, _partiallyParsedExpression) : ASTNodeFactory(*this); |
2223 | 561k | Token token = m_scanner->currentToken(); |
2224 | | |
2225 | 561k | if (!_partiallyParsedExpression && token == Token::Add) |
2226 | 10 | fatalParserError(9636_error, "Use of unary + is disallowed."); |
2227 | | |
2228 | 561k | if (!_partiallyParsedExpression && (TokenTraits::isUnaryOp(token) || TokenTraits::isCountOp(token))) |
2229 | 44.6k | { |
2230 | | // prefix expression |
2231 | 44.6k | advance(); |
2232 | 44.6k | ASTPointer<Expression> subExpression = parseUnaryExpression(); |
2233 | 44.6k | nodeFactory.setEndPositionFromNode(subExpression); |
2234 | 44.6k | return nodeFactory.createNode<UnaryOperation>(token, subExpression, true); |
2235 | 44.6k | } |
2236 | 517k | else |
2237 | 517k | { |
2238 | | // potential postfix expression |
2239 | 517k | ASTPointer<Expression> subExpression = parseLeftHandSideExpression(_partiallyParsedExpression); |
2240 | 517k | token = m_scanner->currentToken(); |
2241 | | |
2242 | 517k | if (!TokenTraits::isCountOp(token)) |
2243 | 504k | return subExpression; |
2244 | 12.3k | nodeFactory.markEndPosition(); |
2245 | 12.3k | advance(); |
2246 | 12.3k | return nodeFactory.createNode<UnaryOperation>(token, subExpression, false); |
2247 | 517k | } |
2248 | 561k | } |
2249 | | |
2250 | | ASTPointer<Expression> Parser::parseLeftHandSideExpression( |
2251 | | ASTPointer<Expression> const& _partiallyParsedExpression |
2252 | | ) |
2253 | 517k | { |
2254 | 517k | RecursionGuard recursionGuard(*this); |
2255 | 517k | ASTNodeFactory nodeFactory = _partiallyParsedExpression ? |
2256 | 486k | ASTNodeFactory(*this, _partiallyParsedExpression) : ASTNodeFactory(*this); |
2257 | | |
2258 | 517k | ASTPointer<Expression> expression; |
2259 | 517k | if (_partiallyParsedExpression) |
2260 | 30.9k | expression = _partiallyParsedExpression; |
2261 | 486k | else if (m_scanner->currentToken() == Token::New) |
2262 | 3.28k | { |
2263 | 3.28k | expectToken(Token::New); |
2264 | 3.28k | ASTPointer<TypeName> typeName(parseTypeName()); |
2265 | 3.28k | nodeFactory.setEndPositionFromNode(typeName); |
2266 | 3.28k | expression = nodeFactory.createNode<NewExpression>(typeName); |
2267 | 3.28k | } |
2268 | 483k | else if (m_scanner->currentToken() == Token::Payable) |
2269 | 275 | { |
2270 | 275 | expectToken(Token::Payable); |
2271 | 275 | nodeFactory.markEndPosition(); |
2272 | 275 | auto expressionType = nodeFactory.createNode<ElementaryTypeName>( |
2273 | 275 | ElementaryTypeNameToken(Token::Address, 0, 0), |
2274 | 275 | std::make_optional(StateMutability::Payable) |
2275 | 275 | ); |
2276 | 275 | expression = nodeFactory.createNode<ElementaryTypeNameExpression>(expressionType); |
2277 | 275 | expectToken(Token::LParen, false); |
2278 | 275 | } |
2279 | 482k | else |
2280 | 482k | expression = parsePrimaryExpression(); |
2281 | | |
2282 | 781k | while (true) |
2283 | 775k | { |
2284 | 775k | switch (m_scanner->currentToken()) |
2285 | 775k | { |
2286 | 100k | case Token::LBrack: |
2287 | 100k | { |
2288 | 100k | advance(); |
2289 | 100k | ASTPointer<Expression> index; |
2290 | 100k | ASTPointer<Expression> endIndex; |
2291 | 100k | if (m_scanner->currentToken() != Token::RBrack && m_scanner->currentToken() != Token::Colon) |
2292 | 98.7k | index = parseExpression(); |
2293 | 100k | if (m_scanner->currentToken() == Token::Colon) |
2294 | 789 | { |
2295 | 789 | expectToken(Token::Colon); |
2296 | 789 | if (m_scanner->currentToken() != Token::RBrack) |
2297 | 409 | endIndex = parseExpression(); |
2298 | 789 | nodeFactory.markEndPosition(); |
2299 | 789 | expectToken(Token::RBrack); |
2300 | 789 | expression = nodeFactory.createNode<IndexRangeAccess>(expression, index, endIndex); |
2301 | 789 | } |
2302 | 99.2k | else |
2303 | 99.2k | { |
2304 | 99.2k | nodeFactory.markEndPosition(); |
2305 | 99.2k | expectToken(Token::RBrack); |
2306 | 99.2k | expression = nodeFactory.createNode<IndexAccess>(expression, index); |
2307 | 99.2k | } |
2308 | 100k | break; |
2309 | 0 | } |
2310 | 127k | case Token::Period: |
2311 | 127k | { |
2312 | 127k | advance(); |
2313 | 127k | nodeFactory.markEndPosition(); |
2314 | 127k | SourceLocation memberLocation = currentLocation(); |
2315 | 127k | ASTPointer<ASTString> memberName = expectIdentifierTokenOrAddress(); |
2316 | 127k | expression = nodeFactory.createNode<MemberAccess>(expression, std::move(memberName), std::move(memberLocation)); |
2317 | 127k | break; |
2318 | 0 | } |
2319 | 39.3k | case Token::LParen: |
2320 | 39.3k | { |
2321 | 39.3k | advance(); |
2322 | 39.3k | auto functionCallArguments = parseFunctionCallArguments(); |
2323 | 39.3k | nodeFactory.markEndPosition(); |
2324 | 39.3k | expectToken(Token::RParen); |
2325 | 39.3k | expression = nodeFactory.createNode<FunctionCall>( |
2326 | 39.3k | expression, |
2327 | 39.3k | functionCallArguments.arguments, |
2328 | 39.3k | functionCallArguments.parameterNames, |
2329 | 39.3k | functionCallArguments.parameterNameLocations); |
2330 | 39.3k | break; |
2331 | 0 | } |
2332 | 943 | case Token::LBrace: |
2333 | 943 | { |
2334 | | // See if this is followed by <identifier>, followed by ":". If not, it is not |
2335 | | // a function call options but a Block (from a try statement). |
2336 | 943 | if ( |
2337 | 943 | m_scanner->peekNextToken() != Token::Identifier || |
2338 | 577 | m_scanner->peekNextNextToken() != Token::Colon |
2339 | 943 | ) |
2340 | 401 | return expression; |
2341 | | |
2342 | 542 | expectToken(Token::LBrace); |
2343 | 542 | auto optionList = parseNamedArguments(); |
2344 | | |
2345 | 542 | nodeFactory.markEndPosition(); |
2346 | 542 | expectToken(Token::RBrace); |
2347 | | |
2348 | 542 | expression = nodeFactory.createNode<FunctionCallOptions>(expression, optionList.arguments, optionList.parameterNames); |
2349 | 542 | break; |
2350 | 943 | } |
2351 | 507k | default: |
2352 | 507k | return expression; |
2353 | 775k | } |
2354 | 775k | } |
2355 | 517k | } |
2356 | | |
2357 | | ASTPointer<Expression> Parser::parseLiteral() |
2358 | 323k | { |
2359 | 323k | RecursionGuard recursionGuard(*this); |
2360 | 323k | ASTNodeFactory nodeFactory(*this); |
2361 | 323k | Token initialToken = m_scanner->currentToken(); |
2362 | 323k | ASTPointer<ASTString> value = std::make_shared<std::string>(m_scanner->currentLiteral()); |
2363 | | |
2364 | 323k | switch (initialToken) |
2365 | 323k | { |
2366 | 8.91k | case Token::TrueLiteral: |
2367 | 16.7k | case Token::FalseLiteral: |
2368 | 297k | case Token::Number: |
2369 | 297k | { |
2370 | 297k | nodeFactory.markEndPosition(); |
2371 | 297k | advance(); |
2372 | 297k | break; |
2373 | 16.7k | } |
2374 | 9.15k | case Token::StringLiteral: |
2375 | 10.0k | case Token::UnicodeStringLiteral: |
2376 | 26.4k | case Token::HexStringLiteral: |
2377 | 26.4k | { |
2378 | 27.5k | while (m_scanner->peekNextToken() == initialToken) |
2379 | 1.15k | { |
2380 | 1.15k | advance(); |
2381 | 1.15k | *value += m_scanner->currentLiteral(); |
2382 | 1.15k | } |
2383 | 26.4k | nodeFactory.markEndPosition(); |
2384 | 26.4k | advance(); |
2385 | 26.4k | if (m_scanner->currentToken() == Token::Illegal) |
2386 | 11 | fatalParserError(5428_error, to_string(m_scanner->currentError())); |
2387 | 26.4k | break; |
2388 | 10.0k | } |
2389 | 0 | default: |
2390 | 0 | solAssert(false); |
2391 | 323k | } |
2392 | | |
2393 | 323k | if (initialToken == Token::Number && ( |
2394 | 280k | TokenTraits::isEtherSubdenomination(m_scanner->currentToken()) || |
2395 | 280k | TokenTraits::isTimeSubdenomination(m_scanner->currentToken()) |
2396 | 280k | )) |
2397 | 475 | { |
2398 | 475 | nodeFactory.markEndPosition(); |
2399 | 475 | Literal::SubDenomination subDenomination = static_cast<Literal::SubDenomination>(m_scanner->currentToken()); |
2400 | 475 | advance(); |
2401 | 475 | return nodeFactory.createNode<Literal>(initialToken, std::move(value), subDenomination); |
2402 | 475 | } |
2403 | | |
2404 | 323k | return nodeFactory.createNode<Literal>(initialToken, std::move(value), Literal::SubDenomination::None); |
2405 | 323k | } |
2406 | | |
2407 | | ASTPointer<Expression> Parser::parsePrimaryExpression() |
2408 | 482k | { |
2409 | 482k | RecursionGuard recursionGuard(*this); |
2410 | 482k | ASTNodeFactory nodeFactory(*this); |
2411 | 482k | Token token = m_scanner->currentToken(); |
2412 | 482k | ASTPointer<Expression> expression; |
2413 | | |
2414 | 482k | switch (token) |
2415 | 482k | { |
2416 | 8.91k | case Token::TrueLiteral: |
2417 | 16.7k | case Token::FalseLiteral: |
2418 | 297k | case Token::Number: |
2419 | 306k | case Token::StringLiteral: |
2420 | 307k | case Token::UnicodeStringLiteral: |
2421 | 323k | case Token::HexStringLiteral: |
2422 | 323k | expression = parseLiteral(); |
2423 | 323k | break; |
2424 | 132k | case Token::Identifier: |
2425 | 132k | nodeFactory.markEndPosition(); |
2426 | 132k | expression = nodeFactory.createNode<Identifier>(getLiteralAndAdvance()); |
2427 | 132k | break; |
2428 | 404 | case Token::Type: |
2429 | | // Inside expressions "type" is the name of a special, globally-available function. |
2430 | 404 | nodeFactory.markEndPosition(); |
2431 | 404 | advance(); |
2432 | 404 | expression = nodeFactory.createNode<Identifier>(std::make_shared<ASTString>("type")); |
2433 | 404 | break; |
2434 | 8.78k | case Token::LParen: |
2435 | 14.0k | case Token::LBrack: |
2436 | 14.0k | { |
2437 | | // Tuple/parenthesized expression or inline array/bracketed expression. |
2438 | | // Special cases: ()/[] is empty tuple/array type, (x) is not a real tuple, |
2439 | | // (x,) is one-dimensional tuple, elements in arrays cannot be left out, only in tuples. |
2440 | 14.0k | advance(); |
2441 | 14.0k | std::vector<ASTPointer<Expression>> components; |
2442 | 14.0k | Token oppositeToken = (token == Token::LParen ? Token::RParen : Token::RBrack); |
2443 | 14.0k | bool isArray = (token == Token::LBrack); |
2444 | | |
2445 | 14.0k | if (m_scanner->currentToken() != oppositeToken) |
2446 | 25.3k | while (true) |
2447 | 20.5k | { |
2448 | 20.5k | if (m_scanner->currentToken() != Token::Comma && m_scanner->currentToken() != oppositeToken) |
2449 | 17.7k | components.push_back(parseExpression()); |
2450 | 2.85k | else if (isArray) |
2451 | 808 | parserError(4799_error, "Expected expression (inline array elements cannot be omitted)."); |
2452 | 2.04k | else |
2453 | 2.04k | components.push_back(ASTPointer<Expression>()); |
2454 | | |
2455 | 20.5k | if (m_scanner->currentToken() == oppositeToken) |
2456 | 8.66k | break; |
2457 | | |
2458 | 11.9k | expectToken(Token::Comma); |
2459 | 11.9k | } |
2460 | 14.0k | nodeFactory.markEndPosition(); |
2461 | 14.0k | expectToken(oppositeToken); |
2462 | 14.0k | expression = nodeFactory.createNode<TupleExpression>(components, isArray); |
2463 | 14.0k | break; |
2464 | 8.78k | } |
2465 | 162 | case Token::Illegal: |
2466 | 162 | fatalParserError(8936_error, to_string(m_scanner->currentError())); |
2467 | 162 | break; |
2468 | 11.5k | default: |
2469 | 11.5k | if (TokenTraits::isElementaryTypeName(token)) |
2470 | 11.0k | { |
2471 | | //used for casts |
2472 | 11.0k | unsigned firstSize; |
2473 | 11.0k | unsigned secondSize; |
2474 | 11.0k | std::tie(firstSize, secondSize) = m_scanner->currentTokenInfo(); |
2475 | 11.0k | auto expressionType = nodeFactory.createNode<ElementaryTypeName>( |
2476 | 11.0k | ElementaryTypeNameToken(m_scanner->currentToken(), firstSize, secondSize) |
2477 | 11.0k | ); |
2478 | 11.0k | expression = nodeFactory.createNode<ElementaryTypeNameExpression>(expressionType); |
2479 | 11.0k | advance(); |
2480 | 11.0k | } |
2481 | 490 | else |
2482 | 490 | fatalParserError(6933_error, "Expected primary expression."); |
2483 | 11.5k | break; |
2484 | 482k | } |
2485 | 477k | return expression; |
2486 | 482k | } |
2487 | | |
2488 | | std::vector<ASTPointer<Expression>> Parser::parseFunctionCallListArguments() |
2489 | 42.0k | { |
2490 | 42.0k | RecursionGuard recursionGuard(*this); |
2491 | 42.0k | std::vector<ASTPointer<Expression>> arguments; |
2492 | 42.0k | if (m_scanner->currentToken() != Token::RParen) |
2493 | 34.6k | { |
2494 | 34.6k | arguments.push_back(parseExpression()); |
2495 | 47.6k | while (m_scanner->currentToken() != Token::RParen) |
2496 | 12.9k | { |
2497 | 12.9k | expectToken(Token::Comma); |
2498 | 12.9k | arguments.push_back(parseExpression()); |
2499 | 12.9k | } |
2500 | 34.6k | } |
2501 | 42.0k | return arguments; |
2502 | 42.0k | } |
2503 | | |
2504 | | Parser::FunctionCallArguments Parser::parseFunctionCallArguments() |
2505 | 41.0k | { |
2506 | 41.0k | RecursionGuard recursionGuard(*this); |
2507 | 41.0k | FunctionCallArguments ret; |
2508 | | |
2509 | 41.0k | Token token = m_scanner->currentToken(); |
2510 | 41.0k | if (token == Token::LBrace) |
2511 | 478 | { |
2512 | | // call({arg1 : 1, arg2 : 2 }) |
2513 | 478 | expectToken(Token::LBrace); |
2514 | 478 | ret = parseNamedArguments(); |
2515 | 478 | expectToken(Token::RBrace); |
2516 | 478 | } |
2517 | 40.5k | else |
2518 | 40.5k | ret.arguments = parseFunctionCallListArguments(); |
2519 | 41.0k | return ret; |
2520 | 41.0k | } |
2521 | | |
2522 | | Parser::FunctionCallArguments Parser::parseNamedArguments() |
2523 | 1.02k | { |
2524 | 1.02k | FunctionCallArguments ret; |
2525 | | |
2526 | 1.02k | bool first = true; |
2527 | 2.80k | while (m_scanner->currentToken() != Token::RBrace) |
2528 | 1.78k | { |
2529 | 1.78k | if (!first) |
2530 | 765 | expectToken(Token::Comma); |
2531 | | |
2532 | 1.78k | auto identifierWithLocation = expectIdentifierWithLocation(); |
2533 | | |
2534 | | // Add name |
2535 | 1.78k | ret.parameterNames.emplace_back(std::move(identifierWithLocation.first)); |
2536 | | // Add location |
2537 | 1.78k | ret.parameterNameLocations.emplace_back(std::move(identifierWithLocation.second)); |
2538 | | |
2539 | 1.78k | expectToken(Token::Colon); |
2540 | 1.78k | ret.arguments.emplace_back(parseExpression()); |
2541 | | |
2542 | 1.78k | if ( |
2543 | 1.78k | m_scanner->currentToken() == Token::Comma && |
2544 | 767 | m_scanner->peekNextToken() == Token::RBrace |
2545 | 1.78k | ) |
2546 | 12 | { |
2547 | 12 | parserError(2074_error, "Unexpected trailing comma."); |
2548 | 12 | advance(); |
2549 | 12 | } |
2550 | | |
2551 | 1.78k | first = false; |
2552 | 1.78k | } |
2553 | | |
2554 | 1.02k | return ret; |
2555 | 1.02k | } |
2556 | | |
2557 | | bool Parser::variableDeclarationStart() |
2558 | 33.5k | { |
2559 | 33.5k | Token currentToken = m_scanner->currentToken(); |
2560 | 33.5k | return |
2561 | 33.5k | currentToken == Token::Identifier || |
2562 | 25.3k | currentToken == Token::Mapping || |
2563 | 24.6k | TokenTraits::isElementaryTypeName(currentToken) || |
2564 | 8.48k | (currentToken == Token::Function && m_scanner->peekNextToken() == Token::LParen); |
2565 | 33.5k | } |
2566 | | |
2567 | | std::optional<std::string> Parser::findLicenseString(std::vector<ASTPointer<ASTNode>> const& _nodes) |
2568 | 27.9k | { |
2569 | | // We circumvent the scanner here, because it skips non-docstring comments. |
2570 | 27.9k | static std::regex const licenseNameRegex("([a-zA-Z0-9 ()+.-]+)"); |
2571 | 27.9k | static std::regex const licenseDeclarationRegex("SPDX-License-Identifier:\\s*(.+?)([\n\r]|(\\*/))"); |
2572 | | |
2573 | | // Search inside all parts of the source not covered by parsed nodes. |
2574 | | // This will leave e.g. "global comments". |
2575 | 27.9k | using iter = std::string::const_iterator; |
2576 | 27.9k | std::vector<std::pair<iter, iter>> sequencesToSearch; |
2577 | 27.9k | std::string const& source = m_scanner->charStream().source(); |
2578 | 27.9k | sequencesToSearch.emplace_back(source.begin(), source.end()); |
2579 | 27.9k | for (ASTPointer<ASTNode> const& node: _nodes) |
2580 | 77.3k | if (node->location().hasText()) |
2581 | 77.3k | { |
2582 | 77.3k | sequencesToSearch.back().second = source.begin() + node->location().start; |
2583 | 77.3k | sequencesToSearch.emplace_back(source.begin() + node->location().end, source.end()); |
2584 | 77.3k | } |
2585 | | |
2586 | 27.9k | std::vector<std::string> licenseNames; |
2587 | 27.9k | for (auto const& [start, end]: sequencesToSearch) |
2588 | 105k | { |
2589 | 105k | auto declarationsBegin = std::sregex_iterator(start, end, licenseDeclarationRegex); |
2590 | 105k | auto declarationsEnd = std::sregex_iterator(); |
2591 | | |
2592 | 105k | for (std::sregex_iterator declIt = declarationsBegin; declIt != declarationsEnd; ++declIt) |
2593 | 361 | if (!declIt->empty()) |
2594 | 361 | { |
2595 | 361 | std::string license = boost::trim_copy(std::string((*declIt)[1])); |
2596 | 361 | licenseNames.emplace_back(std::move(license)); |
2597 | 361 | } |
2598 | 105k | } |
2599 | | |
2600 | 27.9k | if (licenseNames.size() == 1) |
2601 | 289 | { |
2602 | 289 | std::string const& license = licenseNames.front(); |
2603 | 289 | if (regex_match(license, licenseNameRegex)) |
2604 | 261 | return license; |
2605 | 28 | else |
2606 | 28 | parserError( |
2607 | 28 | 1114_error, |
2608 | 28 | {-1, -1, m_scanner->currentLocation().sourceName}, |
2609 | 28 | "Invalid SPDX license identifier." |
2610 | 28 | ); |
2611 | 289 | } |
2612 | 27.6k | else if (licenseNames.empty()) |
2613 | 27.6k | parserWarning( |
2614 | 27.6k | 1878_error, |
2615 | 27.6k | {-1, -1, m_scanner->currentLocation().sourceName}, |
2616 | 27.6k | "SPDX license identifier not provided in source file. " |
2617 | 27.6k | "Before publishing, consider adding a comment containing " |
2618 | 27.6k | "\"SPDX-License-Identifier: <SPDX-License>\" to each source file. " |
2619 | 27.6k | "Use \"SPDX-License-Identifier: UNLICENSED\" for non-open-source code. " |
2620 | 27.6k | "Please see https://spdx.org for more information." |
2621 | 27.6k | ); |
2622 | 19 | else |
2623 | 19 | parserError( |
2624 | 19 | 3716_error, |
2625 | 19 | {-1, -1, m_scanner->currentLocation().sourceName}, |
2626 | 19 | "Multiple SPDX license identifiers found in source file. " |
2627 | 19 | "Use \"AND\" or \"OR\" to combine multiple licenses. " |
2628 | 19 | "Please see https://spdx.org for more information." |
2629 | 19 | ); |
2630 | | |
2631 | 27.7k | return {}; |
2632 | 27.9k | } |
2633 | | |
2634 | | Parser::LookAheadInfo Parser::peekStatementType() const |
2635 | 64.9k | { |
2636 | | // Distinguish between variable declaration (and potentially assignment) and expression statement |
2637 | | // (which include assignments to other expressions and pre-declared variables). |
2638 | | // We have a variable declaration if we get a keyword that specifies a type name. |
2639 | | // If it is an identifier or an elementary type name followed by an identifier |
2640 | | // or a mutability specifier, we also have a variable declaration. |
2641 | | // If we get an identifier followed by a "[" or ".", it can be both ("lib.type[9] a;" or "variable.el[9] = 7;"). |
2642 | | // In all other cases, we have an expression statement. |
2643 | 64.9k | Token token(m_scanner->currentToken()); |
2644 | 64.9k | bool mightBeTypeName = (TokenTraits::isElementaryTypeName(token) || token == Token::Identifier); |
2645 | | |
2646 | 64.9k | if (token == Token::Mapping || token == Token::Function) |
2647 | 306 | return LookAheadInfo::VariableDeclaration; |
2648 | 64.6k | if (mightBeTypeName) |
2649 | 59.2k | { |
2650 | 59.2k | Token next = m_scanner->peekNextToken(); |
2651 | | // So far we only allow ``address payable`` in variable declaration statements and in no other |
2652 | | // kind of statement. This means, for example, that we do not allow type expressions of the form |
2653 | | // ``address payable;``. |
2654 | | // If we want to change this in the future, we need to consider another scanner token here. |
2655 | 59.2k | if (TokenTraits::isElementaryTypeName(token) && TokenTraits::isStateMutabilitySpecifier(next)) |
2656 | 111 | return LookAheadInfo::VariableDeclaration; |
2657 | 59.0k | if (next == Token::Identifier || TokenTraits::isLocationSpecifier(next)) |
2658 | 10.2k | return LookAheadInfo::VariableDeclaration; |
2659 | 48.8k | if (next == Token::LBrack || next == Token::Period) |
2660 | 31.0k | return LookAheadInfo::IndexAccessStructure; |
2661 | 48.8k | } |
2662 | 23.1k | return LookAheadInfo::Expression; |
2663 | 64.6k | } |
2664 | | |
2665 | | Parser::IndexAccessedPath Parser::parseIndexAccessedPath() |
2666 | 31.0k | { |
2667 | 31.0k | IndexAccessedPath iap; |
2668 | 31.0k | if (m_scanner->currentToken() == Token::Identifier) |
2669 | 29.2k | { |
2670 | 29.2k | iap.path.push_back(parseIdentifier()); |
2671 | 69.7k | while (m_scanner->currentToken() == Token::Period) |
2672 | 40.4k | { |
2673 | 40.4k | advance(); |
2674 | 40.4k | if (m_experimentalSolidityEnabledInCurrentSourceUnit && m_scanner->currentToken() == Token::Number) |
2675 | 0 | { |
2676 | 0 | ASTNodeFactory nodeFactory(*this); |
2677 | 0 | nodeFactory.markEndPosition(); |
2678 | 0 | iap.path.push_back(nodeFactory.createNode<Identifier>(getLiteralAndAdvance())); |
2679 | 0 | } |
2680 | 40.4k | else |
2681 | 40.4k | iap.path.push_back(parseIdentifierOrAddress()); |
2682 | 40.4k | } |
2683 | 29.2k | } |
2684 | 1.76k | else |
2685 | 1.76k | { |
2686 | 1.76k | unsigned firstNum; |
2687 | 1.76k | unsigned secondNum; |
2688 | 1.76k | std::tie(firstNum, secondNum) = m_scanner->currentTokenInfo(); |
2689 | 1.76k | auto expressionType = ASTNodeFactory(*this).createNode<ElementaryTypeName>( |
2690 | 1.76k | ElementaryTypeNameToken(m_scanner->currentToken(), firstNum, secondNum) |
2691 | 1.76k | ); |
2692 | 1.76k | iap.path.push_back(ASTNodeFactory(*this).createNode<ElementaryTypeNameExpression>(expressionType)); |
2693 | 1.76k | advance(); |
2694 | 1.76k | } |
2695 | 67.5k | while (m_scanner->currentToken() == Token::LBrack) |
2696 | 36.5k | { |
2697 | 36.5k | expectToken(Token::LBrack); |
2698 | 36.5k | ASTPointer<Expression> index; |
2699 | 36.5k | if (m_scanner->currentToken() != Token::RBrack && m_scanner->currentToken() != Token::Colon) |
2700 | 33.0k | index = parseExpression(); |
2701 | 36.5k | SourceLocation indexLocation = iap.path.front()->location(); |
2702 | 36.5k | if (m_scanner->currentToken() == Token::Colon) |
2703 | 977 | { |
2704 | 977 | expectToken(Token::Colon); |
2705 | 977 | ASTPointer<Expression> endIndex; |
2706 | 977 | if (m_scanner->currentToken() != Token::RBrack) |
2707 | 359 | endIndex = parseExpression(); |
2708 | 977 | indexLocation.end = currentLocation().end; |
2709 | 977 | iap.indices.emplace_back(IndexAccessedPath::Index{index, {endIndex}, indexLocation}); |
2710 | 977 | expectToken(Token::RBrack); |
2711 | 977 | } |
2712 | 35.5k | else |
2713 | 35.5k | { |
2714 | 35.5k | indexLocation.end = currentLocation().end; |
2715 | 35.5k | iap.indices.emplace_back(IndexAccessedPath::Index{index, {}, indexLocation}); |
2716 | 35.5k | expectToken(Token::RBrack); |
2717 | 35.5k | } |
2718 | 36.5k | } |
2719 | | |
2720 | 31.0k | return iap; |
2721 | 31.0k | } |
2722 | | |
2723 | | ASTPointer<TypeName> Parser::typeNameFromIndexAccessStructure(Parser::IndexAccessedPath const& _iap) |
2724 | 12.6k | { |
2725 | 12.6k | if (_iap.empty()) |
2726 | 10.6k | return {}; |
2727 | | |
2728 | 1.95k | RecursionGuard recursionGuard(*this); |
2729 | 1.95k | ASTNodeFactory nodeFactory(*this); |
2730 | 1.95k | SourceLocation location = _iap.path.front()->location(); |
2731 | 1.95k | location.end = _iap.path.back()->location().end; |
2732 | 1.95k | nodeFactory.setLocation(location); |
2733 | | |
2734 | 1.95k | ASTPointer<TypeName> type; |
2735 | 1.95k | if (auto typeName = dynamic_cast<ElementaryTypeNameExpression const*>(_iap.path.front().get())) |
2736 | 1.66k | { |
2737 | 1.66k | solAssert(_iap.path.size() == 1, ""); |
2738 | 1.66k | type = nodeFactory.createNode<ElementaryTypeName>(typeName->type().typeName()); |
2739 | 1.66k | } |
2740 | 290 | else |
2741 | 290 | { |
2742 | 290 | std::vector<ASTString> path; |
2743 | 290 | std::vector<SourceLocation> pathLocations; |
2744 | | |
2745 | 290 | for (auto const& el: _iap.path) |
2746 | 536 | { |
2747 | 536 | auto& identifier = dynamic_cast<Identifier const&>(*el); |
2748 | 536 | path.push_back(identifier.name()); |
2749 | 536 | pathLocations.push_back(identifier.location()); |
2750 | 536 | } |
2751 | | |
2752 | 290 | type = nodeFactory.createNode<UserDefinedTypeName>(nodeFactory.createNode<IdentifierPath>(path, pathLocations)); |
2753 | 290 | } |
2754 | 1.95k | for (auto const& lengthExpression: _iap.indices) |
2755 | 3.38k | { |
2756 | 3.38k | if (lengthExpression.end) |
2757 | 21 | parserError(5464_error, lengthExpression.location, "Expected array length expression."); |
2758 | 3.38k | nodeFactory.setLocation(lengthExpression.location); |
2759 | 3.38k | type = nodeFactory.createNode<ArrayTypeName>(type, lengthExpression.start); |
2760 | 3.38k | } |
2761 | 1.95k | return type; |
2762 | 12.6k | } |
2763 | | |
2764 | | ASTPointer<Expression> Parser::expressionFromIndexAccessStructure( |
2765 | | Parser::IndexAccessedPath const& _iap |
2766 | | ) |
2767 | 53.8k | { |
2768 | 53.8k | if (_iap.empty()) |
2769 | 23.1k | return {}; |
2770 | | |
2771 | 30.7k | RecursionGuard recursionGuard(*this); |
2772 | 30.7k | ASTNodeFactory nodeFactory(*this, _iap.path.front()); |
2773 | 30.7k | ASTPointer<Expression> expression(_iap.path.front()); |
2774 | 70.9k | for (size_t i = 1; i < _iap.path.size(); ++i) |
2775 | 40.2k | { |
2776 | 40.2k | SourceLocation location(_iap.path.front()->location()); |
2777 | 40.2k | location.end = _iap.path[i]->location().end; |
2778 | 40.2k | nodeFactory.setLocation(location); |
2779 | 40.2k | Identifier const& identifier = dynamic_cast<Identifier const&>(*_iap.path[i]); |
2780 | 40.2k | expression = nodeFactory.createNode<MemberAccess>( |
2781 | 40.2k | expression, |
2782 | 40.2k | std::make_shared<ASTString>(identifier.name()), |
2783 | 40.2k | identifier.location() |
2784 | 40.2k | ); |
2785 | 40.2k | } |
2786 | 30.7k | for (auto const& index: _iap.indices) |
2787 | 32.7k | { |
2788 | 32.7k | nodeFactory.setLocation(index.location); |
2789 | 32.7k | if (index.end) |
2790 | 881 | expression = nodeFactory.createNode<IndexRangeAccess>(expression, index.start, *index.end); |
2791 | 31.9k | else |
2792 | 31.9k | expression = nodeFactory.createNode<IndexAccess>(expression, index.start); |
2793 | 32.7k | } |
2794 | 30.7k | return expression; |
2795 | 53.8k | } |
2796 | | |
2797 | | ASTPointer<ParameterList> Parser::createEmptyParameterList() |
2798 | 23.0k | { |
2799 | 23.0k | RecursionGuard recursionGuard(*this); |
2800 | 23.0k | ASTNodeFactory nodeFactory(*this); |
2801 | 23.0k | nodeFactory.setLocationEmpty(); |
2802 | 23.0k | return nodeFactory.createNode<ParameterList>(std::vector<ASTPointer<VariableDeclaration>>()); |
2803 | 23.0k | } |
2804 | | |
2805 | | ASTPointer<ASTString> Parser::expectIdentifierToken() |
2806 | 237k | { |
2807 | 237k | expectToken(Token::Identifier, false /* do not advance */); |
2808 | 237k | return getLiteralAndAdvance(); |
2809 | 237k | } |
2810 | | |
2811 | | ASTPointer<ASTString> Parser::expectIdentifierTokenOrAddress() |
2812 | 168k | { |
2813 | 168k | ASTPointer<ASTString> result; |
2814 | 168k | if (m_scanner->currentToken() == Token::Address) |
2815 | 51 | { |
2816 | 51 | result = std::make_shared<ASTString>("address"); |
2817 | 51 | advance(); |
2818 | 51 | } |
2819 | 167k | else |
2820 | 167k | { |
2821 | 167k | expectToken(Token::Identifier, false /* do not advance */); |
2822 | 167k | result = getLiteralAndAdvance(); |
2823 | 167k | } |
2824 | 168k | return result; |
2825 | 168k | } |
2826 | | |
2827 | | ASTPointer<ASTString> Parser::getLiteralAndAdvance() |
2828 | 539k | { |
2829 | 539k | ASTPointer<ASTString> identifier = std::make_shared<ASTString>(m_scanner->currentLiteral()); |
2830 | 539k | advance(); |
2831 | 539k | return identifier; |
2832 | 539k | } |
2833 | | |
2834 | | bool Parser::isQuotedPath() const |
2835 | 4.13k | { |
2836 | 4.13k | return m_scanner->currentToken() == Token::StringLiteral; |
2837 | 4.13k | } |
2838 | | |
2839 | | bool Parser::isStdlibPath() const |
2840 | 612 | { |
2841 | 612 | return m_experimentalSolidityEnabledInCurrentSourceUnit |
2842 | 47 | && m_scanner->currentToken() == Token::Identifier |
2843 | 26 | && m_scanner->currentLiteral() == "std"; |
2844 | 612 | } |
2845 | | |
2846 | | ASTPointer<ASTString> Parser::getStdlibImportPathAndAdvance() |
2847 | 26 | { |
2848 | 26 | ASTPointer<ASTString> std = expectIdentifierToken(); |
2849 | 26 | if (m_scanner->currentToken() == Token::Period) |
2850 | 25 | advance(); |
2851 | 26 | ASTPointer<ASTString> library = expectIdentifierToken(); |
2852 | 26 | return std::make_shared<ASTString>(*std + "." + *library); |
2853 | 26 | } |
2854 | | |
2855 | | } |