Repository navigation
Commit fd4f1dd
authored
feat(ast): walk the AST export with one cursor; keep the indexed export (#1687)
* feat(ast): walk the AST export with one cursor; keep the indexed export
`Ast::dump` enumerated children with `Node::child(i)` and
`Node::field_name_for_child(i)`, commented as O(1). Both scan the
parent's child array to the index — O(log n) under a balanced
`repeat()`, O(index) under a flat node — so exporting a recovery
`ERROR` was quadratic in its width: 1.75 s against 1.2 ms over 28 000
children.
The default now walks one `Cursor`, which steps between siblings in
amortised O(1) and reports a node's grammar field from its position.
The indexed walk stays as `Ast::dump_indexed` / `AnyParser::dump_indexed`
/ `dump_indexed_inner`, with `dump_cursor` siblings naming the default
explicitly; `Cursor` gains `goto_parent` and `field_name`. Both builders
share one `Frame` / `Export` so the alterator, comment filter and
ancestor chain cannot drift between them.
Two observation counters make the dispatch testable, since no assertion
on a dump can tell the builders apart. A cross-language parity suite
compares the two strategies iteratively on every enabled language's
fixture and on the shapes those fixtures lack; a Tcl fixture pins the
ancestor chain's push half in a default build, which `Ancestors::checked`
cannot see. Three `dump/*` scaling probes price the change: routing the
default back to the indexed builder takes `dump/perl-error-tail-calls`
from 1.02 to 1.98 while its width control holds.
Fixes #1684
* refactor(ast): tighten the #1684 export docs and tests after review
- Export::finish returns ControlFlow instead of a bespoke enum.
- Test helpers take the comment flag and thread the strategy name into
assertion messages; the comment-only test runs both strategies on
both legs; one shared iterative kind counter replaces inline walks.
- Cost prose no longer calls every recovery ERROR flat (only the
EOF-recovery root is), no longer attributes the 1.75 s / 1.2 ms
enumeration micro-benchmark to the export, and states the walk as
O(n log n) on a balanced list rather than linear.
- Export doc says which half of the chain bookkeeping the default-build
debug_assert! sees; the dump/tcl-nested-eval probe is now measured
against the Ancestors::unknown() swap it prices (0.75 -> 2.00).
- Memory paragraph reports Vec capacities as capacities; the recovery
probe list points at RECOVERY_PROBES instead of a hand count.
- Cursor::field_name doc drops the false anonymous-token claim and the
test-path pointer; the grammar-bump re-check lives in the parity
module doc. Bench node counters are private.
Refs #1684
* fix(ast): correct the flat-ERROR claim and pin an inherited field in #1684's export tests
- The flat node is an ERROR at the *root* — a parse that failed at the
top level — not one from a file that ends mid-parse; a nested ERROR is
balanced. Four doc sites corrected (lesson 84; measured by the review).
- "Never quadratic" is scoped to child enumeration: Tcl's
argument_slots_are_readable is O(width) per braced word on an erroring
line, pre-existing on both strategies and on main, now #1686.
- New anchored test: Python's comparison_operator reaches its operator
tokens through an .inherited field-map entry, asserted by name on both
strategies; the parity sweep named no inherited field before.
- The Cursor::reset leg now pins that the cursor moved before asserting
the start node hides its field (a no-op reset passed it).
- Root dispatch test seeds through Ast::dump so a rerouted dump_cursor is
reported by its own row; the metadata test names the explicit strategy
before the default; # Cost heading on both Node accessors; the book's
stale pub(crate) paragraph about Node replaced with the STABILITY.md
rule; benchmarking doc states the measured widths and the count pass's
measured share.
Refs #1684, #1686
* refactor(ast): route the inherited-field test through the shared strategy helpers
Refs #1684
* test(ast): assert exact child shapes instead of failure-only format args
Codecov flagged six lines of the #1684 patch uncovered. All six were
the Debug-rendering arguments of two assert! messages, which only run
when the assertion fails. Both now compare the whole child list through
the kinds_and_fields helper, which is stronger — the `=` test used to
accept any extra child — and leaves nothing in the file that only a
failure executes.
Refs #16841 parent 4dc9ece commit fd4f1dd
13 files changed
Lines changed: 1500 additions & 212 deletions
File tree
- big-code-analysis-ast/src
- macros
- big-code-analysis-bench/src
- big-code-analysis-book/src/library
- docs/development
- src
- spaces
- tests/parity
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
187 | 187 | | |
188 | 188 | | |
189 | 189 | | |
190 | | - | |
191 | | - | |
192 | | - | |
193 | | - | |
194 | | - | |
195 | | - | |
196 | 190 | | |
197 | 191 | | |
198 | 192 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
27 | 39 | | |
28 | 40 | | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
29 | 51 | | |
30 | 52 | | |
31 | 53 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
730 | 730 | | |
731 | 731 | | |
732 | 732 | | |
733 | | - | |
734 | | - | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
735 | 740 | | |
736 | 741 | | |
737 | 742 | | |
| |||
0 commit comments