Merge branch 'develop' of github.com:ethereum/cpp-ethereum into develop

Conflicts:
	test/SolidityEndToEndTest.cpp
	test/SolidityNameAndTypeResolution.cpp
	test/SolidityParser.cpp
This commit is contained in:
Gav Wood 2015-01-29 16:05:17 -08:00
commit 8e84dc27a7
16 changed files with 245 additions and 54 deletions

14
AST.cpp
View File

@ -285,6 +285,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)

49
AST.h
View File

@ -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;
@ -250,6 +253,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;
@ -382,8 +386,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;
@ -398,12 +404,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
};
@ -431,7 +438,6 @@ public:
virtual TypePointer getType(ContractDefinition const* = nullptr) const override;
void checkTypeRequirements();
private:
@ -462,6 +468,37 @@ private:
std::vector<ASTPointer<Expression>> m_arguments;
};
/**
* 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.

View File

@ -45,6 +45,7 @@ class FunctionDefinition;
class VariableDeclaration;
class ModifierDefinition;
class ModifierInvocation;
class EventDefinition;
class MagicVariableDeclaration;
class TypeName;
class ElementaryTypeName;

View File

@ -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--;

View File

@ -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;

View File

@ -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&) { }

View File

@ -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);

View File

@ -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());

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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()
@ -240,8 +245,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();
@ -249,12 +253,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()
@ -284,6 +296,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);
@ -356,19 +385,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();
@ -510,8 +540,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)
{

View File

@ -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();

View File

@ -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) \

View File

@ -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())

View File

@ -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),