///|
/// Preview cached content without forcing child thunks, fields or assertions.
/// Unevaluated/busy/failed thunks are explicit placeholders. Recursive/cyclic
/// values and large previews obey execution step/depth and output-byte limits.
pub fn DebugValue::display(self : DebugValue) -> String raise JsonnetError {
self.check()
let writer : FormatOutput = {
out: StringBuilder(),
bytes: 0,
steps: 0,
line_start: true,
column: 0,
limits: self.vm.limits,
loc: self.location,
}
self.vm.debug_display(self.value, writer, 0) catch {
Error(d) => raise Error(d)
e => raise problem(Runtime, self.location, e.to_string())
}
writer.out.to_string()
}
///|
fn Vm::debug_thunk(
self : Vm,
id : Int,
writer : FormatOutput,
depth : Int,
) -> Unit raise {
self.tick(writer.loc)
match self.thunks[id] {
Ready(value) => self.debug_display(value, writer, depth)
Busy | Running(_) | RunningParameter(_, _) => writer.write("")
Failed(_) => writer.write("")
_ => writer.write("")
}
}
///|
fn Vm::debug_display(
self : Vm,
value : Value,
writer : FormatOutput,
depth : Int,
) -> Unit raise {
self.tick(writer.loc)
if depth >= self.limits.depth {
raise problem(Limit, writer.loc, "debug preview depth limit exceeded")
}
match value {
Nil => writer.write("null")
Bool(value) => writer.write(if value { "true" } else { "false" })
Num(value) => writer.write(manifest_number(value))
Str(value) => writer.write(Json::string(value).stringify())
ArrayValue(items) => {
writer.write("[")
for i, id in items {
if i > 0 {
writer.write(", ")
}
self.debug_thunk(id, writer, depth + 1)
}
writer.write("]")
}
ObjectValue(id, top) => {
let object = self.objects[id]
writer.write("{")
let mut first = true
for name in self.keys(id, top, false) {
self.tick(writer.loc)
let mut layer = top - 1
while layer >= 0 && !object.layers[layer].fields.contains(name) {
layer -= 1
}
if object.cache.get((layer, name)) is Some(thunk) {
if !first {
writer.write(", ")
}
first = false
writer.write(Json::string(name).stringify() + ": ")
self.debug_thunk(thunk, writer, depth + 1)
}
}
writer.write("}")
}
Closure(params, _, _) =>
writer.write("function(" + params.map(p => p.name).join(", ") + ")")
Builtin(name) =>
writer.write("function(" + builtin_params(name).join(", ") + ")")
Native(native) => writer.write("function(" + native.params.join(", ") + ")")
}
}