From 1265be7bb8d77ac7ac2b46abbb5f0036a28b3975 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 9 Feb 2015 15:24:36 +0100 Subject: [PATCH 01/20] Adding enum Token and whitespace style at Token.h --- libsolidity/Token.h | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 5167c1a77..f164e3fcc 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -67,27 +67,27 @@ namespace solidity #define IGNORE_TOKEN(name, string, precedence) -#define TOKEN_LIST(T, K) \ - /* End of source indicator. */ \ - T(EOS, "EOS", 0) \ - \ - /* Punctuators (ECMA-262, section 7.7, page 15). */ \ - T(LParen, "(", 0) \ - T(RParen, ")", 0) \ - T(LBrack, "[", 0) \ - T(RBrack, "]", 0) \ - T(LBrace, "{", 0) \ - T(RBrace, "}", 0) \ - T(Colon, ":", 0) \ - T(Semicolon, ";", 0) \ - T(Period, ".", 0) \ - T(Conditional, "?", 3) \ - T(Arrow, "=>", 0) \ - \ - /* Assignment operators. */ \ - /* IsAssignmentOp() relies on this block of enum values being */ \ - /* contiguous and sorted in the same order!*/ \ - T(Assign, "=", 2) \ +#define TOKEN_LIST(T, K) \ + /* End of source indicator. */ \ + T(EOS, "EOS", 0) \ + \ + /* Punctuators (ECMA-262, section 7.7, page 15). */ \ + T(LParen, "(", 0) \ + T(RParen, ")", 0) \ + T(LBrack, "[", 0) \ + T(RBrack, "]", 0) \ + T(LBrace, "{", 0) \ + T(RBrace, "}", 0) \ + T(Colon, ":", 0) \ + T(Semicolon, ";", 0) \ + T(Period, ".", 0) \ + T(Conditional, "?", 3) \ + T(Arrow, "=>", 0) \ + \ + /* Assignment operators. */ \ + /* IsAssignmentOp() relies on this block of enum values being */ \ + /* contiguous and sorted in the same order!*/ \ + T(Assign, "=", 2) \ /* The following have to be in exactly the same order as the simple binary operators*/ \ T(AssignBitOr, "|=", 2) \ T(AssignBitXor, "^=", 2) \ From 082bfb2300d90482df4c2f55605b4fe72c80f552 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 9 Feb 2015 18:08:56 +0100 Subject: [PATCH 02/20] Parsing enums for Solidity - WIP --- libsolidity/AST.cpp | 16 +++++++++++++++ libsolidity/AST.h | 38 +++++++++++++++++++++++++++++++++++ libsolidity/ASTForward.h | 2 ++ libsolidity/ASTPrinter.cpp | 22 ++++++++++++++++++++ libsolidity/ASTPrinter.h | 4 ++++ libsolidity/ASTVisitor.h | 4 ++++ libsolidity/AST_accept.h | 12 +++++++++++ libsolidity/Parser.cpp | 41 +++++++++++++++++++++++++++++++++++++- libsolidity/Parser.h | 3 +++ 9 files changed, 141 insertions(+), 1 deletion(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 3c6b6007c..0c34cea38 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -255,6 +255,22 @@ void StructDefinition::checkRecursion() const } } +void EnumDefinition::checkValidityOfMembers() const +{ +#if 0 // LTODO: Make this work for the Declarations + vector> members = getMembers(); + sort(begin(members), end(members)); + for (size_t i = 0; i < members.size(); ++i) + if (members[i] == members[i + 1]) + BOOST_THROW_EXCEPTION(createTypeError("Duplicate member detected in Enum")); +#endif +} + +TypePointer EnumDefinition::getType(ContractDefinition const*) const +{ + return make_shared(make_shared(*this)); +} + TypePointer FunctionDefinition::getType(ContractDefinition const*) const { return make_shared(*this); diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 4e79026e8..d3a7853a4 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -165,6 +165,18 @@ private: Declaration const* m_scope; }; +/** + * Declaration of an Enum Value + */ +class EnumDeclaration : public Declaration +{ + EnumDeclaration(Location const& _location, + ASTPointer const& _name): + Declaration(_location, _name) {} + + TypePointer getType(ContractDefinition const*) const; +}; + /** * Abstract class that is added to each AST node that can store local variables. */ @@ -209,6 +221,7 @@ public: ASTPointer const& _documentation, std::vector> const& _baseContracts, std::vector> const& _definedStructs, + std::vector> const& _definedEnums, std::vector> const& _stateVariables, std::vector> const& _definedFunctions, std::vector> const& _functionModifiers, @@ -216,6 +229,7 @@ public: Declaration(_location, _name), Documented(_documentation), m_baseContracts(_baseContracts), m_definedStructs(_definedStructs), + m_definedEnums(_definedEnums), m_stateVariables(_stateVariables), m_definedFunctions(_definedFunctions), m_functionModifiers(_functionModifiers), @@ -227,6 +241,7 @@ public: std::vector> const& getBaseContracts() const { return m_baseContracts; } std::vector> const& getDefinedStructs() const { return m_definedStructs; } + std::vector> const& getDefinedEnums() const { return m_definedEnums; } std::vector> const& getStateVariables() const { return m_stateVariables; } std::vector> const& getFunctionModifiers() const { return m_functionModifiers; } std::vector> const& getDefinedFunctions() const { return m_definedFunctions; } @@ -260,6 +275,7 @@ private: std::vector> m_baseContracts; std::vector> m_definedStructs; + std::vector> m_definedEnums; std::vector> m_stateVariables; std::vector> m_definedFunctions; std::vector> m_functionModifiers; @@ -315,6 +331,28 @@ private: std::vector> m_members; }; +class EnumDefinition: public Declaration +{ +public: + EnumDefinition(Location const& _location, + ASTPointer const& _name, + std::vector> const& _members): + Declaration(_location, _name), m_members(_members) {} + virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; + + std::vector> const& getMembers() const { return m_members; } + + virtual TypePointer getType(ContractDefinition const*) const override; + + /// Checks that the members do not include any duplicate names + void checkValidityOfMembers() const; + +private: + + std::vector> m_members; +}; + /** * Parameter list, used as function parameter list and return list. * None of the parameters is allowed to contain mappings (not even recursively diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h index 22015f26b..a0a6f6832 100644 --- a/libsolidity/ASTForward.h +++ b/libsolidity/ASTForward.h @@ -40,6 +40,8 @@ class Declaration; class ContractDefinition; class InheritanceSpecifier; class StructDefinition; +class EnumDefinition; +class EnumDeclaration; class ParameterList; class FunctionDefinition; class VariableDeclaration; diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index 949740e89..34cd12a98 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -71,6 +71,18 @@ bool ASTPrinter::visit(StructDefinition const& _node) return goDeeper(); } +bool ASTPrinter::visit(EnumDefinition const& _node) +{ + writeLine("EnumDefinition \"" + _node.getName() + "\""); + return goDeeper(); +} + +bool ASTPrinter::visit(EnuumDeclaration const& _node) +{ + writeLine("EnumValue \"" + _node.getName() + "\""); + return goDeeper(); +} + bool ASTPrinter::visit(ParameterList const& _node) { writeLine("ParameterList"); @@ -347,6 +359,16 @@ void ASTPrinter::endVisit(StructDefinition const&) m_indentation--; } +void ASTPrinter::endVisit(EnumDefinition const&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(EnumDeclaration const&) +{ + m_indentation--; +} + void ASTPrinter::endVisit(ParameterList const&) { m_indentation--; diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index ebc163e31..a306e90b5 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -46,6 +46,8 @@ public: bool visit(ContractDefinition const& _node) override; bool visit(InheritanceSpecifier const& _node) override; bool visit(StructDefinition const& _node) override; + bool visit(EnumDefinition const& _node) override; + bool visit(EnumDeclaration const& _node) override; bool visit(ParameterList const& _node) override; bool visit(FunctionDefinition const& _node) override; bool visit(VariableDeclaration const& _node) override; @@ -85,6 +87,8 @@ public: void endVisit(ContractDefinition const&) override; void endVisit(InheritanceSpecifier const&) override; void endVisit(StructDefinition const&) override; + void endVisit(EnumDefinition const&) override; + void endVisit(EnumDeclaration const&) override; void endVisit(ParameterList const&) override; void endVisit(FunctionDefinition const&) override; void endVisit(VariableDeclaration const&) override; diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index 294902778..b05ec6580 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -47,6 +47,7 @@ public: virtual bool visit(ContractDefinition&) { return true; } virtual bool visit(InheritanceSpecifier&) { return true; } virtual bool visit(StructDefinition&) { return true; } + virtual bool visit(EnumDefinition&) { return true; } virtual bool visit(ParameterList&) { return true; } virtual bool visit(FunctionDefinition&) { return true; } virtual bool visit(VariableDeclaration&) { return true; } @@ -88,6 +89,7 @@ public: virtual void endVisit(ContractDefinition&) { } virtual void endVisit(InheritanceSpecifier&) { } virtual void endVisit(StructDefinition&) { } + virtual void endVisit(EnumDefinition&) { } virtual void endVisit(ParameterList&) { } virtual void endVisit(FunctionDefinition&) { } virtual void endVisit(VariableDeclaration&) { } @@ -133,6 +135,7 @@ public: virtual bool visit(ContractDefinition const&) { return true; } virtual bool visit(InheritanceSpecifier const&) { return true; } virtual bool visit(StructDefinition const&) { return true; } + virtual bool visit(EnumDefinition const&) { return true; } virtual bool visit(ParameterList const&) { return true; } virtual bool visit(FunctionDefinition const&) { return true; } virtual bool visit(VariableDeclaration const&) { return true; } @@ -174,6 +177,7 @@ public: virtual void endVisit(ContractDefinition const&) { } virtual void endVisit(InheritanceSpecifier const&) { } virtual void endVisit(StructDefinition const&) { } + virtual void endVisit(EnumDefinition const&) { } virtual void endVisit(ParameterList const&) { } virtual void endVisit(FunctionDefinition const&) { } virtual void endVisit(VariableDeclaration const&) { } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index 38108cd72..15f6b7eeb 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -112,6 +112,18 @@ void StructDefinition::accept(ASTVisitor& _visitor) _visitor.endVisit(*this); } +void EnumDefinition::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this) + _visitor.endVisit(*this); +} + +void EnumDefinition::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this) + _visitor.endVisit(*this); +} + void StructDefinition::accept(ASTConstVisitor& _visitor) const { if (_visitor.visit(*this)) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index f076df876..2f0796d6d 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -119,6 +119,7 @@ ASTPointer Parser::parseContractDefinition() ASTPointer name = expectIdentifierToken(); vector> baseContracts; vector> structs; + vector> enums; vector> stateVariables; vector> functions; vector> modifiers; @@ -140,6 +141,8 @@ ASTPointer Parser::parseContractDefinition() functions.push_back(parseFunctionDefinition(name.get())); else if (currentToken == Token::Struct) structs.push_back(parseStructDefinition()); + else if (currentToken == Token::Enum) + enums.push_back(parseEnumDefinition()); else if (currentToken == Token::Identifier || currentToken == Token::Mapping || Token::isElementaryTypeName(currentToken)) { @@ -157,7 +160,7 @@ ASTPointer Parser::parseContractDefinition() } nodeFactory.markEndPosition(); expectToken(Token::RBrace); - return nodeFactory.createNode(name, docString, baseContracts, structs, + return nodeFactory.createNode(name, docString, baseContracts, structs, enums, stateVariables, functions, modifiers, events); } @@ -263,6 +266,35 @@ ASTPointer Parser::parseStructDefinition() return nodeFactory.createNode(name, members); } +ASTPointer Parser::parseEnumDeclaration() +{ + ASTNodeFactory nodeFactory(*this); + ASTPointer name = expectIdentifierToken(); + nodeFactory.markEndPosition(); + return nodeFactory.createNode(name); +} + +ASTPointer Parser::parseEnumDefinition() +{ + ASTNodeFactory nodeFactory(*this); + expectToken(Token::Enum); + ASTPointer name = expectIdentifierToken(); + vector> members; + expectToken(Token::LBrace); + + while (m_scanner->getCurrentToken() == Token::Identifier) + { + members.push_back(parseEnumDeclaration()); + if (m_scanner->getCurrentToken() == Token::RBrace) + break; + expectToken(Token::Comma); + } + + nodeFactory.markEndPosition(); + expectToken(Token::RBrace); + return nodeFactory.createNode(name, members); +} + ASTPointer Parser::parseVariableDeclaration(VarDeclParserOptions const& _options) { ASTNodeFactory nodeFactory(*this); @@ -823,6 +855,13 @@ ASTPointer Parser::expectIdentifierToken() return getLiteralAndAdvance(); } +ASTPointer Parser::peekIdentifierToken() +{ + if (m_scanner->getCurrentToken() != Token::Identifier) + return nullptr; + return getLiteralAndAdvance(); +} + ASTPointer Parser::getLiteralAndAdvance() { ASTPointer identifier = make_shared(m_scanner->getCurrentLiteral()); diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 5816fec40..734bdd57e 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -61,6 +61,8 @@ private: Declaration::Visibility parseVisibilitySpecifier(Token::Value _token); ASTPointer parseFunctionDefinition(ASTString const* _contractName); ASTPointer parseStructDefinition(); + ASTPointer parseEnumDefinition(); + ASTPointer parseEnumDeclaration(); ASTPointer parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions()); ASTPointer parseModifierDefinition(); ASTPointer parseEventDefinition(); @@ -96,6 +98,7 @@ private: void expectToken(Token::Value _value); Token::Value expectAssignmentOperator(); ASTPointer expectIdentifierToken(); + ASTPointer peekIdentifierToken(); ASTPointer getLiteralAndAdvance(); ///@} From 133969bd2a2b3627dc7758851ef0fae02c176a3d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 10 Feb 2015 13:40:21 +0100 Subject: [PATCH 03/20] Parsing an enum AST node --- libsolidity/AST.cpp | 10 +++++++++- libsolidity/AST.h | 5 ++++- libsolidity/ASTPrinter.cpp | 2 +- libsolidity/ASTVisitor.h | 4 ++++ libsolidity/AST_accept.h | 24 +++++++++++++++++++----- libsolidity/Parser.cpp | 2 +- libsolidity/Token.h | 2 +- 7 files changed, 39 insertions(+), 10 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 0c34cea38..95014fa18 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -206,6 +206,12 @@ vector, FunctionTypePointer>> const& ContractDefinition::getIn return *m_interfaceFunctionList; } +TypePointer EnumDeclaration::getType(ContractDefinition const*) const +{ + // LTODO + return nullptr; +} + void InheritanceSpecifier::checkTypeRequirements() { m_baseName->checkTypeRequirements(); @@ -268,7 +274,9 @@ void EnumDefinition::checkValidityOfMembers() const TypePointer EnumDefinition::getType(ContractDefinition const*) const { - return make_shared(make_shared(*this)); + //LTODO: + return nullptr; + // return make_shared(make_shared(*this)); } TypePointer FunctionDefinition::getType(ContractDefinition const*) const diff --git a/libsolidity/AST.h b/libsolidity/AST.h index d3a7853a4..02493df25 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -170,10 +170,13 @@ private: */ class EnumDeclaration : public Declaration { + public: EnumDeclaration(Location const& _location, ASTPointer const& _name): Declaration(_location, _name) {} + virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; TypePointer getType(ContractDefinition const*) const; }; @@ -717,7 +720,7 @@ public: Expression const& getCondition() const { return *m_condition; } Statement const& getTrueStatement() const { return *m_trueBody; } - /// @returns the "else" part of the if statement or nullptr if there is no "else" part. + /// @returns the "else" part of the if statement or nullptr if there is no "else" part. Statement const* getFalseStatement() const { return m_falseBody.get(); } private: diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index 34cd12a98..b655d309d 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -77,7 +77,7 @@ bool ASTPrinter::visit(EnumDefinition const& _node) return goDeeper(); } -bool ASTPrinter::visit(EnuumDeclaration const& _node) +bool ASTPrinter::visit(EnumDeclaration const& _node) { writeLine("EnumValue \"" + _node.getName() + "\""); return goDeeper(); diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index b05ec6580..108827573 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -48,6 +48,7 @@ public: virtual bool visit(InheritanceSpecifier&) { return true; } virtual bool visit(StructDefinition&) { return true; } virtual bool visit(EnumDefinition&) { return true; } + virtual bool visit(EnumDeclaration&) { return true; } virtual bool visit(ParameterList&) { return true; } virtual bool visit(FunctionDefinition&) { return true; } virtual bool visit(VariableDeclaration&) { return true; } @@ -90,6 +91,7 @@ public: virtual void endVisit(InheritanceSpecifier&) { } virtual void endVisit(StructDefinition&) { } virtual void endVisit(EnumDefinition&) { } + virtual void endVisit(EnumDeclaration&) { } virtual void endVisit(ParameterList&) { } virtual void endVisit(FunctionDefinition&) { } virtual void endVisit(VariableDeclaration&) { } @@ -136,6 +138,7 @@ public: virtual bool visit(InheritanceSpecifier const&) { return true; } virtual bool visit(StructDefinition const&) { return true; } virtual bool visit(EnumDefinition const&) { return true; } + virtual bool visit(EnumDeclaration const&) { return true; } virtual bool visit(ParameterList const&) { return true; } virtual bool visit(FunctionDefinition const&) { return true; } virtual bool visit(VariableDeclaration const&) { return true; } @@ -178,6 +181,7 @@ public: virtual void endVisit(InheritanceSpecifier const&) { } virtual void endVisit(StructDefinition const&) { } virtual void endVisit(EnumDefinition const&) { } + virtual void endVisit(EnumDeclaration const&) { } virtual void endVisit(ParameterList const&) { } virtual void endVisit(FunctionDefinition const&) { } virtual void endVisit(VariableDeclaration const&) { } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index 15f6b7eeb..9568da5b3 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -105,22 +105,36 @@ void InheritanceSpecifier::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } -void StructDefinition::accept(ASTVisitor& _visitor) +void EnumDefinition::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) listAccept(m_members, _visitor); _visitor.endVisit(*this); } -void EnumDefinition::accept(ASTVisitor& _visitor) +void EnumDefinition::accept(ASTConstVisitor& _visitor) const { - _visitor.visit(*this) + if (_visitor.visit(*this)) + listAccept(m_members, _visitor); _visitor.endVisit(*this); } -void EnumDefinition::accept(ASTConstVisitor& _visitor) const +void EnumDeclaration::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void EnumDeclaration::accept(ASTConstVisitor& _visitor) const +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void StructDefinition::accept(ASTVisitor& _visitor) { - _visitor.visit(*this) + if (_visitor.visit(*this)) + listAccept(m_members, _visitor); _visitor.endVisit(*this); } diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 2f0796d6d..fd25d7ce1 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -279,7 +279,7 @@ ASTPointer Parser::parseEnumDefinition() ASTNodeFactory nodeFactory(*this); expectToken(Token::Enum); ASTPointer name = expectIdentifierToken(); - vector> members; + vector> members; expectToken(Token::LBrace); while (m_scanner->getCurrentToken() == Token::Identifier) diff --git a/libsolidity/Token.h b/libsolidity/Token.h index f164e3fcc..5039d5b5f 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -168,7 +168,7 @@ namespace solidity K(Switch, "switch", 0) \ K(Var, "var", 0) \ K(While, "while", 0) \ - \ + K(Enum, "enum", 0) \ \ /* Ether subdenominations */ \ K(SubWei, "wei", 0) \ From ec47c759ea6e0a5bad7744e6e14b491d7890dd64 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 10 Feb 2015 14:51:40 +0100 Subject: [PATCH 04/20] Adding test for Enum Parsing --- test/SolidityParser.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index 84f36170f..035bfd789 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -703,6 +703,20 @@ BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations_in_expression BOOST_CHECK_NO_THROW(parseTextExplainError(text)); } +BOOST_AUTO_TEST_CASE(enum_declaration) +{ + char const* text = R"( + contract c { + enum foo { WARNING, NOTICE, ERROR, CRITICAL }; + function c () + { + a = foo.CRITICAL; + } + uint256 a; + })"; + BOOST_CHECK_NO_THROW(parseTextExplainError(text)); +} + BOOST_AUTO_TEST_SUITE_END() } From 9232b4cd8870113dfc835749a46da5fd971ace2d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 11 Feb 2015 16:37:46 +0100 Subject: [PATCH 05/20] Introducing EnumType and some Parser tests --- libsolidity/AST.cpp | 6 ++---- libsolidity/AST.h | 2 +- libsolidity/Parser.cpp | 1 + libsolidity/Types.cpp | 31 +++++++++++++++++++++++++++++++ libsolidity/Types.h | 28 ++++++++++++++++++++++++---- test/SolidityParser.cpp | 14 ++++++++++++++ 6 files changed, 73 insertions(+), 9 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 95014fa18..488bd4cd1 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -208,7 +208,7 @@ vector, FunctionTypePointer>> const& ContractDefinition::getIn TypePointer EnumDeclaration::getType(ContractDefinition const*) const { - // LTODO + // LTODO: How to get the parent EnumDefinition and return its type here? return nullptr; } @@ -274,9 +274,7 @@ void EnumDefinition::checkValidityOfMembers() const TypePointer EnumDefinition::getType(ContractDefinition const*) const { - //LTODO: - return nullptr; - // return make_shared(make_shared(*this)); + return make_shared(make_shared(*this)); } TypePointer FunctionDefinition::getType(ContractDefinition const*) const diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 02493df25..65c35026c 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -177,7 +177,7 @@ class EnumDeclaration : public Declaration virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - TypePointer getType(ContractDefinition const*) const; + TypePointer getType(ContractDefinition const* = nullptr) const; }; /** diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index fd25d7ce1..a26713a73 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -292,6 +292,7 @@ ASTPointer Parser::parseEnumDefinition() nodeFactory.markEndPosition(); expectToken(Token::RBrace); + expectToken(Token::Semicolon); return nodeFactory.createNode(name, members); } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 16514b148..6b6a70c29 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -662,6 +662,37 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage offset of non-existing member requested.")); } +TypePointer EnumType::unaryOperatorResult(Token::Value _operator) const +{ + return _operator == Token::Delete ? make_shared() : TypePointer(); +} + +bool EnumType::operator==(Type const& _other) const +{ + if (_other.getCategory() != getCategory()) + return false; + EnumType const& other = dynamic_cast(_other); + return other.m_enum == m_enum; +} + +string EnumType::toString() const +{ + return string("enum ") + m_enum.getName(); +} + +MemberList const& EnumType::getMembers() const +{ + // We need to lazy-initialize it because of recursive references. + if (!m_members) + { + map> members; + for (ASTPointer const& enumValue: m_enum.getMembers()) + members.insert(make_pair(enumValue->getName(), make_shared(m_enum))); + m_members.reset(new MemberList(members)); + } + return *m_members; +} + FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal): m_location(_isInternal ? Location::Internal : Location::External), m_isConstant(_function.isDeclaredConst()), diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 5a0e2c429..70703938d 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -76,10 +76,9 @@ class Type: private boost::noncopyable, public std::enable_shared_from_this m_members; }; +/** + * The type of an enum instance, there is one distinct type per enum definition. + */ +class EnumType: public Type +{ +public: + virtual Category getCategory() const override { return Category::Enum; } + explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {} + virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; + virtual bool operator==(Type const& _other) const override; + virtual unsigned getSizeOnStack() const override { return 1; /*@todo*/ } + virtual std::string toString() const override; + + virtual MemberList const& getMembers() const override; + +private: + EnumDefinition const& m_enum; + /// List of member types, will be lazy-initialized because of recursive references. + mutable std::unique_ptr m_members; +}; + /** * The type of a function, identified by its (return) parameter types. * @todo the return parameters should also have names, i.e. return parameters should be a struct diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index 035bfd789..291ec6051 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -717,6 +717,20 @@ BOOST_AUTO_TEST_CASE(enum_declaration) BOOST_CHECK_NO_THROW(parseTextExplainError(text)); } +BOOST_AUTO_TEST_CASE(empty_enum_declaration) +{ + char const* text = R"( + contract c { + enum foo { }; + function c () + { + a = 5; + } + uint256 a; + })"; + BOOST_CHECK_NO_THROW(parseTextExplainError(text)); +} + BOOST_AUTO_TEST_SUITE_END() } From 31014b34575d9168b04f5d0aba9530410dc12b17 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 11 Feb 2015 17:23:13 +0100 Subject: [PATCH 06/20] Disallow trailing comma in Enum Declaration --- libsolidity/Parser.cpp | 5 ++++- test/SolidityParser.cpp | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index a26713a73..e59e698f1 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -282,12 +282,15 @@ ASTPointer Parser::parseEnumDefinition() vector> members; expectToken(Token::LBrace); - while (m_scanner->getCurrentToken() == Token::Identifier) + while (m_scanner->getCurrentToken() != Token::RBrace) { members.push_back(parseEnumDeclaration()); if (m_scanner->getCurrentToken() == Token::RBrace) break; expectToken(Token::Comma); + if (m_scanner->getCurrentToken() != Token::Identifier) { + BOOST_THROW_EXCEPTION(createParserError("Expected Identifier after ,")); + } } nodeFactory.markEndPosition(); diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index 291ec6051..07ec2dcfa 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -731,6 +731,20 @@ BOOST_AUTO_TEST_CASE(empty_enum_declaration) BOOST_CHECK_NO_THROW(parseTextExplainError(text)); } +BOOST_AUTO_TEST_CASE(malformed_enum_declaration) +{ + char const* text = R"( + contract c { + enum foo { WARNING,}; + function c () + { + a = foo.CRITICAL; + } + uint256 a; + })"; + BOOST_CHECK_THROW(parseText(text), ParserError); +} + BOOST_AUTO_TEST_SUITE_END() } From 2dbf7391196295567b3ec55bdf99eec43fa73ba1 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 11 Feb 2015 21:40:47 +0100 Subject: [PATCH 07/20] Enums NameAndTypeResolution - WIP - Also adding an EndToEnd enum test --- libsolidity/AST_accept.h | 2 ++ libsolidity/NameAndTypeResolver.cpp | 15 +++++++++++++++ libsolidity/NameAndTypeResolver.h | 2 ++ libsolidity/Types.cpp | 2 ++ test/SolidityEndToEndTest.cpp | 20 ++++++++++++++++++++ test/SolidityNameAndTypeResolution.cpp | 15 +++++++++++++++ 6 files changed, 56 insertions(+) diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index 9568da5b3..78c2f8c58 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -63,6 +63,7 @@ void ContractDefinition::accept(ASTVisitor& _visitor) { listAccept(m_baseContracts, _visitor); listAccept(m_definedStructs, _visitor); + listAccept(m_definedEnums, _visitor); listAccept(m_stateVariables, _visitor); listAccept(m_events, _visitor); listAccept(m_functionModifiers, _visitor); @@ -77,6 +78,7 @@ void ContractDefinition::accept(ASTConstVisitor& _visitor) const { listAccept(m_baseContracts, _visitor); listAccept(m_definedStructs, _visitor); + listAccept(m_definedEnums, _visitor); listAccept(m_stateVariables, _visitor); listAccept(m_events, _visitor); listAccept(m_functionModifiers, _visitor); diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index 7dc42bc62..859d0097c 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/libsolidity/NameAndTypeResolver.cpp @@ -58,6 +58,8 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) for (ASTPointer const& structDef: _contract.getDefinedStructs()) ReferencesResolver resolver(*structDef, *this, &_contract, nullptr); + for (ASTPointer const& enumDef: _contract.getDefinedEnums()) + ReferencesResolver resolver(*enumDef, *this, &_contract, nullptr); for (ASTPointer const& variable: _contract.getStateVariables()) ReferencesResolver resolver(*variable, *this, &_contract, nullptr); for (ASTPointer const& event: _contract.getEvents()) @@ -79,6 +81,8 @@ void NameAndTypeResolver::checkTypeRequirements(ContractDefinition& _contract) { for (ASTPointer const& structDef: _contract.getDefinedStructs()) structDef->checkValidityOfMembers(); + for (ASTPointer const& enumDef: _contract.getDefinedEnums()) + enumDef->checkValidityOfMembers(); _contract.checkTypeRequirements(); } @@ -221,6 +225,17 @@ void DeclarationRegistrationHelper::endVisit(StructDefinition&) closeCurrentScope(); } +bool DeclarationRegistrationHelper::visit(EnumDefinition& _enum) +{ + registerDeclaration(_enum, true); + return true; +} + +void DeclarationRegistrationHelper::endVisit(EnumDefinition&) +{ + closeCurrentScope(); +} + bool DeclarationRegistrationHelper::visit(FunctionDefinition& _function) { registerDeclaration(_function, true); diff --git a/libsolidity/NameAndTypeResolver.h b/libsolidity/NameAndTypeResolver.h index 4b7ce6e7d..4b1b8c0cd 100644 --- a/libsolidity/NameAndTypeResolver.h +++ b/libsolidity/NameAndTypeResolver.h @@ -98,6 +98,8 @@ private: void endVisit(ContractDefinition& _contract) override; bool visit(StructDefinition& _struct) override; void endVisit(StructDefinition& _struct) override; + bool visit(EnumDefinition& _enum) override; + void endVisit(EnumDefinition& _enum) override; bool visit(FunctionDefinition& _function) override; void endVisit(FunctionDefinition& _function) override; bool visit(ModifierDefinition& _modifier) override; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 6b6a70c29..418d6b17e 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -74,6 +74,8 @@ TypePointer Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) Declaration const* declaration = _typeName.getReferencedDeclaration(); if (StructDefinition const* structDef = dynamic_cast(declaration)) return make_shared(*structDef); + else if (EnumDefinition const* enumDef = dynamic_cast(declaration)) + return make_shared(*enumDef); else if (FunctionDefinition const* function = dynamic_cast(declaration)) return make_shared(*function); else if (ContractDefinition const* contract = dynamic_cast(declaration)) diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 259123db6..7fa7dd251 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2499,6 +2499,26 @@ BOOST_AUTO_TEST_CASE(struct_copy_via_local) BOOST_CHECK(callContractFunction("test()") == encodeArgs(true)); } +BOOST_AUTO_TEST_CASE(using_enums) +{ + char const* sourceCode = R"( + contract test { + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + function test() + { + choices = ActionChoices.GoStraight; + } + function getChoice() returns (uint d) + { + d = choices; + } + ActionChoices choices; + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("getChoice()") == encodeArgs(2)); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 3ead6f1c5..490ab3be5 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -991,6 +991,21 @@ BOOST_AUTO_TEST_CASE(exp_operator_exponent_too_big) })"; BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(enum_member_access) +{ + char const* text = R"( + contract test { + struct foo { uint256 x;} + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + function test() + { + choices = ActionChoices.GoStraight; + } + ActionChoices choices; + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); +} BOOST_AUTO_TEST_SUITE_END() From 5659ed1238d15b024294039414221ee683f92191 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 12 Feb 2015 15:19:04 +0100 Subject: [PATCH 08/20] Correcting and testing enum member access --- libsolidity/Types.cpp | 20 +++++++------------- libsolidity/Types.h | 3 ++- test/SolidityNameAndTypeResolution.cpp | 17 ++++++++++++++++- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 418d6b17e..f25431605 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -682,19 +682,6 @@ string EnumType::toString() const return string("enum ") + m_enum.getName(); } -MemberList const& EnumType::getMembers() const -{ - // We need to lazy-initialize it because of recursive references. - if (!m_members) - { - map> members; - for (ASTPointer const& enumValue: m_enum.getMembers()) - members.insert(make_pair(enumValue->getName(), make_shared(m_enum))); - m_members.reset(new MemberList(members)); - } - return *m_members; -} - FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal): m_location(_isInternal ? Location::Internal : Location::External), m_isConstant(_function.isDeclaredConst()), @@ -957,6 +944,13 @@ MemberList const& TypeType::getMembers() const if (!f->isConstructor() && !f->getName().empty()) members[f->getName()] = make_shared(*f); } + else if (m_actualType->getCategory() == Category::Enum) + { + EnumDefinition const& enumDef = dynamic_cast(*m_actualType).getEnumDefinition(); + for (ASTPointer const& enumValue: enumDef.getMembers()) + members.insert(make_pair(enumValue->getName(), make_shared(enumDef))); + m_members.reset(new MemberList(members)); + } m_members.reset(new MemberList(members)); } return *m_members; diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 70703938d..0b576bd3f 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -379,8 +379,9 @@ public: virtual bool operator==(Type const& _other) const override; virtual unsigned getSizeOnStack() const override { return 1; /*@todo*/ } virtual std::string toString() const override; + virtual bool isValueType() const override { return true; } - virtual MemberList const& getMembers() const override; + EnumDefinition const& getEnumDefinition() const { return m_enum; } private: EnumDefinition const& m_enum; diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 490ab3be5..34f51a4ce 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -991,11 +991,11 @@ BOOST_AUTO_TEST_CASE(exp_operator_exponent_too_big) })"; BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } + BOOST_AUTO_TEST_CASE(enum_member_access) { char const* text = R"( contract test { - struct foo { uint256 x;} enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; function test() { @@ -1007,6 +1007,21 @@ BOOST_AUTO_TEST_CASE(enum_member_access) BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); } +BOOST_AUTO_TEST_CASE(enum_invalid_member_access) +{ + char const* text = R"( + contract test { + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + function test() + { + choices = ActionChoices.RunAroundWavingYourHands; + } + ActionChoices choices; + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From 07886f42bbccb2d217c29ecc335dc58e1d4a50eb Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 12 Feb 2015 17:59:52 +0100 Subject: [PATCH 09/20] Enum type conversion and member value access. - Added tests for the type conversion part. - Enum member value access still needs some work --- libsolidity/AST.cpp | 13 ++++++++++ libsolidity/AST.h | 3 +++ libsolidity/ExpressionCompiler.cpp | 12 ++++++++- libsolidity/Types.cpp | 5 ++++ libsolidity/Types.h | 2 ++ test/SolidityEndToEndTest.cpp | 2 +- test/SolidityNameAndTypeResolution.cpp | 34 ++++++++++++++++++++++++++ 7 files changed, 69 insertions(+), 2 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 488bd4cd1..7653952f4 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -277,6 +277,19 @@ TypePointer EnumDefinition::getType(ContractDefinition const*) const return make_shared(make_shared(*this)); } + +unsigned int EnumDefinition::getMemberValue(ASTString const& _member) const +{ + unsigned int index = 0; + for (ASTPointer const& decl: m_members) + { + if (decl->getName() == _member) + return index; + ++index; + } + BOOST_THROW_EXCEPTION(createTypeError("Requested unknown enum value ." + _member)); +} + TypePointer FunctionDefinition::getType(ContractDefinition const*) const { return make_shared(*this); diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 65c35026c..fdbbcd5b4 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -348,6 +348,9 @@ public: virtual TypePointer getType(ContractDefinition const*) const override; + /// @returns the value that the string has in the Enum + unsigned int getMemberValue(ASTString const& _member) const; + /// Checks that the members do not include any duplicate names void checkValidityOfMembers() const; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 90f860a1e..dd41b485a 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -489,6 +489,12 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess); break; } + case Type::Category::Enum: + { + EnumType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); + EnumDefinition const& enumDef = type.getEnumDefinition(); + m_context << enumDef.getMemberValue(_memberAccess.getMemberName()); + } case Type::Category::TypeType: { TypeType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); @@ -562,6 +568,10 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) { // no-op } + else if (dynamic_cast(declaration)) + { + // no-op + } else { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not expected in expression context.")); @@ -746,7 +756,7 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con } } else if (stackTypeCategory == Type::Category::Integer || stackTypeCategory == Type::Category::Contract || - stackTypeCategory == Type::Category::IntegerConstant) + stackTypeCategory == Type::Category::IntegerConstant || stackTypeCategory == Type::Category::Enum) { if (targetTypeCategory == Type::Category::String && stackTypeCategory == Type::Category::Integer) { diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index f25431605..df0b0f207 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -682,6 +682,11 @@ string EnumType::toString() const return string("enum ") + m_enum.getName(); } +bool EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const +{ + return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::Integer; +} + FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal): m_location(_isInternal ? Location::Internal : Location::External), m_isConstant(_function.isDeclaredConst()), diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 0b576bd3f..15bd86b1b 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -381,6 +381,8 @@ public: virtual std::string toString() const override; virtual bool isValueType() const override { return true; } + virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; + EnumDefinition const& getEnumDefinition() const { return m_enum; } private: diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 7fa7dd251..551607df2 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2510,7 +2510,7 @@ BOOST_AUTO_TEST_CASE(using_enums) } function getChoice() returns (uint d) { - d = choices; + d = uint256(choices); } ActionChoices choices; } diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 34f51a4ce..9399280b0 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -1022,6 +1022,40 @@ BOOST_AUTO_TEST_CASE(enum_invalid_member_access) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } +BOOST_AUTO_TEST_CASE(enum_explicit_conversion_is_okay) +{ + char const* text = R"( + contract test { + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + function test() + { + a = uint256(ActionChoices.GoStraight); + b = uint64(ActionChoices.Sit); + } + uint256 a; + uint64 b; + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); +} + +BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay) +{ + char const* text = R"( + contract test { + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + function test() + { + a = ActionChoices.GoStraight; + b = ActionChoices.Sit; + } + uint256 a; + uint64 b; + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From 5c164fb42c67aa541d00675245b8bedda49b8e1e Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 13 Feb 2015 13:32:18 +0100 Subject: [PATCH 10/20] Enum Value member access should now work properly - Also detection of duplicate enum values and tests for them have been added --- libsolidity/AST.cpp | 14 +++++++------ libsolidity/ExpressionCompiler.cpp | 27 ++++++++++++++++++-------- test/SolidityNameAndTypeResolution.cpp | 17 ++++++++++++++++ 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 7653952f4..65dc57e5e 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -263,13 +263,15 @@ void StructDefinition::checkRecursion() const void EnumDefinition::checkValidityOfMembers() const { -#if 0 // LTODO: Make this work for the Declarations - vector> members = getMembers(); - sort(begin(members), end(members)); - for (size_t i = 0; i < members.size(); ++i) - if (members[i] == members[i + 1]) + vector> members(getMembers()); + auto compareDecls = [](ASTPointer a, ASTPointer b) + { + return a->getName() < b->getName(); + }; + sort(begin(members), end(members), compareDecls); + for (size_t i = 0; i < members.size() - 1; ++i) + if (members[i]->getName() == members[i + 1]->getName()) BOOST_THROW_EXCEPTION(createTypeError("Duplicate member detected in Enum")); -#endif } TypePointer EnumDefinition::getType(ContractDefinition const*) const diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index dd41b485a..4e72aca54 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -494,20 +494,31 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) EnumType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); EnumDefinition const& enumDef = type.getEnumDefinition(); m_context << enumDef.getMemberValue(_memberAccess.getMemberName()); + break; } case Type::Category::TypeType: { TypeType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); + ContractType const* contractType; + EnumType const* enumType; if (type.getMembers().getMemberType(member)) { - ContractDefinition const& contract = dynamic_cast(*type.getActualType()) - .getContractDefinition(); - for (ASTPointer const& function: contract.getDefinedFunctions()) - if (function->getName() == member) - { - m_context << m_context.getFunctionEntryLabel(*function).pushTag(); - return; - } + if ((contractType = dynamic_cast(type.getActualType().get()))) + { + ContractDefinition const& contract = contractType->getContractDefinition(); + for (ASTPointer const& function: contract.getDefinedFunctions()) + if (function->getName() == member) + { + m_context << m_context.getFunctionEntryLabel(*function).pushTag(); + return; + } + } + else if ((enumType = dynamic_cast(type.getActualType().get()))) + { + EnumDefinition const &enumDef = enumType->getEnumDefinition(); + m_context << enumDef.getMemberValue(_memberAccess.getMemberName()); + return; + } } BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to " + type.toString())); } diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 9399280b0..e7482d661 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -1056,6 +1056,23 @@ BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } +BOOST_AUTO_TEST_CASE(enum_duplicate_values) +{ + char const* text = R"( + contract test { + enum ActionChoices { GoLeft, GoRight, GoLeft, Sit }; + function test() + { + a = 1; + b = 2; + } + uint256 a; + uint64 b; + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From fc6210e00f780647b678fbdeda424440e0c91869 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 13 Feb 2015 15:59:30 +0100 Subject: [PATCH 11/20] Indentation fixes --- libsolidity/Parser.cpp | 2 +- libsolidity/Token.h | 66 +++++++++++++------------- libsolidity/Types.cpp | 2 +- test/SolidityNameAndTypeResolution.cpp | 4 +- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index e59e698f1..59c360a41 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -289,7 +289,7 @@ ASTPointer Parser::parseEnumDefinition() break; expectToken(Token::Comma); if (m_scanner->getCurrentToken() != Token::Identifier) { - BOOST_THROW_EXCEPTION(createParserError("Expected Identifier after ,")); + BOOST_THROW_EXCEPTION(createParserError("Expected Identifier after ','")); } } diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 5039d5b5f..3e599a6ee 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -72,26 +72,26 @@ namespace solidity T(EOS, "EOS", 0) \ \ /* Punctuators (ECMA-262, section 7.7, page 15). */ \ - T(LParen, "(", 0) \ - T(RParen, ")", 0) \ - T(LBrack, "[", 0) \ - T(RBrack, "]", 0) \ - T(LBrace, "{", 0) \ - T(RBrace, "}", 0) \ - T(Colon, ":", 0) \ - T(Semicolon, ";", 0) \ - T(Period, ".", 0) \ - T(Conditional, "?", 3) \ - T(Arrow, "=>", 0) \ - \ + T(LParen, "(", 0) \ + T(RParen, ")", 0) \ + T(LBrack, "[", 0) \ + T(RBrack, "]", 0) \ + T(LBrace, "{", 0) \ + T(RBrace, "}", 0) \ + T(Colon, ":", 0) \ + T(Semicolon, ";", 0) \ + T(Period, ".", 0) \ + T(Conditional, "?", 3) \ + T(Arrow, "=>", 0) \ + \ /* Assignment operators. */ \ /* IsAssignmentOp() relies on this block of enum values being */ \ /* contiguous and sorted in the same order!*/ \ - T(Assign, "=", 2) \ + T(Assign, "=", 2) \ /* The following have to be in exactly the same order as the simple binary operators*/ \ - T(AssignBitOr, "|=", 2) \ - T(AssignBitXor, "^=", 2) \ - T(AssignBitAnd, "&=", 2) \ + T(AssignBitOr, "|=", 2) \ + T(AssignBitXor, "^=", 2) \ + T(AssignBitAnd, "&=", 2) \ T(AssignShl, "<<=", 2) \ T(AssignSar, ">>=", 2) \ T(AssignShr, ">>>=", 2) \ @@ -107,9 +107,9 @@ namespace solidity T(Comma, ",", 1) \ T(Or, "||", 4) \ T(And, "&&", 5) \ - T(BitOr, "|", 8) \ - T(BitXor, "^", 9) \ - T(BitAnd, "&", 10) \ + T(BitOr, "|", 8) \ + T(BitXor, "^", 9) \ + T(BitAnd, "&", 10) \ T(SHL, "<<", 11) \ T(SAR, ">>", 11) \ T(SHR, ">>>", 11) \ @@ -123,19 +123,19 @@ namespace solidity /* Compare operators sorted by precedence. */ \ /* IsCompareOp() relies on this block of enum values */ \ /* being contiguous and sorted in the same order! */ \ - T(Equal, "==", 6) \ - T(NotEqual, "!=", 6) \ - T(LessThan, "<", 7) \ - T(GreaterThan, ">", 7) \ - T(LessThanOrEqual, "<=", 7) \ - T(GreaterThanOrEqual, ">=", 7) \ + T(Equal, "==", 6) \ + T(NotEqual, "!=", 6) \ + T(LessThan, "<", 7) \ + T(GreaterThan, ">", 7) \ + T(LessThanOrEqual, "<=", 7) \ + T(GreaterThanOrEqual, ">=", 7) \ K(In, "in", 7) \ \ /* Unary operators. */ \ /* IsUnaryOp() relies on this block of enum values */ \ /* being contiguous and sorted in the same order! */ \ T(Not, "!", 0) \ - T(BitNot, "~", 0) \ + T(BitNot, "~", 0) \ T(Inc, "++", 0) \ T(Dec, "--", 0) \ K(Delete, "delete", 0) \ @@ -168,7 +168,7 @@ namespace solidity K(Switch, "switch", 0) \ K(Var, "var", 0) \ K(While, "while", 0) \ - K(Enum, "enum", 0) \ + K(Enum, "enum", 0) \ \ /* Ether subdenominations */ \ K(SubWei, "wei", 0) \ @@ -316,15 +316,15 @@ namespace solidity K(Text, "text", 0) \ K(Real, "real", 0) \ K(UReal, "ureal", 0) \ - T(TypesEnd, NULL, 0) /* used as type enum end marker */ \ + T(TypesEnd, NULL, 0) /* used as type enum end marker */ \ \ /* Literals */ \ - K(NullLiteral, "null", 0) \ - K(TrueLiteral, "true", 0) \ - K(FalseLiteral, "false", 0) \ + K(NullLiteral, "null", 0) \ + K(TrueLiteral, "true", 0) \ + K(FalseLiteral, "false", 0) \ T(Number, NULL, 0) \ - T(StringLiteral, NULL, 0) \ - T(CommentLiteral, NULL, 0) \ + T(StringLiteral, NULL, 0) \ + T(CommentLiteral, NULL, 0) \ \ /* Identifiers (not keywords or future reserved words). */ \ T(Identifier, NULL, 0) \ diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index df0b0f207..709002bac 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -953,7 +953,7 @@ MemberList const& TypeType::getMembers() const { EnumDefinition const& enumDef = dynamic_cast(*m_actualType).getEnumDefinition(); for (ASTPointer const& enumValue: enumDef.getMembers()) - members.insert(make_pair(enumValue->getName(), make_shared(enumDef))); + members.insert(make_pair(enumValue->getName(), make_shared(enumDef))); m_members.reset(new MemberList(members)); } m_members.reset(new MemberList(members)); diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index e7482d661..051b3dce7 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -1063,8 +1063,8 @@ BOOST_AUTO_TEST_CASE(enum_duplicate_values) enum ActionChoices { GoLeft, GoRight, GoLeft, Sit }; function test() { - a = 1; - b = 2; + a = 1; + b = 2; } uint256 a; uint64 b; From b4302da54292b9ea18c46de887d07bde3113777e Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 13 Feb 2015 17:22:53 +0100 Subject: [PATCH 12/20] EnumDeclaration -> EnumValue --- libsolidity/AST.cpp | 8 ++++---- libsolidity/AST.h | 10 +++++----- libsolidity/ASTForward.h | 2 +- libsolidity/ASTPrinter.cpp | 4 ++-- libsolidity/ASTPrinter.h | 4 ++-- libsolidity/ASTVisitor.h | 8 ++++---- libsolidity/AST_accept.h | 4 ++-- libsolidity/Parser.cpp | 6 +++--- libsolidity/Parser.h | 2 +- libsolidity/Types.cpp | 2 +- 10 files changed, 25 insertions(+), 25 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 65dc57e5e..cdc1f6cb5 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -206,7 +206,7 @@ vector, FunctionTypePointer>> const& ContractDefinition::getIn return *m_interfaceFunctionList; } -TypePointer EnumDeclaration::getType(ContractDefinition const*) const +TypePointer EnumvValue::getType(ContractDefinition const*) const { // LTODO: How to get the parent EnumDefinition and return its type here? return nullptr; @@ -263,8 +263,8 @@ void StructDefinition::checkRecursion() const void EnumDefinition::checkValidityOfMembers() const { - vector> members(getMembers()); - auto compareDecls = [](ASTPointer a, ASTPointer b) + vector> members(getMembers()); + auto compareDecls = [](ASTPointer a, ASTPointer b) { return a->getName() < b->getName(); }; @@ -283,7 +283,7 @@ TypePointer EnumDefinition::getType(ContractDefinition const*) const unsigned int EnumDefinition::getMemberValue(ASTString const& _member) const { unsigned int index = 0; - for (ASTPointer const& decl: m_members) + for (ASTPointer const& decl: m_members) { if (decl->getName() == _member) return index; diff --git a/libsolidity/AST.h b/libsolidity/AST.h index fdbbcd5b4..11dfef590 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -168,10 +168,10 @@ private: /** * Declaration of an Enum Value */ -class EnumDeclaration : public Declaration +class EnumvValue : public Declaration { public: - EnumDeclaration(Location const& _location, + EnumvValue(Location const& _location, ASTPointer const& _name): Declaration(_location, _name) {} @@ -339,12 +339,12 @@ class EnumDefinition: public Declaration public: EnumDefinition(Location const& _location, ASTPointer const& _name, - std::vector> const& _members): + std::vector> const& _members): Declaration(_location, _name), m_members(_members) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - std::vector> const& getMembers() const { return m_members; } + std::vector> const& getMembers() const { return m_members; } virtual TypePointer getType(ContractDefinition const*) const override; @@ -356,7 +356,7 @@ public: private: - std::vector> m_members; + std::vector> m_members; }; /** diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h index a0a6f6832..3370e88a8 100644 --- a/libsolidity/ASTForward.h +++ b/libsolidity/ASTForward.h @@ -41,7 +41,7 @@ class ContractDefinition; class InheritanceSpecifier; class StructDefinition; class EnumDefinition; -class EnumDeclaration; +class EnumvValue; class ParameterList; class FunctionDefinition; class VariableDeclaration; diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index b655d309d..dd66bf0d7 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -77,7 +77,7 @@ bool ASTPrinter::visit(EnumDefinition const& _node) return goDeeper(); } -bool ASTPrinter::visit(EnumDeclaration const& _node) +bool ASTPrinter::visit(EnumvValue const& _node) { writeLine("EnumValue \"" + _node.getName() + "\""); return goDeeper(); @@ -364,7 +364,7 @@ void ASTPrinter::endVisit(EnumDefinition const&) m_indentation--; } -void ASTPrinter::endVisit(EnumDeclaration const&) +void ASTPrinter::endVisit(EnumvValue const&) { m_indentation--; } diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index a306e90b5..dda2f1c4a 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -47,7 +47,7 @@ public: bool visit(InheritanceSpecifier const& _node) override; bool visit(StructDefinition const& _node) override; bool visit(EnumDefinition const& _node) override; - bool visit(EnumDeclaration const& _node) override; + bool visit(EnumvValue const& _node) override; bool visit(ParameterList const& _node) override; bool visit(FunctionDefinition const& _node) override; bool visit(VariableDeclaration const& _node) override; @@ -88,7 +88,7 @@ public: void endVisit(InheritanceSpecifier const&) override; void endVisit(StructDefinition const&) override; void endVisit(EnumDefinition const&) override; - void endVisit(EnumDeclaration const&) override; + void endVisit(EnumvValue const&) override; void endVisit(ParameterList const&) override; void endVisit(FunctionDefinition const&) override; void endVisit(VariableDeclaration const&) override; diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index 108827573..392da7616 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -48,7 +48,7 @@ public: virtual bool visit(InheritanceSpecifier&) { return true; } virtual bool visit(StructDefinition&) { return true; } virtual bool visit(EnumDefinition&) { return true; } - virtual bool visit(EnumDeclaration&) { return true; } + virtual bool visit(EnumvValue&) { return true; } virtual bool visit(ParameterList&) { return true; } virtual bool visit(FunctionDefinition&) { return true; } virtual bool visit(VariableDeclaration&) { return true; } @@ -91,7 +91,7 @@ public: virtual void endVisit(InheritanceSpecifier&) { } virtual void endVisit(StructDefinition&) { } virtual void endVisit(EnumDefinition&) { } - virtual void endVisit(EnumDeclaration&) { } + virtual void endVisit(EnumvValue&) { } virtual void endVisit(ParameterList&) { } virtual void endVisit(FunctionDefinition&) { } virtual void endVisit(VariableDeclaration&) { } @@ -138,7 +138,7 @@ public: virtual bool visit(InheritanceSpecifier const&) { return true; } virtual bool visit(StructDefinition const&) { return true; } virtual bool visit(EnumDefinition const&) { return true; } - virtual bool visit(EnumDeclaration const&) { return true; } + virtual bool visit(EnumvValue const&) { return true; } virtual bool visit(ParameterList const&) { return true; } virtual bool visit(FunctionDefinition const&) { return true; } virtual bool visit(VariableDeclaration const&) { return true; } @@ -181,7 +181,7 @@ public: virtual void endVisit(InheritanceSpecifier const&) { } virtual void endVisit(StructDefinition const&) { } virtual void endVisit(EnumDefinition const&) { } - virtual void endVisit(EnumDeclaration const&) { } + virtual void endVisit(EnumvValue const&) { } virtual void endVisit(ParameterList const&) { } virtual void endVisit(FunctionDefinition const&) { } virtual void endVisit(VariableDeclaration const&) { } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index 78c2f8c58..e6877d937 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -121,13 +121,13 @@ void EnumDefinition::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } -void EnumDeclaration::accept(ASTVisitor& _visitor) +void EnumvValue::accept(ASTVisitor& _visitor) { _visitor.visit(*this); _visitor.endVisit(*this); } -void EnumDeclaration::accept(ASTConstVisitor& _visitor) const +void EnumvValue::accept(ASTConstVisitor& _visitor) const { _visitor.visit(*this); _visitor.endVisit(*this); diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 59c360a41..3e077261b 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -266,12 +266,12 @@ ASTPointer Parser::parseStructDefinition() return nodeFactory.createNode(name, members); } -ASTPointer Parser::parseEnumDeclaration() +ASTPointer Parser::parseEnumDeclaration() { ASTNodeFactory nodeFactory(*this); ASTPointer name = expectIdentifierToken(); nodeFactory.markEndPosition(); - return nodeFactory.createNode(name); + return nodeFactory.createNode(name); } ASTPointer Parser::parseEnumDefinition() @@ -279,7 +279,7 @@ ASTPointer Parser::parseEnumDefinition() ASTNodeFactory nodeFactory(*this); expectToken(Token::Enum); ASTPointer name = expectIdentifierToken(); - vector> members; + vector> members; expectToken(Token::LBrace); while (m_scanner->getCurrentToken() != Token::RBrace) diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 734bdd57e..44b14da06 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -62,7 +62,7 @@ private: ASTPointer parseFunctionDefinition(ASTString const* _contractName); ASTPointer parseStructDefinition(); ASTPointer parseEnumDefinition(); - ASTPointer parseEnumDeclaration(); + ASTPointer parseEnumDeclaration(); ASTPointer parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions()); ASTPointer parseModifierDefinition(); ASTPointer parseEventDefinition(); diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 709002bac..df62773a9 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -952,7 +952,7 @@ MemberList const& TypeType::getMembers() const else if (m_actualType->getCategory() == Category::Enum) { EnumDefinition const& enumDef = dynamic_cast(*m_actualType).getEnumDefinition(); - for (ASTPointer const& enumValue: enumDef.getMembers()) + for (ASTPointer const& enumValue: enumDef.getMembers()) members.insert(make_pair(enumValue->getName(), make_shared(enumDef))); m_members.reset(new MemberList(members)); } From 81ecc03e9df66603cb71d5b38b3b05ac874ff5e8 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 13 Feb 2015 17:32:34 +0100 Subject: [PATCH 13/20] implement getType() for EnumValue --- libsolidity/AST.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index cdc1f6cb5..2baf9dae8 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -208,8 +208,8 @@ vector, FunctionTypePointer>> const& ContractDefinition::getIn TypePointer EnumvValue::getType(ContractDefinition const*) const { - // LTODO: How to get the parent EnumDefinition and return its type here? - return nullptr; + EnumDefinition const* parentDef = dynamic_cast(getScope()); + return make_shared(*parentDef); } void InheritanceSpecifier::checkTypeRequirements() From e5ccf5e2bed4d55508c90b405c59964c442b0191 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 13 Feb 2015 17:34:46 +0100 Subject: [PATCH 14/20] Typo in EnumValue --- libsolidity/AST.cpp | 8 ++++---- libsolidity/AST.h | 14 +++++++------- libsolidity/ASTForward.h | 2 +- libsolidity/ASTPrinter.cpp | 4 ++-- libsolidity/ASTPrinter.h | 4 ++-- libsolidity/ASTVisitor.h | 8 ++++---- libsolidity/AST_accept.h | 4 ++-- libsolidity/Parser.cpp | 6 +++--- libsolidity/Parser.h | 2 +- libsolidity/Types.cpp | 2 +- 10 files changed, 27 insertions(+), 27 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 2baf9dae8..9d7d2169b 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -206,7 +206,7 @@ vector, FunctionTypePointer>> const& ContractDefinition::getIn return *m_interfaceFunctionList; } -TypePointer EnumvValue::getType(ContractDefinition const*) const +TypePointer EnumValue::getType(ContractDefinition const*) const { EnumDefinition const* parentDef = dynamic_cast(getScope()); return make_shared(*parentDef); @@ -263,8 +263,8 @@ void StructDefinition::checkRecursion() const void EnumDefinition::checkValidityOfMembers() const { - vector> members(getMembers()); - auto compareDecls = [](ASTPointer a, ASTPointer b) + vector> members(getMembers()); + auto compareDecls = [](ASTPointer a, ASTPointer b) { return a->getName() < b->getName(); }; @@ -283,7 +283,7 @@ TypePointer EnumDefinition::getType(ContractDefinition const*) const unsigned int EnumDefinition::getMemberValue(ASTString const& _member) const { unsigned int index = 0; - for (ASTPointer const& decl: m_members) + for (ASTPointer const& decl: m_members) { if (decl->getName() == _member) return index; diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 11dfef590..3485631ba 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -168,12 +168,12 @@ private: /** * Declaration of an Enum Value */ -class EnumvValue : public Declaration +class EnumValue: public Declaration { public: - EnumvValue(Location const& _location, - ASTPointer const& _name): - Declaration(_location, _name) {} + EnumValue(Location const& _location, + ASTPointer const& _name): + Declaration(_location, _name) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -339,12 +339,12 @@ class EnumDefinition: public Declaration public: EnumDefinition(Location const& _location, ASTPointer const& _name, - std::vector> const& _members): + std::vector> const& _members): Declaration(_location, _name), m_members(_members) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; - std::vector> const& getMembers() const { return m_members; } + std::vector> const& getMembers() const { return m_members; } virtual TypePointer getType(ContractDefinition const*) const override; @@ -356,7 +356,7 @@ public: private: - std::vector> m_members; + std::vector> m_members; }; /** diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h index 3370e88a8..0b6817e45 100644 --- a/libsolidity/ASTForward.h +++ b/libsolidity/ASTForward.h @@ -41,7 +41,7 @@ class ContractDefinition; class InheritanceSpecifier; class StructDefinition; class EnumDefinition; -class EnumvValue; +class EnumValue; class ParameterList; class FunctionDefinition; class VariableDeclaration; diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp index dd66bf0d7..d380b0029 100644 --- a/libsolidity/ASTPrinter.cpp +++ b/libsolidity/ASTPrinter.cpp @@ -77,7 +77,7 @@ bool ASTPrinter::visit(EnumDefinition const& _node) return goDeeper(); } -bool ASTPrinter::visit(EnumvValue const& _node) +bool ASTPrinter::visit(EnumValue const& _node) { writeLine("EnumValue \"" + _node.getName() + "\""); return goDeeper(); @@ -364,7 +364,7 @@ void ASTPrinter::endVisit(EnumDefinition const&) m_indentation--; } -void ASTPrinter::endVisit(EnumvValue const&) +void ASTPrinter::endVisit(EnumValue const&) { m_indentation--; } diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h index dda2f1c4a..d9072aacc 100644 --- a/libsolidity/ASTPrinter.h +++ b/libsolidity/ASTPrinter.h @@ -47,7 +47,7 @@ public: bool visit(InheritanceSpecifier const& _node) override; bool visit(StructDefinition const& _node) override; bool visit(EnumDefinition const& _node) override; - bool visit(EnumvValue const& _node) override; + bool visit(EnumValue const& _node) override; bool visit(ParameterList const& _node) override; bool visit(FunctionDefinition const& _node) override; bool visit(VariableDeclaration const& _node) override; @@ -88,7 +88,7 @@ public: void endVisit(InheritanceSpecifier const&) override; void endVisit(StructDefinition const&) override; void endVisit(EnumDefinition const&) override; - void endVisit(EnumvValue const&) override; + void endVisit(EnumValue const&) override; void endVisit(ParameterList const&) override; void endVisit(FunctionDefinition const&) override; void endVisit(VariableDeclaration const&) override; diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h index 392da7616..a7fa6b1cf 100644 --- a/libsolidity/ASTVisitor.h +++ b/libsolidity/ASTVisitor.h @@ -48,7 +48,7 @@ public: virtual bool visit(InheritanceSpecifier&) { return true; } virtual bool visit(StructDefinition&) { return true; } virtual bool visit(EnumDefinition&) { return true; } - virtual bool visit(EnumvValue&) { return true; } + virtual bool visit(EnumValue&) { return true; } virtual bool visit(ParameterList&) { return true; } virtual bool visit(FunctionDefinition&) { return true; } virtual bool visit(VariableDeclaration&) { return true; } @@ -91,7 +91,7 @@ public: virtual void endVisit(InheritanceSpecifier&) { } virtual void endVisit(StructDefinition&) { } virtual void endVisit(EnumDefinition&) { } - virtual void endVisit(EnumvValue&) { } + virtual void endVisit(EnumValue&) { } virtual void endVisit(ParameterList&) { } virtual void endVisit(FunctionDefinition&) { } virtual void endVisit(VariableDeclaration&) { } @@ -138,7 +138,7 @@ public: virtual bool visit(InheritanceSpecifier const&) { return true; } virtual bool visit(StructDefinition const&) { return true; } virtual bool visit(EnumDefinition const&) { return true; } - virtual bool visit(EnumvValue const&) { return true; } + virtual bool visit(EnumValue const&) { return true; } virtual bool visit(ParameterList const&) { return true; } virtual bool visit(FunctionDefinition const&) { return true; } virtual bool visit(VariableDeclaration const&) { return true; } @@ -181,7 +181,7 @@ public: virtual void endVisit(InheritanceSpecifier const&) { } virtual void endVisit(StructDefinition const&) { } virtual void endVisit(EnumDefinition const&) { } - virtual void endVisit(EnumvValue const&) { } + virtual void endVisit(EnumValue const&) { } virtual void endVisit(ParameterList const&) { } virtual void endVisit(FunctionDefinition const&) { } virtual void endVisit(VariableDeclaration const&) { } diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h index e6877d937..b71e103df 100644 --- a/libsolidity/AST_accept.h +++ b/libsolidity/AST_accept.h @@ -121,13 +121,13 @@ void EnumDefinition::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } -void EnumvValue::accept(ASTVisitor& _visitor) +void EnumValue::accept(ASTVisitor& _visitor) { _visitor.visit(*this); _visitor.endVisit(*this); } -void EnumvValue::accept(ASTConstVisitor& _visitor) const +void EnumValue::accept(ASTConstVisitor& _visitor) const { _visitor.visit(*this); _visitor.endVisit(*this); diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 3e077261b..28339a464 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -266,12 +266,12 @@ ASTPointer Parser::parseStructDefinition() return nodeFactory.createNode(name, members); } -ASTPointer Parser::parseEnumDeclaration() +ASTPointer Parser::parseEnumDeclaration() { ASTNodeFactory nodeFactory(*this); ASTPointer name = expectIdentifierToken(); nodeFactory.markEndPosition(); - return nodeFactory.createNode(name); + return nodeFactory.createNode(name); } ASTPointer Parser::parseEnumDefinition() @@ -279,7 +279,7 @@ ASTPointer Parser::parseEnumDefinition() ASTNodeFactory nodeFactory(*this); expectToken(Token::Enum); ASTPointer name = expectIdentifierToken(); - vector> members; + vector> members; expectToken(Token::LBrace); while (m_scanner->getCurrentToken() != Token::RBrace) diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 44b14da06..172b45dd5 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -62,7 +62,7 @@ private: ASTPointer parseFunctionDefinition(ASTString const* _contractName); ASTPointer parseStructDefinition(); ASTPointer parseEnumDefinition(); - ASTPointer parseEnumDeclaration(); + ASTPointer parseEnumDeclaration(); ASTPointer parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions()); ASTPointer parseModifierDefinition(); ASTPointer parseEventDefinition(); diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index df62773a9..06c0af320 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -952,7 +952,7 @@ MemberList const& TypeType::getMembers() const else if (m_actualType->getCategory() == Category::Enum) { EnumDefinition const& enumDef = dynamic_cast(*m_actualType).getEnumDefinition(); - for (ASTPointer const& enumValue: enumDef.getMembers()) + for (ASTPointer const& enumValue: enumDef.getMembers()) members.insert(make_pair(enumValue->getName(), make_shared(enumDef))); m_members.reset(new MemberList(members)); } From c3c1b5c63c9834115f3529637c80d109ea3b5992 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 13 Feb 2015 22:52:04 +0100 Subject: [PATCH 15/20] Addressing issues with Enums in Solidity --- libsolidity/AST.cpp | 3 ++- libsolidity/AST.h | 30 ++++++++++----------- libsolidity/ExpressionCompiler.cpp | 36 +++++++++++++------------- libsolidity/Parser.cpp | 17 +++--------- libsolidity/Parser.h | 3 +-- libsolidity/Types.h | 2 +- test/SolidityNameAndTypeResolution.cpp | 7 ----- test/SolidityParser.cpp | 16 +++--------- 8 files changed, 44 insertions(+), 70 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 9d7d2169b..5aa672184 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -209,6 +209,7 @@ vector, FunctionTypePointer>> const& ContractDefinition::getIn TypePointer EnumValue::getType(ContractDefinition const*) const { EnumDefinition const* parentDef = dynamic_cast(getScope()); + solAssert(parentDef, "Enclosing Scope of EnumValue was not set"); return make_shared(*parentDef); } @@ -271,7 +272,7 @@ void EnumDefinition::checkValidityOfMembers() const sort(begin(members), end(members), compareDecls); for (size_t i = 0; i < members.size() - 1; ++i) if (members[i]->getName() == members[i + 1]->getName()) - BOOST_THROW_EXCEPTION(createTypeError("Duplicate member detected in Enum")); + BOOST_THROW_EXCEPTION(members[i]->createTypeError("Duplicate member detected in Enum")); } TypePointer EnumDefinition::getType(ContractDefinition const*) const diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 3485631ba..25c18f4f7 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -165,21 +165,6 @@ private: Declaration const* m_scope; }; -/** - * Declaration of an Enum Value - */ -class EnumValue: public Declaration -{ - public: - EnumValue(Location const& _location, - ASTPointer const& _name): - Declaration(_location, _name) {} - - virtual void accept(ASTVisitor& _visitor) override; - virtual void accept(ASTConstVisitor& _visitor) const override; - TypePointer getType(ContractDefinition const* = nullptr) const; -}; - /** * Abstract class that is added to each AST node that can store local variables. */ @@ -359,6 +344,21 @@ private: std::vector> m_members; }; +/** + * Declaration of an Enum Value + */ +class EnumValue: public Declaration +{ + public: + EnumValue(Location const& _location, + ASTPointer const& _name): + Declaration(_location, _name) {} + + virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; + TypePointer getType(ContractDefinition const* = nullptr) const; +}; + /** * Parameter list, used as function parameter list and return list. * None of the parameters is allowed to contain mappings (not even recursively diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 4e72aca54..00c2dafd1 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -501,26 +501,26 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) TypeType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); ContractType const* contractType; EnumType const* enumType; - if (type.getMembers().getMemberType(member)) + if (!type.getMembers().getMemberType(member)) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to " + type.toString())); + + if ((contractType = dynamic_cast(type.getActualType().get()))) { - if ((contractType = dynamic_cast(type.getActualType().get()))) - { - ContractDefinition const& contract = contractType->getContractDefinition(); - for (ASTPointer const& function: contract.getDefinedFunctions()) - if (function->getName() == member) - { - m_context << m_context.getFunctionEntryLabel(*function).pushTag(); - return; - } - } - else if ((enumType = dynamic_cast(type.getActualType().get()))) - { - EnumDefinition const &enumDef = enumType->getEnumDefinition(); - m_context << enumDef.getMemberValue(_memberAccess.getMemberName()); - return; - } + ContractDefinition const& contract = contractType->getContractDefinition(); + for (ASTPointer const& function: contract.getDefinedFunctions()) + if (function->getName() == member) + { + m_context << m_context.getFunctionEntryLabel(*function).pushTag(); + return; + } } - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to " + type.toString())); + else if ((enumType = dynamic_cast(type.getActualType().get()))) + { + EnumDefinition const &enumDef = enumType->getEnumDefinition(); + m_context << enumDef.getMemberValue(_memberAccess.getMemberName()); + return; + } + } case Type::Category::ByteArray: { diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 28339a464..4277ef54f 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -266,12 +266,11 @@ ASTPointer Parser::parseStructDefinition() return nodeFactory.createNode(name, members); } -ASTPointer Parser::parseEnumDeclaration() +ASTPointer Parser::parseEnumValue() { ASTNodeFactory nodeFactory(*this); - ASTPointer name = expectIdentifierToken(); nodeFactory.markEndPosition(); - return nodeFactory.createNode(name); + return nodeFactory.createNode(expectIdentifierToken()); } ASTPointer Parser::parseEnumDefinition() @@ -284,13 +283,12 @@ ASTPointer Parser::parseEnumDefinition() while (m_scanner->getCurrentToken() != Token::RBrace) { - members.push_back(parseEnumDeclaration()); + members.push_back(parseEnumValue()); if (m_scanner->getCurrentToken() == Token::RBrace) break; expectToken(Token::Comma); - if (m_scanner->getCurrentToken() != Token::Identifier) { + if (m_scanner->getCurrentToken() != Token::Identifier) BOOST_THROW_EXCEPTION(createParserError("Expected Identifier after ','")); - } } nodeFactory.markEndPosition(); @@ -859,13 +857,6 @@ ASTPointer Parser::expectIdentifierToken() return getLiteralAndAdvance(); } -ASTPointer Parser::peekIdentifierToken() -{ - if (m_scanner->getCurrentToken() != Token::Identifier) - return nullptr; - return getLiteralAndAdvance(); -} - ASTPointer Parser::getLiteralAndAdvance() { ASTPointer identifier = make_shared(m_scanner->getCurrentLiteral()); diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 172b45dd5..1bb4ea977 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -62,7 +62,7 @@ private: ASTPointer parseFunctionDefinition(ASTString const* _contractName); ASTPointer parseStructDefinition(); ASTPointer parseEnumDefinition(); - ASTPointer parseEnumDeclaration(); + ASTPointer parseEnumValue(); ASTPointer parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions()); ASTPointer parseModifierDefinition(); ASTPointer parseEventDefinition(); @@ -98,7 +98,6 @@ private: void expectToken(Token::Value _value); Token::Value expectAssignmentOperator(); ASTPointer expectIdentifierToken(); - ASTPointer peekIdentifierToken(); ASTPointer getLiteralAndAdvance(); ///@} diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 15bd86b1b..d8b1b6b7a 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -377,7 +377,7 @@ public: explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {} virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(Type const& _other) const override; - virtual unsigned getSizeOnStack() const override { return 1; /*@todo*/ } + virtual unsigned getSizeOnStack() const override { return 1; } virtual std::string toString() const override; virtual bool isValueType() const override { return true; } diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 051b3dce7..c912939fc 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -1061,13 +1061,6 @@ BOOST_AUTO_TEST_CASE(enum_duplicate_values) char const* text = R"( contract test { enum ActionChoices { GoLeft, GoRight, GoLeft, Sit }; - function test() - { - a = 1; - b = 2; - } - uint256 a; - uint64 b; } )"; BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index 07ec2dcfa..702d1d6db 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -703,14 +703,14 @@ BOOST_AUTO_TEST_CASE(literal_constants_with_ether_subdenominations_in_expression BOOST_CHECK_NO_THROW(parseTextExplainError(text)); } -BOOST_AUTO_TEST_CASE(enum_declaration) +BOOST_AUTO_TEST_CASE(enum_valid_declaration) { char const* text = R"( contract c { - enum foo { WARNING, NOTICE, ERROR, CRITICAL }; + enum validEnum { Value1, Value2, Value3, Value4 }; function c () { - a = foo.CRITICAL; + a = foo.Value3; } uint256 a; })"; @@ -722,11 +722,6 @@ BOOST_AUTO_TEST_CASE(empty_enum_declaration) char const* text = R"( contract c { enum foo { }; - function c () - { - a = 5; - } - uint256 a; })"; BOOST_CHECK_NO_THROW(parseTextExplainError(text)); } @@ -736,11 +731,6 @@ BOOST_AUTO_TEST_CASE(malformed_enum_declaration) char const* text = R"( contract c { enum foo { WARNING,}; - function c () - { - a = foo.CRITICAL; - } - uint256 a; })"; BOOST_CHECK_THROW(parseText(text), ParserError); } From 4a70ec94443f047a875bfb2ed4e32ccf7bec9533 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 13 Feb 2015 22:56:46 +0100 Subject: [PATCH 16/20] adding Enums to grammar.txt --- libsolidity/grammar.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt index 1785b516c..5ba0ef238 100644 --- a/libsolidity/grammar.txt +++ b/libsolidity/grammar.txt @@ -1,7 +1,7 @@ ContractDefinition = 'contract' Identifier ( 'is' InheritanceSpecifier (',' InheritanceSpecifier )* )? '{' ContractPart* '}' -ContractPart = StateVariableDeclaration | StructDefinition | ModifierDefinition | FunctionDefinition +ContractPart = StateVariableDeclaration | StructDefinition | ModifierDefinition | FunctionDefinition | EnumDefinition InheritanceSpecifier = Identifier ( '(' Expression ( ',' Expression )* ')' )? StructDefinition = 'struct' Identifier '{' @@ -11,6 +11,9 @@ ModifierDefinition = 'modifier' Identifier ParameterList? Block FunctionDefinition = 'function' Identifier ParameterList ( Identifier | 'constant' | 'public' | 'protected' | 'private' )* ( 'returns' ParameterList )? Block + +EnumValue = Identifier +EnumDefinition = 'enum' '{' EnumValue (',' EnumValue)* '}' ';' ParameterList = '(' ( VariableDeclaration (',' VariableDeclaration)* )? ')' // semantic restriction: mappings and structs (recursively) containing mappings // are not allowed in argument lists From 58c598b8cb505e576a482c500a1e9ce6755c21df Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 13 Feb 2015 23:03:32 +0100 Subject: [PATCH 17/20] Moving getMemberValue from EnumDefinition to EnumType --- libsolidity/AST.cpp | 13 ------------- libsolidity/AST.h | 3 --- libsolidity/ExpressionCompiler.cpp | 6 ++---- libsolidity/Types.cpp | 12 ++++++++++++ libsolidity/Types.h | 2 ++ 5 files changed, 16 insertions(+), 20 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 5aa672184..683452027 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -280,19 +280,6 @@ TypePointer EnumDefinition::getType(ContractDefinition const*) const return make_shared(make_shared(*this)); } - -unsigned int EnumDefinition::getMemberValue(ASTString const& _member) const -{ - unsigned int index = 0; - for (ASTPointer const& decl: m_members) - { - if (decl->getName() == _member) - return index; - ++index; - } - BOOST_THROW_EXCEPTION(createTypeError("Requested unknown enum value ." + _member)); -} - TypePointer FunctionDefinition::getType(ContractDefinition const*) const { return make_shared(*this); diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 25c18f4f7..4167537e5 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -333,9 +333,6 @@ public: virtual TypePointer getType(ContractDefinition const*) const override; - /// @returns the value that the string has in the Enum - unsigned int getMemberValue(ASTString const& _member) const; - /// Checks that the members do not include any duplicate names void checkValidityOfMembers() const; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 00c2dafd1..63324fe58 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -492,8 +492,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) case Type::Category::Enum: { EnumType const& type = dynamic_cast(*_memberAccess.getExpression().getType()); - EnumDefinition const& enumDef = type.getEnumDefinition(); - m_context << enumDef.getMemberValue(_memberAccess.getMemberName()); + m_context << type.getMemberValue(_memberAccess.getMemberName()); break; } case Type::Category::TypeType: @@ -516,8 +515,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) } else if ((enumType = dynamic_cast(type.getActualType().get()))) { - EnumDefinition const &enumDef = enumType->getEnumDefinition(); - m_context << enumDef.getMemberValue(_memberAccess.getMemberName()); + m_context << enumType->getMemberValue(_memberAccess.getMemberName()); return; } diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 06c0af320..c4a808f89 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -687,6 +687,18 @@ bool EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::Integer; } +unsigned int EnumType::getMemberValue(ASTString const& _member) const +{ + unsigned int index = 0; + for (ASTPointer const& decl: m_enum.getMembers()) + { + if (decl->getName() == _member) + return index; + ++index; + } + BOOST_THROW_EXCEPTION(m_enum.createTypeError("Requested unknown enum value ." + _member)); +} + FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal): m_location(_isInternal ? Location::Internal : Location::External), m_isConstant(_function.isDeclaredConst()), diff --git a/libsolidity/Types.h b/libsolidity/Types.h index d8b1b6b7a..3b4eee57f 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -384,6 +384,8 @@ public: virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; EnumDefinition const& getEnumDefinition() const { return m_enum; } + /// @returns the value that the string has in the Enum + unsigned int getMemberValue(ASTString const& _member) const; private: EnumDefinition const& m_enum; From 64bba8e3ccd0e2b256afec928d912b7045995cdd Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 13 Feb 2015 23:14:58 +0100 Subject: [PATCH 18/20] Explicit conversion from int to Enum --- libsolidity/Types.cpp | 4 +++- test/SolidityNameAndTypeResolution.cpp | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index c4a808f89..c29873b15 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -156,7 +156,9 @@ bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const StaticStringType const& convertTo = dynamic_cast(_convertTo); return isHash() && (m_bits == convertTo.getNumBytes() * 8); } - return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::Contract; + return _convertTo.getCategory() == getCategory() || + _convertTo.getCategory() == Category::Contract || + _convertTo.getCategory() == Category::Enum; } TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index c912939fc..f3edfc313 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -1039,6 +1039,23 @@ BOOST_AUTO_TEST_CASE(enum_explicit_conversion_is_okay) BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); } +BOOST_AUTO_TEST_CASE(int_to_enum_explicit_conversion_is_okay) +{ + char const* text = R"( + contract test { + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + function test() + { + a = 2; + b = ActionChoices(a); + } + uint256 a; + ActionChoices b; + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNamesWithChecks(text)); +} + BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay) { char const* text = R"( From 2370068db6ba572bf88d558f22441c101827da54 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 13 Feb 2015 23:26:03 +0100 Subject: [PATCH 19/20] Small improvement in TypeType::getMembers() --- libsolidity/Types.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index c29873b15..5d753645c 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -966,9 +966,9 @@ MemberList const& TypeType::getMembers() const else if (m_actualType->getCategory() == Category::Enum) { EnumDefinition const& enumDef = dynamic_cast(*m_actualType).getEnumDefinition(); + auto enumType = make_shared(enumDef); for (ASTPointer const& enumValue: enumDef.getMembers()) - members.insert(make_pair(enumValue->getName(), make_shared(enumDef))); - m_members.reset(new MemberList(members)); + members.insert(make_pair(enumValue->getName(), enumType)); } m_members.reset(new MemberList(members)); } From c3c52d59b2d15ca4dad1a307e3d999b7e192a1fa Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 13 Feb 2015 23:47:55 +0100 Subject: [PATCH 20/20] Removing ';' from the end of EnumDefinition --- libsolidity/Parser.cpp | 1 - libsolidity/grammar.txt | 2 +- test/SolidityEndToEndTest.cpp | 2 +- test/SolidityNameAndTypeResolution.cpp | 12 ++++++------ test/SolidityParser.cpp | 6 +++--- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index 4277ef54f..c96593f64 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -293,7 +293,6 @@ ASTPointer Parser::parseEnumDefinition() nodeFactory.markEndPosition(); expectToken(Token::RBrace); - expectToken(Token::Semicolon); return nodeFactory.createNode(name, members); } diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt index 5ba0ef238..5e6e65f85 100644 --- a/libsolidity/grammar.txt +++ b/libsolidity/grammar.txt @@ -13,7 +13,7 @@ FunctionDefinition = 'function' Identifier ParameterList ( 'returns' ParameterList )? Block EnumValue = Identifier -EnumDefinition = 'enum' '{' EnumValue (',' EnumValue)* '}' ';' +EnumDefinition = 'enum' '{' EnumValue (',' EnumValue)* '}' ParameterList = '(' ( VariableDeclaration (',' VariableDeclaration)* )? ')' // semantic restriction: mappings and structs (recursively) containing mappings // are not allowed in argument lists diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 551607df2..2ef2b8038 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2503,7 +2503,7 @@ BOOST_AUTO_TEST_CASE(using_enums) { char const* sourceCode = R"( contract test { - enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } function test() { choices = ActionChoices.GoStraight; diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index f3edfc313..ec49a42d1 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -996,7 +996,7 @@ BOOST_AUTO_TEST_CASE(enum_member_access) { char const* text = R"( contract test { - enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } function test() { choices = ActionChoices.GoStraight; @@ -1011,7 +1011,7 @@ BOOST_AUTO_TEST_CASE(enum_invalid_member_access) { char const* text = R"( contract test { - enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } function test() { choices = ActionChoices.RunAroundWavingYourHands; @@ -1026,7 +1026,7 @@ BOOST_AUTO_TEST_CASE(enum_explicit_conversion_is_okay) { char const* text = R"( contract test { - enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } function test() { a = uint256(ActionChoices.GoStraight); @@ -1043,7 +1043,7 @@ BOOST_AUTO_TEST_CASE(int_to_enum_explicit_conversion_is_okay) { char const* text = R"( contract test { - enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } function test() { a = 2; @@ -1060,7 +1060,7 @@ BOOST_AUTO_TEST_CASE(enum_implicit_conversion_is_not_okay) { char const* text = R"( contract test { - enum ActionChoices { GoLeft, GoRight, GoStraight, Sit }; + enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } function test() { a = ActionChoices.GoStraight; @@ -1077,7 +1077,7 @@ BOOST_AUTO_TEST_CASE(enum_duplicate_values) { char const* text = R"( contract test { - enum ActionChoices { GoLeft, GoRight, GoLeft, Sit }; + enum ActionChoices { GoLeft, GoRight, GoLeft, Sit } } )"; BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); diff --git a/test/SolidityParser.cpp b/test/SolidityParser.cpp index 702d1d6db..af82f612a 100644 --- a/test/SolidityParser.cpp +++ b/test/SolidityParser.cpp @@ -707,7 +707,7 @@ BOOST_AUTO_TEST_CASE(enum_valid_declaration) { char const* text = R"( contract c { - enum validEnum { Value1, Value2, Value3, Value4 }; + enum validEnum { Value1, Value2, Value3, Value4 } function c () { a = foo.Value3; @@ -721,7 +721,7 @@ BOOST_AUTO_TEST_CASE(empty_enum_declaration) { char const* text = R"( contract c { - enum foo { }; + enum foo { } })"; BOOST_CHECK_NO_THROW(parseTextExplainError(text)); } @@ -730,7 +730,7 @@ BOOST_AUTO_TEST_CASE(malformed_enum_declaration) { char const* text = R"( contract c { - enum foo { WARNING,}; + enum foo { WARNING,} })"; BOOST_CHECK_THROW(parseText(text), ParserError); }