From 4a6ed84386ed7bc3abd2b4cf2441b29a5af38816 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 29 Jan 2015 14:35:28 +0100 Subject: Parsing of events. --- AST.cpp | 14 ++++++++++++ AST.h | 48 +++++++++++++++++++++++++++++++++++----- ASTForward.h | 1 + ASTPrinter.cpp | 12 ++++++++++ ASTPrinter.h | 2 ++ ASTVisitor.h | 4 ++++ AST_accept.h | 20 +++++++++++++++-- NameAndTypeResolver.cpp | 8 +++++++ NameAndTypeResolver.h | 1 + Parser.cpp | 59 +++++++++++++++++++++++++++++++++++++------------ Parser.h | 13 +++++++++-- Token.h | 2 ++ Types.cpp | 16 ++++++++++++++ Types.h | 4 +++- 14 files changed, 180 insertions(+), 24 deletions(-) diff --git a/AST.cpp b/AST.cpp index bc6be600..82d58d2a 100644 --- a/AST.cpp +++ b/AST.cpp @@ -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 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 const& statement: m_statements) diff --git a/AST.h b/AST.h index 6c207290..f0d6cb33 100755 --- a/AST.h +++ b/AST.h @@ -202,13 +202,15 @@ public: std::vector> const& _definedStructs, std::vector> const& _stateVariables, std::vector> const& _definedFunctions, - std::vector> const& _functionModifiers): + std::vector> const& _functionModifiers, + std::vector> 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> const& getStateVariables() const { return m_stateVariables; } std::vector> const& getFunctionModifiers() const { return m_functionModifiers; } std::vector> const& getDefinedFunctions() const { return m_definedFunctions; } + std::vector> const& getEvents() const { return m_events; } virtual TypePointer getType(ContractDefinition const* m_currentContract) const override; @@ -248,6 +251,7 @@ private: std::vector> m_stateVariables; std::vector> m_definedFunctions; std::vector> m_functionModifiers; + std::vector> m_events; std::vector m_linearizedBaseContracts; mutable std::unique_ptr, FunctionTypePointer>>> m_interfaceFunctionList; @@ -380,8 +384,10 @@ class VariableDeclaration: public Declaration { public: VariableDeclaration(Location const& _location, ASTPointer const& _type, - ASTPointer const& _name, bool _isPublic, bool _isStateVar = false): - Declaration(_location, _name), m_typeName(_type), m_isPublic(_isPublic), m_isStateVariable(_isStateVar) {} + ASTPointer 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,14 @@ public: bool isLocalVariable() const { return !!dynamic_cast(getScope()); } bool isPublic() const { return m_isPublic; } bool isStateVariable() const { return m_isStateVariable; } + bool isIndexed() const { return m_isIndexed; } private: ASTPointer 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 m_type; ///< derived type, initially empty }; @@ -429,7 +437,6 @@ public: virtual TypePointer getType(ContractDefinition const* = nullptr) const override; - void checkTypeRequirements(); private: @@ -460,6 +467,37 @@ private: std::vector> m_arguments; }; +/** + * Definition of a (loggable) event. + */ +class EventDefinition: public Declaration, public Documented +{ +public: + EventDefinition(Location const& _location, + ASTPointer const& _name, + ASTPointer const& _documentation, + ASTPointer 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> 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(*this); + } + + void checkTypeRequirements(); + +private: + ASTPointer m_parameters; + ASTPointer 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/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 const& variable: _contract.getStateVariables()) ReferencesResolver resolver(*variable, *this, &_contract, nullptr); + for (ASTPointer const& event: _contract.getEvents()) + ReferencesResolver resolver(*event, *this, &_contract, nullptr); for (ASTPointer 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::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(); diff --git a/Parser.cpp b/Parser.cpp index 5cfc8f46..48cca612 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -122,6 +122,7 @@ ASTPointer Parser::parseContractDefinition() vector> stateVariables; vector> functions; vector> modifiers; + vector> events; if (m_scanner->getCurrentToken() == Token::IS) do { @@ -149,19 +150,23 @@ ASTPointer 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(name, docString, baseContracts, structs, - stateVariables, functions, modifiers); + stateVariables, functions, modifiers, events); } ASTPointer Parser::parseInheritanceSpecifier() @@ -236,8 +241,7 @@ ASTPointer 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 Parser::parseStructDefinition() return nodeFactory.createNode(name, members); } -ASTPointer Parser::parseVariableDeclaration(bool _allowVar, bool _isPublic, bool _isStateVariable) +ASTPointer Parser::parseVariableDeclaration(VarDeclParserOptions const& _options) { ASTNodeFactory nodeFactory(*this); - ASTPointer type = parseTypeName(_allowVar); + ASTPointer 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(type, expectIdentifierToken(), _isPublic, _isStateVariable); + return nodeFactory.createNode(type, expectIdentifierToken(), + _options.isPublic, _options.isStateVariable, + isIndexed); } ASTPointer Parser::parseModifierDefinition() @@ -280,6 +292,23 @@ ASTPointer Parser::parseModifierDefinition() return nodeFactory.createNode(name, docstring, parameters, block); } +ASTPointer Parser::parseEventDefinition() +{ + ASTNodeFactory nodeFactory(*this); + ASTPointer docstring; + if (m_scanner->getCurrentCommentLiteral() != "") + docstring = make_shared(m_scanner->getCurrentCommentLiteral()); + + expectToken(Token::EVENT); + ASTPointer name(expectIdentifierToken()); + ASTPointer parameters; + if (m_scanner->getCurrentToken() == Token::LPAREN) + parameters = parseParameterList(true, true); + nodeFactory.markEndPosition(); + expectToken(Token::SEMICOLON); + return nodeFactory.createNode(name, docstring, parameters); +} + ASTPointer Parser::parseModifierInvocation() { ASTNodeFactory nodeFactory(*this); @@ -352,19 +381,20 @@ ASTPointer Parser::parseMapping() return nodeFactory.createNode(keyType, valueType); } -ASTPointer Parser::parseParameterList(bool _allowEmpty) +ASTPointer Parser::parseParameterList(bool _allowEmpty, bool _allowIndexed) { ASTNodeFactory nodeFactory(*this); vector> 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 Parser::parseVarDefOrExprStmt() ASTPointer Parser::parseVariableDefinition() { ASTNodeFactory nodeFactory(*this); - bool const allowVar = true; - ASTPointer variable = parseVariableDeclaration(allowVar); + VarDeclParserOptions options; + options.allowVar = true; + ASTPointer variable = parseVariableDeclaration(options); ASTPointer value; if (m_scanner->getCurrentToken() == Token::ASSIGN) { diff --git a/Parser.h b/Parser.h index d3bff67e..69478c81 100644 --- a/Parser.h +++ b/Parser.h @@ -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 parseImportDirective(); @@ -52,13 +60,14 @@ private: ASTPointer parseInheritanceSpecifier(); ASTPointer parseFunctionDefinition(bool _isPublic, ASTString const* _contractName); ASTPointer parseStructDefinition(); - ASTPointer parseVariableDeclaration(bool _allowVar, bool _isPublic = false, bool _isStateVar = false); + ASTPointer parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions()); ASTPointer parseModifierDefinition(); + ASTPointer parseEventDefinition(); ASTPointer parseModifierInvocation(); ASTPointer parseIdentifier(); ASTPointer parseTypeName(bool _allowVar); ASTPointer parseMapping(); - ASTPointer parseParameterList(bool _allowEmpty = true); + ASTPointer parseParameterList(bool _allowEmpty = true, bool _allowIndexed = false); ASTPointer parseBlock(); ASTPointer parseStatement(); ASTPointer parseIfStatement(); diff --git a/Token.h b/Token.h index 55ec8e8e..ed42f90c 100644 --- a/Token.h +++ b/Token.h @@ -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) \ diff --git a/Types.cpp b/Types.cpp index bebb4be1..0842e40b 100644 --- a/Types.cpp +++ b/Types.cpp @@ -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 paramNames; + params.reserve(_event.getParameters().size()); + paramNames.reserve(_event.getParameters().size()); + for (ASTPointer 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()) diff --git a/Types.h b/Types.h index 4b4d17d0..1f4d27a2 100644 --- a/Types.h +++ b/Types.h @@ -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), -- cgit From 4e72a775469ea0e97475460997336de2e3af80df Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 29 Jan 2015 16:42:59 +0100 Subject: Code generation for events. --- AST.h | 1 - ExpressionCompiler.cpp | 87 ++++++++++++++++++++++++++++++++++---------------- ExpressionCompiler.h | 9 ++++-- 3 files changed, 66 insertions(+), 31 deletions(-) diff --git a/AST.h b/AST.h index f0d6cb33..fb046f19 100755 --- a/AST.h +++ b/AST.h @@ -404,7 +404,6 @@ public: bool isStateVariable() const { return m_isStateVariable; } bool isIndexed() const { return m_isIndexed; } - private: ASTPointer m_typeName; ///< can be empty ("var") bool m_isPublic; ///< Whether there is an accessor for it or not diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 5d44c86f..2b299011 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -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 have length 32."); + m_context << u256(length) << u256(0) << eth::logInstruction(logNumber); + break; + } + case Location::EVENT: + { + _functionCall.getExpression().accept(*this); + auto const& event = dynamic_cast(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(*_indexAccess.getBaseExpression().getType()).getKeyType(), - true); + + TypePointer const& keyType = dynamic_cast(*_indexAccess.getBaseExpression().getType()).getKeyType(); + unsigned length = appendExpressionCopyToMemory(*keyType, _indexAccess.getIndexExpression()); + solAssert(length == 32, "Mapping key length in memory has to be 32."); // @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(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 = _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..18c3817a 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> const& _arguments, - unsigned _memoryOffset = 0); + unsigned appendArgumentCopyToMemory(TypePointers const& _types, + std::vector> 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); -- cgit From 9f8c2620da10aa6dc3ab92de2b4aba7a9aa53be4 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 29 Jan 2015 19:32:32 +0100 Subject: Whitespace and error messages. --- AST.h | 6 +++--- ExpressionCompiler.cpp | 4 ++-- ExpressionCompiler.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/AST.h b/AST.h index fb046f19..ab9815f6 100755 --- a/AST.h +++ b/AST.h @@ -473,9 +473,9 @@ class EventDefinition: public Declaration, public Documented { public: EventDefinition(Location const& _location, - ASTPointer const& _name, - ASTPointer const& _documentation, - ASTPointer const& _parameters): + ASTPointer const& _name, + ASTPointer const& _documentation, + ASTPointer const& _parameters): Declaration(_location, _name), Documented(_documentation), m_parameters(_parameters) {} virtual void accept(ASTVisitor& _visitor) override; diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 2b299011..db71b51d 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -322,7 +322,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) } unsigned length = appendExpressionCopyToMemory(*function.getParameterTypes().front(), *arguments.front()); - solAssert(length == 32, "Log data should have length 32."); + solAssert(length == 32, "Log data should be 32 bytes long (for now)."); m_context << u256(length) << u256(0) << eth::logInstruction(logNumber); break; } @@ -487,7 +487,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) TypePointer const& keyType = dynamic_cast(*_indexAccess.getBaseExpression().getType()).getKeyType(); unsigned length = appendExpressionCopyToMemory(*keyType, _indexAccess.getIndexExpression()); - solAssert(length == 32, "Mapping key length in memory has to be 32."); + solAssert(length == 32, "Mapping key has to take 32 bytes in memory (for now)."); // @todo move this once we actually use memory length += CompilerUtils(m_context).storeInMemory(length); m_context << u256(length) << u256(0) << eth::Instruction::SHA3; diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index 18c3817a..caecbfe8 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -95,8 +95,8 @@ private: /// Appends code that copies the given arguments to memory (with optional offset). /// @returns the number of bytes copied to memory unsigned appendArgumentCopyToMemory(TypePointers const& _types, - std::vector> const& _arguments, - unsigned _memoryOffset = 0); + std::vector> 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, -- cgit From 8d5ee59ee5bd14ab31a6b6c10015df3334b6b641 Mon Sep 17 00:00:00 2001 From: Christian Date: Thu, 29 Jan 2015 20:02:23 +0100 Subject: Padding fixes. --- ExpressionCompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index db71b51d..7d58ea2e 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -828,7 +828,7 @@ unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedT { _expression.accept(*this); appendTypeConversion(*_expression.getType(), _expectedType, true); - unsigned const c_numBytes = _expectedType.getCalldataEncodedSize(); + unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize()); if (c_numBytes == 0 || c_numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) -- cgit