diff options
author | Vincent Ambo <mail@tazj.in> | 2021-01-14T15·03+0300 |
---|---|---|
committer | tazjin <mail@tazj.in> | 2021-01-14T15·19+0000 |
commit | 56d8fa97ed936aacb66b13bb4a8c849a9797db93 (patch) | |
tree | 550c7fcd0598d33b9a68eb2ea1d21173b546326e /users/tazjin | |
parent | fe97398fd9d1e20ad4a953e27d080721b949865a (diff) |
feat(tazjin/rlox): Implement calling user-defined functions r/2105
This slightly jiggles around interpret_block to let callers pass in an environment. Change-Id: I03112a38be0e8696242d8eae8d41da8c2cc66b48 Reviewed-on: https://cl.tvl.fyi/c/depot/+/2392 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
Diffstat (limited to 'users/tazjin')
-rw-r--r-- | users/tazjin/rlox/src/interpreter.rs | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/users/tazjin/rlox/src/interpreter.rs b/users/tazjin/rlox/src/interpreter.rs index bd907542fb5e..ef188b797fa8 100644 --- a/users/tazjin/rlox/src/interpreter.rs +++ b/users/tazjin/rlox/src/interpreter.rs @@ -25,14 +25,23 @@ impl<'a> Callable<'a> { fn arity(&self) -> usize { match self { Callable::Builtin(builtin) => builtin.arity(), - _ => unimplemented!(), + Callable::Function(func) => func.params.len(), } } - fn call(&self, args: Vec<Value>) -> Result<Value<'a>, Error> { + fn call(&self, lox: &mut Interpreter<'a>, args: Vec<Value<'a>>) -> Result<Value<'a>, Error> { match self { Callable::Builtin(builtin) => builtin.call(args), - _ => unimplemented!(), + + Callable::Function(func) => { + let mut fn_env: Environment<'a> = Default::default(); + + for (param, value) in func.params.iter().zip(args.into_iter()) { + fn_env.define(param, value)?; + } + + lox.interpret_block(Rc::new(RwLock::new(fn_env)), &func.body) + }, } } } @@ -208,7 +217,7 @@ impl<'a> Interpreter<'a> { Value::Literal(Literal::String(output)) } Statement::Var(var) => return self.interpret_var(var), - Statement::Block(block) => return self.interpret_block(block), + Statement::Block(block) => return self.interpret_block(Default::default(), block), Statement::If(if_stmt) => return self.interpret_if(if_stmt), Statement::While(while_stmt) => return self.interpret_while(while_stmt), Statement::Function(_) => unimplemented!(), @@ -227,13 +236,17 @@ impl<'a> Interpreter<'a> { Ok(value) } - fn interpret_block(&mut self, block: &parser::Block<'a>) -> Result<Value<'a>, Error> { + fn interpret_block( + &mut self, + env: Rc<RwLock<Environment<'a>>>, + block: &parser::Block<'a>, + ) -> Result<Value<'a>, 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 previous = std::mem::replace(&mut self.env, Default::default()); + let previous = std::mem::replace(&mut self.env, env); self.set_enclosing(previous.clone()); let result = self.interpret(block); @@ -388,7 +401,7 @@ impl<'a> Interpreter<'a> { }); } - callable.call(args) + callable.call(self, args) } } |