use crate::parser::types::{FunctionValue, Value, LambdaParam};
use crate::parser::interpreter::lambda::call_inline_lambda_ast;
use crate::parser::interpreter::Interpreter;
pub fn is_placeholder(val: &Value) -> bool {
match val {
Value::Placeholder => true,
Value::SingleString(s) if s == "_" => true,
Value::StrArray(ss) if ss.len() == 1 && ss[0] == "_" => true,
_ => false,
}
}
pub fn apply_partial_application(
interp: &mut Interpreter,
params: Vec<LambdaParam>,
body_expr: Box<crate::parser::ast::Expr>,
mut bound_args: Vec<Value>,
args: Vec<Value>,
) -> Result<Value, String> {
if params.len() == 1 && matches!(params[0], LambdaParam::Variadic) {
let mut prev_args = match bound_args.pop() {
Some(Value::MixedArray(vals)) => vals,
_ => vec![],
};
let mut supplied = args.into_iter();
for v in prev_args.iter_mut() {
if is_placeholder(v) {
if let Some(next) = supplied.next() {
*v = next;
}
}
}
prev_args.extend(supplied);
let any_ph = prev_args.iter().any(|v| is_placeholder(v));
let final_bound_args = vec![Value::MixedArray(prev_args)];
if !any_ph {
call_inline_lambda_ast(interp, ¶ms, &body_expr, final_bound_args)
} else {
Ok(Value::Function(Box::new(FunctionValue::InlineLambdaASTPartial {
params,
body_expr,
bound_args: final_bound_args,
})))
}
}
else {
let arity = params.len();
let mut arg_idx = 0;
for arg in &args {
while arg_idx < bound_args.len() && !is_placeholder(&bound_args[arg_idx]) {
arg_idx += 1;
}
if arg_idx >= arity {
break;
}
if is_placeholder(arg) {
} else {
bound_args[arg_idx] = arg.clone();
}
arg_idx += 1;
}
if bound_args.iter().all(|v| !is_placeholder(v)) {
call_inline_lambda_ast(interp, ¶ms, &body_expr, bound_args)
} else {
Ok(Value::Function(Box::new(FunctionValue::InlineLambdaASTPartial {
params,
body_expr,
bound_args,
})))
}
}
}