mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
A union that is a Set element or a Map key was a tagged box in the whole program, because the C map hashes and compares union keys by tag and payload. One `Set<Node | undefined>` made every `Node | undefined` value of the program a box, at every read. A union whose arms all compare by identity (records, class instances, arrays, functions), beside at most one undefined and one null arm, now keeps its pointer representation in collections too. The map keys such a union by reference: the pointer carries the identity, and NULL and the null sentinel are two more distinct keys. Unions with a string or another value arm keep their boxes, and library builds keep the earlier rule. The tests of the box paths keep their unions boxed through a new `boxedUnions` emission option instead of a Set of each union.
49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
// Syntax-tree walks through class nodes whose getters return optional
|
|
// children, in a program that also keeps a `Set` of the optional node type.
|
|
class TreeNode {
|
|
readonly kind: number;
|
|
private readonly kids: (TreeNode | undefined)[];
|
|
parentNode: TreeNode | undefined;
|
|
constructor(kind: number, kids: (TreeNode | undefined)[]) {
|
|
this.kind = kind;
|
|
this.kids = kids;
|
|
this.parentNode = undefined;
|
|
for (const kid of kids) if (kid !== undefined) kid.parentNode = this;
|
|
}
|
|
get left(): TreeNode | undefined {
|
|
return this.kids[0];
|
|
}
|
|
get right(): TreeNode | undefined {
|
|
return this.kids[1];
|
|
}
|
|
get parent(): TreeNode | undefined {
|
|
return this.parentNode;
|
|
}
|
|
}
|
|
|
|
function build(depth: number, seed: number): TreeNode {
|
|
if (depth === 0) return new TreeNode(seed % 7, [undefined, undefined]);
|
|
const right = seed % 11 === 0 ? undefined : build(depth - 1, seed * 7 + 3);
|
|
return new TreeNode(seed % 7, [build(depth - 1, seed * 5 + 1), right]);
|
|
}
|
|
|
|
function sumKinds(node: TreeNode | undefined): number {
|
|
let total = 0;
|
|
while (node !== undefined) {
|
|
total += node.kind;
|
|
const up = node.parent;
|
|
if (up !== undefined && up.kind === node.kind) total++;
|
|
total += sumKinds(node.right);
|
|
node = node.left;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
const root = build(20, 1);
|
|
// The one Set of the optional node type.
|
|
const marked = new Set<TreeNode | undefined>([root, root.left, undefined]);
|
|
let total = 0;
|
|
const rounds = 30 * Number(process.argv[2] ?? "1");
|
|
for (let i = 0; i < rounds; i++) total += sumKinds(root);
|
|
console.log(total, marked.size, marked.has(root.right));
|