///|
fn Vm::account_output(self : Vm, size : Int, loc : Location) -> Unit raise {
if size > self.limits.output_bytes - self.output_bytes {
raise problem(Limit, loc, "output byte limit exceeded")
}
self.output_bytes += size
}
///|
fn Vm::manifest(
self : Vm,
value : Value,
loc : Location,
depth : Int,
) -> Json raise {
self.tick(loc)
self.push_frame(loc, false)
defer self.pop_frame()
if depth >= self.limits.depth {
raise problem(
Limit,
loc,
"manifest depth limit exceeded (possibly cyclic object)",
)
}
try {
match value {
ArrayValue(a) => {
self.account_output(2 + Int::max(0, a.length() - 1), loc)
let values : Array[Json] = []
for index, t in a {
values.push(
self.with_trace(Synthetic("Array element \{index}"), () => {
self.manifest(self.force(t, loc), loc, depth + 1)
}),
)
}
Json::array(values)
}
ObjectValue(id, top) => {
self.with_trace(Synthetic("Checking object assertions"), () => {
self.check_assertions(id, loc)
})
let keys = self.keys(id, top, false)
self.account_output(2 + Int::max(0, keys.length() - 1), loc)
let fields : Map[String, Json] = Map([])
for k in keys {
self.account_output(
@utf8.encode(Json::string(k).stringify()).length() + 1,
loc,
)
fields[k] = self.with_trace(Synthetic("Field " + lint_quote(k)), () => {
self.manifest(self.field(id, top, k, loc), loc, depth + 1)
})
}
Json::object(fields)
}
Closure(_, _, _) | Builtin(_) | Native(_) =>
raise problem(Type, loc, "couldn't manifest function as JSON")
_ => {
let j = match value {
Nil => Json::null()
Bool(b) => Json::boolean(b)
Num(n) =>
if n.is_inf() || n.is_nan() {
Json::number(n, repr=manifest_number(n))
} else {
Json::number(n)
}
Str(s) => Json::string(s)
_ => abort("unreachable non-scalar")
}
self.account_output(@utf8.encode(j.stringify()).length(), loc)
j
}
}
} catch {
Error(d) => raise Error(self.traced(d))
e => raise e
}
}