|
fn match_args(&self, args: List, stack: &mut CallStack) -> Result<(List, List), Signal> { |
|
let mut formals = self.formals(); |
|
let ellipsis: List = List::new(); |
|
let matched_args: List = List::new(); |
|
|
|
// assign named args to corresponding formals |
|
|
|
let mut indices: Vec<i32> = Vec::new(); |
|
|
|
for (i, (maybe_name, value)) in args.pairs_ref().iter().enumerate() { |
|
if let Character::Some(name) = maybe_name { |
|
if let Some((Some(_), _)) = formals.remove_named(name) { |
|
matched_args.push_named(Character::Some(name.clone()), value.clone()); |
|
continue; |
|
} |
|
} |
|
indices.push(i as i32); |
|
} |
|
|
|
let indices: Vec<Integer> = indices.into_iter().map(Integer::Some).collect(); |
|
let subset = Subset::Indices(indices.into()); |
|
let args = args.subset(subset).materialize(); |
|
|
|
// TODO(bug): need to evaluate trailing unassigned params that have |
|
// a default value before popping off remaining trailing params |
|
|
|
// remove any Ellipsis param, and any trailing unassigned params |
|
let remainder = formals.pop_trailing(); |
|
|
|
// backfill unnamed args, populating ellipsis with overflow |
|
for (key, value) in args.iter_pairs() { |
|
match key { |
|
// named args go directly to ellipsis, they did not match a formal |
|
Character::Some(arg) => ellipsis.push_named(Character::Some(arg), value), |
|
|
|
// unnamed args populate next formal, or ellipsis if formals exhausted |
|
Character::NA => { |
|
let next_unassigned_formal = formals.remove(0); |
|
if let Some((Some(param), _)) = next_unassigned_formal { |
|
matched_args.push_named(Character::Some(param), value); |
|
} else { |
|
ellipsis.push_named(Character::NA, value); |
|
} |
|
} |
|
} |
|
} |
|
|
|
// add back in parameter defaults that weren't filled with args |
|
for (param, default) in formals.into_iter() { |
|
matched_args.push_named( |
|
param.into(), |
|
Obj::Promise(None, default, stack.last_frame().env().clone()), |
|
) |
|
} |
|
|
|
if let Some(Expr::Ellipsis(Some(name))) = remainder.get(0) { |
|
matched_args.push_named(Character::Some(name), Obj::List(ellipsis.clone())); |
|
} else if !remainder.is_empty() { |
|
matched_args.push_named( |
|
Character::Some("...".to_string()), |
|
Obj::List(ellipsis.clone()), |
|
); |
|
} |
|
|
|
Ok((matched_args, ellipsis)) |
|
} |
The
Callable::match_args()(R/src/callable/core.rs
Lines 39 to 104 in 79d788a
E.g.
should throw an error because the second argument
2is unused.