aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-10-09 00:01:12 +0800
committerchriseth <c@ethdev.com>2015-10-09 00:25:44 +0800
commitb9a166061bc94cd06458c945d66bf52e76e84b70 (patch)
tree9e317a5de58a050f49187a0318fff0e4981d7c98
parent23865e39295dd9199769727b037c1d126807b20e (diff)
downloaddexon-solidity-b9a166061bc94cd06458c945d66bf52e76e84b70.tar.gz
dexon-solidity-b9a166061bc94cd06458c945d66bf52e76e84b70.tar.zst
dexon-solidity-b9a166061bc94cd06458c945d66bf52e76e84b70.zip
Refactoring to allow multi-variable declarations.
-rw-r--r--libsolidity/AST.h21
-rw-r--r--libsolidity/AST_accept.h16
-rw-r--r--libsolidity/Compiler.cpp9
-rw-r--r--libsolidity/NameAndTypeResolver.cpp4
-rw-r--r--libsolidity/Parser.cpp36
-rw-r--r--libsolidity/TypeChecker.cpp88
-rw-r--r--libsolidity/TypeChecker.h1
7 files changed, 120 insertions, 55 deletions
diff --git a/libsolidity/AST.h b/libsolidity/AST.h
index 075c1ff5..354beb7c 100644
--- a/libsolidity/AST.h
+++ b/libsolidity/AST.h
@@ -963,20 +963,31 @@ public:
* Definition of a variable as a statement inside a function. It requires a type name (which can
* also be "var") but the actual assignment can be missing.
* Examples: var a = 2; uint256 a;
+ * As a second form, multiple variables can be declared, cannot have a type and must be assigned
+ * right away. If the first or last component is unnamed, it can "consume" an arbitrary number
+ * of components.
+ * Examples: var (a, b) = f(); var (a,,,c) = g(); var (a,) = d();
*/
class VariableDeclarationStatement: public Statement
{
public:
- VariableDeclarationStatement(SourceLocation const& _location, ASTPointer<VariableDeclaration> _variable):
- Statement(_location), m_variable(_variable) {}
+ VariableDeclarationStatement(
+ SourceLocation const& _location,
+ std::vector<ASTPointer<VariableDeclaration>> const& _variables,
+ ASTPointer<Expression> const& _initialValue
+ ):
+ Statement(_location), m_variables(_variables), m_initialValue(_initialValue) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- VariableDeclaration const& declaration() const { return *m_variable; }
- Expression const* expression() const { return m_variable->value().get(); }
+ std::vector<ASTPointer<VariableDeclaration>> const& declarations() const { return m_variables; }
+ Expression const* initialValue() const { return m_initialValue.get(); }
private:
- ASTPointer<VariableDeclaration> m_variable;
+ /// List of variables, some of which can be empty pointers (unnamed components).
+ std::vector<ASTPointer<VariableDeclaration>> m_variables;
+ /// The assigned expression / initial value.
+ ASTPointer<Expression> m_initialValue;
};
/**
diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h
index dfa9c425..994bfc8d 100644
--- a/libsolidity/AST_accept.h
+++ b/libsolidity/AST_accept.h
@@ -516,14 +516,26 @@ void ExpressionStatement::accept(ASTConstVisitor& _visitor) const
void VariableDeclarationStatement::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
- m_variable->accept(_visitor);
+ {
+ for (ASTPointer<VariableDeclaration> const& var: m_variables)
+ if (var)
+ var->accept(_visitor);
+ if (m_initialValue)
+ m_initialValue->accept(_visitor);
+ }
_visitor.endVisit(*this);
}
void VariableDeclarationStatement::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
- m_variable->accept(_visitor);
+ {
+ for (ASTPointer<VariableDeclaration> const& var: m_variables)
+ if (var)
+ var->accept(_visitor);
+ if (m_initialValue)
+ m_initialValue->accept(_visitor);
+ }
_visitor.endVisit(*this);
}
diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp
index 7ce2121e..64a67a4f 100644
--- a/libsolidity/Compiler.cpp
+++ b/libsolidity/Compiler.cpp
@@ -623,10 +623,13 @@ bool Compiler::visit(VariableDeclarationStatement const& _variableDeclarationSta
{
StackHeightChecker checker(m_context);
CompilerContext::LocationSetter locationSetter(m_context, _variableDeclarationStatement);
- if (Expression const* expression = _variableDeclarationStatement.expression())
+ solAssert(_variableDeclarationStatement.declarations().size() == 1, "To be implemented.");
+ solAssert(!!_variableDeclarationStatement.declarations().front(), "");
+ VariableDeclaration const& varDecl = *_variableDeclarationStatement.declarations().front();
+ if (Expression const* expression = _variableDeclarationStatement.initialValue())
{
- compileExpression(*expression, _variableDeclarationStatement.declaration().annotation().type);
- CompilerUtils(m_context).moveToStackVariable(_variableDeclarationStatement.declaration());
+ compileExpression(*expression, varDecl.annotation().type);
+ CompilerUtils(m_context).moveToStackVariable(varDecl);
}
checker.check();
return false;
diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp
index 0ce20f3c..0d2c3b02 100644
--- a/libsolidity/NameAndTypeResolver.cpp
+++ b/libsolidity/NameAndTypeResolver.cpp
@@ -350,7 +350,9 @@ void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _vari
// Register the local variables with the function
// This does not fit here perfectly, but it saves us another AST visit.
solAssert(m_currentFunction, "Variable declaration without function.");
- m_currentFunction->addLocalVariable(_variableDeclarationStatement.declaration());
+ for (ASTPointer<VariableDeclaration> const& var: _variableDeclarationStatement.declarations())
+ if (var)
+ m_currentFunction->addLocalVariable(*var);
}
bool DeclarationRegistrationHelper::visit(VariableDeclaration& _declaration)
diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp
index 94e9c0ea..c6b74e1c 100644
--- a/libsolidity/Parser.cpp
+++ b/libsolidity/Parser.cpp
@@ -771,13 +771,35 @@ ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStateme
ASTPointer<TypeName> const& _lookAheadArrayType
)
{
- VarDeclParserOptions options;
- options.allowVar = true;
- options.allowInitialValue = true;
- options.allowLocationSpecifier = true;
- ASTPointer<VariableDeclaration> variable = parseVariableDeclaration(options, _lookAheadArrayType);
- ASTNodeFactory nodeFactory(*this, variable);
- return nodeFactory.createNode<VariableDeclarationStatement>(variable);
+ ASTNodeFactory nodeFactory(*this);
+ if (_lookAheadArrayType)
+ nodeFactory.setLocation(_lookAheadArrayType->location());
+ vector<ASTPointer<VariableDeclaration>> variables;
+ ASTPointer<Expression> value;
+ if (
+ !_lookAheadArrayType &&
+ m_scanner->currentToken() == Token::Var &&
+ m_scanner->peekNextToken() == Token::LParen
+ )
+ {
+ // Parse `var (a, b, ,, c) = ...` into a single VariableDeclarationStatement with multiple variables.
+ solAssert(false, "To be implemented.");
+ }
+ else
+ {
+ VarDeclParserOptions options;
+ options.allowVar = true;
+ options.allowLocationSpecifier = true;
+ options.allowInitialValue = false;
+ variables.push_back(parseVariableDeclaration(options, _lookAheadArrayType));
+ }
+ if (m_scanner->currentToken() == Token::Assign)
+ {
+ m_scanner->next();
+ value = parseExpression();
+ nodeFactory.setEndPositionFromNode(value);
+ }
+ return nodeFactory.createNode<VariableDeclarationStatement>(variables, value);
}
ASTPointer<ExpressionStatement> Parser::parseExpressionStatement(
diff --git a/libsolidity/TypeChecker.cpp b/libsolidity/TypeChecker.cpp
index 5bbbd072..8207e1ff 100644
--- a/libsolidity/TypeChecker.cpp
+++ b/libsolidity/TypeChecker.cpp
@@ -424,16 +424,17 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
// Note that assignments before the first declaration are legal because of the special scoping
// rules inherited from JavaScript.
- // This only infers the type from its type name.
- // If an explicit type is required, it throws, otherwise it returns TypePointer();
+ // type is filled either by ReferencesResolver directly from the type name or by
+ // TypeChecker at the VariableDeclarationStatement level.
TypePointer varType = _variable.annotation().type;
+ solAssert(!!varType, "Failed to infer variable type.");
if (_variable.isConstant())
{
if (!dynamic_cast<ContractDefinition const*>(_variable.scope()))
typeError(_variable, "Illegal use of \"constant\" specifier.");
if (!_variable.value())
typeError(_variable, "Uninitialized \"constant\" variable.");
- if (varType && !varType->isValueType())
+ if (!varType->isValueType())
{
bool constImplemented = false;
if (auto arrayType = dynamic_cast<ArrayType const*>(varType.get()))
@@ -446,43 +447,20 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
);
}
}
- if (varType)
- {
- if (_variable.value())
- expectType(*_variable.value(), *varType);
- else
- {
- if (auto ref = dynamic_cast<ReferenceType const *>(varType.get()))
- if (ref->dataStoredIn(DataLocation::Storage) && _variable.isLocalVariable() && !_variable.isCallableParameter())
- {
- auto err = make_shared<Warning>();
- *err <<
- errinfo_sourceLocation(_variable.location()) <<
- errinfo_comment("Uninitialized storage pointer. Did you mean '<type> memory " + _variable.name() + "'?");
- m_errors.push_back(err);
- }
- }
- }
+ if (_variable.value())
+ expectType(*_variable.value(), *varType);
else
{
- // Infer type from value.
- if (!_variable.value())
- fatalTypeError(_variable, "Assignment necessary for type detection.");
- _variable.value()->accept(*this);
-
- TypePointer const& valueType = type(*_variable.value());
- solAssert(!!valueType, "");
- if (
- valueType->category() == Type::Category::IntegerConstant &&
- !dynamic_pointer_cast<IntegerConstantType const>(valueType)->integerType()
- )
- fatalTypeError(*_variable.value(), "Invalid integer constant " + valueType->toString() + ".");
- else if (valueType->category() == Type::Category::Void)
- fatalTypeError(_variable, "Variable cannot have void type.");
- varType = valueType->mobileType();
+ if (auto ref = dynamic_cast<ReferenceType const *>(varType.get()))
+ if (ref->dataStoredIn(DataLocation::Storage) && _variable.isLocalVariable() && !_variable.isCallableParameter())
+ {
+ auto err = make_shared<Warning>();
+ *err <<
+ errinfo_sourceLocation(_variable.location()) <<
+ errinfo_comment("Uninitialized storage pointer. Did you mean '<type> memory " + _variable.name() + "'?");
+ m_errors.push_back(err);
+ }
}
- solAssert(!!varType, "");
- _variable.annotation().type = varType;
if (!_variable.isStateVariable())
{
if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData))
@@ -621,6 +599,42 @@ void TypeChecker::endVisit(Return const& _return)
}
}
+bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
+{
+ solAssert(_statement.declarations().size() == 1, "To be implemented.");
+ solAssert(!!_statement.declarations().front(), "");
+ VariableDeclaration const& var = *_statement.declarations().front();
+ solAssert(!var.value(), "Value has to be tied to statement.");
+ if (!var.annotation().type)
+ {
+ solAssert(!var.typeName(), "");
+ // Infer type from value.
+ if (!_statement.initialValue())
+ fatalTypeError(_statement, "Assignment necessary for type detection.");
+ _statement.initialValue()->accept(*this);
+
+ TypePointer const& valueType = type(*_statement.initialValue());
+ solAssert(!!valueType, "");
+ if (
+ valueType->category() == Type::Category::IntegerConstant &&
+ !dynamic_pointer_cast<IntegerConstantType const>(valueType)->integerType()
+ )
+ fatalTypeError(*_statement.initialValue(), "Invalid integer constant " + valueType->toString() + ".");
+ else if (valueType->category() == Type::Category::Void)
+ fatalTypeError(_statement, "Variable cannot have void type.");
+ var.annotation().type = valueType->mobileType();
+ var.accept(*this);
+ return false;
+ }
+ else
+ {
+ var.accept(*this);
+ if (_statement.initialValue())
+ expectType(*_statement.initialValue(), *var.annotation().type);
+ }
+ return false;
+}
+
void TypeChecker::endVisit(ExpressionStatement const& _statement)
{
if (type(_statement.expression())->category() == Type::Category::IntegerConstant)
diff --git a/libsolidity/TypeChecker.h b/libsolidity/TypeChecker.h
index 97262ed0..cb65d5a8 100644
--- a/libsolidity/TypeChecker.h
+++ b/libsolidity/TypeChecker.h
@@ -87,6 +87,7 @@ private:
virtual bool visit(WhileStatement const& _whileStatement) override;
virtual bool visit(ForStatement const& _forStatement) override;
virtual void endVisit(Return const& _return) override;
+ virtual bool visit(VariableDeclarationStatement const& _variable) override;
virtual void endVisit(ExpressionStatement const& _statement) override;
virtual bool visit(Assignment const& _assignment) override;
virtual void endVisit(BinaryOperation const& _operation) override;