about summary refs log tree commit diff
path: root/users/tazjin/rlox
diff options
context:
space:
mode:
Diffstat (limited to 'users/tazjin/rlox')
-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),