Files
lamm/src/function.rs
2024-10-27 22:01:20 -04:00

169 lines
6.0 KiB
Rust

use crate::parser::ParseTree;
use crate::executor::Executor;
use crate::{Type, Object, Value};
use super::error::Error;
use std::collections::HashMap;
use std::fmt::{self, Display};
use std::sync::{Arc, Mutex};
#[derive(Clone, Debug, PartialEq)]
pub struct FunctionType(pub Box<Type>, pub Vec<Type>);
impl Display for FunctionType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Function({}, {})", self.0, self.1.iter().map(|x| format!("{x}")).collect::<Vec<_>>().join(", "))
}
}
#[derive(Clone, Debug)]
pub struct Function {
name: Option<String>,
t: FunctionType,
globals: Option<HashMap<String, Arc<Mutex<Object>>>>,
locals: Option<HashMap<String, Arc<Mutex<Object>>>>,
arg_names: Option<Vec<String>>,
body: Box<ParseTree>,
}
impl Function {
pub(crate) fn lambda(t: FunctionType, arg_names: Vec<String>, body: Box<ParseTree>) -> Self {
Self {
name: None,
t,
globals: None,
locals: None,
arg_names: Some(arg_names),
body
}
}
pub(crate) fn named(name: &str, t: FunctionType, arg_names: Vec<String>, body: Box<ParseTree>) -> Self {
Self {
name: Some(name.to_string()),
t,
globals: None,
locals: None,
arg_names: Some(arg_names),
body
}
}
pub(crate) fn _generated(t: FunctionType, body: Box<ParseTree>) -> Self {
Self {
name: None,
t,
globals: None,
locals: None,
arg_names: None,
body,
}
}
pub(crate) fn locals(mut self, locals: HashMap<String, Arc<Mutex<Object>>>) -> Self {
self.locals = Some(locals);
self
}
pub(crate) fn globals(mut self, globals: HashMap<String, Arc<Mutex<Object>>>) -> Self {
self.globals = Some(globals);
self
}
fn _replace_locals(mut self) -> Self {
fn replace_locals_(body: Box<ParseTree>, args: &Vec<String>) -> Box<ParseTree> {
match *body {
ParseTree::Operator(op, a) =>
Box::new(ParseTree::Operator(
op,
a.into_iter().map(|x| *replace_locals_(Box::new(x), args)).collect())),
ParseTree::Equ(name, body, scope) =>
Box::new(ParseTree::Equ(
name,
replace_locals_(body, args),
replace_locals_(scope, args))),
ParseTree::LazyEqu(name, body, scope) =>
Box::new(ParseTree::LazyEqu(
name,
replace_locals_(body, args),
replace_locals_(scope, args))),
ParseTree::FunctionDefinition(func, scope) =>
Box::new(ParseTree::FunctionDefinition(func, replace_locals_(scope, args))),
ParseTree::LambdaDefinition(_) => body,
ParseTree::FunctionCall(ref func, ref a) =>
if let Some(idx) = args.into_iter().position(|r| *r == *func) {
Box::new(ParseTree::_FunctionCallLocal(
idx,
a.into_iter().map(|x| *replace_locals_(Box::new(x.clone()), args)).collect()))
} else {
Box::new(ParseTree::FunctionCall(
func.clone(),
a.into_iter().map(|x| *replace_locals_(Box::new(x.clone()), args)).collect()))
}
ParseTree::Variable(ref var) => {
if let Some(idx) = args.into_iter().position(|r| *r == *var) {
Box::new(ParseTree::_Local(idx))
} else {
body
}
},
ParseTree::If(cond, branch) =>
Box::new(ParseTree::If(replace_locals_(cond, args),
replace_locals_(branch, args))),
ParseTree::IfElse(cond, t, f) =>
Box::new(ParseTree::IfElse(replace_locals_(cond, args),
replace_locals_(t, args),
replace_locals_(f, args))),
ParseTree::_FunctionCallLocal(_, _) => body,
ParseTree::_Local(_) => body,
ParseTree::Value(_) => body,
ParseTree::Nop => body,
ParseTree::Export(_) => body,
ParseTree::NonCall(ref var) => if let Some(idx) =
args.into_iter().position(|r| *r == *var) {
Box::new(ParseTree::_Local(idx))
} else {
body
}
ParseTree::GeneratedFunction(_) => todo!(),
}
}
self.body = replace_locals_(self.body, &self.arg_names.take().unwrap());
self
}
pub(crate) fn name(&self) -> Option<&str> {
self.name.as_ref().map(|x| x.as_str())
}
pub(crate) fn get_type(&self) -> FunctionType {
self.t.clone()
}
pub(crate) fn call(&mut self, args: Vec<Arc<Mutex<Object>>>) -> Result<Value, Error> {
let globals = self.globals.clone().unwrap();
let locals = self.locals.clone().unwrap();
let mut exec = Executor::new().add_globals(globals).locals(locals.clone());
if let Some(names) = self.arg_names.clone() {
for (obj, name) in std::iter::zip(args.clone().into_iter(), names.into_iter()) {
exec = exec.add_local(name, obj);
}
}
if let Some(name) = self.clone().name().map(|x| x.to_string()) {
exec = exec.add_local(name, Arc::new(Mutex::new(Object::function(self.clone(), self.globals.clone().unwrap(), locals))));
}
exec.exec(*self.body.clone())
}
}
impl Display for Function {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.t)
}
}