diff options
author | Vincent Ambo <mail@tazj.in> | 2020-12-31T14·31+0300 |
---|---|---|
committer | tazjin <mail@tazj.in> | 2020-12-31T15·33+0000 |
commit | 26ed836e1d12ce7a3205bdfbe20e4e5a59f5062b (patch) | |
tree | 73dc6c5b64059ec203cb2f943dc0ea832b9a404a /users/tazjin/rlox/src/interpreter.rs | |
parent | 48a54625ce287ff233219432b82d950bcfe10339 (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.rs | 34 |
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()), + }) + } + } } } |