about summary refs log tree commit diff
path: root/users/tazjin/rlox
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-01-06T17·49+0300
committertazjin <mail@tazj.in>2021-01-06T23·02+0000
commitd47e55ba4db53445a48cdf634e10e823b1c115da (patch)
treebc0c506c595ba5a25d234e7da6879df60a6edb4c /users/tazjin/rlox
parent0a0335ae6cd957f48086a41832cef794998f7271 (diff)
feat(tazjin/rlox): Parse & interpret while statements r/2062
Change-Id: Iee772274de95dfd6a6d4af973402859aeda17b1d
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2325
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
Diffstat (limited to 'users/tazjin/rlox')
-rw-r--r--users/tazjin/rlox/src/interpreter.rs9
-rw-r--r--users/tazjin/rlox/src/parser.rs31
2 files changed, 40 insertions, 0 deletions
diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs
index 738542b6b8..28eb23f994 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<Literal, Error> {
         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 ac99f19cb2..62296ca02c 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<Box<Statement<'a>>>,
 }
 
+#[derive(Debug)]
+pub struct While<'a> {
+    pub condition: Expr<'a>,
+    pub body: Box<Statement<'a>>,
+}
+
 pub type Block<'a> = Vec<Statement<'a>>;
 
 #[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)?;