rlox/interpreter/src/function.rs

146 lines
3.7 KiB
Rust

use std::fmt::{Debug, Display};
use std::rc::Rc;
use rlox2_frontend::parser::Stmt;
use smol_str::SmolStr;
use crate::environment::{ClosureScope, HeapedValue};
use super::environment::Environment;
use super::interpreter::EvalResult;
use super::{Runtime, Value};
#[derive(Debug, Clone)]
pub struct LoxFunction {
name: SmolStr,
closure: ClosureScope,
param_names: Vec<SmolStr>,
body: Box<Stmt>,
}
impl LoxFunction {
pub fn new(
name: impl Into<SmolStr>,
closure: ClosureScope,
param_names: Vec<SmolStr>,
body: Stmt,
) -> Rc<Self> {
let name = name.into();
let body = Box::new(body);
let fun = LoxFunction {
name,
closure,
param_names,
body,
};
Rc::new(fun)
}
pub fn name(&self) -> &str {
&self.name
}
pub fn closure(&self) -> &ClosureScope {
&self.closure
}
pub fn param_names(&self) -> &[SmolStr] {
&self.param_names
}
pub fn body(&self) -> &Stmt {
&self.body
}
pub fn arity(&self) -> usize {
self.param_names().len()
}
pub fn inject_closed_var(&mut self, name: impl Into<SmolStr>, value: Value) {
let name = name.into();
let heaped_value = HeapedValue::new(value);
self.closure.insert(name, heaped_value);
}
}
impl Display for LoxFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<fun {}>", self.name)
}
}
// slightly hacky: two functions are equal if they are stored at the same location
// since a LoxFunction is always (supposed to be) behind an Rc anyways, we might as well compare their pointers
impl PartialEq for LoxFunction {
fn eq(&self, other: &Self) -> bool {
let self_ptr = self as *const LoxFunction;
let other_ptr = other as *const LoxFunction;
self_ptr == other_ptr
}
}
/*====================================================================================================================*/
pub type ExternFunClosure = fn(Vec<Value>, &mut Environment) -> EvalResult<Value>;
#[derive(Clone)]
pub struct LoxExternFunction {
name: String,
arity: usize,
closure: ExternFunClosure,
}
impl LoxExternFunction {
pub fn new(name: impl Into<String>, arity: usize, closure: ExternFunClosure) -> Self {
let name = name.into();
LoxExternFunction {
name,
arity,
closure,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn arity(&self) -> usize {
self.arity
}
pub fn closure(&self) -> ExternFunClosure {
self.closure
}
pub fn register(self, env: &mut Runtime) {
let name = self.name.clone();
let fun = Value::extern_function(self);
env.define_global(name, fun);
}
}
impl Display for LoxExternFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<extern fun {}>", self.name)
}
}
impl Debug for LoxExternFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LoxExternFunction")
.field("name", &self.name)
.field("closure", &"<closure>")
.finish()
}
}
// slightly hacky: two extern functions are equal if they are stored at the same location
// since a LoxExternFunction is always (supposed to be) behind an Rc anyways, we might as well compare their pointers
impl PartialEq for LoxExternFunction {
fn eq(&self, other: &Self) -> bool {
let self_ptr = self as *const LoxExternFunction;
let other_ptr = other as *const LoxExternFunction;
self_ptr == other_ptr
}
}