Browse Source

Inline member initialisation

renamed VariableDefinition class to VariableDeclarationStatement
added tests
cl-refactor
Liana Husikyan 10 years ago
parent
commit
87e956729c
  1. 22
      libsolidity/AST.cpp
  2. 21
      libsolidity/AST.h
  3. 2
      libsolidity/ASTForward.h
  4. 4
      libsolidity/ASTJsonConverter.cpp
  5. 4
      libsolidity/ASTJsonConverter.h
  6. 4
      libsolidity/ASTPrinter.cpp
  7. 4
      libsolidity/ASTPrinter.h
  8. 8
      libsolidity/ASTVisitor.h
  9. 12
      libsolidity/AST_accept.h
  10. 14
      libsolidity/Compiler.cpp
  11. 3
      libsolidity/Compiler.h
  12. 30
      libsolidity/ExpressionCompiler.cpp
  13. 13
      libsolidity/ExpressionCompiler.h
  14. 6
      libsolidity/NameAndTypeResolver.cpp
  15. 2
      libsolidity/NameAndTypeResolver.h
  16. 43
      libsolidity/Parser.cpp
  17. 9
      libsolidity/Parser.h
  18. 2
      libsolidity/Types.cpp
  19. 55
      test/SolidityEndToEndTest.cpp

22
libsolidity/AST.cpp

