about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2021-01-17T09·05+0300
committertazjin <mail@tazj.in>2021-01-17T09·34+0000
commit052f8976bb3273d16fb0e1c4643de5abcaf0f135 (patch)
treec73e6913757abc3cb37be918d2c11b90a1fb7a5d
parent06a6aa5dc08ffff2ba82af2254256ea60c6a5bec (diff)
fix(tazjin/rlox): Include static globals in resolution r/2119
Change-Id: Id377ce1fe4c9b9cd65395d15873399d9b6d38af8
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2408
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
-rw-r--r--users/tazjin/rlox/src/interpreter.rs61
-rw-r--r--users/tazjin/rlox/src/resolver.rs29
2 files changed, 51 insertions, 39 deletions
diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs
index e7f87577bb..c9de3831c8 100644
--- a/users/tazjin/rlox/src/interpreter.rs
+++ b/users/tazjin/rlox/src/interpreter.rs
@@ -223,8 +223,39 @@ impl Interpreter {
 
     // Interpreter itself
     pub fn interpret(&mut self, mut program: Block) -> Result<Value, Error> {
-        resolver::resolve(&mut program)?;
-        self.interpret_block(&program)
+        let globals = self.env.read()
+            .expect("static globals lock poisoned")
+            .values.keys().map(Clone::clone)
+            .collect::<Vec<String>>();
+
+        resolver::resolve(&globals, &mut program)?;
+        self.interpret_block_with_env(None, &program)
+    }
+
+    /// Interpret the block in the supplied environment. If no
+    /// environment is supplied, a new one is created using the
+    /// current one as its parent.
+    fn interpret_block_with_env(
+        &mut self,
+        env: Option<Rc<RwLock<Environment>>>,
+        block: &parser::Block,
+    ) -> Result<Value, Error> {
+        let env = match env {
+            Some(env) => env,
+            None => {
+                let env: Rc<RwLock<Environment>> = Default::default();
+                set_enclosing_env(&env, self.env.clone());
+                env
+            }
+        };
+
+        let previous = std::mem::replace(&mut self.env, env);
+        let result = self.interpret_block(block);
+
+        // Swap it back, discarding the child env.
+        self.env = previous;
+
+        return result;
     }
 
     fn interpret_block(&mut self, program: &Block) -> Result<Value, Error> {
@@ -272,32 +303,6 @@ impl Interpreter {
         Ok(value)
     }
 
-    /// Interpret the block in the supplied environment. If no
-    /// environment is supplied, a new one is created using the
-    /// current one as its parent.
-    fn interpret_block_with_env(
-        &mut self,
-        env: Option<Rc<RwLock<Environment>>>,
-        block: &parser::Block,
-    ) -> Result<Value, Error> {
-        let env = match env {
-            Some(env) => env,
-            None => {
-                let env: Rc<RwLock<Environment>> = Default::default();
-                set_enclosing_env(&env, self.env.clone());
-                env
-            }
-        };
-
-        let previous = std::mem::replace(&mut self.env, env);
-        let result = self.interpret_block(block);
-
-        // Swap it back, discarding the child env.
-        self.env = previous;
-
-        return result;
-    }
-
     fn interpret_if(&mut self, if_stmt: &parser::If) -> Result<Value, Error> {
         let condition = self.eval(&if_stmt.condition)?;
 
diff --git a/users/tazjin/rlox/src/resolver.rs b/users/tazjin/rlox/src/resolver.rs
index 03ac3c8e67..5e15d386c7 100644
--- a/users/tazjin/rlox/src/resolver.rs
+++ b/users/tazjin/rlox/src/resolver.rs
@@ -69,26 +69,26 @@ impl<'a> Resolver<'a> {
     }
 
     fn resolve_var(&mut self, var: &'a mut parser::Var) -> Result<(), Error> {
-        self.declare(&var.name);
+        self.declare(&var.name.lexeme);
 
         if let Some(init) = &mut var.initialiser {
             self.resolve_expr(init)?;
         }
 
-        self.define(&var.name);
+        self.define(&var.name.lexeme);
 
         Ok(())
     }
 
     fn resolve_function(&mut self, func: &'a mut parser::Function) -> Result<(), Error> {
-        self.declare(&func.name);
-        self.define(&func.name);
+        self.declare(&func.name.lexeme);
+        self.define(&func.name.lexeme);
 
         self.begin_scope();
 
         for param in &func.params {
-            self.declare(param);
-            self.define(param);
+            self.declare(&param.lexeme);
+            self.define(&param.lexeme);
         }
 
         for stmt in &mut func.body {
@@ -165,15 +165,15 @@ impl<'a> Resolver<'a> {
 
     // Internal helpers
 
-    fn declare(&mut self, name: &'a Token) {
+    fn declare(&mut self, name: &'a str) {
         if let Some(scope) = self.scopes.last_mut() {
-            scope.insert(&name.lexeme, false);
+            scope.insert(&name, false);
         }
     }
 
-    fn define(&mut self, name: &'a Token) {
+    fn define(&mut self, name: &'a str) {
         if let Some(scope) = self.scopes.last_mut() {
-            scope.insert(&name.lexeme, true);
+            scope.insert(&name, true);
         }
     }
 
@@ -186,7 +186,14 @@ impl<'a> Resolver<'a> {
     }
 }
 
-pub fn resolve(block: &mut parser::Block) -> Result<(), Error> {
+pub fn resolve(globals: &[String], block: &mut parser::Block) -> Result<(), Error> {
     let mut resolver: Resolver = Default::default();
+
+    // Scope for static globals only starts, never ends.
+    resolver.begin_scope();
+    for global in globals {
+        resolver.define(global);
+    }
+
     resolver.resolve(block)
 }