From 337fde9d11adac85800b405a3fdb4bcd09039ebf Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 8 Sep 2015 16:48:33 +0200 Subject: Parsing and type checking of libraries without inheritance. --- libsolidity/AST.cpp | 18 ++++++++++++ libsolidity/AST.h | 12 ++++++-- libsolidity/Parser.cpp | 12 ++++---- libsolidity/Parser.h | 8 ++++-- libsolidity/Token.h | 3 +- libsolidity/grammar.txt | 2 +- test/libsolidity/SolidityNameAndTypeResolution.cpp | 33 ++++++++++++++++++++++ test/libsolidity/SolidityParser.cpp | 10 +++++++ 8 files changed, 85 insertions(+), 13 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 1b22c44f..5e51d222 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -103,6 +103,9 @@ void ContractDefinition::checkTypeRequirements() )); hashes.insert(hash); } + + if (isLibrary()) + checkLibraryRequirements(); } map, FunctionTypePointer> ContractDefinition::interfaceFunctions() const @@ -332,6 +335,17 @@ void ContractDefinition::checkExternalTypeClashes() const )); } +void ContractDefinition::checkLibraryRequirements() const +{ + solAssert(m_isLibrary, ""); + if (!m_baseContracts.empty()) + BOOST_THROW_EXCEPTION(createTypeError("Library is not allowed to inherit.")); + + for (auto const& var: m_stateVariables) + if (!var->isConstant()) + BOOST_THROW_EXCEPTION(var->createTypeError("Library cannot have non-constant state variables")); +} + vector> const& ContractDefinition::interfaceEvents() const { if (!m_interfaceEvents) @@ -449,6 +463,10 @@ void InheritanceSpecifier::checkTypeRequirements() ContractDefinition const* base = dynamic_cast(&m_baseName->referencedDeclaration()); solAssert(base, "Base contract not available."); + + if (base->isLibrary()) + BOOST_THROW_EXCEPTION(createTypeError("Libraries cannot be inherited from.")); + TypePointers parameterTypes = ContractType(*base).constructorType()->parameterTypes(); if (!m_arguments.empty() && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError( diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 48790e6a..da6a7d58 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -215,7 +215,7 @@ protected: /// @} /** - * Definition of a contract. This is the only AST nodes where child nodes are not visited in + * 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 * finally all function declarations. */ @@ -232,7 +232,8 @@ public: std::vector> const& _stateVariables, std::vector> const& _definedFunctions, std::vector> const& _functionModifiers, - std::vector> const& _events + std::vector> const& _events, + bool _isLibrary ): Declaration(_location, _name), Documented(_documentation), @@ -243,7 +244,8 @@ public: m_stateVariables(_stateVariables), m_definedFunctions(_definedFunctions), m_functionModifiers(_functionModifiers), - m_events(_events) + m_events(_events), + m_isLibrary(_isLibrary) {} virtual void accept(ASTVisitor& _visitor) override; @@ -257,6 +259,7 @@ public: std::vector> const& definedFunctions() const { return m_definedFunctions; } std::vector> const& events() const { return m_events; } std::vector> const& interfaceEvents() const; + bool isLibrary() const { return m_isLibrary; } virtual TypePointer type(ContractDefinition const* m_currentContract) const override; @@ -297,6 +300,8 @@ private: /// Checks that different functions with external visibility end up having different /// external argument types (i.e. different signature). void checkExternalTypeClashes() const; + /// Checks that all requirements for a library are fulfilled if this is a library. + void checkLibraryRequirements() const; std::vector, FunctionTypePointer>> const& interfaceFunctionList() const; @@ -307,6 +312,7 @@ private: std::vector> m_definedFunctions; std::vector> m_functionModifiers; std::vector> m_events; + bool m_isLibrary; // parsed Natspec documentation of the contract. std::string m_userDocumentation; diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 7f779ed0..24f7734c 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -71,13 +71,14 @@ ASTPointer Parser::parse(shared_ptr const& _scanner) vector> nodes; while (m_scanner->currentToken() != Token::EOS) { - switch (m_scanner->currentToken()) + switch (auto token = m_scanner->currentToken()) { case Token::Import: nodes.push_back(parseImportDirective()); break; case Token::Contract: - nodes.push_back(parseContractDefinition()); + case Token::Library: + nodes.push_back(parseContractDefinition(token == Token::Library)); break; default: BOOST_THROW_EXCEPTION(createParserError(std::string("Expected import directive or contract definition."))); @@ -113,13 +114,13 @@ ASTPointer Parser::parseImportDirective() return nodeFactory.createNode(url); } -ASTPointer Parser::parseContractDefinition() +ASTPointer Parser::parseContractDefinition(bool _isLibrary) { ASTNodeFactory nodeFactory(*this); ASTPointer docString; if (m_scanner->currentCommentLiteral() != "") docString = make_shared(m_scanner->currentCommentLiteral()); - expectToken(Token::Contract); + expectToken(_isLibrary ? Token::Library : Token::Contract); ASTPointer name = expectIdentifierToken(); vector> baseContracts; vector> structs; @@ -177,7 +178,8 @@ ASTPointer Parser::parseContractDefinition() stateVariables, functions, modifiers, - events + events, + _isLibrary ); } diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 36302f74..79eb73f0 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -61,15 +61,17 @@ private: ///@{ ///@name Parsing functions for the AST nodes ASTPointer parseImportDirective(); - ASTPointer parseContractDefinition(); + ASTPointer parseContractDefinition(bool _isLibrary); ASTPointer parseInheritanceSpecifier(); Declaration::Visibility parseVisibilitySpecifier(Token::Value _token); ASTPointer parseFunctionDefinition(ASTString const* _contractName); ASTPointer parseStructDefinition(); ASTPointer parseEnumDefinition(); ASTPointer parseEnumValue(); - ASTPointer parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions(), - ASTPointer const& _lookAheadArrayType = ASTPointer()); + ASTPointer parseVariableDeclaration( + VarDeclParserOptions const& _options = VarDeclParserOptions(), + ASTPointer const& _lookAheadArrayType = ASTPointer() + ); ASTPointer parseModifierDefinition(); ASTPointer parseEventDefinition(); ASTPointer parseModifierInvocation(); diff --git a/libsolidity/Token.h b/libsolidity/Token.h index bc242ecf..1632a693 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -160,6 +160,7 @@ namespace solidity K(Internal, "internal", 0) \ K(Import, "import", 0) \ K(Is, "is", 0) \ + K(Library, "library", 0) \ K(Mapping, "mapping", 0) \ K(Memory, "memory", 0) \ K(Modifier, "modifier", 0) \ @@ -305,7 +306,7 @@ namespace solidity /* Identifiers (not keywords or future reserved words). */ \ T(Identifier, NULL, 0) \ \ - /* Keywords reserved for future. use. */ \ + /* Keywords reserved for future use. */ \ K(As, "as", 0) \ K(Case, "case", 0) \ K(Catch, "catch", 0) \ diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt index 6503516c..467aebee 100644 --- a/libsolidity/grammar.txt +++ b/libsolidity/grammar.txt @@ -1,4 +1,4 @@ -ContractDefinition = 'contract' Identifier +ContractDefinition = ( 'contract' | 'library' ) Identifier ( 'is' InheritanceSpecifier (',' InheritanceSpecifier )* )? '{' ContractPart* '}' ContractPart = StateVariableDeclaration | StructDefinition | ModifierDefinition | FunctionDefinition | EnumDefinition diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 883d7807..adff9499 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -2194,6 +2194,39 @@ BOOST_AUTO_TEST_CASE(string_bytes_conversion) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } +BOOST_AUTO_TEST_CASE(inheriting_from_library) +{ + char const* text = R"( + library Lib {} + contract Test is Lib {} + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + +BOOST_AUTO_TEST_CASE(inheriting_library) +{ + char const* text = R"( + contract Test {} + library Lib is Test {} + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + +BOOST_AUTO_TEST_CASE(library_having_variables) +{ + char const* text = R"( + library Lib { uint x; } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + +BOOST_AUTO_TEST_CASE(valid_library) +{ + char const* text = R"( + library Lib { uint constant x = 9; } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} BOOST_AUTO_TEST_CASE(creating_contract_within_the_contract) { diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index 14b9e9e4..1e034863 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -924,6 +924,16 @@ BOOST_AUTO_TEST_CASE(empty_comment) BOOST_CHECK_NO_THROW(parseText(text)); } +BOOST_AUTO_TEST_CASE(library_simple) +{ + char const* text = R"( + library Lib { + function f() { } + } + )"; + BOOST_CHECK_NO_THROW(parseText(text)); +} + BOOST_AUTO_TEST_SUITE_END() } -- cgit