From 9b477975d4d26bdbb7f2a54d8fe9eee76bdc0ca9 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Thu, 14 Jan 2021 03:28:04 +0300 Subject: feat(tazjin/rlox): Always return values from interpreter This makes it easier to write interpreter tests, as we don't need to look at output and such. Change-Id: I6f8ce0cb0c482b8c00707d09e6be750c8e534176 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2384 Reviewed-by: tazjin Tested-by: BuildkiteCI --- users/tazjin/rlox/src/interpreter.rs | 43 +++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 20 deletions(-) (limited to 'users/tazjin') diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs index 5944bdfec8d9..ef76af916838 100644 --- a/users/tazjin/rlox/src/interpreter.rs +++ b/users/tazjin/rlox/src/interpreter.rs @@ -172,43 +172,45 @@ impl Interpreter { } // Interpreter itself - pub fn interpret<'a>(&mut self, program: &Block<'a>) -> Result<(), Error> { + pub fn interpret<'a>(&mut self, program: &Block<'a>) -> Result { + let mut value = Value::Literal(Literal::Nil); + for stmt in program { - self.interpret_stmt(stmt)?; + value = self.interpret_stmt(stmt)?; } - Ok(()) + Ok(value) } - fn interpret_stmt<'a>(&mut self, stmt: &Statement<'a>) -> Result<(), Error> { - match stmt { - Statement::Expr(expr) => { - self.eval(expr)?; - } + fn interpret_stmt<'a>(&mut self, stmt: &Statement<'a>) -> Result { + let value = match stmt { + Statement::Expr(expr) => self.eval(expr)?, Statement::Print(expr) => { let result = self.eval(expr)?; - println!("{:?}", result) + let output = format!("{:?}", result); + println!("{}", output); + Value::Literal(Literal::String(output)) } 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(()) + Ok(value) } - fn interpret_var<'a>(&mut self, var: &parser::Var<'a>) -> Result<(), Error> { + fn interpret_var<'a>(&mut self, var: &parser::Var<'a>) -> Result { let init = var.initialiser.as_ref().ok_or_else(|| Error { line: var.name.line, kind: ErrorKind::InternalError("missing variable initialiser".into()), })?; let value = self.eval(init)?; - self.define_var(&var.name, value)?; - return Ok(()); + self.define_var(&var.name, value.clone())?; + Ok(value) } - fn interpret_block<'a>(&mut self, block: &parser::Block<'a>) -> Result<(), Error> { + fn interpret_block<'a>(&mut self, block: &parser::Block<'a>) -> Result { // Initialise a new environment and point it at the parent // (this is a bit tedious because we need to wrap it in and // out of the Rc). @@ -225,7 +227,7 @@ impl Interpreter { return result; } - fn interpret_if<'a>(&mut self, if_stmt: &parser::If<'a>) -> Result<(), Error> { + fn interpret_if<'a>(&mut self, if_stmt: &parser::If<'a>) -> Result { let condition = self.eval(&if_stmt.condition)?; if eval_truthy(&condition) { @@ -233,16 +235,17 @@ impl Interpreter { } else if let Some(else_branch) = &if_stmt.else_branch { self.interpret_stmt(else_branch) } else { - Ok(()) + Ok(Value::Literal(Literal::Nil)) } } - fn interpret_while<'a>(&mut self, stmt: &parser::While<'a>) -> Result<(), Error> { + fn interpret_while<'a>(&mut self, stmt: &parser::While<'a>) -> Result { + let mut value = Value::Literal(Literal::Nil); while eval_truthy(&self.eval(&stmt.condition)?) { - self.interpret_stmt(&stmt.body)?; + value = self.interpret_stmt(&stmt.body)?; } - Ok(()) + Ok(value) } fn eval<'a>(&mut self, expr: &Expr<'a>) -> Result { -- cgit 1.4.1