From d71cd3aa2b235f877b7928b57c94159e2c16865c Mon Sep 17 00:00:00 2001 From: chriseth Date: Sun, 22 Nov 2015 20:39:10 +0100 Subject: Added the `using x for y` directive. --- libsolidity/analysis/NameAndTypeResolver.h | 4 ++-- libsolidity/analysis/TypeChecker.cpp | 11 ++++++++- libsolidity/analysis/TypeChecker.h | 1 + libsolidity/ast/AST.h | 27 ++++++++++++++++++++++ libsolidity/ast/ASTVisitor.h | 4 ++++ libsolidity/ast/AST_accept.h | 22 ++++++++++++++++++ libsolidity/parsing/Parser.cpp | 20 ++++++++++++++++ libsolidity/parsing/Parser.h | 1 + test/libsolidity/SolidityNameAndTypeResolution.cpp | 22 ++++++++++++++++++ test/libsolidity/SolidityParser.cpp | 15 ++++++++++++ 10 files changed, 124 insertions(+), 3 deletions(-) diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h index 0d9b2477..1547a274 100644 --- a/libsolidity/analysis/NameAndTypeResolver.h +++ b/libsolidity/analysis/NameAndTypeResolver.h @@ -160,8 +160,8 @@ private: void fatalDeclarationError(SourceLocation _sourceLocation, std::string const& _description); std::map& m_scopes; - Declaration const* m_currentScope; - VariableScope* m_currentFunction; + Declaration const* m_currentScope = nullptr; + VariableScope* m_currentFunction = nullptr; ErrorList& m_errors; }; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 1d2d0258..22fb1e96 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -356,7 +356,16 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) " to " + parameterTypes[i]->toString() + " requested." - ); + ); +} + +void TypeChecker::endVisit(UsingForDirective const& _usingFor) +{ + ContractDefinition const* library = dynamic_cast( + _usingFor.libraryName().annotation().referencedDeclaration + ); + if (!library || !library->isLibrary()) + typeError(_usingFor.libraryName().location(), "Library name expected."); } bool TypeChecker::visit(StructDefinition const& _struct) diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 9563d4a9..7829a23d 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -76,6 +76,7 @@ private: void checkLibraryRequirements(ContractDefinition const& _contract); virtual void endVisit(InheritanceSpecifier const& _inheritance) override; + virtual void endVisit(UsingForDirective const& _usingFor) override; virtual bool visit(StructDefinition const& _struct) override; virtual bool visit(FunctionDefinition const& _function) override; virtual bool visit(VariableDeclaration const& _variable) override; diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index a28d9f4f..2d6e9cfc 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -335,6 +335,33 @@ private: std::vector> m_arguments; }; +/** + * `using LibraryName for uint` will attach all functions from the library LibraryName + * to `uint` if the first parameter matches the type. `using LibraryName for *` attaches + * the function to any matching type. + */ +class UsingForDirective: public ASTNode +{ +public: + UsingForDirective( + SourceLocation const& _location, + ASTPointer const& _libraryName, + ASTPointer const& _typeName + ): + ASTNode(_location), m_libraryName(_libraryName), m_typeName(_typeName) {} + + virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; + + Identifier const& libraryName() const { return *m_libraryName; } + /// @returns the type name the library is attached to, null for `*`. + TypeName const* typeName() const { return m_typeName.get(); } + +private: + ASTPointer m_libraryName; + ASTPointer m_typeName; +}; + class StructDefinition: public Declaration { public: diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h index 14c09fb4..f04d9682 100644 --- a/libsolidity/ast/ASTVisitor.h +++ b/libsolidity/ast/ASTVisitor.h @@ -47,6 +47,7 @@ public: virtual bool visit(ImportDirective& _node) { return visitNode(_node); } virtual bool visit(ContractDefinition& _node) { return visitNode(_node); } virtual bool visit(InheritanceSpecifier& _node) { return visitNode(_node); } + virtual bool visit(UsingForDirective& _node) { return visitNode(_node); } virtual bool visit(StructDefinition& _node) { return visitNode(_node); } virtual bool visit(EnumDefinition& _node) { return visitNode(_node); } virtual bool visit(EnumValue& _node) { return visitNode(_node); } @@ -88,6 +89,7 @@ public: virtual void endVisit(ImportDirective& _node) { endVisitNode(_node); } virtual void endVisit(ContractDefinition& _node) { endVisitNode(_node); } virtual void endVisit(InheritanceSpecifier& _node) { endVisitNode(_node); } + virtual void endVisit(UsingForDirective& _node) { endVisitNode(_node); } virtual void endVisit(StructDefinition& _node) { endVisitNode(_node); } virtual void endVisit(EnumDefinition& _node) { endVisitNode(_node); } virtual void endVisit(EnumValue& _node) { endVisitNode(_node); } @@ -142,6 +144,7 @@ public: virtual bool visit(ContractDefinition const& _node) { return visitNode(_node); } virtual bool visit(InheritanceSpecifier const& _node) { return visitNode(_node); } virtual bool visit(StructDefinition const& _node) { return visitNode(_node); } + virtual bool visit(UsingForDirective const& _node) { return visitNode(_node); } virtual bool visit(EnumDefinition const& _node) { return visitNode(_node); } virtual bool visit(EnumValue const& _node) { return visitNode(_node); } virtual bool visit(ParameterList const& _node) { return visitNode(_node); } @@ -182,6 +185,7 @@ public: virtual void endVisit(ImportDirective const& _node) { endVisitNode(_node); } virtual void endVisit(ContractDefinition const& _node) { endVisitNode(_node); } virtual void endVisit(InheritanceSpecifier const& _node) { endVisitNode(_node); } + virtual void endVisit(UsingForDirective const& _node) { endVisitNode(_node); } virtual void endVisit(StructDefinition const& _node) { endVisitNode(_node); } virtual void endVisit(EnumDefinition const& _node) { endVisitNode(_node); } virtual void endVisit(EnumValue const& _node) { endVisitNode(_node); } diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h index f65595b8..3f7b8d36 100644 --- a/libsolidity/ast/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -123,6 +123,28 @@ void EnumValue::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } +void UsingForDirective::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + if (m_libraryName) + m_libraryName->accept(_visitor); + m_typeName->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void UsingForDirective::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + if (m_libraryName) + m_libraryName->accept(_visitor); + m_typeName->accept(_visitor); + } + _visitor.endVisit(*this); +} + void StructDefinition::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 9272eb4b..2b886121 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -168,6 +168,8 @@ ASTPointer Parser::parseContractDefinition(bool _isLibrary) subNodes.push_back(parseModifierDefinition()); else if (currentTokenValue == Token::Event) subNodes.push_back(parseEventDefinition()); + else if (currentTokenValue == Token::Using) + subNodes.push_back(parseUsingDirective()); else fatalParserError(std::string("Function, variable, struct or modifier declaration expected.")); } @@ -475,6 +477,24 @@ ASTPointer Parser::parseEventDefinition() return nodeFactory.createNode(name, docstring, parameters, anonymous); } +ASTPointer Parser::parseUsingDirective() +{ + ASTNodeFactory nodeFactory(*this); + + expectToken(Token::Using); + //@todo this should actually parse a full path. + ASTPointer library(parseIdentifier()); + ASTPointer typeName; + expectToken(Token::For); + if (m_scanner->currentToken() == Token::Mul) + m_scanner->next(); + else + typeName = parseTypeName(false); + nodeFactory.markEndPosition(); + expectToken(Token::Semicolon); + return nodeFactory.createNode(library, typeName); +} + ASTPointer Parser::parseModifierInvocation() { ASTNodeFactory nodeFactory(*this); diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 663c0f92..5ff46242 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -74,6 +74,7 @@ private: ); ASTPointer parseModifierDefinition(); ASTPointer parseEventDefinition(); + ASTPointer parseUsingDirective(); ASTPointer parseModifierInvocation(); ASTPointer parseIdentifier(); ASTPointer parseTypeName(bool _allowVar); diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 4f26fa4d..f96f7046 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -2529,6 +2529,28 @@ BOOST_AUTO_TEST_CASE(member_access_parser_ambiguity) BOOST_CHECK(success(text)); } +BOOST_AUTO_TEST_CASE(using_for_library) +{ + char const* text = R"( + library D { } + contract C { + using D for uint; + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(using_for_not_library) +{ + char const* text = R"( + contract D { } + contract C { + using D for uint; + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + BOOST_AUTO_TEST_CASE(create_memory_arrays) { char const* text = R"( diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index 7451397e..fd9076c3 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -1032,6 +1032,21 @@ BOOST_AUTO_TEST_CASE(member_access_parser_ambiguity) BOOST_CHECK(successParse(text)); } +BOOST_AUTO_TEST_CASE(using_for) +{ + char const* text = R"( + contract C { + struct s { uint a; } + using LibraryName for uint; + using Library2 for *; + using Lib for s; + function f() { + } + } + )"; + BOOST_CHECK(successParse(text)); +} + BOOST_AUTO_TEST_SUITE_END() } -- cgit v1.2.3