feat(tazjin/rlox): Add support for scoped environments

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
This commit is contained in:
Vincent Ambo 2020-12-31 17:31:09 +03:00 committed by tazjin
parent 48a54625ce
commit 26ed836e1d

View file

@ -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()),
})
}
}
}
}