diff options
author | Gav Wood <g@ethdev.com> | 2015-01-30 07:44:42 +0800 |
---|---|---|
committer | Gav Wood <g@ethdev.com> | 2015-01-30 07:44:42 +0800 |
commit | dc6f9e3ac0370835b6db8136ba39ea7100ae93a1 (patch) | |
tree | 6b8c569ec7377da58425fe00b1ed6548f46855fb | |
parent | a604202f33f1f7dc3abda1080e1bc02b2a2cbcb3 (diff) | |
parent | 8d5ee59ee5bd14ab31a6b6c10015df3334b6b641 (diff) | |
download | dexon-solidity-dc6f9e3ac0370835b6db8136ba39ea7100ae93a1.tar.gz dexon-solidity-dc6f9e3ac0370835b6db8136ba39ea7100ae93a1.tar.zst dexon-solidity-dc6f9e3ac0370835b6db8136ba39ea7100ae93a1.zip |
Merge pull request #893 from chriseth/sol_events
Events in Solidity
-rw-r--r-- | AST.cpp | 14 | ||||
-rwxr-xr-x | AST.h | 49 | ||||
-rw-r--r-- | ASTForward.h | 1 | ||||
-rw-r--r-- | ASTPrinter.cpp | 12 | ||||
-rw-r--r-- | ASTPrinter.h | 2 | ||||
-rw-r--r-- | ASTVisitor.h | 4 | ||||
-rw-r--r-- | AST_accept.h | 20 | ||||
-rw-r--r-- | ExpressionCompiler.cpp | 87 | ||||
-rw-r--r-- | ExpressionCompiler.h | 7 | ||||
-rw-r--r-- | NameAndTypeResolver.cpp | 8 | ||||
-rw-r--r-- | NameAndTypeResolver.h | 1 | ||||
-rw-r--r-- | Parser.cpp | 59 | ||||
-rw-r--r-- | Parser.h | 13 | ||||
-rw-r--r-- | Token.h | 2 | ||||
-rw-r--r-- | Types.cpp | 16 | ||||
-rw-r--r-- | Types.h | 4 |
16 files changed, 245 insertions, 54 deletions
@@ -271,6 +271,20 @@ void ModifierInvocation::checkTypeRequirements() BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in modifier invocation.")); } +void EventDefinition::checkTypeRequirements() +{ + int numIndexed = 0; + for (ASTPointer<VariableDeclaration> const& var: getParameters()) + { + if (var->isIndexed()) + numIndexed++; + if (!var->getType()->canLiveOutsideStorage()) + BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); + } + if (numIndexed > 3) + BOOST_THROW_EXCEPTION(createTypeError("More than 3 indexed arguments for event.")); +} + void Block::checkTypeRequirements() { for (shared_ptr<Statement> const& statement: m_statements) @@ -202,13 +202,15 @@ public: std::vector<ASTPointer<StructDefinition>> const& _definedStructs, std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables, std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions, - std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers): + std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers, + std::vector<ASTPointer<EventDefinition>> const& _events): Declaration(_location, _name), Documented(_documentation), m_baseContracts(_baseContracts), m_definedStructs(_definedStructs), m_stateVariables(_stateVariables), m_definedFunctions(_definedFunctions), - m_functionModifiers(_functionModifiers) + m_functionModifiers(_functionModifiers), + m_events(_events) {} virtual void accept(ASTVisitor& _visitor) override; @@ -219,6 +221,7 @@ public: std::vector<ASTPointer<VariableDeclaration>> const& getStateVariables() const { return m_stateVariables; } std::vector<ASTPointer<ModifierDefinition>> const& getFunctionModifiers() const { return m_functionModifiers; } std::vector<ASTPointer<FunctionDefinition>> const& getDefinedFunctions() const { return m_definedFunctions; } + std::vector<ASTPointer<EventDefinition>> const& getEvents() const { return m_events; } virtual TypePointer getType(ContractDefinition const* m_currentContract) const override; @@ -248,6 +251,7 @@ private: std::vector<ASTPointer<VariableDeclaration>> m_stateVariables; std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions; std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers; + std::vector<ASTPointer<EventDefinition>> m_events; std::vector<ContractDefinition const*> m_linearizedBaseContracts; mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList; @@ -380,8 +384,10 @@ class VariableDeclaration: public Declaration { public: VariableDeclaration(Location const& _location, ASTPointer<TypeName> const& _type, - ASTPointer<ASTString> const& _name, bool _isPublic, bool _isStateVar = false): - Declaration(_location, _name), m_typeName(_type), m_isPublic(_isPublic), m_isStateVariable(_isStateVar) {} + ASTPointer<ASTString> const& _name, bool _isPublic, bool _isStateVar = false, + bool _isIndexed = false): + Declaration(_location, _name), m_typeName(_type), + m_isPublic(_isPublic), m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -396,12 +402,13 @@ public: bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); } bool isPublic() const { return m_isPublic; } bool isStateVariable() const { return m_isStateVariable; } - + bool isIndexed() const { return m_isIndexed; } private: ASTPointer<TypeName> m_typeName; ///< can be empty ("var") bool m_isPublic; ///< Whether there is an accessor for it or not bool m_isStateVariable; ///< Whether or not this is a contract state variable + bool m_isIndexed; ///< Whether this is an indexed variable (used by events). std::shared_ptr<Type const> m_type; ///< derived type, initially empty }; @@ -429,7 +436,6 @@ public: virtual TypePointer getType(ContractDefinition const* = nullptr) const override; - void checkTypeRequirements(); private: @@ -461,6 +467,37 @@ private: }; /** + * Definition of a (loggable) event. + */ +class EventDefinition: public Declaration, public Documented +{ +public: + EventDefinition(Location const& _location, + ASTPointer<ASTString> const& _name, + ASTPointer<ASTString> const& _documentation, + ASTPointer<ParameterList> const& _parameters): + Declaration(_location, _name), Documented(_documentation), m_parameters(_parameters) {} + + virtual void accept(ASTVisitor& _visitor) override; + virtual void accept(ASTConstVisitor& _visitor) const override; + + std::vector<ASTPointer<VariableDeclaration>> const& getParameters() const { return m_parameters->getParameters(); } + ParameterList const& getParameterList() const { return *m_parameters; } + Block const& getBody() const { return *m_body; } + + virtual TypePointer getType(ContractDefinition const* = nullptr) const override + { + return std::make_shared<FunctionType>(*this); + } + + void checkTypeRequirements(); + +private: + ASTPointer<ParameterList> m_parameters; + ASTPointer<Block> m_body; +}; + +/** * Pseudo AST node that is used as declaration for "this", "msg", "tx", "block" and the global * functions when such an identifier is encountered. Will never have a valid location in the source code. */ diff --git a/ASTForward.h b/ASTForward.h index aa5cd49c..22015f26 100644 --- a/ASTForward.h +++ b/ASTForward.h @@ -45,6 +45,7 @@ class FunctionDefinition; class VariableDeclaration; class ModifierDefinition; class ModifierInvocation; +class EventDefinition; class MagicVariableDeclaration; class TypeName; class ElementaryTypeName; diff --git a/ASTPrinter.cpp b/ASTPrinter.cpp index 05b24c63..949740e8 100644 --- a/ASTPrinter.cpp +++ b/ASTPrinter.cpp @@ -108,6 +108,13 @@ bool ASTPrinter::visit(ModifierInvocation const& _node) return goDeeper(); } +bool ASTPrinter::visit(EventDefinition const& _node) +{ + writeLine("EventDefinition \"" + _node.getName() + "\""); + printSourcePart(_node); + return goDeeper(); +} + bool ASTPrinter::visit(TypeName const& _node) { writeLine("TypeName"); @@ -365,6 +372,11 @@ void ASTPrinter::endVisit(ModifierInvocation const&) m_indentation--; } +void ASTPrinter::endVisit(EventDefinition const&) +{ + m_indentation--; +} + void ASTPrinter::endVisit(TypeName const&) { m_indentation--; diff --git a/ASTPrinter.h b/ASTPrinter.h index 77025b2d..ebc163e3 100644 --- a/ASTPrinter.h +++ b/ASTPrinter.h @@ -51,6 +51,7 @@ public: bool visit(VariableDeclaration const& _node) override; bool visit(ModifierDefinition const& _node) override; bool visit(ModifierInvocation const& _node) override; + bool visit(EventDefinition const& _node) override; bool visit(TypeName const& _node) override; bool visit(ElementaryTypeName const& _node) override; bool visit(UserDefinedTypeName const& _node) override; @@ -89,6 +90,7 @@ public: void endVisit(VariableDeclaration const&) override; void endVisit(ModifierDefinition const&) override; void endVisit(ModifierInvocation const&) override; + void endVisit(EventDefinition const&) override; void endVisit(TypeName const&) override; void endVisit(ElementaryTypeName const&) override; void endVisit(UserDefinedTypeName const&) override; diff --git a/ASTVisitor.h b/ASTVisitor.h index 53fbd191..29490277 100644 --- a/ASTVisitor.h +++ b/ASTVisitor.h @@ -52,6 +52,7 @@ public: virtual bool visit(VariableDeclaration&) { return true; } virtual bool visit(ModifierDefinition&) { return true; } virtual bool visit(ModifierInvocation&) { return true; } + virtual bool visit(EventDefinition&) { return true; } virtual bool visit(TypeName&) { return true; } virtual bool visit(ElementaryTypeName&) { return true; } virtual bool visit(UserDefinedTypeName&) { return true; } @@ -92,6 +93,7 @@ public: virtual void endVisit(VariableDeclaration&) { } virtual void endVisit(ModifierDefinition&) { } virtual void endVisit(ModifierInvocation&) { } + virtual void endVisit(EventDefinition&) { } virtual void endVisit(TypeName&) { } virtual void endVisit(ElementaryTypeName&) { } virtual void endVisit(UserDefinedTypeName&) { } @@ -136,6 +138,7 @@ public: virtual bool visit(VariableDeclaration const&) { return true; } virtual bool visit(ModifierDefinition const&) { return true; } virtual bool visit(ModifierInvocation const&) { return true; } + virtual bool visit(EventDefinition const&) { return true; } virtual bool visit(TypeName const&) { return true; } virtual bool visit(ElementaryTypeName const&) { return true; } virtual bool visit(UserDefinedTypeName const&) { return true; } @@ -176,6 +179,7 @@ public: virtual void endVisit(VariableDeclaration const&) { } virtual void endVisit(ModifierDefinition const&) { } virtual void endVisit(ModifierInvocation const&) { } + virtual void endVisit(EventDefinition const&) { } virtual void endVisit(TypeName const&) { } virtual void endVisit(ElementaryTypeName const&) { } virtual void endVisit(UserDefinedTypeName const&) { } diff --git a/AST_accept.h b/AST_accept.h index 481b150b..38108cd7 100644 --- a/AST_accept.h +++ b/AST_accept.h @@ -64,8 +64,9 @@ void ContractDefinition::accept(ASTVisitor& _visitor) listAccept(m_baseContracts, _visitor); listAccept(m_definedStructs, _visitor); listAccept(m_stateVariables, _visitor); - listAccept(m_definedFunctions, _visitor); + listAccept(m_events, _visitor); listAccept(m_functionModifiers, _visitor); + listAccept(m_definedFunctions, _visitor); } _visitor.endVisit(*this); } @@ -77,8 +78,9 @@ void ContractDefinition::accept(ASTConstVisitor& _visitor) const listAccept(m_baseContracts, _visitor); listAccept(m_definedStructs, _visitor); listAccept(m_stateVariables, _visitor); - listAccept(m_definedFunctions, _visitor); + listAccept(m_events, _visitor); listAccept(m_functionModifiers, _visitor); + listAccept(m_definedFunctions, _visitor); } _visitor.endVisit(*this); } @@ -219,6 +221,20 @@ void ModifierInvocation::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } +void EventDefinition::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + m_parameters->accept(_visitor); + _visitor.endVisit(*this); +} + +void EventDefinition::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + m_parameters->accept(_visitor); + _visitor.endVisit(*this); +} + void TypeName::accept(ASTVisitor& _visitor) { _visitor.visit(*this); diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 5d44c86f..7d58ea2e 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -23,6 +23,7 @@ #include <utility> #include <numeric> #include <libdevcore/Common.h> +#include <libdevcrypto/SHA3.h> #include <libsolidity/AST.h> #include <libsolidity/ExpressionCompiler.h> #include <libsolidity/CompilerContext.h> @@ -304,10 +305,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << eth::Instruction::SUICIDE; break; case Location::SHA3: - arguments.front()->accept(*this); - appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); - // @todo move this once we actually use memory - CompilerUtils(m_context).storeInMemory(0); + appendExpressionCopyToMemory(*function.getParameterTypes().front(), *arguments.front()); m_context << u256(32) << u256(0) << eth::Instruction::SHA3; break; case Location::LOG0: @@ -317,14 +315,41 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) case Location::LOG4: { unsigned logNumber = int(function.getLocation()) - int(Location::LOG0); - for (int arg = logNumber; arg >= 0; --arg) + for (unsigned arg = logNumber; arg > 0; --arg) { arguments[arg]->accept(*this); appendTypeConversion(*arguments[arg]->getType(), *function.getParameterTypes()[arg], true); } - // @todo move this once we actually use memory - CompilerUtils(m_context).storeInMemory(0); - m_context << u256(32) << u256(0) << eth::logInstruction(logNumber); + unsigned length = appendExpressionCopyToMemory(*function.getParameterTypes().front(), + *arguments.front()); + solAssert(length == 32, "Log data should be 32 bytes long (for now)."); + m_context << u256(length) << u256(0) << eth::logInstruction(logNumber); + break; + } + case Location::EVENT: + { + _functionCall.getExpression().accept(*this); + auto const& event = dynamic_cast<EventDefinition const&>(function.getDeclaration()); + // Copy all non-indexed arguments to memory (data) + unsigned numIndexed = 0; + unsigned memLength = 0; + for (unsigned arg = 0; arg < arguments.size(); ++arg) + if (!event.getParameters()[arg]->isIndexed()) + memLength += appendExpressionCopyToMemory(*function.getParameterTypes()[arg], + *arguments[arg], memLength); + // All indexed arguments go to the stack + for (unsigned arg = arguments.size(); arg > 0; --arg) + if (event.getParameters()[arg - 1]->isIndexed()) + { + ++numIndexed; + arguments[arg - 1]->accept(*this); + appendTypeConversion(*arguments[arg - 1]->getType(), + *function.getParameterTypes()[arg - 1], true); + } + m_context << u256(h256::Arith(dev::sha3(function.getCanonicalSignature(event.getName())))); + ++numIndexed; + solAssert(numIndexed <= 4, "Too many indexed arguments."); + m_context << u256(memLength) << u256(0) << eth::logInstruction(numIndexed); break; } case Location::BLOCKHASH: @@ -459,14 +484,13 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) { _indexAccess.getBaseExpression().accept(*this); - _indexAccess.getIndexExpression().accept(*this); - appendTypeConversion(*_indexAccess.getIndexExpression().getType(), - *dynamic_cast<MappingType const&>(*_indexAccess.getBaseExpression().getType()).getKeyType(), - true); + + TypePointer const& keyType = dynamic_cast<MappingType const&>(*_indexAccess.getBaseExpression().getType()).getKeyType(); + unsigned length = appendExpressionCopyToMemory(*keyType, _indexAccess.getIndexExpression()); + solAssert(length == 32, "Mapping key has to take 32 bytes in memory (for now)."); // @todo move this once we actually use memory - CompilerUtils(m_context).storeInMemory(0); - CompilerUtils(m_context).storeInMemory(32); - m_context << u256(64) << u256(0) << eth::Instruction::SHA3; + length += CompilerUtils(m_context).storeInMemory(length); + m_context << u256(length) << u256(0) << eth::Instruction::SHA3; m_currentLValue = LValue(m_context, LValue::STORAGE, *_indexAccess.getType()); m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess); @@ -495,6 +519,10 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) { // no-op } + else if (dynamic_cast<EventDefinition const*>(declaration)) + { + // no-op + } else { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not expected in expression context.")); @@ -791,22 +819,25 @@ unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _typ { unsigned length = 0; for (unsigned i = 0; i < _arguments.size(); ++i) - { - _arguments[i]->accept(*this); - appendTypeConversion(*_arguments[i]->getType(), *_types[i], true); - unsigned const c_numBytes = _types[i]->getCalldataEncodedSize(); - if (c_numBytes == 0 || c_numBytes > 32) - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(_arguments[i]->getLocation()) - << errinfo_comment("Type " + _types[i]->toString() + " not yet supported.")); - bool const c_leftAligned = _types[i]->getCategory() == Type::Category::STRING; - bool const c_padToWords = true; - length += CompilerUtils(m_context).storeInMemory(_memoryOffset + length, c_numBytes, - c_leftAligned, c_padToWords); - } + length += appendExpressionCopyToMemory(*_types[i], *_arguments[i], _memoryOffset + length); return length; } +unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, + Expression const& _expression, unsigned _memoryOffset) +{ + _expression.accept(*this); + appendTypeConversion(*_expression.getType(), _expectedType, true); + unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize()); + if (c_numBytes == 0 || c_numBytes > 32) + BOOST_THROW_EXCEPTION(CompilerError() + << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Type " + _expectedType.toString() + " not yet supported.")); + bool const c_leftAligned = _expectedType.getCategory() == Type::Category::STRING; + bool const c_padToWords = true; + return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords); +} + void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) { m_currentLValue.fromStateVariable(_varDecl, _varDecl.getType()); diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index 748cc6c6..caecbfe8 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -94,8 +94,13 @@ private: bool bare = false); /// Appends code that copies the given arguments to memory (with optional offset). /// @returns the number of bytes copied to memory - unsigned appendArgumentCopyToMemory(TypePointers const& _functionType, std::vector<ASTPointer<Expression const>> const& _arguments, + unsigned appendArgumentCopyToMemory(TypePointers const& _types, + std::vector<ASTPointer<Expression const>> const& _arguments, unsigned _memoryOffset = 0); + /// Appends code that evaluates a single expression and copies it to memory (with optional offset). + /// @returns the number of bytes copied to memory + unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression, + unsigned _memoryOffset = 0); /// Appends code for a State Variable accessor function void appendStateVariableAccessor(VariableDeclaration const& _varDecl); diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp index 43201fe1..75df637c 100644 --- a/NameAndTypeResolver.cpp +++ b/NameAndTypeResolver.cpp @@ -60,6 +60,8 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) ReferencesResolver resolver(*structDef, *this, &_contract, nullptr); for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables()) ReferencesResolver resolver(*variable, *this, &_contract, nullptr); + for (ASTPointer<EventDefinition> const& event: _contract.getEvents()) + ReferencesResolver resolver(*event, *this, &_contract, nullptr); for (ASTPointer<ModifierDefinition> const& modifier: _contract.getFunctionModifiers()) { m_currentScope = &m_scopes[modifier.get()]; @@ -259,6 +261,12 @@ bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) return true; } +bool DeclarationRegistrationHelper::visit(EventDefinition& _event) +{ + registerDeclaration(_event, false); + return true; +} + void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declaration) { map<ASTNode const*, DeclarationContainer>::iterator iter; diff --git a/NameAndTypeResolver.h b/NameAndTypeResolver.h index ba327a59..4555491f 100644 --- a/NameAndTypeResolver.h +++ b/NameAndTypeResolver.h @@ -104,6 +104,7 @@ private: void endVisit(ModifierDefinition& _modifier); void endVisit(VariableDefinition& _variableDefinition); bool visit(VariableDeclaration& _declaration); + bool visit(EventDefinition& _event); void enterNewSubScope(Declaration const& _declaration); void closeCurrentScope(); @@ -122,6 +122,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition() vector<ASTPointer<VariableDeclaration>> stateVariables; vector<ASTPointer<FunctionDefinition>> functions; vector<ASTPointer<ModifierDefinition>> modifiers; + vector<ASTPointer<EventDefinition>> events; if (m_scanner->getCurrentToken() == Token::IS) do { @@ -149,19 +150,23 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition() else if (currentToken == Token::IDENTIFIER || currentToken == Token::MAPPING || Token::isElementaryTypeName(currentToken)) { - bool const allowVar = false; - stateVariables.push_back(parseVariableDeclaration(allowVar, visibilityIsPublic, true)); + VarDeclParserOptions options; + options.isPublic = visibilityIsPublic; + options.isStateVariable = true; + stateVariables.push_back(parseVariableDeclaration(options)); expectToken(Token::SEMICOLON); } else if (currentToken == Token::MODIFIER) modifiers.push_back(parseModifierDefinition()); + else if (currentToken == Token::EVENT) + events.push_back(parseEventDefinition()); else BOOST_THROW_EXCEPTION(createParserError("Function, variable, struct or modifier declaration expected.")); } nodeFactory.markEndPosition(); expectToken(Token::RBRACE); return nodeFactory.createNode<ContractDefinition>(name, docString, baseContracts, structs, - stateVariables, functions, modifiers); + stateVariables, functions, modifiers, events); } ASTPointer<InheritanceSpecifier> Parser::parseInheritanceSpecifier() @@ -236,8 +241,7 @@ ASTPointer<StructDefinition> Parser::parseStructDefinition() expectToken(Token::LBRACE); while (m_scanner->getCurrentToken() != Token::RBRACE) { - bool const allowVar = false; - members.push_back(parseVariableDeclaration(allowVar)); + members.push_back(parseVariableDeclaration()); expectToken(Token::SEMICOLON); } nodeFactory.markEndPosition(); @@ -245,12 +249,20 @@ ASTPointer<StructDefinition> Parser::parseStructDefinition() return nodeFactory.createNode<StructDefinition>(name, members); } -ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(bool _allowVar, bool _isPublic, bool _isStateVariable) +ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(VarDeclParserOptions const& _options) { ASTNodeFactory nodeFactory(*this); - ASTPointer<TypeName> type = parseTypeName(_allowVar); + ASTPointer<TypeName> type = parseTypeName(_options.allowVar); + bool isIndexed = false; + if (_options.allowIndexed && m_scanner->getCurrentToken() == Token::INDEXED) + { + isIndexed = true; + m_scanner->next(); + } nodeFactory.markEndPosition(); - return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken(), _isPublic, _isStateVariable); + return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken(), + _options.isPublic, _options.isStateVariable, + isIndexed); } ASTPointer<ModifierDefinition> Parser::parseModifierDefinition() @@ -280,6 +292,23 @@ ASTPointer<ModifierDefinition> Parser::parseModifierDefinition() return nodeFactory.createNode<ModifierDefinition>(name, docstring, parameters, block); } +ASTPointer<EventDefinition> Parser::parseEventDefinition() +{ + ASTNodeFactory nodeFactory(*this); + ASTPointer<ASTString> docstring; + if (m_scanner->getCurrentCommentLiteral() != "") + docstring = make_shared<ASTString>(m_scanner->getCurrentCommentLiteral()); + + expectToken(Token::EVENT); + ASTPointer<ASTString> name(expectIdentifierToken()); + ASTPointer<ParameterList> parameters; + if (m_scanner->getCurrentToken() == Token::LPAREN) + parameters = parseParameterList(true, true); + nodeFactory.markEndPosition(); + expectToken(Token::SEMICOLON); + return nodeFactory.createNode<EventDefinition>(name, docstring, parameters); +} + ASTPointer<ModifierInvocation> Parser::parseModifierInvocation() { ASTNodeFactory nodeFactory(*this); @@ -352,19 +381,20 @@ ASTPointer<Mapping> Parser::parseMapping() return nodeFactory.createNode<Mapping>(keyType, valueType); } -ASTPointer<ParameterList> Parser::parseParameterList(bool _allowEmpty) +ASTPointer<ParameterList> Parser::parseParameterList(bool _allowEmpty, bool _allowIndexed) { ASTNodeFactory nodeFactory(*this); vector<ASTPointer<VariableDeclaration>> parameters; + VarDeclParserOptions options; + options.allowIndexed = _allowIndexed; expectToken(Token::LPAREN); if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN) { - bool const allowVar = false; - parameters.push_back(parseVariableDeclaration(allowVar)); + parameters.push_back(parseVariableDeclaration(options)); while (m_scanner->getCurrentToken() != Token::RPAREN) { expectToken(Token::COMMA); - parameters.push_back(parseVariableDeclaration(allowVar)); + parameters.push_back(parseVariableDeclaration(options)); } } nodeFactory.markEndPosition(); @@ -506,8 +536,9 @@ ASTPointer<Statement> Parser::parseVarDefOrExprStmt() ASTPointer<VariableDefinition> Parser::parseVariableDefinition() { ASTNodeFactory nodeFactory(*this); - bool const allowVar = true; - ASTPointer<VariableDeclaration> variable = parseVariableDeclaration(allowVar); + VarDeclParserOptions options; + options.allowVar = true; + ASTPointer<VariableDeclaration> variable = parseVariableDeclaration(options); ASTPointer<Expression> value; if (m_scanner->getCurrentToken() == Token::ASSIGN) { @@ -45,6 +45,14 @@ private: /// End position of the current token int getEndPosition() const; + struct VarDeclParserOptions { + VarDeclParserOptions() {} + bool allowVar = false; + bool isPublic = false; + bool isStateVariable = false; + bool allowIndexed = false; + }; + ///@{ ///@name Parsing functions for the AST nodes ASTPointer<ImportDirective> parseImportDirective(); @@ -52,13 +60,14 @@ private: ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier(); ASTPointer<FunctionDefinition> parseFunctionDefinition(bool _isPublic, ASTString const* _contractName); ASTPointer<StructDefinition> parseStructDefinition(); - ASTPointer<VariableDeclaration> parseVariableDeclaration(bool _allowVar, bool _isPublic = false, bool _isStateVar = false); + ASTPointer<VariableDeclaration> parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions()); ASTPointer<ModifierDefinition> parseModifierDefinition(); + ASTPointer<EventDefinition> parseEventDefinition(); ASTPointer<ModifierInvocation> parseModifierInvocation(); ASTPointer<Identifier> parseIdentifier(); ASTPointer<TypeName> parseTypeName(bool _allowVar); ASTPointer<Mapping> parseMapping(); - ASTPointer<ParameterList> parseParameterList(bool _allowEmpty = true); + ASTPointer<ParameterList> parseParameterList(bool _allowEmpty = true, bool _allowIndexed = false); ASTPointer<Block> parseBlock(); ASTPointer<Statement> parseStatement(); ASTPointer<IfStatement> parseIfStatement(); @@ -153,7 +153,9 @@ namespace solidity K(DEFAULT, "default", 0) \ K(DO, "do", 0) \ K(ELSE, "else", 0) \ + K(EVENT, "event", 0) \ K(IS, "is", 0) \ + K(INDEXED, "indexed", 0) \ K(FOR, "for", 0) \ K(FUNCTION, "function", 0) \ K(IF, "if", 0) \ @@ -633,6 +633,22 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): swap(retParamNames, m_returnParameterNames); } +FunctionType::FunctionType(const EventDefinition& _event): + m_location(Location::EVENT), m_declaration(&_event) +{ + TypePointers params; + vector<string> paramNames; + params.reserve(_event.getParameters().size()); + paramNames.reserve(_event.getParameters().size()); + for (ASTPointer<VariableDeclaration> const& var: _event.getParameters()) + { + paramNames.push_back(var->getName()); + params.push_back(var->getType()); + } + swap(params, m_parameterTypes); + swap(paramNames, m_parameterNames); +} + bool FunctionType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) @@ -350,16 +350,18 @@ public: /// INTERNAL: jump tag, EXTERNAL: contract address + function identifier, /// BARE: contract address (non-abi contract call) /// OTHERS: special virtual function, nothing on the stack + /// @todo This documentation is outdated, and Location should rather be named "Type" enum class Location { INTERNAL, EXTERNAL, CREATION, SEND, SHA3, SUICIDE, ECRECOVER, SHA256, RIPEMD160, - LOG0, LOG1, LOG2, LOG3, LOG4, + LOG0, LOG1, LOG2, LOG3, LOG4, EVENT, SET_GAS, SET_VALUE, BLOCKHASH, BARE }; virtual Category getCategory() const override { return Category::FUNCTION; } explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true); explicit FunctionType(VariableDeclaration const& _varDecl); + explicit FunctionType(EventDefinition const& _event); FunctionType(strings const& _parameterTypes, strings const& _returnParameterTypes, Location _location = Location::INTERNAL): FunctionType(parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), |