emit-portable: incremental tree reuse for portable targets (#57 S7a–S7c)#69
Merged
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
#57) Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
This was referenced Jul 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Completes the parsing side of incremental
editfor portable targets (#57): top-level subtrees outside the damage window are now reused across edits instead of reparsing the whole document. Three commits, one per layer:1.
emit-portable: record token spans on CST nodes (S7a)Every CST node now records its parse-consumption interval
[tokStart, tokEnd)in token-stream indices. Consumption semantics (entrypos→ finishpos) deliberately include trailing$punctthat CST compression drops fromchildren— byte spans alone cannot recover this (alet a=1;Stmt has byte span[0,7)but consumes the;at 7). Pratt LED nodes take the leftmost operand's start, not the led trigger position.tok-spansrunner mode + gate assertions: cross-target byte-identical output, top-level spans form a strictly increasing contiguous partition of the consumed stream.2.
emit-portable: reuse top-level subtrees across edits in TS target (S7b)Doc.edit()on eligible grammars (entry =star(rule)/star(alt(rule…)), e.g. calc and javascript) keeps top-level statements outside the damage window:ext):peek()maintainsmaxLook; each top-level subtree recordsext = max(tokEnd, maxLook). keep-prefix requiresext <= prefix— consumption span alone is unsound because backtracking (e.g. arrow-parameter probing) can peek far past what a statement ultimately consumed. A mutant usingtokEnd <= prefixis caught by the gate's peek-trap scenario.tokStart >= oldN - suffix; the damaged middle is reparsed viaparseTopOne()and adoption happens only on an exact boundary hit (pos === candidate.tokStart + tokDelta). Any miss (mid reject, overshoot) falls back to a full parse with zero mutation of old nodes.offset/end += byteDelta, token fields+= tokDelta).aligngainsreused(adopted top-level subtree count); validated mode gains atreeEqself-check (reused tree ≡ fresh parse, byte-compared), mirroringstreamEqfrom emit-portable: make streamEq self-check opt-in (S6a, #57) #68. Ineligible grammars (envspec) keep the full-parse path withreused: 0.3.
emit-portable: arena-persistent tree reuse in Go/Rust targets (S7c)Same algorithm on the flat-arena representation, which requires arenas to survive across edits:
Docnow owns long-livednodes/kids(no borrowed fields inNode); each edit builds a short-livedParserborrowing the text, moving the arena in and out viamem::take. Nounsafe.len(nodes) > 4 × max(baseline, live), the edit rebuilds fresh. Probe: 500 mid-document edits stay at max 607 rows (live 151) vs unbounded 3151 with reclamation disabled.parsewrapper returned partial trees (pos != len(toks)), unlike TS/Rust. After a rejecting edit,Dockept a partial root and the next edit's reuse path resurrected it — Go accepted documents that fresh parses reject.parsenow rejects partial consumption, matching TS, and the gate pins reject-then-edit / reject-then-repair scenarios.Validation
reusedexpectations (min/max/exact) per scenario; a 24-batch long session asserts per-batchtreeEq; alignment fields cross-checked against the oracle lexer.