use std::rc::Rc; use itertools::Itertools; use rpds::HashTrieMap; use derive_more::Constructor; use crate::bytecode::Func as BFunc; use crate::error::Result; use crate::ir; use crate::ty::internal::{Thunk, Value}; use crate::vm::{Env, VM}; #[derive(Debug, Clone)] pub enum Param { Ident(usize), Formals { formals: Vec<(usize, Option)>, ellipsis: bool, alias: Option, }, } impl From for Param { fn from(value: ir::Param) -> Self { match value { ir::Param::Ident(ident) => Param::Ident(ident), ir::Param::Formals { formals, ellipsis, alias, } => Param::Formals { formals: formals .into_iter() .map(|(sym, default)| (sym, default.map(|default| default.idx))) .collect(), ellipsis, alias, }, } } } pub type JITFunc<'vm> = unsafe extern "C" fn(vm: *mut VM<'_>, *mut Env<'vm>, *mut Value<'vm>) -> Value<'vm>; #[derive(Debug, Clone, Constructor)] pub struct Func<'vm> { pub func: &'vm BFunc, pub env: Rc>, pub compiled: Option> } impl<'vm> Func<'vm> { pub fn call(self, vm: &'vm VM<'_>, arg: Value<'vm>) -> Result> { use Param::*; let env = Rc::new(self.env.as_ref().clone()); match self.func.param.clone() { Ident(ident) => env.enter(HashTrieMap::new().insert(ident.into(), arg)), Formals { formals, ellipsis, alias, } => { let arg = arg.unwrap_attr_set(); let mut new = HashTrieMap::new(); if !ellipsis && arg .as_inner() .iter() .map(|(k, _)| k) .sorted() .ne(formals.iter().map(|(k, _)| k).sorted()) { todo!() } for (formal, default) in formals { let formal = formal.clone().into(); let arg = arg .select(formal) .or_else(|| default.map(|idx| Value::Thunk(Thunk::new(vm.get_thunk(idx))))) .unwrap(); new.insert_mut(formal, arg); } if let Some(alias) = alias { new.insert_mut(alias.clone().into(), Value::AttrSet(arg)); } env.enter(new); } } vm.eval(self.func.opcodes.clone(), env) } } impl PartialEq for Func<'_> { fn eq(&self, _: &Self) -> bool { false } }