mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-02 08:35:07 +08:00
- mapType back-references mint placeholder shapes/unions finalized at frame exit; identity is per checker type, and context-sensitive (generic/mixin) knots stay fenced - every type walk survives cyclic shape graphs: coinductive JSON/dyn-safety predicates, guarded formatIrType/jsvalLiftable, cycle headers via the existing collector fixpoint on both backends - JSON.stringify throws V8's byte-exact circular TypeError (hop lines, ellipsis rule); cyclic values crossing into checked-dynamic slots trap instead of hanging - console.log/util.inspect render <ref *N>/[Circular *N] exactly (SEMANTICS 129 resolved; depth:null lowers) and deepStrictEqual terminates through Node's pair memo - corpus 2480-2488 green on C, LLVM, and the sanitized RC-audit lane, which proves child->parent cycles collect
55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
// Recursive record types: a self-referential interface maps to a named
|
|
// recursive shape (the mu-type knot) instead of fencing — trees build,
|
|
// traverse, mutate, and reduce exactly like Node.
|
|
interface TreeNode { label: string; children: TreeNode[] }
|
|
|
|
const leafA: TreeNode = { label: "a", children: [] };
|
|
const leafB: TreeNode = { label: "b", children: [] };
|
|
const mid: TreeNode = { label: "mid", children: [leafA, leafB] };
|
|
const root: TreeNode = { label: "root", children: [mid, { label: "c", children: [] }] };
|
|
|
|
function count(n: TreeNode): number {
|
|
let total = 1;
|
|
for (const c of n.children) total += count(c);
|
|
return total;
|
|
}
|
|
|
|
function labels(n: TreeNode): string {
|
|
let out = n.label;
|
|
for (const c of n.children) out += "," + labels(c);
|
|
return out;
|
|
}
|
|
|
|
function depth(n: TreeNode): number {
|
|
let deepest = 0;
|
|
for (const c of n.children) {
|
|
const d = depth(c);
|
|
if (d > deepest) deepest = d;
|
|
}
|
|
return deepest + 1;
|
|
}
|
|
|
|
console.log(count(root));
|
|
console.log(labels(root));
|
|
console.log(depth(root));
|
|
|
|
// Mutation through the recursive field: grafting a subtree.
|
|
mid.children.push({ label: "d", children: [{ label: "e", children: [] }] });
|
|
console.log(count(root), labels(root), depth(root));
|
|
|
|
// Recursive values flow through arrays, params, and returns like any
|
|
// other record.
|
|
function collect(n: TreeNode, into: TreeNode[]): TreeNode[] {
|
|
into.push(n);
|
|
for (const c of n.children) collect(c, into);
|
|
return into;
|
|
}
|
|
const all = collect(root, []);
|
|
console.log(all.length);
|
|
let joined = "";
|
|
for (const n of all) joined += n.label;
|
|
console.log(joined);
|
|
|
|
// Reference equality is pointer identity, exactly Node.
|
|
console.log(root.children[0] === mid, leafA === leafB);
|