about summary refs log tree commit diff
path: root/users/tazjin/rlox/src/interpreter.rs
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2020-12-31T14·31+0300
committertazjin <mail@tazj.in>2020-12-31T15·33+0000
commit26ed836e1d12ce7a3205bdfbe20e4e5a59f5062b (patch)
tree73dc6c5b64059ec203cb2f943dc0ea832b9a404a /users/tazjin/rlox/src/interpreter.rs
parent48a54625ce287ff233219432b82d950bcfe10339 (diff)
feat(tazjin/rlox): Add support for scoped environments r/2035
Adds scoped environments using a sophisticated structure known as an
SRPT, which stands for "shitty parent pointer tree".

Change-Id: I62f66aabe6eb32ea01c4cabcca5b03cfefcc28ee
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2301
Reviewed-by: tazjin <mail@tazj.in>
Tested-by: BuildkiteCI
Diffstat (limited to 'users/tazjin/rlox/src/interpreter.rs')
-rw-r--r--users/tazjin/rlox/src/interpreter.rs34
1 files changed, 26 insertions, 8 deletions
diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs
index 8d968a1f20dd..c0af7d047652 100644
--- a/users/tazjin/rlox/src/interpreter.rs
+++ b/users/tazjin/rlox/src/interpreter.rs
@@ -2,11 +2,14 @@ use crate::errors::{Error, ErrorKind};
 use crate::parser::{self, Declaration, Expr, Literal, Program, Statement};
 use crate::scanner::{self, TokenKind};
 use std::collections::HashMap;
+use std::rc::Rc;
+use std::sync::RwLock;
 
 // Tree-walk interpreter
 
 #[derive(Debug, Default)]
 struct Environment {
+    enclosing: Option<Rc<RwLock<Environment>>>,
     values: HashMap<String, Literal>,
 }
 
@@ -27,19 +30,34 @@ impl Environment {
                 line: name.0.line,
                 kind: ErrorKind::UndefinedVariable(ident.into()),
             })
+            .or_else(|err| {
+                if let Some(parent) = &self.enclosing {
+                    parent.read().unwrap().get(name)
+                } else {
+                    Err(err)
+                }
+            })
     }
 
     fn assign(&mut self, name: &scanner::Token, value: Literal) -> Result<(), Error> {
         let ident = identifier_str(name)?;
-        let target = self.values
-            .get_mut(ident)
-            .ok_or_else(|| Error {
-                line: name.line,
-                kind: ErrorKind::UndefinedVariable(ident.into()),
-            })?;
 
-        *target = value;
-        Ok(())
+        match self.values.get_mut(ident) {
+            Some(target) => {
+                *target = value;
+                Ok(())
+            }
+            None => {
+                if let Some(parent) = &self.enclosing {
+                    return parent.write().unwrap().assign(name, value);
+                }
+
+                Err(Error {
+                    line: name.line,
+                    kind: ErrorKind::UndefinedVariable(ident.into()),
+                })
+            }
+        }
     }
 }