///|
// Source std.map and std.slice defer the indexing expression itself. Capturing
// the current thunk would miss a subsequent removeAt mutation of the array.
fn Vm::defer_index(
self : Vm,
value : Value,
index : Double,
loc : Location,
) -> Int {
let env : Env = {
parent: None,
names: Map([("a", self.store(Ready(value)))]),
import_from: "",
debug_visible: None,
diagnostic_context: ("$", "anonymous"),
diagnostic_suppressed: false,
}
self.store(
Pending(
{
kind: Index({ kind: Var("a"), loc, end: None, }, {
kind: Literal(Json::number(index)),
loc,
end: None,
}),
loc,
end: None,
},
env,
),
)
}
///|
fn Vm::sequence(self : Vm, value : Value, loc : Location) -> Array[Int] raise {
match value {
ArrayValue(a) => a
Str(s) =>
s
.to_array()
.map(c => {
self.tick(loc)
self.store(Ready(Str(c.to_string())))
})
_ => raise problem(Type, loc, "expected array or string")
}
}
///|
fn Vm::flat_map(
self : Vm,
func : Value,
input : Value,
loc : Location,
) -> Value raise {
if value_type(func) != "function" {
raise problem(
Type,
loc,
"Unexpected type " + value_type(func) + ", expected function",
)
}
match input {
ArrayValue(items) => {
let out = []
for t in items {
self.tick(loc)
let returned = array_value(self.call(func, [(None, t)], loc), loc)
for element in returned {
self.tick(loc)
out.push(element)
}
}
ArrayValue(out)
}
Str(s) => {
let out = StringBuilder()
let mut bytes = 0
for c in s.iter() {
self.tick(loc)
let t = self.store(Ready(Str(c.to_string())))
let returned = text_value(self.call(func, [(None, t)], loc), loc)
let size = @utf8.encode(returned).length()
if size > self.limits.output_bytes - bytes {
raise problem(Limit, loc, "flatMap string exceeds output limit")
}
bytes += size
out.write_string(returned)
}
Str(out.to_string())
}
_ =>
raise problem(
Type,
loc,
"std.flatMap second param must be array / string, got " +
value_type(input),
)
}
}
///|
// Array generators defer both the call and its arguments until an element is used.
fn Vm::defer_call(
self : Vm,
func : Value,
args : Array[Int],
loc : Location,
) -> Int {
self.store(GeneratedCall(func, args, loc))
}