aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AST.cpp11
-rw-r--r--AST.h36
-rw-r--r--ASTForward.h1
-rw-r--r--ASTPrinter.cpp12
-rw-r--r--ASTPrinter.h2
-rw-r--r--ASTVisitor.h4
-rw-r--r--AST_accept.h30
-rw-r--r--Compiler.cpp34
-rw-r--r--Compiler.h1
-rw-r--r--CompilerStack.cpp9
-rw-r--r--NameAndTypeResolver.cpp13
-rw-r--r--NameAndTypeResolver.h2
-rw-r--r--Parser.cpp67
-rw-r--r--Parser.h5
-rw-r--r--grammar.txt5
15 files changed, 213 insertions, 19 deletions
diff --git a/AST.cpp b/AST.cpp
index 5e344ead..4c042f2c 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -130,6 +130,17 @@ void WhileStatement::checkTypeRequirements()
m_body->checkTypeRequirements();
}
+void ForStatement::checkTypeRequirements()
+{
+ if (m_initExpression)
+ m_initExpression->checkTypeRequirements();
+ if (m_condExpression)
+ m_condExpression->expectType(BoolType());
+ if (m_loopExpression)
+ m_loopExpression->checkTypeRequirements();
+ m_body->checkTypeRequirements();
+}
+
void Return::checkTypeRequirements()
{
if (!m_expression)
diff --git a/AST.h b/AST.h
index 4bb623b4..c8369044 100644
--- a/AST.h
+++ b/AST.h
@@ -509,6 +509,42 @@ private:
ASTPointer<Statement> m_body;
};
+/**
+ * For loop statement
+ */
+class ForStatement: public BreakableStatement
+{
+public:
+ ForStatement(Location const& _location,
+ ASTPointer<Statement> const& _initExpression,
+ ASTPointer<Expression> const& _conditionExpression,
+ ASTPointer<ExpressionStatement> const& _loopExpression,
+ ASTPointer<Statement> const& _body):
+ BreakableStatement(_location),
+ m_initExpression(_initExpression),
+ m_condExpression(_conditionExpression),
+ m_loopExpression(_loopExpression),
+ m_body(_body) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+ virtual void checkTypeRequirements() override;
+
+ Statement const* getInitializationExpression() const { return m_initExpression.get(); }
+ Expression const* getCondition() const { return m_condExpression.get(); }
+ ExpressionStatement const* getLoopExpression() const { return m_loopExpression.get(); }
+ Statement const& getBody() const { return *m_body; }
+
+private:
+ /// For statement's initialization expresion. for(XXX; ; ). Can be empty
+ ASTPointer<Statement> m_initExpression;
+ /// For statement's condition expresion. for(; XXX ; ). Can be empty
+ ASTPointer<Expression> m_condExpression;
+ /// For statement's loop expresion. for(;;XXX). Can be empty
+ ASTPointer<ExpressionStatement> m_loopExpression;
+ /// The body of the loop
+ ASTPointer<Statement> m_body;
+};
+
class Continue: public Statement
{
public:
diff --git a/ASTForward.h b/ASTForward.h
index d6c4c9f4..c960fc8f 100644
--- a/ASTForward.h
+++ b/ASTForward.h
@@ -52,6 +52,7 @@ class Block;
class IfStatement;
class BreakableStatement;
class WhileStatement;
+class ForStatement;
class Continue;
class Break;
class Return;
diff --git a/ASTPrinter.cpp b/ASTPrinter.cpp
index 970822a9..916fca1e 100644
--- a/ASTPrinter.cpp
+++ b/ASTPrinter.cpp
@@ -150,6 +150,13 @@ bool ASTPrinter::visit(WhileStatement const& _node)
return goDeeper();
}
+bool ASTPrinter::visit(ForStatement const& _node)
+{
+ writeLine("ForStatement");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
bool ASTPrinter::visit(Continue const& _node)
{
writeLine("Continue");
@@ -360,6 +367,11 @@ void ASTPrinter::endVisit(WhileStatement const&)
m_indentation--;
}
+void ASTPrinter::endVisit(ForStatement const&)
+{
+ m_indentation--;
+}
+
void ASTPrinter::endVisit(Continue const&)
{
m_indentation--;
diff --git a/ASTPrinter.h b/ASTPrinter.h
index 15b65e3f..fc5fb4ac 100644
--- a/ASTPrinter.h
+++ b/ASTPrinter.h
@@ -57,6 +57,7 @@ public:
bool visit(IfStatement const& _node) override;
bool visit(BreakableStatement const& _node) override;
bool visit(WhileStatement const& _node) override;
+ bool visit(ForStatement const& _node) override;
bool visit(Continue const& _node) override;
bool visit(Break const& _node) override;
bool visit(Return const& _node) override;
@@ -90,6 +91,7 @@ public:
void endVisit(IfStatement const&) override;
void endVisit(BreakableStatement const&) override;
void endVisit(WhileStatement const&) override;
+ void endVisit(ForStatement const&) override;
void endVisit(Continue const&) override;
void endVisit(Break const&) override;
void endVisit(Return const&) override;
diff --git a/ASTVisitor.h b/ASTVisitor.h
index 5728cd3d..33a8a338 100644
--- a/ASTVisitor.h
+++ b/ASTVisitor.h
@@ -58,6 +58,7 @@ public:
virtual bool visit(IfStatement&) { return true; }
virtual bool visit(BreakableStatement&) { return true; }
virtual bool visit(WhileStatement&) { return true; }
+ virtual bool visit(ForStatement&) { return true; }
virtual bool visit(Continue&) { return true; }
virtual bool visit(Break&) { return true; }
virtual bool visit(Return&) { return true; }
@@ -93,6 +94,7 @@ public:
virtual void endVisit(IfStatement&) { }
virtual void endVisit(BreakableStatement&) { }
virtual void endVisit(WhileStatement&) { }
+ virtual void endVisit(ForStatement&) { }
virtual void endVisit(Continue&) { }
virtual void endVisit(Break&) { }
virtual void endVisit(Return&) { }
@@ -132,6 +134,7 @@ public:
virtual bool visit(IfStatement const&) { return true; }
virtual bool visit(BreakableStatement const&) { return true; }
virtual bool visit(WhileStatement const&) { return true; }
+ virtual bool visit(ForStatement const&) { return true; }
virtual bool visit(Continue const&) { return true; }
virtual bool visit(Break const&) { return true; }
virtual bool visit(Return const&) { return true; }
@@ -167,6 +170,7 @@ public:
virtual void endVisit(IfStatement const&) { }
virtual void endVisit(BreakableStatement const&) { }
virtual void endVisit(WhileStatement const&) { }
+ virtual void endVisit(ForStatement const&) { }
virtual void endVisit(Continue const&) { }
virtual void endVisit(Break const&) { }
virtual void endVisit(Return const&) { }
diff --git a/AST_accept.h b/AST_accept.h
index e0454d33..0e5a71b6 100644
--- a/AST_accept.h
+++ b/AST_accept.h
@@ -267,6 +267,36 @@ void WhileStatement::accept(ASTConstVisitor& _visitor) const
_visitor.endVisit(*this);
}
+void ForStatement::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ if (m_initExpression)
+ m_initExpression->accept(_visitor);
+ if (m_condExpression)
+ m_condExpression->accept(_visitor);
+ if (m_loopExpression)
+ m_loopExpression->accept(_visitor);
+ m_body->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void ForStatement::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ if (m_initExpression)
+ m_initExpression->accept(_visitor);
+ if (m_condExpression)
+ m_condExpression->accept(_visitor);
+ if (m_loopExpression)
+ m_loopExpression->accept(_visitor);
+ m_body->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
void Continue::accept(ASTVisitor& _visitor)
{
_visitor.visit(*this);
diff --git a/Compiler.cpp b/Compiler.cpp
index 0f85cda3..394ae5f8 100644
--- a/Compiler.cpp
+++ b/Compiler.cpp
@@ -302,6 +302,40 @@ bool Compiler::visit(WhileStatement const& _whileStatement)
return false;
}
+bool Compiler::visit(ForStatement const& _forStatement)
+{
+ eth::AssemblyItem loopStart = m_context.newTag();
+ eth::AssemblyItem loopEnd = m_context.newTag();
+ m_continueTags.push_back(loopStart);
+ m_breakTags.push_back(loopEnd);
+
+ if (_forStatement.getInitializationExpression())
+ _forStatement.getInitializationExpression()->accept(*this);
+
+ m_context << loopStart;
+
+ // if there is no terminating condition in for, default is to always be true
+ if (_forStatement.getCondition())
+ {
+ compileExpression(*_forStatement.getCondition());
+ m_context << eth::Instruction::ISZERO;
+ m_context.appendConditionalJumpTo(loopEnd);
+ }
+
+ _forStatement.getBody().accept(*this);
+
+ // for's loop expression if existing
+ if (_forStatement.getLoopExpression())
+ _forStatement.getLoopExpression()->accept(*this);
+
+ m_context.appendJumpTo(loopStart);
+ m_context << loopEnd;
+
+ m_continueTags.pop_back();
+ m_breakTags.pop_back();
+ return false;
+}
+
bool Compiler::visit(Continue const&)
{
if (!m_continueTags.empty())
diff --git a/Compiler.h b/Compiler.h
index b30e85ae..8471fae2 100644
--- a/Compiler.h
+++ b/Compiler.h
@@ -59,6 +59,7 @@ private:
virtual bool visit(FunctionDefinition const& _function) override;
virtual bool visit(IfStatement const& _ifStatement) override;
virtual bool visit(WhileStatement const& _whileStatement) override;
+ virtual bool visit(ForStatement const& _forStatement) override;
virtual bool visit(Continue const& _continue) override;
virtual bool visit(Break const& _break) override;
virtual bool visit(Return const& _return) override;
diff --git a/CompilerStack.cpp b/CompilerStack.cpp
index 23f5fd68..1242c0ab 100644
--- a/CompilerStack.cpp
+++ b/CompilerStack.cpp
@@ -73,6 +73,15 @@ void CompilerStack::parse()
resolver.resolveNamesAndTypes(*contract);
m_contracts[contract->getName()].contract = contract;
}
+ for (Source const* source: m_sourceOrder)
+ for (ASTPointer<ASTNode> const& node: source->ast->getNodes())
+ if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
+ {
+ m_globalContext->setCurrentContract(*contract);
+ resolver.updateDeclaration(*m_globalContext->getCurrentThis());
+ resolver.checkTypeRequirements(*contract);
+ m_contracts[contract->getName()].contract = contract;
+ }
m_parseSuccessful = true;
}
diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp
index 2ad27680..80732615 100644
--- a/NameAndTypeResolver.cpp
+++ b/NameAndTypeResolver.cpp
@@ -49,8 +49,6 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
m_currentScope = &m_scopes[&_contract];
for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs())
ReferencesResolver resolver(*structDef, *this, nullptr);
- for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs())
- structDef->checkValidityOfMembers();
for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables())
ReferencesResolver resolver(*variable, *this, nullptr);
for (ASTPointer<FunctionDefinition> const& function: _contract.getDefinedFunctions())
@@ -59,13 +57,16 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
ReferencesResolver referencesResolver(*function, *this,
function->getReturnParameterList().get());
}
- // First, the parameter types of all functions need to be resolved before we can check
- // the types, since it is possible to call functions that are only defined later
- // in the source.
- _contract.checkTypeRequirements();
m_currentScope = &m_scopes[nullptr];
}
+void NameAndTypeResolver::checkTypeRequirements(ContractDefinition& _contract)
+{
+ for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs())
+ structDef->checkValidityOfMembers();
+ _contract.checkTypeRequirements();
+}
+
void NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
{
m_scopes[nullptr].registerDeclaration(_declaration, true);
diff --git a/NameAndTypeResolver.h b/NameAndTypeResolver.h
index 1ff9febf..23ac5fe7 100644
--- a/NameAndTypeResolver.h
+++ b/NameAndTypeResolver.h
@@ -46,6 +46,8 @@ public:
void registerDeclarations(SourceUnit& _sourceUnit);
/// Resolves all names and types referenced from the given contract.
void resolveNamesAndTypes(ContractDefinition& _contract);
+ /// Check all type requirements in the given contract.
+ void checkTypeRequirements(ContractDefinition& _contract);
/// Updates the given global declaration (used for "this"). Not to be used with declarations
/// that create their own scope.
void updateDeclaration(Declaration const& _declaration);
diff --git a/Parser.cpp b/Parser.cpp
index 21651eb1..e287319d 100644
--- a/Parser.cpp
+++ b/Parser.cpp
@@ -304,6 +304,8 @@ ASTPointer<Statement> Parser::parseStatement()
return parseIfStatement();
case Token::WHILE:
return parseWhileStatement();
+ case Token::FOR:
+ return parseForStatement();
case Token::LBRACE:
return parseBlock();
// starting from here, all statements must be terminated by a semicolon
@@ -328,18 +330,7 @@ ASTPointer<Statement> Parser::parseStatement()
}
break;
default:
- // distinguish between variable definition (and potentially assignment) and expression statement
- // (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
- // in the case of a user-defined type, we have two identifiers following each other.
- if (m_scanner->getCurrentToken() == Token::MAPPING ||
- m_scanner->getCurrentToken() == Token::VAR ||
- ((Token::isElementaryTypeName(m_scanner->getCurrentToken()) ||
- m_scanner->getCurrentToken() == Token::IDENTIFIER) &&
- m_scanner->peekNextToken() == Token::IDENTIFIER))
- statement = parseVariableDefinition();
- else // "ordinary" expression statement
- statement = parseExpressionStatement();
+ statement = parseVarDefOrExprStmt();
}
expectToken(Token::SEMICOLON);
return statement;
@@ -377,6 +368,44 @@ ASTPointer<WhileStatement> Parser::parseWhileStatement()
return nodeFactory.createNode<WhileStatement>(condition, body);
}
+ASTPointer<ForStatement> Parser::parseForStatement()
+{
+ ASTNodeFactory nodeFactory(*this);
+ ASTPointer<Statement> initExpression;
+ ASTPointer<Expression> conditionExpression;
+ ASTPointer<ExpressionStatement> loopExpression;
+ expectToken(Token::FOR);
+ expectToken(Token::LPAREN);
+
+ // LTODO: Maybe here have some predicate like peekExpression() instead of checking for semicolon and RPAREN?
+ if (m_scanner->getCurrentToken() != Token::SEMICOLON)
+ initExpression = parseVarDefOrExprStmt();
+ expectToken(Token::SEMICOLON);
+
+ if (m_scanner->getCurrentToken() != Token::SEMICOLON)
+ conditionExpression = parseExpression();
+ expectToken(Token::SEMICOLON);
+
+ if (m_scanner->getCurrentToken() != Token::RPAREN)
+ loopExpression = parseExpressionStatement();
+ expectToken(Token::RPAREN);
+
+ ASTPointer<Statement> body = parseStatement();
+ nodeFactory.setEndPositionFromNode(body);
+ return nodeFactory.createNode<ForStatement>(initExpression,
+ conditionExpression,
+ loopExpression,
+ body);
+}
+
+ASTPointer<Statement> Parser::parseVarDefOrExprStmt()
+{
+ if (peekVariableDefinition())
+ return parseVariableDefinition();
+ else
+ return parseExpressionStatement();
+}
+
ASTPointer<VariableDefinition> Parser::parseVariableDefinition()
{
ASTNodeFactory nodeFactory(*this);
@@ -566,6 +595,20 @@ vector<ASTPointer<Expression>> Parser::parseFunctionCallArguments()
return arguments;
}
+
+bool Parser::peekVariableDefinition()
+{
+ // distinguish between variable definition (and potentially assignment) and expression statement
+ // (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
+ // in the case of a user-defined type, we have two identifiers following each other.
+ return (m_scanner->getCurrentToken() == Token::MAPPING ||
+ m_scanner->getCurrentToken() == Token::VAR ||
+ ((Token::isElementaryTypeName(m_scanner->getCurrentToken()) ||
+ m_scanner->getCurrentToken() == Token::IDENTIFIER) &&
+ m_scanner->peekNextToken() == Token::IDENTIFIER));
+}
+
void Parser::expectToken(Token::Value _value)
{
if (m_scanner->getCurrentToken() != _value)
diff --git a/Parser.h b/Parser.h
index 52a374e0..bf3a6bea 100644
--- a/Parser.h
+++ b/Parser.h
@@ -59,6 +59,8 @@ private:
ASTPointer<Statement> parseStatement();
ASTPointer<IfStatement> parseIfStatement();
ASTPointer<WhileStatement> parseWhileStatement();
+ ASTPointer<ForStatement> parseForStatement();
+ ASTPointer<Statement> parseVarDefOrExprStmt();
ASTPointer<VariableDefinition> parseVariableDefinition();
ASTPointer<ExpressionStatement> parseExpressionStatement();
ASTPointer<Expression> parseExpression();
@@ -72,6 +74,9 @@ private:
///@{
///@name Helper functions
+ /// Peeks ahead in the scanner to determine if a variable definition is going to follow
+ bool peekVariableDefinition();
+
/// If current token value is not _value, throw exception otherwise advance token.
void expectToken(Token::Value _value);
Token::Value expectAssignmentOperator();
diff --git a/grammar.txt b/grammar.txt
index a26f717a..8c34997b 100644
--- a/grammar.txt
+++ b/grammar.txt
@@ -16,10 +16,13 @@ Mapping = 'mapping' '(' ElementaryTypeName '=>' TypeName ')'
Block = '{' Statement* '}'
Statement = IfStatement | WhileStatement | Block |
- ( Continue | Break | Return | VariableDefinition | Expression ) ';'
+ ( Continue | Break | Return | VariableDefinition | ExpressionStatement ) ';'
+ExpressionStatement = Expression
IfStatement = 'if' '(' Expression ')' Statement ( 'else' Statement )?
WhileStatement = 'while' '(' Expression ')' Statement
+VardefOrExprStmt = Variabledefinition | ExpressionStatement
+ForStatement = 'for' '(' (VardefOrExprStmt)? ';' (Expression)? ';' (ExpressionStatement)? ')' Statement
Continue = 'continue' ';'
Break = 'break' ';'
Return = 'return' Expression? ';'