62 lines
1.6 KiB
Rust
62 lines
1.6 KiB
Rust
|
use crate::{
|
||
|
callable::{Callable, CallingError},
|
||
|
environment::Environment,
|
||
|
interpreter::Interpreter,
|
||
|
statement::Statement,
|
||
|
token::Token,
|
||
|
value::Value,
|
||
|
};
|
||
|
use core::fmt::Debug;
|
||
|
use std::{cell::RefCell, fmt::Display, rc::Rc};
|
||
|
|
||
|
/// A lox function.
|
||
|
#[derive(Debug, Clone)]
|
||
|
pub struct Function {
|
||
|
pub name: Token,
|
||
|
pub params: Vec<Token>,
|
||
|
pub body: Vec<Statement>,
|
||
|
pub closure: Rc<RefCell<Environment>>,
|
||
|
}
|
||
|
|
||
|
impl Display for Function {
|
||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
|
write!(f, "{}", self.name.lexeme)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl PartialEq for Function {
|
||
|
fn eq(&self, other: &Self) -> bool {
|
||
|
self.name == other.name && self.params == other.params && self.body == other.body
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Callable for Function {
|
||
|
fn name(&self) -> String {
|
||
|
self.name.lexeme.clone()
|
||
|
}
|
||
|
|
||
|
fn arity(&self) -> usize {
|
||
|
self.params.len()
|
||
|
}
|
||
|
|
||
|
fn call(&self, interpreter: &mut Interpreter, args: Vec<Value>) -> Result<Value, CallingError> {
|
||
|
let mut env = Environment::with_enclosing(self.closure.clone());
|
||
|
for (i, param) in self.params.iter().enumerate() {
|
||
|
let arg = args
|
||
|
.get(i)
|
||
|
.ok_or(CallingError::ArgumentMismatch(
|
||
|
self.params.len(),
|
||
|
args.len(),
|
||
|
))?
|
||
|
.clone();
|
||
|
env.define(param.lexeme.clone(), arg);
|
||
|
}
|
||
|
|
||
|
let result = interpreter
|
||
|
.block(&self.body, env)
|
||
|
.map_err(|e| CallingError::CallInterpretationFailed(e.to_string()))?
|
||
|
.unwrap_or(Value::Nil);
|
||
|
Ok(result)
|
||
|
}
|
||
|
}
|