@ -77,6 +77,9 @@ void ContractDefinition::checkTypeRequirements()
for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions())
function->checkTypeRequirements(); function->checkTypeRequirements();
for (ASTPointer<VariableDeclaration> const& variable: m_stateVariables)
variable->checkTypeRequirements();
// check for hash collisions in function signatures // check for hash collisions in function signatures
set<FixedHash<4>> hashes; set<FixedHash<4>> hashes;
for (auto const& it: getInterfaceFunctionList()) for (auto const& it: getInterfaceFunctionList())
@ -294,6 +297,12 @@ bool VariableDeclaration::isLValue() const
return !isExternalFunctionParameter(); return !isExternalFunctionParameter();
} }
void VariableDeclaration::checkTypeRequirements()
{
if (m_value)
m_value->checkTypeRequirements();
}
bool VariableDeclaration::isExternalFunctionParameter() const bool VariableDeclaration::isExternalFunctionParameter() const
{ {
auto const* function = dynamic_cast<FunctionDefinition const*>(getScope()); auto const* function = dynamic_cast<FunctionDefinition const*>(getScope());
@ -390,26 +399,26 @@ void Return::checkTypeRequirements()
m_expression->expectType(*m_returnParameters->getParameters().front()->getType()); m_expression->expectType(*m_returnParameters->getParameters().front()->getType());
} }
void VariableDefinition::checkTypeRequirements() void VariableDeclarationStatement::checkTypeRequirements()
{ {
// Variables can be declared without type (with "var"), in which case the first assignment // Variables can be declared without type (with "var"), in which case the first assignment
// sets the type. // sets the type.
// Note that assignments before the first declaration are legal because of the special scoping // Note that assignments before the first declaration are legal because of the special scoping
// rules inherited from JavaScript. // rules inherited from JavaScript.
if (m_value) if (m_variable->getValue())
{ {
if (m_variable->getType()) if (m_variable->getType())
m_value->expectType(*m_variable->getType()); m_variable->getValue()->expectType(*m_variable->getType());
else else
{ {
// no type declared and no previous assignment, infer the type // no type declared and no previous assignment, infer the type
m_value->checkTypeRequirements(); m_variable->getValue()->checkTypeRequirements();
TypePointer type = m_value->getType(); TypePointer type = m_variable->getValue()->getType();
if (type->getCategory() == Type::Category::IntegerConstant) if (type->getCategory() == Type::Category::IntegerConstant)
{ {
auto intType = dynamic_pointer_cast<IntegerConstantType const>(type)->getIntegerType(); auto intType = dynamic_pointer_cast<IntegerConstantType const>(type)->getIntegerType();
if (!intType) if (!intType)
BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString())); BOOST_THROW_EXCEPTION(m_variable->getValue()->createTypeError("Invalid integer constant " + type->toString()));
type = intType; type = intType;
} }
else if (type->getCategory() == Type::Category::Void) else if (type->getCategory() == Type::Category::Void)
@ -418,7 +427,6 @@ void VariableDefinition::checkTypeRequirements()
} }
} }
} }
void Assignment::checkTypeRequirements() void Assignment::checkTypeRequirements()
{ {
m_leftHandSide->checkTypeRequirements(); m_leftHandSide->checkTypeRequirements();

21
libsolidity/AST.h

@ -432,14 +432,17 @@ class VariableDeclaration: public Declaration
{ {
public: public:
VariableDeclaration(Location const& _location, ASTPointer<TypeName> const& _type, VariableDeclaration(Location const& _location, ASTPointer<TypeName> const& _type,
ASTPointer<ASTString> const& _name, Visibility _visibility, ASTPointer<ASTString> const& _name, ASTPointer<Expression> _value,
Visibility _visibility,
bool _isStateVar = false, bool _isIndexed = false): bool _isStateVar = false, bool _isIndexed = false):
Declaration(_location, _name, _visibility), m_typeName(_type), Declaration(_location, _name, _visibility),
m_typeName(_type), m_value(_value),
m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {} m_isStateVariable(_isStateVar), m_isIndexed(_isIndexed) {}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override; virtual void accept(ASTConstVisitor& _visitor) const override;
TypeName const* getTypeName() const { return m_typeName.get(); } TypeName const* getTypeName() const { return m_typeName.get(); }
ASTPointer<Expression> const& getValue() const { return m_value; }
/// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly /// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly
/// declared and there is no assignment to the variable that fixes the type. /// declared and there is no assignment to the variable that fixes the type.
@ -447,6 +450,9 @@ public:
void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; } void setType(std::shared_ptr<Type const> const& _type) { m_type = _type; }
virtual bool isLValue() const override; virtual bool isLValue() const override;
/// Checks that all parameters have allowed types and calls checkTypeRequirements on the body.
void checkTypeRequirements();
bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); } bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(getScope()); }
bool isExternalFunctionParameter() const; bool isExternalFunctionParameter() const;
bool isStateVariable() const { return m_isStateVariable; } bool isStateVariable() const { return m_isStateVariable; }
@ -457,6 +463,7 @@ protected:
private: private:
ASTPointer<TypeName> m_typeName; ///< can be empty ("var") ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
ASTPointer<Expression> m_value; ///< the assigned value, can be missing
bool m_isStateVariable; ///< Whether or not this is a contract state variable bool m_isStateVariable; ///< Whether or not this is a contract state variable
bool m_isIndexed; ///< Whether this is an indexed variable (used by events). bool m_isIndexed; ///< Whether this is an indexed variable (used by events).
@ -833,22 +840,20 @@ private:
* also be "var") but the actual assignment can be missing. * also be "var") but the actual assignment can be missing.
* Examples: var a = 2; uint256 a; * Examples: var a = 2; uint256 a;
*/ */
class VariableDefinition: public Statement class VariableDeclarationStatement: public Statement
{ {
public: public:
VariableDefinition(Location const& _location, ASTPointer<VariableDeclaration> _variable, VariableDeclarationStatement(Location const& _location, ASTPointer<VariableDeclaration> _variable):
ASTPointer<Expression> _value): Statement(_location), m_variable(_variable) {}
Statement(_location), m_variable(_variable), m_value(_value) {}
virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override; virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override; virtual void checkTypeRequirements() override;
VariableDeclaration const& getDeclaration() const { return *m_variable; } VariableDeclaration const& getDeclaration() const { return *m_variable; }
Expression const* getExpression() const { return m_value.get(); } Expression const* getExpression() const { return m_variable->getValue().get(); }
private: private:
ASTPointer<VariableDeclaration> m_variable; ASTPointer<VariableDeclaration> m_variable;
ASTPointer<Expression> m_value; ///< the assigned value, can be missing
}; };
/** /**

2
libsolidity/ASTForward.h

@ -63,7 +63,7 @@ class ForStatement;
class Continue; class Continue;
class Break; class Break;
class Return; class Return;
class VariableDefinition; class VariableDeclarationStatement;
class ExpressionStatement; class ExpressionStatement;
class Expression; class Expression;
class Assignment; class Assignment;

4
libsolidity/ASTJsonConverter.cpp

@ -198,7 +198,7 @@ bool ASTJsonConverter::visit(Return const&)
return true; return true;
} }
bool ASTJsonConverter::visit(VariableDefinition const&) bool ASTJsonConverter::visit(VariableDeclarationStatement const&)
{ {
addJsonNode("VariableDefinition", {}, true); addJsonNode("VariableDefinition", {}, true);
return true; return true;
@ -394,7 +394,7 @@ void ASTJsonConverter::endVisit(Return const&)
goUp(); goUp();
} }
void ASTJsonConverter::endVisit(VariableDefinition const&) void ASTJsonConverter::endVisit(VariableDeclarationStatement const&)
{ {
goUp(); goUp();
} }

4
libsolidity/ASTJsonConverter.h

@ -64,7 +64,7 @@ public:
bool visit(Continue const& _node) override; bool visit(Continue const& _node) override;
bool visit(Break const& _node) override; bool visit(Break const& _node) override;
bool visit(Return const& _node) override; bool visit(Return const& _node) override;
bool visit(VariableDefinition const& _node) override; bool visit(VariableDeclarationStatement const& _node) override;
bool visit(ExpressionStatement const& _node) override; bool visit(ExpressionStatement const& _node) override;
bool visit(Expression const& _node) override; bool visit(Expression const& _node) override;
bool visit(Assignment const& _node) override; bool visit(Assignment const& _node) override;
@ -98,7 +98,7 @@ public:
void endVisit(Continue const&) override; void endVisit(Continue const&) override;
void endVisit(Break const&) override; void endVisit(Break const&) override;
void endVisit(Return const&) override; void endVisit(Return const&) override;
void endVisit(VariableDefinition const&) override; void endVisit(VariableDeclarationStatement const&) override;
void endVisit(ExpressionStatement const&) override; void endVisit(ExpressionStatement const&) override;
void endVisit(Expression const&) override; void endVisit(Expression const&) override;
void endVisit(Assignment const&) override; void endVisit(Assignment const&) override;

4
libsolidity/ASTPrinter.cpp

@ -225,7 +225,7 @@ bool ASTPrinter::visit(Return const& _node)
return goDeeper(); return goDeeper();
} }
bool ASTPrinter::visit(VariableDefinition const& _node) bool ASTPrinter::visit(VariableDeclarationStatement const& _node)
{ {
writeLine("VariableDefinition"); writeLine("VariableDefinition");
printSourcePart(_node); printSourcePart(_node);
@ -469,7 +469,7 @@ void ASTPrinter::endVisit(Return const&)
m_indentation--; m_indentation--;
} }
void ASTPrinter::endVisit(VariableDefinition const&) void ASTPrinter::endVisit(VariableDeclarationStatement const&)
{ {
m_indentation--; m_indentation--;
} }

4
libsolidity/ASTPrinter.h

@ -68,7 +68,7 @@ public:
bool visit(Continue const& _node) override; bool visit(Continue const& _node) override;
bool visit(Break const& _node) override; bool visit(Break const& _node) override;
bool visit(Return const& _node) override; bool visit(Return const& _node) override;
bool visit(VariableDefinition const& _node) override; bool visit(VariableDeclarationStatement const& _node) override;
bool visit(ExpressionStatement const& _node) override; bool visit(ExpressionStatement const& _node) override;
bool visit(Expression const& _node) override; bool visit(Expression const& _node) override;
bool visit(Assignment const& _node) override; bool visit(Assignment const& _node) override;
@ -109,7 +109,7 @@ public:
void endVisit(Continue const&) override; void endVisit(Continue const&) override;
void endVisit(Break const&) override; void endVisit(Break const&) override;
void endVisit(Return const&) override; void endVisit(Return const&) override;
void endVisit(VariableDefinition const&) override; void endVisit(VariableDeclarationStatement const&) override;
void endVisit(ExpressionStatement const&) override; void endVisit(ExpressionStatement const&) override;
void endVisit(Expression const&) override; void endVisit(Expression const&) override;
void endVisit(Assignment const&) override; void endVisit(Assignment const&) override;

8
libsolidity/ASTVisitor.h

@ -69,7 +69,7 @@ public:
virtual bool visit(Continue&) { return true; } virtual bool visit(Continue&) { return true; }
virtual bool visit(Break&) { return true; } virtual bool visit(Break&) { return true; }
virtual bool visit(Return&) { return true; } virtual bool visit(Return&) { return true; }
virtual bool visit(VariableDefinition&) { return true; } virtual bool visit(VariableDeclarationStatement&) { return true; }
virtual bool visit(ExpressionStatement&) { return true; } virtual bool visit(ExpressionStatement&) { return true; }
virtual bool visit(Expression&) { return true; } virtual bool visit(Expression&) { return true; }
virtual bool visit(Assignment&) { return true; } virtual bool visit(Assignment&) { return true; }
@ -112,7 +112,7 @@ public:
virtual void endVisit(Continue&) { } virtual void endVisit(Continue&) { }
virtual void endVisit(Break&) { } virtual void endVisit(Break&) { }
virtual void endVisit(Return&) { } virtual void endVisit(Return&) { }
virtual void endVisit(VariableDefinition&) { } virtual void endVisit(VariableDeclarationStatement&) { }
virtual void endVisit(ExpressionStatement&) { } virtual void endVisit(ExpressionStatement&) { }
virtual void endVisit(Expression&) { } virtual void endVisit(Expression&) { }
virtual void endVisit(Assignment&) { } virtual void endVisit(Assignment&) { }
@ -159,7 +159,7 @@ public:
virtual bool visit(Continue const&) { return true; } virtual bool visit(Continue const&) { return true; }
virtual bool visit(Break const&) { return true; } virtual bool visit(Break const&) { return true; }
virtual bool visit(Return const&) { return true; } virtual bool visit(Return const&) { return true; }
virtual bool visit(VariableDefinition const&) { return true; } virtual bool visit(VariableDeclarationStatement const&) { return true; }
virtual bool visit(ExpressionStatement const&) { return true; } virtual bool visit(ExpressionStatement const&) { return true; }
virtual bool visit(Expression const&) { return true; } virtual bool visit(Expression const&) { return true; }
virtual bool visit(Assignment const&) { return true; } virtual bool visit(Assignment const&) { return true; }
@ -202,7 +202,7 @@ public:
virtual void endVisit(Continue const&) { } virtual void endVisit(Continue const&) { }
virtual void endVisit(Break const&) { } virtual void endVisit(Break const&) { }
virtual void endVisit(Return const&) { } virtual void endVisit(Return const&) { }
virtual void endVisit(VariableDefinition const&) { } virtual void endVisit(VariableDeclarationStatement const&) { }
virtual void endVisit(ExpressionStatement const&) { } virtual void endVisit(ExpressionStatement const&) { }
virtual void endVisit(Expression const&) { } virtual void endVisit(Expression const&) { }
virtual void endVisit(Assignment const&) { } virtual void endVisit(Assignment const&) { }

12
libsolidity/AST_accept.h

@ -475,24 +475,24 @@ void ExpressionStatement::accept(ASTConstVisitor& _visitor) const
_visitor.endVisit(*this); _visitor.endVisit(*this);
} }
void VariableDefinition::accept(ASTVisitor& _visitor) void VariableDeclarationStatement::accept(ASTVisitor& _visitor)
{ {
if (_visitor.visit(*this)) if (_visitor.visit(*this))
{ {
m_variable->accept(_visitor); m_variable->accept(_visitor);
if (m_value) if (m_variable->getValue())
m_value->accept(_visitor); m_variable->getValue()->accept(_visitor);
} }
_visitor.endVisit(*this); _visitor.endVisit(*this);
} }
void VariableDefinition::accept(ASTConstVisitor& _visitor) const void VariableDeclarationStatement::accept(ASTConstVisitor& _visitor) const
{ {
if (_visitor.visit(*this)) if (_visitor.visit(*this))
{ {
m_variable->accept(_visitor); m_variable->accept(_visitor);
if (m_value) if (m_variable->getValue())
m_value->accept(_visitor); m_variable->getValue()->accept(_visitor);
} }
_visitor.endVisit(*this); _visitor.endVisit(*this);
} }

14
libsolidity/Compiler.cpp

@ -85,12 +85,14 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract, Comp
{ {
ContractDefinition const* base = bases[bases.size() - i]; ContractDefinition const* base = bases[bases.size() - i];
solAssert(base, ""); solAssert(base, "");
initializeStateVariables(*base);
FunctionDefinition const* baseConstructor = base->getConstructor(); FunctionDefinition const* baseConstructor = base->getConstructor();
if (!baseConstructor) if (!baseConstructor)
continue; continue;
solAssert(baseArguments[base], ""); solAssert(baseArguments[base], "");
appendBaseConstructorCall(*baseConstructor, *baseArguments[base]); appendBaseConstructorCall(*baseConstructor, *baseArguments[base]);
} }
initializeStateVariables(_contract);
if (_contract.getConstructor()) if (_contract.getConstructor())
appendConstructorCall(*_contract.getConstructor()); appendConstructorCall(*_contract.getConstructor());
@ -247,6 +249,16 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract)
m_context.addStateVariable(*variable); m_context.addStateVariable(*variable);
} }
void Compiler::initializeStateVariables(ContractDefinition const& _contract)
{
for(ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables())
if (variable->getValue())
{
compileExpression(*(variable->getValue()), (variable->getValue())->getType());
ExpressionCompiler::appendStateVariableInitialization(m_context, *variable);
}
}
bool Compiler::visit(VariableDeclaration const& _variableDeclaration) bool Compiler::visit(VariableDeclaration const& _variableDeclaration)
{ {
solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration."); solAssert(_variableDeclaration.isStateVariable(), "Compiler visit to non-state variable declaration.");
@ -429,7 +441,7 @@ bool Compiler::visit(Return const& _return)
return false; return false;
} }
bool Compiler::visit(VariableDefinition const& _variableDefinition) bool Compiler::visit(VariableDeclarationStatement const& _variableDefinition)
{ {
if (Expression const* expression = _variableDefinition.getExpression()) if (Expression const* expression = _variableDefinition.getExpression())
{ {

3
libsolidity/Compiler.h

@ -59,6 +59,7 @@ private:
void appendReturnValuePacker(TypePointers const& _typeParameters); void appendReturnValuePacker(TypePointers const& _typeParameters);
void registerStateVariables(ContractDefinition const& _contract); void registerStateVariables(ContractDefinition const& _contract);
void initializeStateVariables(ContractDefinition const& _contract);
virtual bool visit(VariableDeclaration const& _variableDeclaration) override; virtual bool visit(VariableDeclaration const& _variableDeclaration) override;
virtual bool visit(FunctionDefinition const& _function) override; virtual bool visit(FunctionDefinition const& _function) override;
@ -68,7 +69,7 @@ private:
virtual bool visit(Continue const& _continue) override; virtual bool visit(Continue const& _continue) override;
virtual bool visit(Break const& _break) override; virtual bool visit(Break const& _break) override;
virtual bool visit(Return const& _return) override; virtual bool visit(Return const& _return) override;
virtual bool visit(VariableDefinition const& _variableDefinition) override; virtual bool visit(VariableDeclarationStatement const& _variableDefinition) override;
virtual bool visit(ExpressionStatement const& _expressionStatement) override; virtual bool visit(ExpressionStatement const& _expressionStatement) override;
virtual bool visit(PlaceholderStatement const&) override; virtual bool visit(PlaceholderStatement const&) override;

30
libsolidity/ExpressionCompiler.cpp

@ -56,6 +56,19 @@ void ExpressionCompiler::appendStateVariableAccessor(CompilerContext& _context,
compiler.appendStateVariableAccessor(_varDecl); compiler.appendStateVariableAccessor(_varDecl);
} }
void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize)
{
ExpressionCompiler compiler(_context, _optimize);
compiler.appendStateVariableInitialization(_varDecl);
}
void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl)
{
m_currentLValue.fromStateVariable(_varDecl);
m_currentLValue.storeValue(*_varDecl.getType(), _varDecl.getLocation());
m_currentLValue.reset();
}
bool ExpressionCompiler::visit(Assignment const& _assignment) bool ExpressionCompiler::visit(Assignment const& _assignment)
{ {
_assignment.getRightHandSide().accept(*this); _assignment.getRightHandSide().accept(*this);
@ -77,7 +90,6 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
} }
m_currentLValue.storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation()); m_currentLValue.storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation());
m_currentLValue.reset(); m_currentLValue.reset();
return false; return false;
} }
@ -1018,12 +1030,24 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D
m_dataType = _identifier.getType(); m_dataType = _identifier.getType();
solAssert(m_dataType->getStorageSize() <= numeric_limits<unsigned>::max(), solAssert(m_dataType->getStorageSize() <= numeric_limits<unsigned>::max(),
"The storage size of " + m_dataType->toString() + " should fit in an unsigned"); "The storage size of " + m_dataType->toString() + " should fit in an unsigned");
m_size = unsigned(m_dataType->getStorageSize()); } m_size = unsigned(m_dataType->getStorageSize());
}
else else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation()) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation())
<< errinfo_comment("Identifier type not supported or identifier not found.")); << errinfo_comment("Identifier type not supported or identifier not found."));
} }
void ExpressionCompiler::LValue::fromStateVariable(VariableDeclaration const& _declaration)
{
solAssert(m_context->isStateVariable(&_declaration), "Not a state variable.");
*m_context << m_context->getStorageLocationOfVariable(_declaration);
m_type = LValueType::Storage;
m_dataType = _declaration.getType();
solAssert(m_dataType->getStorageSize() <= numeric_limits<unsigned>::max(),
"The storage size of " + m_dataType->toString() + " should fit in an unsigned");
m_size = unsigned(m_dataType->getStorageSize());
}
void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _remove) const void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _remove) const
{ {
switch (m_type) switch (m_type)
@ -1117,7 +1141,7 @@ void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location co
} }
else else
{ {
solAssert(_sourceType.getCategory() == m_dataType->getCategory(), ""); solAssert(_sourceType.getCategory() == m_dataType->getCategory(), "Wrong type conversation for assignment.");
if (m_dataType->getCategory() == Type::Category::ByteArray) if (m_dataType->getCategory() == Type::Category::ByteArray)
{ {
CompilerUtils(*m_context).copyByteArrayToStorage( CompilerUtils(*m_context).copyByteArrayToStorage(

13
libsolidity/ExpressionCompiler.h

@ -59,6 +59,9 @@ public:
/// Appends code for a State Variable accessor function /// Appends code for a State Variable accessor function
static void appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false); static void appendStateVariableAccessor(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false);
/// Appends code for a State Variable Initialization function
static void appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize = false);
private: private:
explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false): explicit ExpressionCompiler(CompilerContext& _compilerContext, bool _optimize = false):
m_optimize(_optimize), m_context(_compilerContext), m_currentLValue(m_context) {} m_optimize(_optimize), m_context(_compilerContext), m_currentLValue(m_context) {}
@ -111,6 +114,9 @@ private:
/// Appends code for a State Variable accessor function /// Appends code for a State Variable accessor function
void appendStateVariableAccessor(VariableDeclaration const& _varDecl); void appendStateVariableAccessor(VariableDeclaration const& _varDecl);
/// Appends code for a State Variable initialization
void appendStateVariableInitialization(VariableDeclaration const& _varDecl);
/** /**
* Helper class to store and retrieve lvalues to and from various locations. * Helper class to store and retrieve lvalues to and from various locations.
* All types except STACK store a reference in a slot on the stack, STACK just * All types except STACK store a reference in a slot on the stack, STACK just
@ -126,8 +132,13 @@ private:
std::shared_ptr<Type const> const& _dataType, unsigned _baseStackOffset = 0); std::shared_ptr<Type const> const& _dataType, unsigned _baseStackOffset = 0);
/// Set type according to the declaration and retrieve the reference. /// Set type according to the declaration and retrieve the reference.
/// @a _expression is the current expression /// @a _identifier is the current identifier
void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration); void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration);
/// Set type according to the declaration and retrieve the reference.
/// @a _declaration is the variable declaration
void fromStateVariable(VariableDeclaration const& _declaration);
void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; } void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; }
bool isValid() const { return m_type != LValueType::None; } bool isValid() const { return m_type != LValueType::None; }

6
libsolidity/NameAndTypeResolver.cpp

@ -267,12 +267,12 @@ void DeclarationRegistrationHelper::endVisit(ModifierDefinition&)
closeCurrentScope(); closeCurrentScope();
} }
void DeclarationRegistrationHelper::endVisit(VariableDefinition& _variableDefinition) void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _variableDeclarationStatement)
{ {
// Register the local variables with the function // Register the local variables with the function
// This does not fit here perfectly, but it saves us another AST visit. // This does not fit here perfectly, but it saves us another AST visit.
solAssert(m_currentFunction, "Variable definition without function."); solAssert(m_currentFunction, "Variable declaration without function.");
m_currentFunction->addLocalVariable(_variableDefinition.getDeclaration()); m_currentFunction->addLocalVariable(_variableDeclarationStatement.getDeclaration());
} }
bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration) bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration)

2
libsolidity/NameAndTypeResolver.h

@ -105,7 +105,7 @@ private:
void endVisit(FunctionDefinition& _function) override; void endVisit(FunctionDefinition& _function) override;
bool visit(ModifierDefinition& _modifier) override; bool visit(ModifierDefinition& _modifier) override;
void endVisit(ModifierDefinition& _modifier) override; void endVisit(ModifierDefinition& _modifier) override;
void endVisit(VariableDefinition& _variableDefinition) override; void endVisit(VariableDeclarationStatement& _variableDeclarationStatement) override;
bool visit(VariableDeclaration& _declaration) override; bool visit(VariableDeclaration& _declaration) override;
bool visit(EventDefinition& _event) override; bool visit(EventDefinition& _event) override;
void endVisit(EventDefinition& _event) override; void endVisit(EventDefinition& _event) override;

43
libsolidity/Parser.cpp

@ -148,6 +148,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
{ {
VarDeclParserOptions options; VarDeclParserOptions options;
options.isStateVariable = true; options.isStateVariable = true;
options.allowInitialValue = true;
stateVariables.push_back(parseVariableDeclaration(options)); stateVariables.push_back(parseVariableDeclaration(options));
expectToken(Token::Semicolon); expectToken(Token::Semicolon);
} }
@ -324,7 +325,17 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(VarDeclParserOp
} }
else else
identifier = expectIdentifierToken(); identifier = expectIdentifierToken();
return nodeFactory.createNode<VariableDeclaration>(type, identifier, ASTPointer<Expression> value;
if (_options.allowInitialValue)
{
if (m_scanner->getCurrentToken() == Token::Assign)
{
m_scanner->next();
value = parseExpression();
nodeFactory.setEndPositionFromNode(value);
}
}
return nodeFactory.createNode<VariableDeclaration>(type, identifier, value,
visibility, _options.isStateVariable, visibility, _options.isStateVariable,
isIndexed); isIndexed);
} }
@ -519,7 +530,7 @@ ASTPointer<Statement> Parser::parseStatement()
} }
// fall-through // fall-through
default: default:
statement = parseVarDefOrExprStmt(); statement = parseVarDeclOrExprStmt();
} }
expectToken(Token::Semicolon); expectToken(Token::Semicolon);
return statement; return statement;
@ -568,7 +579,7 @@ ASTPointer<ForStatement> Parser::parseForStatement()
// LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen? // LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RParen?
if (m_scanner->getCurrentToken() != Token::Semicolon) if (m_scanner->getCurrentToken() != Token::Semicolon)
initExpression = parseVarDefOrExprStmt(); initExpression = parseVarDeclOrExprStmt();
expectToken(Token::Semicolon); expectToken(Token::Semicolon);
if (m_scanner->getCurrentToken() != Token::Semicolon) if (m_scanner->getCurrentToken() != Token::Semicolon)
@ -587,30 +598,22 @@ ASTPointer<ForStatement> Parser::parseForStatement()
body); body);
} }
ASTPointer<Statement> Parser::parseVarDefOrExprStmt() ASTPointer<Statement> Parser::parseVarDeclOrExprStmt()
{ {
if (peekVariableDefinition()) if (peekVariableDeclarationStatement())
return parseVariableDefinition(); return parseVariableDeclarationStatement();
else else
return parseExpressionStatement(); return parseExpressionStatement();
} }
ASTPointer<VariableDefinition> Parser::parseVariableDefinition() ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStatement()
{ {
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
VarDeclParserOptions options; VarDeclParserOptions options;
options.allowVar = true; options.allowVar = true;
options.allowInitialValue = true;
ASTPointer<VariableDeclaration> variable = parseVariableDeclaration(options); ASTPointer<VariableDeclaration> variable = parseVariableDeclaration(options);
ASTPointer<Expression> value; return nodeFactory.createNode<VariableDeclarationStatement>(variable);
if (m_scanner->getCurrentToken() == Token::Assign)
{
m_scanner->next();
value = parseExpression();
nodeFactory.setEndPositionFromNode(value);
}
else
nodeFactory.setEndPositionFromNode(variable);
return nodeFactory.createNode<VariableDefinition>(variable, value);
} }
ASTPointer<ExpressionStatement> Parser::parseExpressionStatement() ASTPointer<ExpressionStatement> Parser::parseExpressionStatement()
@ -822,11 +825,11 @@ pair<vector<ASTPointer<Expression>>, vector<ASTPointer<ASTString>>> Parser::pars
} }
bool Parser::peekVariableDefinition() bool Parser::peekVariableDeclarationStatement()
{ {
// distinguish between variable definition (and potentially assignment) and expression statement // distinguish between variable declaration (and potentially assignment) and expression statement
// (which include assignments to other expressions and pre-declared variables) // (which include assignments to other expressions and pre-declared variables)
// We have a variable definition if we get a keyword that specifies a type name, or // We have a variable declaration if we get a keyword that specifies a type name, or
// in the case of a user-defined type, we have two identifiers following each other. // in the case of a user-defined type, we have two identifiers following each other.
return (m_scanner->getCurrentToken() == Token::Mapping || return (m_scanner->getCurrentToken() == Token::Mapping ||
m_scanner->getCurrentToken() == Token::Var || m_scanner->getCurrentToken() == Token::Var ||

9
libsolidity/Parser.h

@ -51,6 +51,7 @@ private:
bool isStateVariable = false; bool isStateVariable = false;
bool allowIndexed = false; bool allowIndexed = false;
bool allowEmptyName = false; bool allowEmptyName = false;
bool allowInitialValue = false;
}; };
///@{ ///@{
@ -76,8 +77,8 @@ private:
ASTPointer<IfStatement> parseIfStatement(); ASTPointer<IfStatement> parseIfStatement();
ASTPointer<WhileStatement> parseWhileStatement(); ASTPointer<WhileStatement> parseWhileStatement();
ASTPointer<ForStatement> parseForStatement(); ASTPointer<ForStatement> parseForStatement();
ASTPointer<Statement> parseVarDefOrExprStmt(); ASTPointer<Statement> parseVarDeclOrExprStmt();
ASTPointer<VariableDefinition> parseVariableDefinition(); ASTPointer<VariableDeclarationStatement> parseVariableDeclarationStatement();
ASTPointer<ExpressionStatement> parseExpressionStatement(); ASTPointer<ExpressionStatement> parseExpressionStatement();
ASTPointer<Expression> parseExpression(); ASTPointer<Expression> parseExpression();
ASTPointer<Expression> parseBinaryExpression(int _minPrecedence = 4); ASTPointer<Expression> parseBinaryExpression(int _minPrecedence = 4);
@ -91,8 +92,8 @@ private:
///@{ ///@{
///@name Helper functions ///@name Helper functions
/// Peeks ahead in the scanner to determine if a variable definition is going to follow /// Peeks ahead in the scanner to determine if a variable declaration statement is going to follow
bool peekVariableDefinition(); bool peekVariableDeclarationStatement();
/// If current token value is not _value, throw exception otherwise advance token. /// If current token value is not _value, throw exception otherwise advance token.
void expectToken(Token::Value _value); void expectToken(Token::Value _value);

2
libsolidity/Types.cpp

@ -653,7 +653,7 @@ MemberList const& StructType::getMembers() const
// We need to lazy-initialize it because of recursive references. // We need to lazy-initialize it because of recursive references.
if (!m_members) if (!m_members)
{ {
vector<pair<string, TypePointer>> members; MemberList::MemberMap members;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers()) for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
members.push_back(make_pair(variable->getName(), variable->getType())); members.push_back(make_pair(variable->getName(), variable->getType()));
m_members.reset(new MemberList(members)); m_members.reset(new MemberList(members));

55
test/SolidityEndToEndTest.cpp

@ -2570,6 +2570,61 @@ BOOST_AUTO_TEST_CASE(constructing_enums_from_ints)
BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); BOOST_CHECK(callContractFunction("test()") == encodeArgs(1));
} }
BOOST_AUTO_TEST_CASE(inline_member_init)
{
char const* sourceCode = R"(
contract test {
function test(){
m_b = 6;
m_c = 8;
}
uint m_a = 5;
uint m_b;
uint m_c = 7;
function get() returns (uint a, uint b, uint c){
a = m_a;
b = m_b;
c = m_c;
}
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("get()") == encodeArgs(5, 6, 8));
}
BOOST_AUTO_TEST_CASE(inline_member_init_inheritence)
{
char const* sourceCode = R"(
contract Base {
function Base(){}
uint m_base = 5;
function getBMember() returns (uint i) { return m_base; }
}
contract Derived is Base {
function Derived(){}
uint m_derived = 6;
function getDMember() returns (uint i) { return m_derived; }
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("getBMember()") == encodeArgs(5));
BOOST_CHECK(callContractFunction("getDMember()") == encodeArgs(6));
}
BOOST_AUTO_TEST_CASE(inline_member_init_inheritence_without_constructor)
{
char const* sourceCode = R"(
contract Base {
uint m_base = 5;
function getBMember() returns (uint i) { return m_base; }
}
contract Derived is Base {
uint m_derived = 6;
function getDMember() returns (uint i) { return m_derived; }
})";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("getBMember()") == encodeArgs(5));
BOOST_CHECK(callContractFunction("getDMember()") == encodeArgs(6));
}
BOOST_AUTO_TEST_CASE(external_function) BOOST_AUTO_TEST_CASE(external_function)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(

Loading…
Cancel
Save