feat(tazjin/rlox): Implement block scope in interpreter

This is currently a bit hacky because of the environment
wrapping/unwrapping, will refactor this to just keep a single Rc
around instead.

Change-Id: Iad1cbbe35112d0329248d4655a09260fc60644c8
Reviewed-on: https://cl.tvl.fyi/c/depot/+/2304
Tested-by: BuildkiteCI
Reviewed-by: tazjin <mail@tazj.in>
This commit is contained in:
Vincent Ambo 2020-12-31 18:32:28 +03:00 committed by tazjin
parent 8915cd6fba
commit b55caf0338

View file

@ -96,7 +96,7 @@ impl Interpreter {
println!("{:?}", result)
}
Statement::Var(var) => return self.interpret_var(var),
Statement::Block(_) => unimplemented!(),
Statement::Block(block) => return self.interpret_block(block),
}
Ok(())
@ -112,6 +112,33 @@ impl Interpreter {
return Ok(());
}
fn interpret_block<'a>(&mut self, block: &parser::Block<'a>) -> Result<(), Error> {
// Initialise a new environment and point it at the parent
// (this is a bit tedious because we need to wrap it in and
// out of the Rc).
//
// TODO(tazjin): Refactor this to use Rc on the interpreter itself.
let mut previous = Rc::new(RwLock::new(std::mem::replace(
&mut self.globals,
Environment::default(),
)));
self.globals.enclosing = Some(previous);
let result = self.interpret(block);
// Swap it back, discarding the child env.
previous = self
.globals
.enclosing
.take()
.expect("child environment should not simply vanish");
self.globals = Rc::try_unwrap(previous).unwrap().into_inner().unwrap();
return result;
}
fn eval<'a>(&mut self, expr: &Expr<'a>) -> Result<Literal, Error> {
match expr {
Expr::Assign(assign) => self.eval_assign(assign),