diff options
author | Vincent Ambo <mail@tazj.in> | 2020-12-31T15·32+0300 |
---|---|---|
committer | tazjin <mail@tazj.in> | 2020-12-31T19·10+0000 |
commit | b55caf0338f9bc4bfa4685c657e169940b4a7738 (patch) | |
tree | bc47115741c82f9a50a96847c6a40d2e65a1cd4b | |
parent | 8915cd6fba9a7d449efc13543d7d0db4fca9d0d5 (diff) |
feat(tazjin/rlox): Implement block scope in interpreter r/2038
This is currently a bit hacky because of the environment wrapping/unwrapping, will refactor this to just keep a single Rc around instead. Change-Id: Iad1cbbe35112d0329248d4655a09260fc60644c8 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2304 Tested-by: BuildkiteCI Reviewed-by: tazjin <mail@tazj.in>
-rw-r--r-- | users/tazjin/rlox/src/interpreter.rs | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs index ba66faf79b16..b7b3570b5da9 100644 --- a/users/tazjin/rlox/src/interpreter.rs +++ b/users/tazjin/rlox/src/interpreter.rs @@ -96,7 +96,7 @@ impl Interpreter { println!("{:?}", result) } Statement::Var(var) => return self.interpret_var(var), - Statement::Block(_) => unimplemented!(), + Statement::Block(block) => return self.interpret_block(block), } Ok(()) @@ -112,6 +112,33 @@ impl Interpreter { return Ok(()); } + fn interpret_block<'a>(&mut self, block: &parser::Block<'a>) -> Result<(), 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). + // + // TODO(tazjin): Refactor this to use Rc on the interpreter itself. + let mut previous = Rc::new(RwLock::new(std::mem::replace( + &mut self.globals, + Environment::default(), + ))); + + self.globals.enclosing = Some(previous); + + let result = self.interpret(block); + + // Swap it back, discarding the child env. + previous = self + .globals + .enclosing + .take() + .expect("child environment should not simply vanish"); + + self.globals = Rc::try_unwrap(previous).unwrap().into_inner().unwrap(); + + return result; + } + fn eval<'a>(&mut self, expr: &Expr<'a>) -> Result<Literal, Error> { match expr { Expr::Assign(assign) => self.eval_assign(assign), |