use ecow::EcoString; use itertools::Itertools; use rpds::HashTrieMap; use crate::bytecode::{OpCodes, ThunkIdx}; use crate::error::Result; use crate::ty::internal::Value; use crate::vm::{CapturedEnv, VM}; use crate::ir; #[derive(Debug, Clone)] pub enum Param { Ident(EcoString), Formals { formals: Vec<(EcoString, 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 } } } } #[derive(Debug, Clone)] pub struct Func { pub env: Option, pub param: Param, pub opcodes: OpCodes } impl Func { pub fn call(self, vm: &VM, arg: Value) -> Result { use Param::*; let env = self.env.unwrap().released(); match self.param { Ident(ident) => env.enter(HashTrieMap::new_sync().insert(ident.into(), arg)), Formals { formals, ellipsis, alias, } => { let arg = arg.unwrap_attr_set(); let mut new = HashTrieMap::new_sync(); if !ellipsis && arg .as_inner() .iter() .map(|(k, _)| k.as_inner()) .sorted() .ne(formals.iter().map(|(k, _)| k).sorted()) { todo!() } for (formal, default) in formals { let arg = arg .select(formal.clone().into()) .or_else(|| default.map(|idx| Value::Thunk(vm.get_thunk(idx)))) .unwrap(); new.insert_mut(formal.into(), arg); } if let Some(alias) = alias { new.insert_mut(alias.into(), Value::AttrSet(arg)); } env.enter(new); } } vm.eval(self.opcodes, env) } } impl PartialEq for Func { fn eq(&self, _: &Self) -> bool { false } }