Expand description
The VM’s normalized differential render — format-locked to
sui_eval::render::render_tree, and refusing (never placeholdering) an
unforced thunk.
The VM’s normalized differential render — the third member of a
format-locked family.
§Why this is not to_string_keyed + string_keyed_to_json
Two renders for a VM value already existed and neither can be used for a differential:
VMValue::to_string_keyedmaps an unforced thunk toStringKeyedValue::Lambda. A value the VM failed to force therefore renders exactly like a value that legitimately is a function — and on the other side of the comparison the tree-walker’s real lambda renders<<lambda>>too. The two compare equal, so a fixture the VM could not evaluate reports agreement.string_keyed_to_json(private, in thesuibinary atsrc/main.rs) renders a thunk as the literal string"<thunk>"and has neither CppNix’soutPath/__toStringrule nor any forcing. It disagrees with the walker’sValue::to_jsonon both counts. It is not lifted here — see the divergence note below.
§What this does instead
[render_vm] emits the byte-identical form of
[sui_eval::render::render_tree] — CppNix float format, attrs sorted by
resolved name, the walker’s string escaping, raw (unquoted) paths, and
the same 128-deep <...> cap — with one deliberate difference:
A residual thunk is an Err, never a placeholder.
VM::execute already deep-forces its result, so a
Thunk still standing at render time means forcing genuinely did not
happen. Rendering that as <<lambda>> (what to_string_keyed does) or as
"<thunk>" (what the binary’s helper does) would let it compare equal to
the other engine’s placeholder. Refusing is the only rendering that cannot
launder a non-answer into an agreement.
§The residual placeholder, stated rather than hidden
<<lambda>> and <<builtin n>> are still emitted for values that really
are functions, exactly as render_tree does for the walker. Two engines
that both produce a function agree on the render without agreeing on the
body. That is a property of the walker’s own differential render, not
something introduced here, and it is why lang_corpus_vm.rs additionally
pins that no agreeing corpus row contains a placeholder at all.
§Divergence recorded, not papered over
The binary’s string_keyed_to_json and the walker’s Value::to_json
disagree: the walker implements CppNix’s rule that an attrset carrying
outPath / __toString serializes as that string, and it forces thunks;
the binary’s helper does neither. This module sides with neither — it is
not a JSON renderer at all, it is the walker’s differential render, which
is a third form that predates both and is the one already used to compare
two engines (sui-ir/tests/common/render.rs). The outPath rule is
therefore out of scope here and still unreconciled between those two JSON
paths; nothing in this file makes that better or worse.
Constants§
- DEEP_
SENTINEL - The identical marker every engine emits past
MAX_RENDER_DEPTH. - MAX_
RENDER_ DEPTH - Render-recursion depth cap — must equal
sui_eval::render::MAX_RENDER_DEPTHandsui_ir::render::MAX_RENDER_DEPTH.
Functions§
- escape_
str - The walker’s
Displaystring escaping — must equalsui_eval::render::escape_str. - render_
vm - Render a
VMValueto the normalized differential form.