diff options
author | Vincent Ambo <mail@tazj.in> | 2021-01-14T00·28+0300 |
---|---|---|
committer | tazjin <mail@tazj.in> | 2021-01-14T00·31+0000 |
commit | 9b477975d4d26bdbb7f2a54d8fe9eee76bdc0ca9 (patch) | |
tree | e04def95ef5eb2359144eecb308b90671b2b351d | |
parent | a03b509fb85ee4fb3b397b3e279ca77d625bc5f6 (diff) |
feat(tazjin/rlox): Always return values from interpreter r/2098
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 <mail@tazj.in> Tested-by: BuildkiteCI
-rw-r--r-- | users/tazjin/rlox/src/interpreter.rs | 43 |
1 files changed, 23 insertions, 20 deletions
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<Value, Error> { + 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<Value, Error> { + 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<Value, Error> { 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<Value, Error> { // 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<Value, Error> { 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<Value, Error> { + 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<Value, Error> { |