feat: Identifier and Bool nodes in tinyest - #2973
aleksanderkatan wants to merge 40 commits into
Conversation
|
pkg.pr.new packages benchmark commit |
Bundle size comparison (
|
| 🟢 Decreased | ➖ Unchanged | 🔴 Increased (max 0.22%) | ❔ Unknown |
|---|---|---|---|
| 0 | 319 | 6 | 0 |
No notable changes.
If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.
Resolution Time Benchmark---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Random Branching (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [1.03, 2.15, 5.00, 6.80, 8.22, 12.91, 25.50, 26.19]
line [0.99, 2.09, 4.30, 7.01, 7.66, 14.15, 27.38, 26.23]
line [0.98, 1.95, 4.50, 6.33, 7.57, 12.83, 24.54, 24.36]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Linear Recursion (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.29, 0.54, 0.73, 0.89, 1.19, 1.31, 1.51, 1.67]
line [0.30, 0.49, 0.69, 0.83, 1.18, 1.20, 1.45, 1.59]
line [0.26, 0.48, 0.71, 0.86, 1.16, 1.18, 1.47, 1.62]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Full Tree (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [1.05, 2.59, 4.98, 8.55, 13.47, 28.14, 59.45, 121.06]
line [0.83, 2.58, 3.87, 7.62, 13.16, 27.77, 59.43, 120.46]
line [0.95, 2.26, 3.48, 7.06, 12.82, 26.44, 57.18, 114.92]
|
7bfa8f1 to
2493b19
Compare
0875f09 to
ad791e6
Compare
f185e99 to
bb25ec2
Compare
bb25ec2 to
80d8699
Compare
|
@pullfrog review |
There was a problem hiding this comment.
Important
Verbose-node support is incomplete in two places. The wgslGenerator one is a latent correctness bug: extractObject never unwraps the new identifier node, so in verboseNodes mode a reassigned variable is not promoted to var and the generator can emit invalid WGSL.
Reviewed changes
Adds dedicated identifier and booleanLiteral nodes to tinyest plus an opt-in verboseNodes transpilation option, then threads the new encoding through the stringifier, the WGSL generator, and the obfuscator.
- New node types —
NodeTypeCataloggainsidentifier: 9andbooleanLiteral: 107;Identifier = string | readonly [9, string]andBool = boolean | readonly [107, boolean], withExpression/Literal/Let/Const/MemberAccesswidened to accept both encodings. TranspilationOptions.verboseNodes—transpileAcornFn/transpileBabelFn/transpileAcornNode/transpileBabelNodeaccept options (type exported from the package index); the deprecatedtranspileFn/transpileNodepass{}.- Parser support —
Identifier, external chains, acornLiteral, and babelBooleanLiteralemit the verbose nodes when the option is on. - Consumer support —
tseynit.stringifyNode,wgslGenerator(_expression, member access,let/const,for...of), andobfuscatehandle the new nodes; snapshots cover the transpilers, stringifier, and obfuscator.
ℹ️ No test exercises verbose nodes through codegen
Every added test stops at the transpiler, obfuscator, or stringifier layer; none resolves a verboseNodes AST into WGSL. That is why the extractObject miss above is not caught.
Technical details
# Verbose-path codegen coverage
## Affected sites
- `packages/typegpu/tests/` — no test drives a verbose AST through `WgslGenerator` / `tgpu.resolve`.
- `packages/typegpu/src/tgsl/wgslGenerator.ts:1998` — `extractObject` only recognizes string identifiers.
## Required outcome
- Add at least one codegen test covering verbose identifiers: a reassignment that must become `var`, and a `for...of` loop variable.
## Open questions for the human
- Is `verboseNodes` intended to become the production encoding (e.g. enabled by the plugin)? If so these wgslGenerator gaps block that step; if it stays test-only they can be follow-up.DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
| } | ||
| } | ||
|
|
||
| function extractId(ident: tinyest.Identifier): string { |
There was a problem hiding this comment.
extractId unwraps the new [NODE.identifier, name] shape, but extractObject just above (wgslGenerator.ts:1998) still returns only when typeof object === 'string'. In verboseNodes mode every identifier is a node, so tryMarkModified silently no-ops and a reassigned variable is never added to scope.modifiedVariables, staying let instead of var (wgslGenerator.ts:1160) — invalid WGSL. Unwrap the identifier the same way extractId does.
| if (node[0] === NODE.let) { | ||
| if (node[2] !== undefined) { | ||
| return `${ident}let ${node[1]} = ${stringifyExpression(node[2], ident)};`; | ||
| return `${ident}let ${stringifyExpression(node[1], ident)} = ${stringifyExpression(node[2], ident)};`; |
There was a problem hiding this comment.
This branch now routes the binding through stringifyExpression, but the no-initializer branches on lines 42 and 49 still interpolate node[1] directly, and the for...of loop variable on line 76 does the same. With verboseNodes, node[1] is a [9, name] tuple, so they print as let 9,a; and for (const 9,x of …). Route the binding through stringifyExpression in all three spots.
1c24007 to
5ef352c
Compare

Changes: