use std::fmt::Display; use itertools::izip; use super::{ Callable, Environment, EnvironmentRef, Interpretable, InterpreterFlowControl, InterpreterState, Value, }; use crate::{ast, errors::SloxResult, tokens::Token}; /// A function implemented in the Lox-ish language. #[derive(Debug, Clone)] pub struct Function { name: Option<Token>, params: Vec<Token>, body: Vec<ast::StmtNode>, env: EnvironmentRef, } impl Function { pub(super) fn new( name: Option<&Token>, params: &[Token], body: &[ast::StmtNode], environment: EnvironmentRef, ) -> Self { Self { name: name.cloned(), params: params.to_owned(), body: body.to_owned(), env: environment, } } } impl Callable for Function { fn arity(&self) -> usize { self.params.len() } fn call(&self, itpr_state: &mut InterpreterState, arguments: Vec<Value>) -> SloxResult<Value> { assert_eq!(arguments.len(), self.arity()); let param_env = InterpreterState { environment: Environment::create_child(&self.env), globals: itpr_state.globals.clone(), locals: itpr_state.locals, }; for (arg, value) in izip!(self.params.iter(), arguments.into_iter()) { param_env .environment .borrow_mut() .define(arg, Some(value)) .unwrap(); } let mut child = InterpreterState::create_child(¶m_env); for stmt in self.body.iter() { let result = stmt.interpret(&mut child)?; match result { InterpreterFlowControl::Result(_) => (), InterpreterFlowControl::Return(v) => return Ok(v), _ => panic!("unexpected flow control {:?}", result), } } Ok(Value::Nil) } } impl Display for Function { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &self.name { None => f.write_str("<lambda>"), Some(token) => { f.write_str("<fun ")?; f.write_str(&token.lexeme)?; f.write_str(">") } } } }