diff --git a/src/interpreter/callable.rs b/src/interpreter/callable.rs index b84c846..d6f9e59 100644 --- a/src/interpreter/callable.rs +++ b/src/interpreter/callable.rs @@ -5,7 +5,7 @@ use crate::errors::SloxResult; use super::{InterpreterState, Value}; /// A callable is some object that supports being called. -pub(super) trait Callable: Debug + ToString { +pub trait Callable: Debug + ToString { /// Return the amount of arguments supported by the callable. fn arity(&self) -> usize; @@ -15,4 +15,4 @@ pub(super) trait Callable: Debug + ToString { } /// A reference to a callable. -pub(super) type CallableRef = Rc>; +pub type CallableRef = Rc>; diff --git a/src/interpreter/interpretable.rs b/src/interpreter/interpretable.rs index 3cb1dc7..4d916a1 100644 --- a/src/interpreter/interpretable.rs +++ b/src/interpreter/interpretable.rs @@ -10,12 +10,7 @@ use crate::{ /// Evaluate an interpretable, returning its value. pub fn evaluate(ast: &ast::ProgramNode, vars: ResolvedVariables) -> SloxResult { - let env = Rc::new(RefCell::new(Environment::default())); - let mut state = InterpreterState{ - environment: env.clone(), - globals: env, - variables: &vars, - }; + let mut state = InterpreterState::new(&vars); ast.interpret(&mut state).map(|v| v.result()) } @@ -25,12 +20,36 @@ pub fn evaluate(ast: &ast::ProgramNode, vars: ResolvedVariables) -> SloxResult { +pub struct InterpreterState<'a> { pub(super) globals: EnvironmentRef, pub(super) environment: EnvironmentRef, pub(super) variables: &'a ResolvedVariables, } +impl<'a> InterpreterState<'a> { + /// Initialize the interpreter state from the resolved variables map. + fn new(vars: &'a ResolvedVariables) -> Self { + let env = Rc::new(RefCell::new(Environment::default())); + Self { + environment: env.clone(), + globals: env, + variables: &vars, + } + } + + /// Create a child state. + fn create_child<'b>(parent: &InterpreterState<'b>) -> Self + where + 'b: 'a, + { + InterpreterState { + environment: Environment::create_child(&parent.environment), + globals: parent.globals.clone(), + variables: parent.variables, + } + } +} + /// Interpreter flow control, which may be either a value, a loop break or a /// loop continuation. #[derive(Debug)] @@ -129,9 +148,7 @@ impl Interpretable for ast::StmtNode { is_break, loop_name, } => self.on_loop_control_statemement(*is_break, loop_name), - ast::StmtNode::Return { token: _, value } => { - self.on_return_statement(es, value) - } + ast::StmtNode::Return { token: _, value } => self.on_return_statement(es, value), } } } @@ -184,11 +201,7 @@ impl ast::StmtNode { /// Execute the contents of a block. fn on_block(&self, es: &mut InterpreterState, stmts: &[ast::StmtNode]) -> InterpreterResult { - let mut child = InterpreterState{ - environment: Environment::create_child(&es.environment), - globals: es.globals.clone(), - variables: es.variables, - }; + let mut child = InterpreterState::create_child(es); for stmt in stmts.iter() { let result = stmt.interpret(&mut child)?; if result.is_flow_control() {