use crate::parser::interpreter::{Interpreter, DynamicFn};
use crate::parser::types::{
FunctionValue,
Value,
ComposeMode,
FunctionValue::{Composition, CompositionPartial},
};
use std::sync::{Arc, Mutex};
pub fn compose_bridge_fn(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, String> {
handle_compose_or_pipe(true, args)
}
pub fn pipe_bridge_fn(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, String> {
handle_compose_or_pipe(false, args)
}
fn handle_compose_or_pipe(is_compose: bool, raw_args: Vec<Value>) -> Result<Value, String> {
let mode = if is_compose {
ComposeMode::Compose
} else {
ComposeMode::Pipe
};
let mut slots: Vec<Option<Box<FunctionValue>>> = Vec::new();
for val in raw_args {
match val {
Value::Placeholder => {
slots.push(None);
}
Value::Function(fb) => {
slots.push(Some(fb));
}
other => {
let name = if is_compose { "compose" } else { "pipe" };
return Err(format!(
"{}(...) => each param must be a Function(...) or `_`, got {:?}",
name, other
));
}
}
}
let all_filled = slots.iter().all(|mb| mb.is_some());
if all_filled {
let fvec = slots
.into_iter()
.map(|mb| mb.unwrap())
.collect::<Vec<Box<FunctionValue>>>();
let final_comp = Composition(fvec, mode);
Ok(Value::Function(Box::new(final_comp)))
} else {
let partial = CompositionPartial { mode, slots };
Ok(Value::Function(Box::new(partial)))
}
}
pub fn register_compose_and_pipe(interp: &mut Interpreter) {
let cfn: DynamicFn = Arc::new(Mutex::new(compose_bridge_fn));
interp.register_dynamic_function("compose", cfn.clone());
interp.set_variable(
"compose",
Value::Function(Box::new(FunctionValue::Named("compose".to_string())))
);
let pfn: DynamicFn = Arc::new(Mutex::new(pipe_bridge_fn));
interp.register_dynamic_function("pipe", pfn.clone());
interp.set_variable(
"pipe",
Value::Function(Box::new(FunctionValue::Named("pipe".to_string())))
);
}