use crate::common::*; #[derive(Derivative)] #[derivative(Debug, Clone, PartialEq = "feature_allow_slow_enum")] pub(crate) enum Thunk<'src> { Nullary { name: Name<'src>, #[derivative(Debug = "ignore", PartialEq = "ignore")] function: fn(&FunctionContext) -> Result, }, Unary { name: Name<'src>, #[derivative(Debug = "ignore", PartialEq = "ignore")] function: fn(&FunctionContext, &str) -> Result, arg: Box>, }, Binary { name: Name<'src>, #[derivative(Debug = "ignore", PartialEq = "ignore")] function: fn(&FunctionContext, &str, &str) -> Result, args: [Box>; 2], }, Ternary { name: Name<'src>, #[derivative(Debug = "ignore", PartialEq = "ignore")] function: fn(&FunctionContext, &str, &str, &str) -> Result, args: [Box>; 3], }, } impl<'src> Thunk<'src> { pub(crate) fn resolve( name: Name<'src>, mut arguments: Vec>, ) -> CompileResult<'src, Thunk<'src>> { if let Some(function) = crate::function::TABLE.get(&name.lexeme()) { match (function, arguments.len()) { (Function::Nullary(function), 0) => Ok(Thunk::Nullary { function: *function, name, }), (Function::Unary(function), 1) => Ok(Thunk::Unary { function: *function, arg: Box::new(arguments.pop().unwrap()), name, }), (Function::Binary(function), 2) => { let b = Box::new(arguments.pop().unwrap()); let a = Box::new(arguments.pop().unwrap()); Ok(Thunk::Binary { function: *function, args: [a, b], name, }) } (Function::Ternary(function), 3) => { let c = Box::new(arguments.pop().unwrap()); let b = Box::new(arguments.pop().unwrap()); let a = Box::new(arguments.pop().unwrap()); Ok(Thunk::Ternary { function: *function, args: [a, b, c], name, }) } _ => Err(name.error(CompileErrorKind::FunctionArgumentCountMismatch { function: name.lexeme(), found: arguments.len(), expected: function.argc(), })), } } else { Err(name.error(CompileErrorKind::UnknownFunction { function: name.lexeme(), })) } } } impl Display for Thunk<'_> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { use Thunk::*; match self { Nullary { name, .. } => write!(f, "{}()", name.lexeme()), Unary { name, arg, .. } => write!(f, "{}({})", name.lexeme(), arg), Binary { name, args: [a, b], .. } => write!(f, "{}({}, {})", name.lexeme(), a, b), Ternary { name, args: [a, b, c], .. } => write!(f, "{}({}, {}, {})", name.lexeme(), a, b, c), } } }