///|
// Validate the entire call before forcing arguments or inserting defaults.
// Positional overflow precedes named checks; missing names follow declaration
// order, including repeated formal names accepted by the parser.
fn bind_arguments(
parameters : Array[(String, Bool)],
arguments : Array[(String?, Int)],
location : Location,
) -> Map[String, Int] raise {
let positional = arguments.iter().filter(pair => pair.0 is None).count()
if positional > parameters.length() {
raise problem(
Runtime,
location,
"function expected \{parameters.length()} positional argument(s), but got \{positional}",
)
}
let accepted : Map[String, Bool] = Map([])
for (name, _) in parameters {
accepted[name] = true
}
let bound : Map[String, Int] = Map([])
let mut position = 0
for (name, thunk) in arguments {
match name {
None => {
bound[parameters[position].0] = thunk
position += 1
}
Some(name) => {
if bound.contains(name) {
raise problem(
Runtime,
location,
"Argument " + name + " already provided",
)
}
if !accepted.contains(name) {
raise problem(Runtime, location, "function has no parameter " + name)
}
bound[name] = thunk
}
}
}
for (name, required) in parameters {
if required && !bound.contains(name) {
raise problem(Runtime, location, "Missing argument: " + name)
}
}
bound
}