mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #1093 from LianaHus/sol_InlineMemberInits
Inline member inits
This commit is contained in:
commit
75498a48d8
22
AST.cpp
22
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
AST.h
21
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;
|
||||||
|
|
||||||
|
/// Calls checkTypeRequirments for all state variables.
|
||||||
|
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
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -225,9 +225,9 @@ 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("VariableDeclarationStatement");
|
||||||
printSourcePart(_node);
|
printSourcePart(_node);
|
||||||
return goDeeper();
|
return goDeeper();
|
||||||
}
|
}
|
||||||
@ -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--;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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&) { }
|
||||||
|
20
AST_accept.h
20
AST_accept.h
@ -196,16 +196,24 @@ void FunctionDefinition::accept(ASTConstVisitor& _visitor) const
|
|||||||
void VariableDeclaration::accept(ASTVisitor& _visitor)
|
void VariableDeclaration::accept(ASTVisitor& _visitor)
|
||||||
{
|
{
|
||||||
if (_visitor.visit(*this))
|
if (_visitor.visit(*this))
|
||||||
|
{
|
||||||
if (m_typeName)
|
if (m_typeName)
|
||||||
m_typeName->accept(_visitor);
|
m_typeName->accept(_visitor);
|
||||||
|
if (m_value)
|
||||||
|
m_value->accept(_visitor);
|
||||||
|
}
|
||||||
_visitor.endVisit(*this);
|
_visitor.endVisit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VariableDeclaration::accept(ASTConstVisitor& _visitor) const
|
void VariableDeclaration::accept(ASTConstVisitor& _visitor) const
|
||||||
{
|
{
|
||||||
if (_visitor.visit(*this))
|
if (_visitor.visit(*this))
|
||||||
|
{
|
||||||
if (m_typeName)
|
if (m_typeName)
|
||||||
m_typeName->accept(_visitor);
|
m_typeName->accept(_visitor);
|
||||||
|
if (m_value)
|
||||||
|
m_value->accept(_visitor);
|
||||||
|
}
|
||||||
_visitor.endVisit(*this);
|
_visitor.endVisit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,25 +483,17 @@ 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)
|
|
||||||
m_value->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)
|
|
||||||
m_value->accept(_visitor);
|
|
||||||
}
|
|
||||||
_visitor.endVisit(*this);
|
_visitor.endVisit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
Compiler.cpp
11
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,13 @@ 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())
|
||||||
|
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 +438,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())
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -56,6 +56,23 @@ void ExpressionCompiler::appendStateVariableAccessor(CompilerContext& _context,
|
|||||||
compiler.appendStateVariableAccessor(_varDecl);
|
compiler.appendStateVariableAccessor(_varDecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExpressionCompiler::appendStateVariableInitialization(CompilerContext& _context, VariableDeclaration const& _varDecl, bool _optimize)
|
||||||
|
{
|
||||||
|
compileExpression(_context, *(_varDecl.getValue()), _optimize);
|
||||||
|
if (_varDecl.getValue()->getType())
|
||||||
|
appendTypeConversion(_context, *(_varDecl.getValue())->getType(), *(_varDecl.getValue())->getType());
|
||||||
|
|
||||||
|
ExpressionCompiler compiler(_context, _optimize);
|
||||||
|
compiler.appendStateVariableInitialization(_varDecl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration const& _varDecl)
|
||||||
|
{
|
||||||
|
LValue var = LValue(m_context);
|
||||||
|
var.fromDeclaration(_varDecl, _varDecl.getValue()->getLocation());
|
||||||
|
var.storeValue(*_varDecl.getType(), _varDecl.getLocation());
|
||||||
|
}
|
||||||
|
|
||||||
bool ExpressionCompiler::visit(Assignment const& _assignment)
|
bool ExpressionCompiler::visit(Assignment const& _assignment)
|
||||||
{
|
{
|
||||||
_assignment.getRightHandSide().accept(*this);
|
_assignment.getRightHandSide().accept(*this);
|
||||||
@ -77,7 +94,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,7 +588,7 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
|
|||||||
m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag();
|
m_context << m_context.getVirtualFunctionEntryLabel(*functionDef).pushTag();
|
||||||
else if (dynamic_cast<VariableDeclaration const*>(declaration))
|
else if (dynamic_cast<VariableDeclaration const*>(declaration))
|
||||||
{
|
{
|
||||||
m_currentLValue.fromIdentifier(_identifier, *declaration);
|
m_currentLValue.fromDeclaration(*declaration, _identifier.getLocation());
|
||||||
m_currentLValue.retrieveValueIfLValueNotRequested(_identifier);
|
m_currentLValue.retrieveValueIfLValueNotRequested(_identifier);
|
||||||
}
|
}
|
||||||
else if (dynamic_cast<ContractDefinition const*>(declaration))
|
else if (dynamic_cast<ContractDefinition const*>(declaration))
|
||||||
@ -1002,12 +1018,12 @@ ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType
|
|||||||
m_size = unsigned(m_dataType->getSizeOnStack());
|
m_size = unsigned(m_dataType->getSizeOnStack());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration)
|
void ExpressionCompiler::LValue::fromDeclaration(Declaration const& _declaration, Location const& _location)
|
||||||
{
|
{
|
||||||
if (m_context->isLocalVariable(&_declaration))
|
if (m_context->isLocalVariable(&_declaration))
|
||||||
{
|
{
|
||||||
m_type = LValueType::Stack;
|
m_type = LValueType::Stack;
|
||||||
m_dataType = _identifier.getType();
|
m_dataType = _declaration.getType();
|
||||||
m_size = m_dataType->getSizeOnStack();
|
m_size = m_dataType->getSizeOnStack();
|
||||||
m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration);
|
m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration);
|
||||||
}
|
}
|
||||||
@ -1015,12 +1031,13 @@ void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, D
|
|||||||
{
|
{
|
||||||
*m_context << m_context->getStorageLocationOfVariable(_declaration);
|
*m_context << m_context->getStorageLocationOfVariable(_declaration);
|
||||||
m_type = LValueType::Storage;
|
m_type = LValueType::Storage;
|
||||||
m_dataType = _identifier.getType();
|
m_dataType = _declaration.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(_location)
|
||||||
<< errinfo_comment("Identifier type not supported or identifier not found."));
|
<< errinfo_comment("Identifier type not supported or identifier not found."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1117,7 +1134,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(
|
||||||
|
@ -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,9 @@ 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 _location is the current location
|
||||||
void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration);
|
void fromDeclaration(Declaration const& _declaration, Location const& _location);
|
||||||
|
|
||||||
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; }
|
||||||
|
@ -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)
|
||||||
|
@ -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
Parser.cpp
43
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
Parser.h
9
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);
|
||||||
|
@ -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));
|
||||||
|
Loading…
Reference in New Issue
Block a user