Interpreter - Fixed closures

* Environment for function execution is now based on their
    declaration.
  * I had missed that part while skimming over the book.
This commit is contained in:
Emmanuel BENOîT 2023-01-07 08:59:13 +01:00
parent ec70ded29e
commit 363cdab86f
2 changed files with 12 additions and 12 deletions

View file

@ -3,28 +3,32 @@ use std::{cell::RefCell, rc::Rc};
use itertools::izip; use itertools::izip;
use super::{ use super::{
Callable, Environment, Interpretable, InterpreterFlowControl, InterpreterState, Value, Callable, Environment, EnvironmentRef, Interpretable, InterpreterFlowControl, InterpreterState,
Value,
}; };
use crate::{ast, errors::SloxResult, tokens::Token}; use crate::{ast, errors::SloxResult, tokens::Token};
/// A function implemented in the Lox-ish language. /// A function implemented in the Lox-ish language.
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Function { pub(super) struct Function {
name: Option<Token>, name: Option<Token>,
params: Vec<Token>, params: Vec<Token>,
body: Vec<ast::StmtNode>, body: Vec<ast::StmtNode>,
env: EnvironmentRef,
} }
impl Function { impl Function {
pub(crate) fn new( pub(super) fn new(
name: Option<&Token>, name: Option<&Token>,
params: &[Token], params: &[Token],
body: &[ast::StmtNode], body: &[ast::StmtNode],
environment: EnvironmentRef,
) -> Rc<RefCell<Self>> { ) -> Rc<RefCell<Self>> {
let fun = Self { let fun = Self {
name: name.cloned(), name: name.cloned(),
params: params.to_owned(), params: params.to_owned(),
body: body.to_owned(), body: body.to_owned(),
env: environment,
}; };
Rc::new(RefCell::new(fun)) Rc::new(RefCell::new(fun))
} }
@ -38,7 +42,7 @@ impl Callable for Function {
fn call(&self, es: &mut InterpreterState, arguments: Vec<Value>) -> SloxResult<Value> { fn call(&self, es: &mut InterpreterState, arguments: Vec<Value>) -> SloxResult<Value> {
assert_eq!(arguments.len(), self.arity()); assert_eq!(arguments.len(), self.arity());
let param_env = InterpreterState { let param_env = InterpreterState {
environment: Environment::create_child(&es.environment), environment: Environment::create_child(&self.env),
globals: es.globals.clone(), globals: es.globals.clone(),
variables: es.variables, variables: es.variables,
}; };
@ -50,11 +54,7 @@ impl Callable for Function {
.unwrap(); .unwrap();
} }
let mut child = InterpreterState { let mut child = InterpreterState::create_child(&param_env);
environment: Environment::create_child(&param_env.environment),
globals: es.globals.clone(),
variables: es.variables,
};
for stmt in self.body.iter() { for stmt in self.body.iter() {
let result = stmt.interpret(&mut child)?; let result = stmt.interpret(&mut child)?;
match result { match result {

View file

@ -38,7 +38,7 @@ impl<'a> InterpreterState<'a> {
} }
/// Create a child state. /// Create a child state.
fn create_child<'b>(parent: &InterpreterState<'b>) -> Self pub(super) fn create_child<'b>(parent: &InterpreterState<'b>) -> Self
where where
'b: 'a, 'b: 'a,
{ {
@ -209,7 +209,7 @@ impl ast::StmtNode {
params: &[Token], params: &[Token],
body: &[ast::StmtNode], body: &[ast::StmtNode],
) -> InterpreterResult { ) -> InterpreterResult {
let fun = Function::new(Some(name), params, body); let fun = Function::new(Some(name), params, body, es.environment.clone());
es.environment es.environment
.borrow_mut() .borrow_mut()
.define(name, Some(Value::Callable(fun)))?; .define(name, Some(Value::Callable(fun)))?;
@ -336,7 +336,7 @@ impl Interpretable for ast::ExprNode {
arguments, arguments,
} => self.on_call(es, callee, right_paren, arguments), } => self.on_call(es, callee, right_paren, arguments),
ast::ExprNode::Lambda { params, body } => { ast::ExprNode::Lambda { params, body } => {
Ok(Value::Callable(Function::new(None, params, body)).into()) Ok(Value::Callable(Function::new(None, params, body, es.environment.clone())).into())
} }
} }
} }