diff --git a/able-script-test/interlace.able b/able-script-test/interlace.able new file mode 100644 index 00000000..2dca191c --- /dev/null +++ b/able-script-test/interlace.able @@ -0,0 +1,44 @@ +functio arity_0() { + "this function has arity 0" print; +} + +functio arity_1(arg1) { + "this function has arity 1" print; + arg1 print; +} + +functio arity_2(arg1, arg2) { + "this function has arity 2" print; + arg1 print; + arg2 print; +} + +functio arity_3(arg1, arg2, arg3) { + "this function has arity 3" print; + arg1 print; + arg2 print; + arg3 print; +} + +owo arity_0(); +owo arity_1("foo"); +owo arity_2("foo", "bar"); +owo arity_3("foo", "bar", "baz"); + +var i1 = arity_0 * arity_1; +i1("second"); + +"----" print; + +var i2 = arity_1 * arity_0; +i2("first"); + +"----" print; + +var ifancy = arity_3 * arity_3; +ifancy("left1", "right1", "left2", "right2", "left3", "right3"); + +"----" print; + +var another = arity_0 * arity_3; +another("right1", "right2", "right3"); diff --git a/ablescript/src/interpret.rs b/ablescript/src/interpret.rs index 0d234812..40c26369 100644 --- a/ablescript/src/interpret.rs +++ b/ablescript/src/interpret.rs @@ -9,6 +9,7 @@ #![deny(missing_docs)] use std::{ cell::RefCell, + cmp::Ordering, collections::{HashMap, VecDeque}, io::{stdin, stdout, Read, Write}, mem::take, @@ -408,12 +409,18 @@ impl ExecEnv { Functio::Chain { functios, kind } => { let (left_functio, right_functio) = *functios; let (left_args, right_args) = match kind { - crate::variables::FunctioChainKind::Ordered => args.split_at(args.len() / 2), - crate::variables::FunctioChainKind::Interlaced => todo!(), + crate::variables::FunctioChainKind::Ordered => { + let (l, r) = args.split_at(args.len() / 2); + // TODO: avoid this clone + (l.to_owned(), r.to_owned()) + } + crate::variables::FunctioChainKind::Interlaced => { + Self::deinterlace(args, (left_functio.arity(), right_functio.arity())) + } }; - self.fn_call_with_values(left_functio, left_args, span)?; - self.fn_call_with_values(right_functio, right_args, span)?; + self.fn_call_with_values(left_functio, &left_args, span)?; + self.fn_call_with_values(right_functio, &right_args, span)?; } Functio::Eval(code) => { if !args.is_empty() { @@ -430,6 +437,41 @@ impl ExecEnv { Ok(()) } + fn deinterlace( + args: &[Rc>], + arities: (usize, usize), + ) -> (Vec>>, Vec>>) { + let n_alternations = usize::min(arities.0, arities.1); + let (extra_l, extra_r) = match Ord::cmp(&arities.0, &arities.1) { + Ordering::Less => (0, arities.1 - arities.0), + Ordering::Equal => (0, 0), + Ordering::Greater => (arities.0 - arities.1, 0), + }; + + ( + args.chunks(2) + .take(n_alternations) + .map(|chunk| Rc::clone(&chunk[0])) + .chain( + args[2 * n_alternations..] + .iter() + .map(|r| Rc::clone(r)) + .take(extra_l), + ) + .collect(), + args.chunks(2) + .take(n_alternations) + .map(|chunk| Rc::clone(&chunk[1])) + .chain( + args[2 * n_alternations..] + .iter() + .map(|r| Rc::clone(r)) + .take(extra_r), + ) + .collect(), + ) + } + /// Get a single bit from the bit buffer, or refill it from /// standard input if it is empty. fn get_bit(&mut self) -> Result { diff --git a/ablescript/src/variables.rs b/ablescript/src/variables.rs index 11782976..c5b933f8 100644 --- a/ablescript/src/variables.rs +++ b/ablescript/src/variables.rs @@ -51,6 +51,20 @@ pub enum Functio { Eval(String), } +impl Functio { + pub fn arity(&self) -> usize { + match self { + Functio::Bf { + instructions: _, + tape_len: _, + } => 0, + Functio::Able { params, body: _ } => params.len(), + Functio::Chain { functios, kind: _ } => functios.0.arity() + functios.1.arity(), + Functio::Eval(_) => 0, + } + } +} + #[derive(Debug, PartialEq, Copy, Clone, Hash)] pub enum FunctioChainKind { Ordered, @@ -504,7 +518,7 @@ impl ops::Sub for Value { Functio::Chain { functios, .. } => { let rhs = rhs.into_functio(); let (a, b) = *functios; - + match (a == rhs, b == rhs) { (_, true) => a, (true, _) => b,