diff --git a/docs/Solidity.g4 b/docs/Solidity.g4 index 239cbbdd3..b2f2303ff 100644 --- a/docs/Solidity.g4 +++ b/docs/Solidity.g4 @@ -48,7 +48,6 @@ importDeclaration interfaceDefinition : 'interface' identifier 'from' StringLiteralFragment - | 'interface' identifier 'as' AbiString | 'interface' identifier contractInheritanceDefinition? contractBody ; AbiString diff --git a/liblangutil/Scanner.h b/liblangutil/Scanner.h index 5e613cfdf..3429f1802 100644 --- a/liblangutil/Scanner.h +++ b/liblangutil/Scanner.h @@ -132,6 +132,15 @@ public: return ElementaryTypeNameToken(m_tokens[Current].token, firstSize, secondSize); } + /// Tests if current keyword is an identifier and matches the given value @p _name. + /// + /// This is best used for directives that cannot be reserved as keywords but + /// in some context should be treated like one. + bool isIdentifier(std::string const& _name) const + { + return currentToken() == Token::Identifier && currentLiteral() == _name; + } + SourceLocation currentLocation() const { return m_tokens[Current].location; } std::string const& currentLiteral() const { return m_tokens[Current].literal; } std::tuple const& currentTokenInfo() const { return m_tokens[Current].extendedTokenInfo; } diff --git a/liblangutil/Token.h b/liblangutil/Token.h index cdc04bb35..d9d4471cb 100644 --- a/liblangutil/Token.h +++ b/liblangutil/Token.h @@ -160,7 +160,6 @@ namespace solidity::langutil K(External, "external", 0) \ K(Fallback, "fallback", 0) \ K(For, "for", 0) \ - K(From, "from", 0) \ K(Function, "function", 0) \ K(Hex, "hex", 0) \ K(If, "if", 0) \ diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index cecf6afb9..6a7c3cb19 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -171,7 +171,7 @@ public: SourceUnitAnnotation& annotation() const override; std::optional const& licenseString() const { return m_licenseString; } - std::vector> nodes() const { return m_nodes; } + std::vector> const& nodes() const { return m_nodes; } /// Replaces given top-level AST node with a new AST node. void replaceNode(ASTPointer _oldNode, ASTPointer _newNode); @@ -453,6 +453,24 @@ protected: /// @} +class ImportedContractDefinition: public Declaration +{ +public: + ImportedContractDefinition( + int64_t _id, + SourceLocation const& _location, + ASTPointer const& _name, + ASTPointer const& _path + ); + + void accept(ASTVisitor& _visitor) override; + void accept(ASTConstVisitor& _visitor) const override; + +private: + ASTPointer m_name; + ASTPointer m_path; +}; + /** * Definition of a contract or library. This is the only AST nodes where child nodes are not visited in * document order. It first visits all struct declarations, then all variable declarations and diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 7e5a24dd9..f38d83420 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -278,9 +278,12 @@ void CompilerStack::loadMissingInterfaces() { for (auto const& sourcePair: m_sources) { - ASTPointer const& source = sourcePair.second.ast;; + ASTPointer const& source = sourcePair.second.ast; + if (!source) + // This can happen if the input source code contained invalid source code. + continue; - for (auto const& astNode: source->nodes()) + for (ASTPointer const& astNode: source->nodes()) { if (auto* contract = dynamic_cast(astNode.get())) { diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 85016db79..47a216a09 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -250,7 +250,7 @@ ASTPointer Parser::parseImportDirective() fatalParserError(9478_error, "Expected string literal (path), \"*\" or alias list."); // "from" is not a keyword but parsed as an identifier because of backwards // compatibility and because it is a really common word. - if (m_scanner->currentToken() != Token::Identifier || m_scanner->currentLiteral() != "from") + if (!m_scanner->isIdentifier("from")) fatalParserError(8208_error, "Expected \"from\"."); m_scanner->next(); if (m_scanner->currentToken() != Token::StringLiteral) @@ -307,7 +307,7 @@ ASTPointer Parser::parseInterfaceDefinition() ASTPointer documentation = parseStructuredDocumentation(); vector> baseContracts; - if (m_scanner->currentToken() == Token::From) + if (m_scanner->isIdentifier("from")) { m_scanner->next(); if (m_scanner->currentToken() != Token::StringLiteral)