feat(tazjin/rlox): Implement for loops via desugaring to while
Change-Id: I31a93efcc8e0c2bcb8549e2a2c05bb58d2dc74ca Reviewed-on: https://cl.tvl.fyi/c/depot/+/2326 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
This commit is contained in:
parent
d47e55ba4d
commit
0b4e280a07
1 changed files with 62 additions and 0 deletions
|
@ -104,11 +104,16 @@ declaration → varDecl
|
||||||
| statement ;
|
| statement ;
|
||||||
|
|
||||||
statement → exprStmt
|
statement → exprStmt
|
||||||
|
| forStmt
|
||||||
| ifStmt
|
| ifStmt
|
||||||
| printStmt
|
| printStmt
|
||||||
| whileStmt
|
| whileStmt
|
||||||
| block ;
|
| block ;
|
||||||
|
|
||||||
|
forStmt → "for" "(" ( varDecl | exprStmt | ";" )
|
||||||
|
expression? ";"
|
||||||
|
expression? ")" statement ;
|
||||||
|
|
||||||
whileStmt → "while" "(" expression ")" statement ;
|
whileStmt → "while" "(" expression ")" statement ;
|
||||||
|
|
||||||
exprStmt → expression ";" ;
|
exprStmt → expression ";" ;
|
||||||
|
@ -184,6 +189,8 @@ impl<'a> Parser<'a> {
|
||||||
self.if_statement()
|
self.if_statement()
|
||||||
} else if self.match_token(&[TokenKind::While]) {
|
} else if self.match_token(&[TokenKind::While]) {
|
||||||
self.while_statement()
|
self.while_statement()
|
||||||
|
} else if self.match_token(&[TokenKind::For]) {
|
||||||
|
self.for_statement()
|
||||||
} else {
|
} else {
|
||||||
self.expr_statement()
|
self.expr_statement()
|
||||||
}
|
}
|
||||||
|
@ -252,6 +259,61 @@ impl<'a> Parser<'a> {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn for_statement(&mut self) -> StmtResult<'a> {
|
||||||
|
// Parsing of clauses ...
|
||||||
|
self.consume(
|
||||||
|
&TokenKind::LeftParen,
|
||||||
|
ErrorKind::ExpectedToken("Expected '(' after 'for'"),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let initialiser = if self.match_token(&[TokenKind::Semicolon]) {
|
||||||
|
None
|
||||||
|
} else if self.match_token(&[TokenKind::Var]) {
|
||||||
|
Some(self.var_declaration()?)
|
||||||
|
} else {
|
||||||
|
Some(self.expr_statement()?)
|
||||||
|
};
|
||||||
|
|
||||||
|
let condition = if self.check_token(&TokenKind::Semicolon) {
|
||||||
|
// unspecified condition => infinite loop
|
||||||
|
Expr::Literal(Literal::Boolean(true))
|
||||||
|
} else {
|
||||||
|
self.expression()?
|
||||||
|
};
|
||||||
|
|
||||||
|
self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?;
|
||||||
|
|
||||||
|
let increment = if self.check_token(&TokenKind::RightParen) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.expression()?)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.consume(
|
||||||
|
&TokenKind::RightParen,
|
||||||
|
ErrorKind::ExpectedToken("Expected ')' after for clauses"),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut body = self.statement()?;
|
||||||
|
|
||||||
|
// ... desugaring to while
|
||||||
|
|
||||||
|
if let Some(inc) = increment {
|
||||||
|
body = Statement::Block(vec![body, Statement::Expr(inc)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
body = Statement::While(While {
|
||||||
|
condition,
|
||||||
|
body: Box::new(body),
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(init) = initialiser {
|
||||||
|
body = Statement::Block(vec![init, body]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(body)
|
||||||
|
}
|
||||||
|
|
||||||
fn expr_statement(&mut self) -> StmtResult<'a> {
|
fn expr_statement(&mut self) -> StmtResult<'a> {
|
||||||
let expr = self.expression()?;
|
let expr = self.expression()?;
|
||||||
self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?;
|
self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?;
|
||||||
|
|
Loading…
Reference in a new issue