From d47e55ba4db53445a48cdf634e10e823b1c115da Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Wed, 6 Jan 2021 20:49:20 +0300 Subject: [PATCH] feat(tazjin/rlox): Parse & interpret while statements Change-Id: Iee772274de95dfd6a6d4af973402859aeda17b1d Reviewed-on: https://cl.tvl.fyi/c/depot/+/2325 Reviewed-by: tazjin Tested-by: BuildkiteCI --- users/tazjin/rlox/src/interpreter.rs | 9 ++++++++ users/tazjin/rlox/src/parser.rs | 31 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs index 738542b6b..28eb23f99 100644 --- a/users/tazjin/rlox/src/interpreter.rs +++ b/users/tazjin/rlox/src/interpreter.rs @@ -128,6 +128,7 @@ impl Interpreter { Statement::Var(var) => return self.interpret_var(var), Statement::Block(block) => return self.interpret_block(block), Statement::If(if_stmt) => return self.interpret_if(if_stmt), + Statement::While(while_stmt) => return self.interpret_while(while_stmt), } Ok(()) @@ -172,6 +173,14 @@ impl Interpreter { } } + fn interpret_while<'a>(&mut self, stmt: &parser::While<'a>) -> Result<(), Error> { + while eval_truthy(&self.eval(&stmt.condition)?) { + self.interpret_stmt(&stmt.body)?; + } + + Ok(()) + } + fn eval<'a>(&mut self, expr: &Expr<'a>) -> Result { match expr { Expr::Assign(assign) => self.eval_assign(assign), diff --git a/users/tazjin/rlox/src/parser.rs b/users/tazjin/rlox/src/parser.rs index ac99f19cb..62296ca02 100644 --- a/users/tazjin/rlox/src/parser.rs +++ b/users/tazjin/rlox/src/parser.rs @@ -77,6 +77,12 @@ pub struct If<'a> { pub else_branch: Option>>, } +#[derive(Debug)] +pub struct While<'a> { + pub condition: Expr<'a>, + pub body: Box>, +} + pub type Block<'a> = Vec>; #[derive(Debug)] @@ -86,6 +92,7 @@ pub enum Statement<'a> { Var(Var<'a>), Block(Block<'a>), If(If<'a>), + While(While<'a>), } // Parser @@ -99,8 +106,11 @@ declaration → varDecl statement → exprStmt | ifStmt | printStmt + | whileStmt | block ; +whileStmt → "while" "(" expression ")" statement ; + exprStmt → expression ";" ; ifStmt → "if" "(" expression ")" statement @@ -172,6 +182,8 @@ impl<'a> Parser<'a> { self.block_statement() } else if self.match_token(&[TokenKind::If]) { self.if_statement() + } else if self.match_token(&[TokenKind::While]) { + self.while_statement() } else { self.expr_statement() } @@ -221,6 +233,25 @@ impl<'a> Parser<'a> { Ok(Statement::If(stmt)) } + fn while_statement(&mut self) -> StmtResult<'a> { + self.consume( + &TokenKind::LeftParen, + ErrorKind::ExpectedToken("Expected '(' after 'while'"), + )?; + + let condition = self.expression()?; + + self.consume( + &TokenKind::RightParen, + ErrorKind::ExpectedToken("Expected ')' after 'while'"), + )?; + + Ok(Statement::While(While { + condition, + body: Box::new(self.statement()?), + })) + } + fn expr_statement(&mut self) -> StmtResult<'a> { let expr = self.expression()?; self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?;