aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGav Wood <g@ethdev.com>2015-01-30 07:44:42 +0800
committerGav Wood <g@ethdev.com>2015-01-30 07:44:42 +0800
commitdc6f9e3ac0370835b6db8136ba39ea7100ae93a1 (patch)
tree6b8c569ec7377da58425fe00b1ed6548f46855fb
parenta604202f33f1f7dc3abda1080e1bc02b2a2cbcb3 (diff)
parent8d5ee59ee5bd14ab31a6b6c10015df3334b6b641 (diff)
downloaddexon-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.cpp14
-rwxr-xr-xAST.h49
-rw-r--r--ASTForward.h1
-rw-r--r--ASTPrinter.cpp12
-rw-r--r--ASTPrinter.h2
-rw-r--r--ASTVisitor.h4
-rw-r--r--AST_accept.h20
-rw-r--r--ExpressionCompiler.cpp87
-rw-r--r--ExpressionCompiler.h7
-rw-r--r--NameAndTypeResolver.cpp8
-rw-r--r--NameAndTypeResolver.h1
-rw-r--r--Parser.cpp59
-rw-r--r--Parser.h13
-rw-r--r--Token.h2
-rw-r--r--Types.cpp16
-rw-r--r--Types.h4
16 files changed, 245 insertions, 54 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<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)
diff --git a/AST.h b/AST.h
index 6c207290..ab9815f6 100755
--- a/AST.h
+++ b/AST.h
@@ -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();
diff --git a/Parser.cpp b/Parser.cpp
index 5cfc8f46..48cca612 100644
--- a/Parser.cpp
+++ b/Parser.cpp
@@ -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)
{
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<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();
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<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())
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),