diff options
-rw-r--r-- | users/tazjin/rlox/src/interpreter.rs | 38 | ||||
-rw-r--r-- | users/tazjin/rlox/src/interpreter/tests.rs | 5 |
2 files changed, 31 insertions, 12 deletions
diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs index 6c61288d5a7d..01ea217f8201 100644 --- a/users/tazjin/rlox/src/interpreter.rs +++ b/users/tazjin/rlox/src/interpreter.rs @@ -106,23 +106,33 @@ impl Environment { Ok(()) } - fn get(&self, name: &parser::Variable) -> Result<Value, Error> { - let ident = identifier_str(&name.name)?; + fn get(&self, ident: &str, line: usize, depth: usize) -> Result<Value, Error> { + println!("looking up {} at depth {}", ident, depth); + if depth > 0 { + match &self.enclosing { + None => { + return Err(Error { + line, + kind: ErrorKind::InternalError(format!( + "invalid depth {} for {}", + depth, ident + )), + }) + } + Some(parent) => { + let env = parent.read().expect("fatal: environment lock poisoned"); + return env.get(ident, line, depth - 1); + } + } + } self.values .get(ident) .map(Clone::clone) .ok_or_else(|| Error { - line: name.name.line, + 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: Value) -> Result<(), Error> { @@ -198,10 +208,16 @@ impl Interpreter { } fn get_var(&mut self, var: &parser::Variable) -> Result<Value, Error> { + let ident = identifier_str(&var.name)?; + let depth = var.depth.ok_or_else(|| Error { + line: var.name.line, + kind: ErrorKind::UndefinedVariable(ident.into()), + })?; + self.env .read() .expect("environment lock is poisoned") - .get(var) + .get(ident, var.name.line, depth) } // Interpreter itself diff --git a/users/tazjin/rlox/src/interpreter/tests.rs b/users/tazjin/rlox/src/interpreter/tests.rs index 875116593e44..4698583dfc11 100644 --- a/users/tazjin/rlox/src/interpreter/tests.rs +++ b/users/tazjin/rlox/src/interpreter/tests.rs @@ -1,10 +1,13 @@ use super::*; +use crate::resolver; /// Evaluate a code snippet, returning a value. fn parse_eval(code: &str) -> Value { let chars: Vec<char> = code.chars().collect(); let tokens = scanner::scan(&chars).expect("could not scan code"); - let program = parser::parse(tokens).expect("could not parse code"); + let mut program = parser::parse(tokens).expect("could not parse code"); + program = resolver::resolve(program).expect("could not resolve code"); + Interpreter::create() .interpret(&program) .expect("could not eval code") |