Arity-based functio deinterlacing

This commit is contained in:
Alex Bethel 2021-12-14 15:56:40 -06:00
parent db95d2f718
commit 57939a87b0
3 changed files with 105 additions and 5 deletions

View file

@ -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");

View file

@ -9,6 +9,7 @@
#![deny(missing_docs)] #![deny(missing_docs)]
use std::{ use std::{
cell::RefCell, cell::RefCell,
cmp::Ordering,
collections::{HashMap, VecDeque}, collections::{HashMap, VecDeque},
io::{stdin, stdout, Read, Write}, io::{stdin, stdout, Read, Write},
mem::take, mem::take,
@ -408,12 +409,18 @@ impl ExecEnv {
Functio::Chain { functios, kind } => { Functio::Chain { functios, kind } => {
let (left_functio, right_functio) = *functios; let (left_functio, right_functio) = *functios;
let (left_args, right_args) = match kind { let (left_args, right_args) = match kind {
crate::variables::FunctioChainKind::Ordered => args.split_at(args.len() / 2), crate::variables::FunctioChainKind::Ordered => {
crate::variables::FunctioChainKind::Interlaced => todo!(), 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(left_functio, &left_args, span)?;
self.fn_call_with_values(right_functio, right_args, span)?; self.fn_call_with_values(right_functio, &right_args, span)?;
} }
Functio::Eval(code) => { Functio::Eval(code) => {
if !args.is_empty() { if !args.is_empty() {
@ -430,6 +437,41 @@ impl ExecEnv {
Ok(()) Ok(())
} }
fn deinterlace(
args: &[Rc<RefCell<Value>>],
arities: (usize, usize),
) -> (Vec<Rc<RefCell<Value>>>, Vec<Rc<RefCell<Value>>>) {
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 /// Get a single bit from the bit buffer, or refill it from
/// standard input if it is empty. /// standard input if it is empty.
fn get_bit(&mut self) -> Result<bool, Error> { fn get_bit(&mut self) -> Result<bool, Error> {

View file

@ -51,6 +51,20 @@ pub enum Functio {
Eval(String), 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)] #[derive(Debug, PartialEq, Copy, Clone, Hash)]
pub enum FunctioChainKind { pub enum FunctioChainKind {
Ordered, Ordered,