Arity-based functio deinterlacing
This commit is contained in:
parent
cd902e0036
commit
f890d6248b
44
able-script-test/interlace.able
Normal file
44
able-script-test/interlace.able
Normal 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");
|
|
@ -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> {
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -504,7 +518,7 @@ impl ops::Sub for Value {
|
||||||
Functio::Chain { functios, .. } => {
|
Functio::Chain { functios, .. } => {
|
||||||
let rhs = rhs.into_functio();
|
let rhs = rhs.into_functio();
|
||||||
let (a, b) = *functios;
|
let (a, b) = *functios;
|
||||||
|
|
||||||
match (a == rhs, b == rhs) {
|
match (a == rhs, b == rhs) {
|
||||||
(_, true) => a,
|
(_, true) => a,
|
||||||
(true, _) => b,
|
(true, _) => b,
|
||||||
|
|
Loading…
Reference in a new issue