diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index bb79d335..af679d4b 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -407,6 +407,7 @@ impl ExecEnv { self.stack.pop(); res?; } + Functio::Builtin(b) => b.call(args).map_err(|e| Error::new(e, span.clone()))?, Functio::Chain { functios, kind } => { let (left_functio, right_functio) = *functios; match kind { diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 545f2d45..05157d46 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -44,6 +44,7 @@ pub enum Functio { params: Vec, body: Vec, }, + Builtin(BuiltinFunctio), Chain { functios: Box<(Functio, Functio)>, kind: FunctioChainKind, @@ -59,12 +60,57 @@ impl Functio { tape_len: _, } => 0, Functio::Able { params, body: _ } => params.len(), + Functio::Builtin(b) => b.arity, Functio::Chain { functios, kind: _ } => functios.0.arity() + functios.1.arity(), Functio::Eval(_) => 0, } } } +#[derive(Clone)] +pub struct BuiltinFunctio { + function: Rc>]) -> Result<(), crate::error::ErrorKind>>, + arity: usize, +} + +impl BuiltinFunctio { + pub fn new(f: F, arity: usize) -> Self + where + F: Fn(&[Rc>]) -> Result<(), crate::error::ErrorKind> + 'static, + { + Self { + function: Rc::new(f), + arity, + } + } + + pub fn call(&self, args: &[Rc>]) -> Result<(), crate::error::ErrorKind> { + (self.function)(args) + } +} + +impl std::fmt::Debug for BuiltinFunctio { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("BuiltinFunctio") + .field("function", &"built-in") + .field("arity", &self.arity) + .finish() + } +} + +impl PartialEq for BuiltinFunctio { + fn eq(&self, other: &Self) -> bool { + Rc::ptr_eq(&self.function, &other.function) && self.arity == other.arity + } +} + +impl Hash for BuiltinFunctio { + fn hash(&self, state: &mut H) { + (Rc::as_ptr(&self.function) as *const () as usize).hash(state); + self.arity.hash(state); + } +} + #[derive(Debug, PartialEq, Copy, Clone, Hash)] pub enum FunctioChainKind { Equal, @@ -134,6 +180,7 @@ impl Value { .sum::() + body.len() as i32 } + Functio::Builtin(_) => todo!(), Functio::Chain { functios, kind } => { let (lf, rf) = *functios; Value::Functio(lf).into_i32() @@ -222,6 +269,7 @@ impl Value { Value::Int((params + body) % 3 - 1).into_abool() } + Functio::Builtin(_) => todo!(), Functio::Chain { functios, kind } => { let (lhs, rhs) = *functios; match kind { @@ -391,6 +439,7 @@ impl Value { ); cart } + Functio::Builtin(_) => todo!(), Functio::Chain { functios, kind } => { let (lhs, rhs) = *functios; match kind { @@ -440,6 +489,7 @@ impl Value { tape_len, } => (instructions.len() + tape_len) as _, Functio::Able { params, body } => (params.len() + format!("{:?}", body).len()) as _, + Functio::Builtin(_) => todo!(), Functio::Chain { functios, kind } => { let (lhs, rhs) = *functios.clone(); match kind { @@ -564,6 +614,7 @@ impl ops::Sub for Value { ) .into_functio(), }, + Functio::Builtin(_) => todo!(), Functio::Chain { functios, .. } => { let rhs = rhs.into_functio(); let (a, b) = *functios; @@ -692,6 +743,7 @@ impl ops::Div for Value { .collect(), } } + Functio::Builtin(_) => todo!(), Functio::Chain { functios, kind } => { let functios = *functios; Functio::Chain { @@ -765,6 +817,7 @@ impl ops::Not for Value { Functio::Able { params, body } } + Functio::Builtin(_) => todo!(), Functio::Chain { functios, kind } => { let (a, b) = *functios; Functio::Chain { @@ -858,6 +911,7 @@ impl Display for Value { body, ) } + Functio::Builtin(_) => todo!(), Functio::Chain { functios, kind } => { let (a, b) = *functios.clone(); write!(