Skip to content

compiler: stamp node ids once, at compile time - #416

Merged
davydog187 merged 1 commit into
mainfrom
perf/ids-single-walk
Jul 27, 2026
Merged

compiler: stamp node ids once, at compile time#416
davydog187 merged 1 commit into
mainfrom
perf/ids-single-walk

Conversation

@davydog187

Copy link
Copy Markdown
Contributor

Follow-up to #400. That PR keyed scope resolution and codegen by meta.id, stamping ids in Lua.Parser.parse_chunk/1 and then again in Lua.Compiler.compile/2 — the second stamp is required for correctness (a Lua.AST.Builder chunk, or a parsed chunk with hand-built nodes spliced in, arrives unstamped or partially stamped, and an "already stamped?" early-out would cost the very walk it saves). So every parsed chunk paid for two full AST walks.

Only Lua.Compiler.Scope and Lua.Compiler.Codegen read meta.id — nothing between parse and compile touches it (verified across lib/ and website/). That makes the parser-side pass pure duplication, so this drops it.

Result

One walk per compile instead of two. Interleaved A/B (8 rounds × 20 iterations, min-of-rounds, comparing parse against parse + the removed Ids.assign):

chunk parse now parse + old stamp saved
api.lua (32 KB) 1102 µs 1561 µs 458 µs (29.4%)
strings.lua (13 KB) 466 µs 688 µs 222 µs (32.2%)

This is strictly better than both current main and pre-#400: every path that compiles still gets numbered exactly once, and the hand-built path that #400 fixed stays fixed.

Behavior change

Lua.Parser.parse/1 (and parse_raw/1, parse_structured/1, parse_chunk/1) now return chunks with meta.id unset — ids are a compiler concern, established at the compiler's boundary. Node ids were introduced in #400 and have never shipped in a release (latest tag is v1.0.1, which predates it), so no published contract changes. Docstrings on Lua.Parser.parse_chunk/1 and Lua.AST.Ids updated to say where stamping happens and that it reassigns from scratch.

test/lua/ast/ids_test.exs now applies Ids.assign/1 before asserting — including the idempotence test, which becomes the real property (assign(assign(c)) == assign(c)) rather than a statement about parser output.

Validation

https://claude.ai/code/session_01BYHGFLoHBJAsUrTzjVp5nC

`Lua.Parser.parse_chunk/1` stamped every node with a `meta.id`, and
`Lua.Compiler.compile/2` then stamped the whole chunk again — it has to,
because a chunk built with `Lua.AST.Builder` (or one carrying hand-built
nodes spliced into a parsed one) arrives unstamped, and skipping the walk
for an "already stamped" chunk would need a walk to prove.

Only scope resolution and codegen read `meta.id`, so the parser-side pass
was pure duplication. Dropping it leaves exactly one walk per compile and
saves roughly 30% of parse time (~460us on a 32KB chunk), while keeping
every compilation path — parsed, hand-built, or mixed — correctly numbered.

Parsed chunks now come back with `meta.id` unset; ids are a compiler
concern, established at the compiler's own boundary.

Claude-Session: https://claude.ai/code/session_01BYHGFLoHBJAsUrTzjVp5nC
@davydog187
davydog187 force-pushed the perf/ids-single-walk branch from a894de1 to 59f5d2c Compare July 27, 2026 19:58
@davydog187
davydog187 merged commit 9431258 into main Jul 27, 2026
5 checks passed
@davydog187
davydog187 deleted the perf/ids-single-walk branch July 27, 2026 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant