mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
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:
commit
8e84dc27a7
14
AST.cpp
14
AST.cpp
@ -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
49
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;
|
||||
|
||||
@ -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.
|
||||
|
@ -45,6 +45,7 @@ class FunctionDefinition;
|
||||
class VariableDeclaration;
|
||||
class ModifierDefinition;
|
||||
class ModifierInvocation;
|
||||
class EventDefinition;
|
||||
class MagicVariableDeclaration;
|
||||
class TypeName;
|
||||
class ElementaryTypeName;
|
||||
|
@ -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--;
|
||||
|
@ -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;
|
||||
|
@ -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&) { }
|
||||
|
20
AST_accept.h
20
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);
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
59
Parser.cpp
59
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()
|
||||
@ -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)
|
||||
{
|
||||
|
13
Parser.h
13
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();
|
||||
|
2
Token.h
2
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) \
|
||||
|
16
Types.cpp
16
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())
|
||||
|
4
Types.h
4
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),
|
||||
|
Loading…
Reference in New Issue
Block a user