Skip to content

Commit

Permalink
for loops
Browse files Browse the repository at this point in the history
  • Loading branch information
lgyanf committed Oct 9, 2023
1 parent a50d578 commit 352e820
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 1 deletion.
62 changes: 62 additions & 0 deletions src/ast/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl Parser<'_> {
Some(token) if token.type_ == TokenType::LeftBrace => self.block(),
Some(token) if token.type_ == TokenType::If => self.if_statement(),
Some(token) if token.type_ == TokenType::While => self.while_loop_statement(),
Some(token) if token.type_ == TokenType::For => self.for_statement(),
_ => self.expression_statement(),
}
}
Expand Down Expand Up @@ -188,6 +189,67 @@ impl Parser<'_> {
)
}

fn for_statement(&mut self) -> Result<Statement, LoxError> {
let for_keyword = self.token_iterator.next().unwrap();
self.consume_or_error(
&TokenType::LeftParen,
&for_keyword.position,
"for loop declaration",
)?;
let initializer = match self.token_iterator.peek() {
Some(t) if t.type_ == TokenType::Semicolon => {
self.consume_or_error(
&TokenType::Semicolon,
&for_keyword.position,
"for loop initializer",
);
None
},
Some(t) if t.type_ == TokenType::Var => Some((self.var_declaration()?).boxed()),
Some(_) => Some((self.expression_statement()?).boxed()),
None => {
return Err(LoxError {
kind: LoxErrorKind::Syntax,
message: "Expected variable declaration, expression or ';' in for loop initializer".to_owned(),
position: PositionRange::from_bounds(
&for_keyword.position,
&self.token_iterator.last_position().unwrap(),
),
});
},
};
let condition = match self.token_iterator.peek() {
Some(t) if t.type_ == TokenType::Semicolon => None,
_ => Some(self.expression()?),
};
self.consume_or_error(
&TokenType::Semicolon,
&for_keyword.position,
"loop condition"
)?;
let increment = match self.token_iterator.peek() {
Some(t) if t.type_ == TokenType::RightParen => None,
_ => Some(self.expression()?),
}.map(|expr| {
let position = expr.position.clone();
Statement::Expression { expr, position }.boxed()
});
self.consume_or_error(
&TokenType::RightParen,
&for_keyword.position,
"for loop clauses",
)?;
let body = self.statement()?;
let body_position = body.position().clone();
Ok(Statement::For {
initializer,
condition,
increment,
body: body.boxed(),
position: PositionRange::from_bounds(&for_keyword.position, &body_position),
})
}

fn expression_statement(&mut self) -> Result<Statement, LoxError> {
let expr = self.expression()?;
let semicolon = self.consume_semicolon(&expr.position, "expression")?;
Expand Down
8 changes: 8 additions & 0 deletions src/ast/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ pub enum Statement {
condition: Expr,
body: Box<Statement>,
position: PositionRange,
},
For {
initializer: Option<Box<Statement>>,
condition: Option<Expr>,
increment: Option<Box<Statement>>,
body: Box<Statement>,
position: PositionRange,
}
}

Expand All @@ -50,6 +57,7 @@ impl Statement {
position
},
Statement::While { condition: _, body: _, position } => position,
Statement::For {initializer: _, condition: _, increment: _, body: _, position} => position,
}
}

Expand Down
52 changes: 51 additions & 1 deletion src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,17 @@ impl StatementVisitor for Interpreter<'_> {
self.visit_statement(body)?;
}
},
ast::Statement::For { initializer, condition, increment, body, position: _ } => {
if let Some(initializer) = initializer {
self.visit_statement(&initializer);

Check failure on line 221 in src/interpreter/mod.rs

View workflow job for this annotation

GitHub Actions / Clippy

this expression creates a reference which is immediately dereferenced by the compiler
}
while condition.is_none() || Self::is_truthy(&self.visit_expr(&condition.as_ref().unwrap())?) {
self.visit_statement(&body)?;
if let Some(increment) = increment {
self.visit_statement(&increment)?;
}
}
},
};
Ok(())
}
Expand Down Expand Up @@ -499,6 +510,45 @@ hello\n",
Ok(()),
"",
),

for_loop: (
"
var a = 0;
var temp;
for (var b = 1; a < 3; b = temp + b) {
print a;
temp = a;
a = b;
}
",
Ok(()),
"0
1
1
2\n",
),
for_loop_no_initializer: (
"
var a = 0;
for (; a < 3; a = a + 1) {
print a;
}
",
Ok(()),
"0
1
2\n",
),
for_loop_no_increment: (
"
for (var a = 0; a < 3;) {
print a;
a = a + 1;
}
",
Ok(()),
"0
1
2\n",
),
);
}

0 comments on commit 352e820

Please sign in to comment.