2023-01-25 19:01:13 +01:00
|
|
|
use std::fmt::{Debug, Display};
|
2023-01-28 14:19:12 +01:00
|
|
|
use std::rc::Rc;
|
2023-01-25 19:01:13 +01:00
|
|
|
|
2023-01-28 01:11:55 +01:00
|
|
|
use rlox2_frontend::parser::Stmt;
|
2024-09-02 05:19:30 +02:00
|
|
|
use smol_str::SmolStr;
|
2023-01-25 19:01:13 +01:00
|
|
|
|
2024-09-01 23:15:36 +02:00
|
|
|
use crate::environment::{ClosureScope, HeapedValue};
|
2023-01-28 14:19:12 +01:00
|
|
|
|
2024-09-01 23:15:36 +02:00
|
|
|
use super::environment::Environment;
|
2024-09-01 23:20:32 +02:00
|
|
|
use super::interpreter::EvalResult;
|
2023-01-28 01:11:55 +01:00
|
|
|
use super::{Runtime, Value};
|
2023-01-25 19:01:13 +01:00
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct LoxFunction {
|
2024-09-02 05:19:30 +02:00
|
|
|
name: SmolStr,
|
2024-09-01 23:15:36 +02:00
|
|
|
closure: ClosureScope,
|
2024-09-02 05:19:30 +02:00
|
|
|
param_names: Vec<SmolStr>,
|
2023-01-25 19:01:13 +01:00
|
|
|
body: Box<Stmt>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LoxFunction {
|
2024-09-01 19:16:30 +02:00
|
|
|
pub fn new(
|
2024-09-02 05:19:30 +02:00
|
|
|
name: impl Into<SmolStr>,
|
2024-09-01 23:15:36 +02:00
|
|
|
closure: ClosureScope,
|
2024-09-02 05:19:30 +02:00
|
|
|
param_names: Vec<SmolStr>,
|
2024-09-01 19:16:30 +02:00
|
|
|
body: Stmt,
|
|
|
|
|
) -> Rc<Self> {
|
2023-01-25 19:01:13 +01:00
|
|
|
let name = name.into();
|
|
|
|
|
let body = Box::new(body);
|
2023-01-28 14:19:12 +01:00
|
|
|
let fun = LoxFunction {
|
2023-01-25 19:01:13 +01:00
|
|
|
name,
|
2023-01-28 01:11:55 +01:00
|
|
|
closure,
|
2023-01-25 19:01:13 +01:00
|
|
|
param_names,
|
|
|
|
|
body,
|
2023-01-28 14:19:12 +01:00
|
|
|
};
|
|
|
|
|
Rc::new(fun)
|
2023-01-25 19:01:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn name(&self) -> &str {
|
|
|
|
|
&self.name
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-01 23:15:36 +02:00
|
|
|
pub fn closure(&self) -> &ClosureScope {
|
2023-01-25 19:01:13 +01:00
|
|
|
&self.closure
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-02 05:19:30 +02:00
|
|
|
pub fn param_names(&self) -> &[SmolStr] {
|
2023-01-28 14:19:12 +01:00
|
|
|
&self.param_names
|
2023-01-25 19:01:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn body(&self) -> &Stmt {
|
|
|
|
|
&self.body
|
|
|
|
|
}
|
2023-01-28 14:19:12 +01:00
|
|
|
|
|
|
|
|
pub fn arity(&self) -> usize {
|
|
|
|
|
self.param_names().len()
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-02 05:19:30 +02:00
|
|
|
pub fn inject_closed_var(&mut self, name: impl Into<SmolStr>, value: Value) {
|
2023-01-28 14:19:12 +01:00
|
|
|
let name = name.into();
|
|
|
|
|
let heaped_value = HeapedValue::new(value);
|
|
|
|
|
self.closure.insert(name, heaped_value);
|
|
|
|
|
}
|
2023-01-25 19:01:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Display for LoxFunction {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
write!(f, "<fun {}>", self.name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-28 14:19:12 +01:00
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-25 19:01:13 +01:00
|
|
|
/*====================================================================================================================*/
|
|
|
|
|
|
|
|
|
|
pub type ExternFunClosure = fn(Vec<Value>, &mut Environment) -> EvalResult<Value>;
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct LoxExternFunction {
|
|
|
|
|
name: String,
|
2023-01-28 14:19:12 +01:00
|
|
|
arity: usize,
|
2023-01-25 19:01:13 +01:00
|
|
|
closure: ExternFunClosure,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LoxExternFunction {
|
2023-01-28 14:19:12 +01:00
|
|
|
pub fn new(name: impl Into<String>, arity: usize, closure: ExternFunClosure) -> Self {
|
2023-01-25 19:01:13 +01:00
|
|
|
let name = name.into();
|
|
|
|
|
|
2024-09-01 19:16:30 +02:00
|
|
|
LoxExternFunction {
|
|
|
|
|
name,
|
|
|
|
|
arity,
|
|
|
|
|
closure,
|
|
|
|
|
}
|
2023-01-28 14:19:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn name(&self) -> &str {
|
|
|
|
|
&self.name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn arity(&self) -> usize {
|
|
|
|
|
self.arity
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn closure(&self) -> ExternFunClosure {
|
|
|
|
|
self.closure
|
2023-01-25 19:01:13 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-28 01:11:55 +01:00
|
|
|
pub fn register(self, env: &mut Runtime) {
|
2023-01-25 19:01:13 +01:00
|
|
|
let name = self.name.clone();
|
|
|
|
|
let fun = Value::extern_function(self);
|
2023-01-28 01:11:55 +01:00
|
|
|
env.define_global(name, fun);
|
2023-01-25 19:01:13 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-28 14:19:12 +01:00
|
|
|
// 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
|
2023-01-25 19:01:13 +01:00
|
|
|
impl PartialEq for LoxExternFunction {
|
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
2023-01-28 14:19:12 +01:00
|
|
|
let self_ptr = self as *const LoxExternFunction;
|
|
|
|
|
let other_ptr = other as *const LoxExternFunction;
|
|
|
|
|
self_ptr == other_ptr
|
2023-01-25 19:01:13 +01:00
|
|
|
}
|
|
|
|
|
}
|