use crate::parser::types::{FunctionValue, Value, ComposeMode};
use crate::parser::interpreter::Interpreter;
use std::sync::{Arc, Mutex};
pub fn handle_composition(
interp: &mut Interpreter,
f_vec: Vec<Box<FunctionValue>>,
mode: ComposeMode,
args: Vec<Value>,
) -> Result<Value, String> {
if args.len() != 1 {
return Err(format!("Composition => expected 1 argument, got {}", args.len()));
}
let mut current_val = args.into_iter().next().unwrap();
match mode {
ComposeMode::Compose => {
for fv_box in f_vec.iter().rev() {
current_val = super::apply::apply_n_ary_function_value(interp, fv_box.clone(), vec![current_val])?;
}
}
ComposeMode::Pipe => {
for fv_box in f_vec.iter() {
current_val = super::apply::apply_n_ary_function_value(interp, fv_box.clone(), vec![current_val])?;
}
}
}
Ok(current_val)
}
pub fn handle_composition_partial(
_interp: &mut Interpreter,
mode: ComposeMode,
mut slots: Vec<Option<Box<FunctionValue>>>,
args: Vec<Value>,
) -> Result<Value, String> {
for val in args {
let mut assigned = false;
for slot in slots.iter_mut() {
if slot.is_none() {
match val {
Value::Function(fb) => {
*slot = Some(fb);
assigned = true;
break;
}
Value::Placeholder => {
assigned = true;
break;
}
other => {
return Err(format!(
"CompositionPartial => slot expects function, got {:?}",
other
));
}
}
}
if assigned {
break;
}
}
if !assigned {
return Err("CompositionPartial => no open slot or unexpected argument".to_string());
}
}
if slots.iter().all(|mb| mb.is_some()) {
let final_fvec: Vec<Box<FunctionValue>> =
slots.into_iter().map(|op| op.unwrap()).collect();
Ok(Value::Function(Box::new(FunctionValue::Composition(final_fvec, mode))))
} else {
Ok(Value::Function(Box::new(FunctionValue::CompositionPartial { mode, slots })))
}
}
pub fn handle_curried_prop(
_interp: &mut Interpreter,
k: String,
args: Vec<Value>,
) -> Result<Value, String> {
if args.is_empty() {
return Ok(Value::Function(Box::new(FunctionValue::CurriedProp(k))));
}
if args.len() > 1 {
return Err(format!("CurriedProp => expected 0 or 1 arg, got {}", args.len()));
}
let obj_val = args.into_iter().next().unwrap();
match obj_val {
Value::Placeholder => Ok(Value::Function(Box::new(FunctionValue::CurriedProp(k)))),
Value::KeyedArray(map) => {
if let Some(v) = map.get(&k) {
Ok(v.clone())
} else {
Err(format!("CurriedProp => no key '{}' in keyed array", k))
}
}
other => Err(format!(
"CurriedProp => final object must be keyed array, got {:?}",
other
)),
}
}
pub fn handle_curried_assoc(
_interp: &mut Interpreter,
k: String,
v: Value,
args: Vec<Value>,
) -> Result<Value, String> {
if args.is_empty() {
return Ok(Value::Function(Box::new(FunctionValue::CurriedAssoc(k, v))));
}
if args.len() > 1 {
return Err(format!("CurriedAssoc => expected 1 argument, got {}", args.len()));
}
let obj_val = args.into_iter().next().unwrap();
match obj_val {
Value::KeyedArray(map) => {
let mut new_map = map.clone();
new_map.insert(k, v);
Ok(Value::KeyedArray(new_map))
}
other => Err(format!(
"CurriedAssoc => final object must be keyed array, got {:?}",
other
)),
}
}
pub fn handle_rust_closure(
interp: &mut Interpreter,
desc: String,
closure_arc: Arc<Mutex<dyn for<'x> Fn(&'x mut Interpreter, Vec<Value>) -> Result<Value, String> + Send + Sync + 'static>>,
arity: usize,
args: Vec<Value>,
) -> Result<Value, String> {
if arity != 0 && args.len() != arity {
return Err(format!(
"RustClosure({}): expected {} arg(s), got {}",
desc, arity, args.len()
));
}
let lock = closure_arc
.lock()
.map_err(|_| format!("Cannot lock RustClosure for '{}'", desc))?;
lock(interp, args)
}