The target-agnostic emitter (#6, #56) emits portable parsers in TypeScript, Go, and Rust, but they are full-parse only — they expose tokenize(src) + parse(tokens) and have no incremental re-parse. Incremental edit exists only in the JS paths:
| Path |
Incremental |
createParser() interpreter |
✅ .edit(...) |
jsTarget (optimized JS emit) |
✅ exported parseEdited (PR #38) |
portable tsTarget / goTarget / rustTarget |
❌ full parse(tokenize(src)) only |
Why
The incremental machinery — watermarked memo carry, subtree reuse (adoptPath), and the maxPos watermark — lives in the optimized path (src/emit-parser.ts / src/gen-parser.ts), shipped as parseEdited in PR #38 and gated ≡ fresh (1.4–5.6×). The portable emitter (src/emit-portable.ts's buildIR) renders a different, simpler parser: a clean backtracking recursive-descent + Pratt core with no memo / no incremental infrastructure. So nothing in the portable IR or the target-*.ts renderers can carry a prior parse forward.
What it would take
- Lift the memo-carry + watermark + subtree-reuse model into the language-agnostic IR layer so each
Target can render it.
- Per-target incremental state: ts via module globals; go/rust need incremental arena reclamation (reusing surviving subtrees without leaking the flat
nodes/kids slices).
- Extend
test/portable-targets.ts to assert edit ≡ fresh for the portable targets, mirroring the existing JS incremental gate.
Substantial — not a single-construct change. Tracking it as a known boundary of the portable emitter; the JS interpreter / jsTarget remain the path for incremental use until then.
The target-agnostic emitter (#6, #56) emits portable parsers in TypeScript, Go, and Rust, but they are full-parse only — they expose
tokenize(src)+parse(tokens)and have no incremental re-parse. Incrementaleditexists only in the JS paths:createParser()interpreter.edit(...)jsTarget(optimized JS emit)parseEdited(PR #38)tsTarget/goTarget/rustTargetparse(tokenize(src))onlyWhy
The incremental machinery — watermarked memo carry, subtree reuse (
adoptPath), and the maxPos watermark — lives in the optimized path (src/emit-parser.ts/src/gen-parser.ts), shipped asparseEditedin PR #38 and gated≡ fresh(1.4–5.6×). The portable emitter (src/emit-portable.ts'sbuildIR) renders a different, simpler parser: a clean backtracking recursive-descent + Pratt core with no memo / no incremental infrastructure. So nothing in the portable IR or thetarget-*.tsrenderers can carry a prior parse forward.What it would take
Targetcan render it.nodes/kidsslices).test/portable-targets.tsto assertedit ≡ freshfor the portable targets, mirroring the existing JS incremental gate.Substantial — not a single-construct change. Tracking it as a known boundary of the portable emitter; the JS interpreter /
jsTargetremain the path for incremental use until then.