18 - the parse keeps each node's readable spelling, so the directive ask spells it once #105

Merged
lilleman merged 5 commits from directive-spelling-subtree into main 2026-09-19 13:50:09 +02:00
3 changed files with 12 additions and 7 deletions
Showing only changes of commit cd3bdf0d5d - Show all commits
+1 -1
View File
@@ -317,7 +317,7 @@ someone spells it or pins it.
node once rather than once per level above it (18). The node reference is the key, which holds node once rather than once per level above it (18). The node reference is the key, which holds
because the parse builds one object per position; `adfToMarkdown` passes no memo, where a because the parse builds one object per position; `adfToMarkdown` passes no memo, where a
consumer's document may hold one node at two positions (4b). `text` and `spelling` carry no depth consumer's document may hold one node at two positions (4b). `text` and `spelling` carry no depth
and `headroom` is affine in it, so a read above the depth that filled the entry rebases; a read and `headroom` is affine in it, so a read at or above the depth that filled the entry rebases; a read
below re-spells, because a hit skips the depth guards the walk it replaces runs and an ordered below re-spells, because a hit skips the depth guards the walk it replaces runs and an ordered
list past the marker cap gives way, spending two emitter levels where the parser spent one. A list past the marker cap gives way, spending two emitter levels where the parser spent one. A
give-way is kept too and serves any depth, reading the node's shape alone. Only what succeeded is give-way is kept too and serves any depth, reading the node's shape alone. Only what succeeded is
@@ -690,6 +690,9 @@ test('refuses input nested deeper than the parser carries', () => {
const overflowed = (panels: number): string => asking(overflowing(overflowing(asking(`---\n${nest(repeated('panel', panels), 'Part.\n')}`)))) const overflowed = (panels: number): string => asking(overflowing(overflowing(asking(`---\n${nest(repeated('panel', panels), 'Part.\n')}`))))
assert.equal(code(markdownToAdf(overflowed(493))), 'unsupported-node-shape') assert.equal(code(markdownToAdf(overflowed(493))), 'unsupported-node-shape')
assert.equal(code(markdownToAdf(overflowed(494))), 'unsupported-nesting-depth') assert.equal(code(markdownToAdf(overflowed(494))), 'unsupported-nesting-depth')
const rebasing = (panels: number): string => asking(`---\n${overflowing(asking(`---\n${nest(repeated('panel', panels), 'Part.\n')}`))}`)
assert.ok(markdownToAdf(rebasing(494)).ok)
assert.equal(code(markdownToAdf(rebasing(495))), 'unsupported-nesting-depth')
assert.ok(markdownToAdf(`${'- '.repeat(largestNesting)}a\n`).ok) assert.ok(markdownToAdf(`${'- '.repeat(largestNesting)}a\n`).ok)
assert.equal(code(markdownToAdf(`${'- '.repeat(largestNesting + 1)}a\n`)), 'unsupported-nesting-depth') assert.equal(code(markdownToAdf(`${'- '.repeat(largestNesting + 1)}a\n`)), 'unsupported-nesting-depth')
}) })
+8 -6
View File
@@ -840,12 +840,14 @@ The done `todo.md` items in full, as they were written. `todo.md` keeps a one-li
250 nested directive lists fall from 1.22 s to 0.04 s at 16.1 kB and from 5.20 s to 0.12 s at 250 nested directive lists fall from 1.22 s to 0.04 s at 16.1 kB and from 5.20 s to 0.12 s at
261 kB; a panel between every pair of lists 1.00 s to 0.05 s, an opaque carry in every item 261 kB; a panel between every pair of lists 1.00 s to 0.05 s, an opaque carry in every item
1.08 s to 0.03 s. No figure enters the gate (§14), as 4c settled for a behaviour-preserving 1.08 s to 0.03 s. No figure enters the gate (§14), as 4c settled for a behaviour-preserving
cost fix; what the gate holds is the refusal. The rebase's sign is pinned by the two cost fix; what the gate holds is the refusal. An ordered list past the marker cap gives way,
depth-boundary tests already there, its magnitude by a third case the review found: an ordered so the emitter spends two levels where the parser spent one: one such list between an ask and
list past the marker cap gives way, so the emitter spends two levels where the parser spent a kept entry cancels the credit the directive form starts with, and two put the read below the
one, and two such lists put a read below the depth that filled its entry — which a hit would depth that filled it — which a hit would answer without the depth guards the walk runs. That
answer without the depth guards the walk runs, naming a different refusal at a different path. read re-spells. Three cases hold the arithmetic between them: the two depth-boundary tests
That read re-spells (the stability-reviewer, 2026-09-19). The one list accounting was not already there pin the sign, the two-overflow case pins the guard, and the one-overflow case
pins the magnitude, a constant rebase accepting there a document the emitter then refuses
(the stability-reviewer, 2026-09-19). The one list accounting was not
taken: 4b settled that accounting the day this was filed, and reopening it is an ask rather taken: 4b settled that accounting the day this was filed, and reopening it is an ask rather
than a chunk. than a chunk.