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:
Vincent Ambo 2021-01-07 01:57:37 +03:00 committed by tazjin
parent d47e55ba4d
commit 0b4e280a07

View file

@ -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)?;