about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2020-12-31T15·32+0300
committertazjin <mail@tazj.in>2020-12-31T19·10+0000
commitb55caf0338f9bc4bfa4685c657e169940b4a7738 (patch)
treebc47115741c82f9a50a96847c6a40d2e65a1cd4b
parent8915cd6fba9a7d449efc13543d7d0db4fca9d0d5 (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.rs29
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),