From 0b4e280a0791cea82f3d076c5e6ddebfaed9d704 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Thu, 7 Jan 2021 01:57:37 +0300 Subject: [PATCH] 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 Tested-by: BuildkiteCI --- users/tazjin/rlox/src/parser.rs | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/users/tazjin/rlox/src/parser.rs b/users/tazjin/rlox/src/parser.rs index 62296ca02..fd1f7c9ea 100644 --- a/users/tazjin/rlox/src/parser.rs +++ b/users/tazjin/rlox/src/parser.rs @@ -104,11 +104,16 @@ declaration → varDecl | statement ; statement → exprStmt + | forStmt | ifStmt | printStmt | whileStmt | block ; +forStmt → "for" "(" ( varDecl | exprStmt | ";" ) + expression? ";" + expression? ")" statement ; + whileStmt → "while" "(" expression ")" statement ; exprStmt → expression ";" ; @@ -184,6 +189,8 @@ impl<'a> Parser<'a> { self.if_statement() } else if self.match_token(&[TokenKind::While]) { self.while_statement() + } else if self.match_token(&[TokenKind::For]) { + self.for_statement() } else { 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> { let expr = self.expression()?; self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?;