diff options
author | chriseth <c@ethdev.com> | 2015-12-15 01:01:40 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-12-18 19:46:54 +0800 |
commit | d3c459b5a99715c96733825f78d63cc57265ee3c (patch) | |
tree | f1add9102a402a3942caec4e0f296a69493759e7 /libsolidity | |
parent | fe23cc82263c75f34e05795e12fedb08bc14e6a4 (diff) | |
download | dexon-solidity-d3c459b5a99715c96733825f78d63cc57265ee3c.tar.gz dexon-solidity-d3c459b5a99715c96733825f78d63cc57265ee3c.tar.zst dexon-solidity-d3c459b5a99715c96733825f78d63cc57265ee3c.zip |
Parse complex import directives.
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/NameAndTypeResolver.cpp | 2 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 26 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.cpp | 2 | ||||
-rw-r--r-- | libsolidity/ast/ASTPrinter.cpp | 2 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 2 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 87 |
6 files changed, 93 insertions, 28 deletions
diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index efdb1953..02e4d7ab 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -78,7 +78,7 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, So "Import \"" + path + "\" (referenced as \"" + - imp->identifier() + + imp->path() + "\") not found." ); error = true; diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 1ba4f65b..e270afd5 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -129,23 +129,39 @@ private: /** * Import directive for referencing other files / source objects. - * Example: import "abc.sol" + * Example: import "abc.sol" // imports all symbols of "abc.sol" into current scope * Source objects are identified by a string which can be a file name but does not have to be. + * Other ways to use it: + * import "abc" as x; // creates symbol "x" that contains all symbols in "abc" + * import * as x from "abc"; // same as above + * import {a as b, c} from "abc"; // creates new symbols "b" and "c" referencing "a" and "c" in "abc", respectively. */ class ImportDirective: public ASTNode { public: - ImportDirective(SourceLocation const& _location, ASTPointer<ASTString> const& _identifier): - ASTNode(_location), m_identifier(_identifier) {} + ImportDirective( + SourceLocation const& _location, + ASTPointer<ASTString> const& _path, + ASTPointer<ASTString> const& _unitAlias, + std::vector<std::pair<ASTPointer<Identifier>, ASTPointer<ASTString>>>&& _symbolAliases + ): + ASTNode(_location), m_path(_path), m_unitAlias(_unitAlias), m_symbolAliases(_symbolAliases) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - ASTString const& identifier() const { return *m_identifier; } + ASTString const& path() const { return *m_path; } virtual ImportAnnotation& annotation() const override; private: - ASTPointer<ASTString> m_identifier; + ASTPointer<ASTString> m_path; + /// The alias for the module itself. If present, import the whole unit under that name and + /// ignore m_symbolAlias. + ASTPointer<ASTString> m_unitAlias; + /// The aliases for the specific symbols to import. If non-empty import the specific symbols. + /// If the second component is empty, import the identifier unchanged. + /// If both m_unitAlias and m_symbolAlias are empty, import all symbols into the current scope. + std::vector<std::pair<ASTPointer<Identifier>, ASTPointer<ASTString>>> m_symbolAliases; }; /** diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index f208c3c9..377fa7e6 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -91,7 +91,7 @@ Json::Value const& ASTJsonConverter::json() bool ASTJsonConverter::visit(ImportDirective const& _node) { - addJsonNode("Import", { make_pair("file", _node.identifier())}); + addJsonNode("Import", { make_pair("file", _node.path())}); return true; } diff --git a/libsolidity/ast/ASTPrinter.cpp b/libsolidity/ast/ASTPrinter.cpp index 9253e0bf..b2ce1c26 100644 --- a/libsolidity/ast/ASTPrinter.cpp +++ b/libsolidity/ast/ASTPrinter.cpp @@ -49,7 +49,7 @@ void ASTPrinter::print(ostream& _stream) bool ASTPrinter::visit(ImportDirective const& _node) { - writeLine("ImportDirective \"" + _node.identifier() + "\""); + writeLine("ImportDirective \"" + _node.path() + "\""); printSourcePart(_node); return goDeeper(); } diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 7f097523..3238423a 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -376,7 +376,7 @@ void CompilerStack::resolveImports() for (ASTPointer<ASTNode> const& node: _source->ast->nodes()) if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get())) { - string path = absolutePath(import->identifier(), _sourceName); + string path = absolutePath(import->path(), _sourceName); import->annotation().absolutePath = path; if (!m_sources.count(path)) BOOST_THROW_EXCEPTION( diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index caf38b1d..2b856930 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -83,7 +83,7 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner) nodes.push_back(parseContractDefinition(token == Token::Library)); break; default: - fatalParserError(std::string("Expected import directive or contract definition.")); + fatalParserError(string("Expected import directive or contract definition.")); } } return nodeFactory.createNode<SourceUnit>(nodes); @@ -113,14 +113,65 @@ int Parser::endPosition() const ASTPointer<ImportDirective> Parser::parseImportDirective() { + // import "abc" [as x]; + // import * as x from "abc"; + // import {a as b, c} from "abc"; ASTNodeFactory nodeFactory(*this); expectToken(Token::Import); - if (m_scanner->currentToken() != Token::StringLiteral) - fatalParserError(std::string("Expected string literal (URL).")); - ASTPointer<ASTString> url = getLiteralAndAdvance(); + ASTPointer<ASTString> path; + ASTPointer<ASTString> unitAlias; + vector<pair<ASTPointer<Identifier>, ASTPointer<ASTString>>> symbolAliases; + + if (m_scanner->currentToken() == Token::StringLiteral) + { + path = getLiteralAndAdvance(); + if (m_scanner->currentToken() == Token::As) + { + m_scanner->next(); + unitAlias = expectIdentifierToken(); + } + } + else + { + if (m_scanner->currentToken() == Token::LBrace) + { + m_scanner->next(); + while (true) + { + ASTPointer<Identifier> id = parseIdentifier(); + ASTPointer<ASTString> alias; + if (m_scanner->currentToken() == Token::As) + { + expectToken(Token::As); + alias = expectIdentifierToken(); + } + symbolAliases.push_back(move(make_pair(move(id), move(alias)))); + if (m_scanner->currentToken() != Token::Comma) + break; + m_scanner->next(); + } + expectToken(Token::RBrace); + } + else if (m_scanner->currentToken() == Token::Mul) + { + m_scanner->next(); + expectToken(Token::As); + unitAlias = expectIdentifierToken(); + } + else + fatalParserError("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") + fatalParserError("Expected \"from\"."); + m_scanner->next(); + if (m_scanner->currentToken() != Token::StringLiteral) + fatalParserError("Expected import path."); + path = getLiteralAndAdvance(); + } nodeFactory.markEndPosition(); expectToken(Token::Semicolon); - return nodeFactory.createNode<ImportDirective>(url); + return nodeFactory.createNode<ImportDirective>(path, unitAlias, move(symbolAliases)); } ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary) @@ -171,7 +222,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary) else if (currentTokenValue == Token::Using) subNodes.push_back(parseUsingDirective()); else - fatalParserError(std::string("Function, variable, struct or modifier declaration expected.")); + fatalParserError(string("Function, variable, struct or modifier declaration expected.")); } nodeFactory.markEndPosition(); expectToken(Token::RBrace); @@ -250,7 +301,7 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* else if (Token::isVisibilitySpecifier(token)) { if (visibility != Declaration::Visibility::Default) - fatalParserError(std::string("Multiple visibility specifiers.")); + fatalParserError(string("Multiple visibility specifiers.")); visibility = parseVisibilitySpecifier(token); } else @@ -327,7 +378,7 @@ ASTPointer<EnumDefinition> Parser::parseEnumDefinition() break; expectToken(Token::Comma); if (m_scanner->currentToken() != Token::Identifier) - fatalParserError(std::string("Expected Identifier after ','")); + fatalParserError(string("Expected Identifier after ','")); } nodeFactory.markEndPosition(); @@ -363,7 +414,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( if (_options.isStateVariable && Token::isVariableVisibilitySpecifier(token)) { if (visibility != Declaration::Visibility::Default) - fatalParserError(std::string("Visibility already specified.")); + fatalParserError(string("Visibility already specified.")); visibility = parseVisibilitySpecifier(token); } else @@ -375,9 +426,9 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( else if (_options.allowLocationSpecifier && Token::isLocationSpecifier(token)) { if (location != VariableDeclaration::Location::Default) - fatalParserError(std::string("Location already specified.")); + fatalParserError(string("Location already specified.")); if (!type) - fatalParserError(std::string("Location specifier needs explicit type name.")); + fatalParserError(string("Location specifier needs explicit type name.")); location = ( token == Token::Memory ? VariableDeclaration::Location::Memory : @@ -532,7 +583,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) else if (token == Token::Var) { if (!_allowVar) - fatalParserError(std::string("Expected explicit type name.")); + fatalParserError(string("Expected explicit type name.")); m_scanner->next(); } else if (token == Token::Mapping) @@ -551,7 +602,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar) type = nodeFactory.createNode<UserDefinedTypeName>(identifierPath); } else - fatalParserError(std::string("Expected type name")); + fatalParserError(string("Expected type name")); if (type) // Parse "[...]" postfixes for arrays. @@ -574,7 +625,7 @@ ASTPointer<Mapping> Parser::parseMapping() expectToken(Token::Mapping); expectToken(Token::LParen); if (!Token::isElementaryTypeName(m_scanner->currentToken())) - fatalParserError(std::string("Expected elementary type name for mapping key type")); + fatalParserError(string("Expected elementary type name for mapping key type")); ASTPointer<ElementaryTypeName> keyType; keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(m_scanner->currentToken()); m_scanner->next(); @@ -1072,7 +1123,7 @@ ASTPointer<Expression> Parser::parsePrimaryExpression() m_scanner->next(); } else - fatalParserError(std::string("Expected primary expression.")); + fatalParserError(string("Expected primary expression.")); break; } return expression; @@ -1221,8 +1272,7 @@ Token::Value Parser::expectAssignmentOperator() Token::Value op = m_scanner->currentToken(); if (!Token::isAssignmentOp(op)) fatalParserError( - std::string("Expected assignment operator ") + - string(" got '") + + string("Expected assignment operator, got '") + string(Token::name(m_scanner->currentToken())) + string("'") ); @@ -1234,8 +1284,7 @@ ASTPointer<ASTString> Parser::expectIdentifierToken() { if (m_scanner->currentToken() != Token::Identifier) fatalParserError( - std::string("Expected identifier ") + - string(" got '") + + string("Expected identifier, got '") + string(Token::name(m_scanner->currentToken())) + string("'") ); |