mustflow 2.116.1 → 2.116.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/default/i18n.toml +72 -6
- package/templates/default/locales/en/.mustflow/skills/INDEX.md +37 -11
- package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/SKILL.md +477 -0
- package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/compiler-diagnostics-abi-linker-checklist.md +778 -0
- package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/compiler-generators-properties-checklist.md +501 -0
- package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/compiler-test-strategy-differential-checklist.md +498 -0
- package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/debug-symbol-symbolication-checklist.md +412 -0
- package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/ir-design-ssa-pass-pipeline-checklist.md +759 -0
- package/templates/default/locales/en/.mustflow/skills/compiler-engineering-review/references/miscompile-reduction-ir-checklist.md +434 -0
- package/templates/default/locales/en/.mustflow/skills/cross-platform-filesystem-safety/SKILL.md +55 -36
- package/templates/default/locales/en/.mustflow/skills/cross-platform-filesystem-safety/references/path-containment-handle-checklist.md +251 -0
- package/templates/default/locales/en/.mustflow/skills/file-upload-security-review/SKILL.md +133 -32
- package/templates/default/locales/en/.mustflow/skills/file-upload-security-review/references/file-upload-parser-ssrf-resource-checklist.md +306 -0
- package/templates/default/locales/en/.mustflow/skills/formal-verification-review/SKILL.md +310 -0
- package/templates/default/locales/en/.mustflow/skills/formal-verification-review/references/formal-concurrency-model-checking-smt-checklist.md +457 -0
- package/templates/default/locales/en/.mustflow/skills/formal-verification-review/references/formal-contracts-modeling-checklist.md +434 -0
- package/templates/default/locales/en/.mustflow/skills/formal-verification-review/references/formal-memory-bounds-ci-checklist.md +509 -0
- package/templates/default/locales/en/.mustflow/skills/fuzz-harness-review/SKILL.md +439 -0
- package/templates/default/locales/en/.mustflow/skills/fuzz-harness-review/references/fuzz-harness-campaign-checklist.md +379 -0
- package/templates/default/locales/en/.mustflow/skills/fuzz-harness-review/references/fuzz-oracle-triage-ci-checklist.md +307 -0
- package/templates/default/locales/en/.mustflow/skills/idempotency-integrity-review/SKILL.md +48 -28
- package/templates/default/locales/en/.mustflow/skills/idempotency-integrity-review/references/operation-ordering-stale-write-checklist.md +259 -0
- package/templates/default/locales/en/.mustflow/skills/input-boundary-validation-review/SKILL.md +329 -0
- package/templates/default/locales/en/.mustflow/skills/input-boundary-validation-review/references/input-boundary-security-checklist.md +319 -0
- package/templates/default/locales/en/.mustflow/skills/input-event-synchronization-review/SKILL.md +306 -0
- package/templates/default/locales/en/.mustflow/skills/input-event-synchronization-review/references/input-session-state-checklist.md +298 -0
- package/templates/default/locales/en/.mustflow/skills/input-event-synchronization-review/references/remote-input-transport-interaction-checklist.md +328 -0
- package/templates/default/locales/en/.mustflow/skills/interpreter-engineering-review/SKILL.md +353 -0
- package/templates/default/locales/en/.mustflow/skills/interpreter-engineering-review/references/interpreter-diagnostics-recovery-checklist.md +267 -0
- package/templates/default/locales/en/.mustflow/skills/interpreter-engineering-review/references/interpreter-execution-closure-performance-checklist.md +428 -0
- package/templates/default/locales/en/.mustflow/skills/interpreter-engineering-review/references/interpreter-gc-verification-checklist.md +457 -0
- package/templates/default/locales/en/.mustflow/skills/interpreter-engineering-review/references/interpreter-semantics-runtime-checklist.md +391 -0
- package/templates/default/locales/en/.mustflow/skills/modal-loop-reentrancy-review/SKILL.md +294 -0
- package/templates/default/locales/en/.mustflow/skills/modal-loop-reentrancy-review/references/modal-loop-reentrancy-checklist.md +290 -0
- package/templates/default/locales/en/.mustflow/skills/modal-loop-reentrancy-review/references/nested-modal-state-lifetime-checklist.md +297 -0
- package/templates/default/locales/en/.mustflow/skills/name-resolution-integrity-review/SKILL.md +252 -0
- package/templates/default/locales/en/.mustflow/skills/name-resolution-integrity-review/references/dns-network-resolution-checklist.md +394 -0
- package/templates/default/locales/en/.mustflow/skills/name-resolution-integrity-review/references/language-symbol-resolution-checklist.md +282 -0
- package/templates/default/locales/en/.mustflow/skills/name-resolution-integrity-review/references/module-package-loader-resolution-checklist.md +352 -0
- package/templates/default/locales/en/.mustflow/skills/parser-engineering-review/SKILL.md +103 -17
- package/templates/default/locales/en/.mustflow/skills/parser-engineering-review/references/cst-ast-lowering-checklist.md +260 -0
- package/templates/default/locales/en/.mustflow/skills/parser-engineering-review/references/lexer-tokenization-checklist.md +397 -0
- package/templates/default/locales/en/.mustflow/skills/parser-engineering-review/references/tree-serialization-compatibility-checklist.md +164 -0
- package/templates/default/locales/en/.mustflow/skills/parser-engineering-review/references/tree-traversal-rewrite-checklist.md +209 -0
- package/templates/default/locales/en/.mustflow/skills/race-condition-review/SKILL.md +68 -11
- package/templates/default/locales/en/.mustflow/skills/race-condition-review/references/race-reproduction-memory-model-checklist.md +268 -0
- package/templates/default/locales/en/.mustflow/skills/routes.toml +151 -0
- package/templates/default/locales/en/.mustflow/skills/session-handoff-integrity-review/SKILL.md +343 -0
- package/templates/default/locales/en/.mustflow/skills/session-handoff-integrity-review/references/session-auth-stream-resume-checklist.md +413 -0
- package/templates/default/locales/en/.mustflow/skills/session-handoff-integrity-review/references/session-handoff-protocol-checklist.md +485 -0
- package/templates/default/locales/en/.mustflow/skills/two-phase-transition-integrity-review/SKILL.md +267 -0
- package/templates/default/locales/en/.mustflow/skills/two-phase-transition-integrity-review/references/admission-decision-recovery-checklist.md +308 -0
- package/templates/default/locales/en/.mustflow/skills/two-phase-transition-integrity-review/references/two-phase-transition-checklist.md +229 -0
- package/templates/default/locales/en/.mustflow/skills/ui-dispatch-lifecycle-review/SKILL.md +300 -0
- package/templates/default/locales/en/.mustflow/skills/ui-dispatch-lifecycle-review/references/ui-affinity-event-loop-checklist.md +277 -0
- package/templates/default/locales/en/.mustflow/skills/ui-dispatch-lifecycle-review/references/ui-dispatch-lifecycle-checklist.md +292 -0
- package/templates/default/manifest.toml +115 -1
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# CST to AST Lowering Checklist
|
|
2
|
+
|
|
3
|
+
Use this checklist when a parser produces a concrete syntax tree, surface AST, semantic AST, HIR,
|
|
4
|
+
or another lowered tree consumed by diagnostics, formatting, refactoring, compilation, or execution.
|
|
5
|
+
|
|
6
|
+
## Contents
|
|
7
|
+
|
|
8
|
+
1. [Layer contract ledger](#layer-contract-ledger)
|
|
9
|
+
2. [Lossless CST invariants](#lossless-cst-invariants)
|
|
10
|
+
3. [Surface AST boundary](#surface-ast-boundary)
|
|
11
|
+
4. [AST schema and local invariants](#ast-schema-and-local-invariants)
|
|
12
|
+
5. [Absence, recovery, and synthetic states](#absence-recovery-and-synthetic-states)
|
|
13
|
+
6. [Tokens, trivia, parentheses, and source views](#tokens-trivia-parentheses-and-source-views)
|
|
14
|
+
7. [Lowering map and origin evidence](#lowering-map-and-origin-evidence)
|
|
15
|
+
8. [Semantic-sensitive syntax](#semantic-sensitive-syntax)
|
|
16
|
+
9. [Evaluation order, scope, and reference semantics](#evaluation-order-scope-and-reference-semantics)
|
|
17
|
+
10. [Identity, side tables, and snapshots](#identity-side-tables-and-snapshots)
|
|
18
|
+
11. [Tree verification](#tree-verification)
|
|
19
|
+
12. [Test matrix](#test-matrix)
|
|
20
|
+
13. [Failure matrix](#failure-matrix)
|
|
21
|
+
14. [Invariants and handoffs](#invariants-and-handoffs)
|
|
22
|
+
|
|
23
|
+
## Layer contract ledger
|
|
24
|
+
|
|
25
|
+
Classify a tree by what it may lose, not by whether its type name contains `AST`, `syntax`, or
|
|
26
|
+
`parse tree`. Write one row per layer:
|
|
27
|
+
|
|
28
|
+
| Layer | Must preserve | May normalize | Primary consumers |
|
|
29
|
+
| --- | --- | --- | --- |
|
|
30
|
+
| Source and tokens | Original units, token boundaries, raw spelling, trivia, invalid input | Derived line and display coordinates | lexer, diagnostics, syntax tree |
|
|
31
|
+
| Lossless CST | Every source unit, delimiters, missing and unexpected syntax, exact order | Parser-only rule wrappers when reconstruction remains exact | formatter, refactoring, IDE, lowering |
|
|
32
|
+
| Surface AST | User-visible language constructs, semantic punctuation, order, scope owners, syntax origin | Pure grammar wrappers and non-semantic trivia | binder, type checker, source tools |
|
|
33
|
+
| HIR or core tree | Explicit evaluation order, normalized constructs, generated temporaries, origin map | Surface sugar and redundant grouping | semantic analysis, optimization, execution |
|
|
34
|
+
| Side tables | Symbols, types, constants, control-flow facts, phase and snapshot identity | Derived query indexes | later analyses and tools |
|
|
35
|
+
|
|
36
|
+
For every removed field or node, name the first layer that is allowed to remove it and the consumer
|
|
37
|
+
that no longer needs it. A successful parse is not evidence that the loss boundary is correct.
|
|
38
|
+
|
|
39
|
+
## Lossless CST invariants
|
|
40
|
+
|
|
41
|
+
- Account for every original source unit exactly once through tokens, trivia, skipped input, or
|
|
42
|
+
unexpected-syntax nodes.
|
|
43
|
+
- Represent a required but absent token as a zero-width missing token at one insertion point. Do not
|
|
44
|
+
print it as if the user wrote it.
|
|
45
|
+
- Keep unexpected tokens and recovery spans distinct from accepted children. Do not discard them or
|
|
46
|
+
coerce them into plausible normal tokens.
|
|
47
|
+
- Preserve delimiter tokens and their exact order even when a later AST represents the resulting
|
|
48
|
+
structure without punctuation nodes.
|
|
49
|
+
- Make reconstruction of the original source possible for valid and malformed input without asking
|
|
50
|
+
the AST to guess whitespace, comments, escapes, or invalid bytes.
|
|
51
|
+
- Keep grammar-helper nodes only when they carry observable structure, recovery boundaries, or a
|
|
52
|
+
stable incremental responsibility. Do not expose every factored production as a public tree API.
|
|
53
|
+
|
|
54
|
+
## Surface AST boundary
|
|
55
|
+
|
|
56
|
+
Use the question `must a downstream semantic or source-aware consumer distinguish these forms?` to
|
|
57
|
+
decide whether two CST forms may become one AST form.
|
|
58
|
+
|
|
59
|
+
- Collapse grammar wrappers that exist only for precedence encoding, conflict removal, or parser
|
|
60
|
+
control flow.
|
|
61
|
+
- Preserve constructs whose evaluation, scope, binding, control flow, arity, reference behavior,
|
|
62
|
+
diagnostics, or refactoring behavior differs.
|
|
63
|
+
- Classify punctuation as disposable separator, semantic field, or structural discriminator before
|
|
64
|
+
removing it. An operator normally becomes a typed field; a comma, newline, or delimiter can decide
|
|
65
|
+
tuple, elision, statement, pattern, or argument structure.
|
|
66
|
+
- Preserve explicit grouping through a syntax reference, grouping node, or ordered delimiter ranges
|
|
67
|
+
when formatting, refactoring, diagnostics, or user-intent preservation needs it.
|
|
68
|
+
- Keep a surface construct until a dedicated lowering step can prove that desugaring preserves
|
|
69
|
+
evaluation count, evaluation order, exceptions, scope, and source origin.
|
|
70
|
+
- Introduce a separate HIR or core layer when source tools need surface constructs but execution and
|
|
71
|
+
analysis need normalized forms. Do not make one node schema alternate between both contracts.
|
|
72
|
+
|
|
73
|
+
## AST schema and local invariants
|
|
74
|
+
|
|
75
|
+
- Use closed tagged unions for material categories and variants. Make visitors exhaustive when a new
|
|
76
|
+
expression, statement, declaration, pattern, type, or target is added.
|
|
77
|
+
- Separate `Expr`, `Stmt`, `Decl`, `Pattern`, `TypeNode`, and `AssignmentTarget` when their legal
|
|
78
|
+
positions and invariants differ.
|
|
79
|
+
- Expose children through named fields. Keep repeated children in immutable source-order sequences;
|
|
80
|
+
derive maps or sets as indexes rather than replacing order-bearing syntax.
|
|
81
|
+
- Encode cardinality in field types: required child, optional child, or non-null immutable sequence.
|
|
82
|
+
Do not overload one null value with absence, error, not-yet-computed, and empty collection.
|
|
83
|
+
- Construct a complete immutable node in one step. Keep partially initialized builders private and
|
|
84
|
+
prevent incomplete nodes from escaping.
|
|
85
|
+
- Enforce local invariants in constructors and context-dependent invariants in a separate validation
|
|
86
|
+
pass. A child constructor cannot decide whether `break`, `await`, or a binding is legal in its
|
|
87
|
+
eventual parent context.
|
|
88
|
+
- Give structural children one logical parent. Share immutable storage nodes or interned payloads,
|
|
89
|
+
and derive parent views separately when structural reuse is required.
|
|
90
|
+
|
|
91
|
+
## Absence, recovery, and synthetic states
|
|
92
|
+
|
|
93
|
+
Model distinct states explicitly:
|
|
94
|
+
|
|
95
|
+
| State | Meaning |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `Absent` | An optional construct was not written. |
|
|
98
|
+
| `Missing` | Required syntax was absent and recovery inserted a placeholder. |
|
|
99
|
+
| `Synthetic` | A tool or lowering pass created the node. |
|
|
100
|
+
| `Empty` | The user wrote a valid empty construct. |
|
|
101
|
+
| `Elided` | The language permits an omitted slot whose position remains meaningful. |
|
|
102
|
+
| `Error` | Source was present but no normal semantic node can truthfully represent it. |
|
|
103
|
+
|
|
104
|
+
- Keep category-specific error nodes such as `ErrorExpr`, `ErrorStmt`, or `ErrorPattern` so later
|
|
105
|
+
passes remain type-safe without inventing executable meaning.
|
|
106
|
+
- Never replace missing names, numbers, operands, or delimiters with empty names, zero values, null
|
|
107
|
+
literals, or normal tokens unless the language explicitly defines that recovery semantics.
|
|
108
|
+
- Give synthetic nodes a generation reason, originating node identity, and primary or secondary
|
|
109
|
+
source origins. Do not rely on a single `isSynthetic` flag.
|
|
110
|
+
- Prevent compilation, execution, or serialization as valid code when a required error or missing
|
|
111
|
+
state remains, unless the consumer explicitly accepts an incomplete-tree contract.
|
|
112
|
+
|
|
113
|
+
## Tokens, trivia, parentheses, and source views
|
|
114
|
+
|
|
115
|
+
- Keep original source storage and a lossless token stream as the source-aware truth. Let AST nodes
|
|
116
|
+
refer to syntax instead of copying partial source fragments into every semantic node.
|
|
117
|
+
- Preserve token kind, canonical raw range, raw spelling or source slice, cooked value or invalid
|
|
118
|
+
state, and applicable lexical provenance separately.
|
|
119
|
+
- Distinguish node span, full span including trivia, name span, operator span, and delimiter spans.
|
|
120
|
+
Make each consumer request the range it actually needs.
|
|
121
|
+
- Treat token gaps as the canonical trivia location. Compute leading, trailing, dangling, preamble,
|
|
122
|
+
end-of-file, and unattached ownership through a deterministic attachment policy.
|
|
123
|
+
- Preserve whitespace as source slices or typed runs when exact reconstruction matters. Do not
|
|
124
|
+
collapse tabs, spaces, line endings, escaped newlines, or other whitespace into one count.
|
|
125
|
+
- Preserve nested parentheses and per-pair ranges through CST or syntax references. One boolean
|
|
126
|
+
cannot represent repeated grouping, comments inside delimiters, or exact edit boundaries.
|
|
127
|
+
- Reuse unchanged source slices when printing unchanged syntax and format only changed subtrees.
|
|
128
|
+
Reconcile boundary trivia explicitly instead of reformatting the whole file.
|
|
129
|
+
|
|
130
|
+
## Lowering map and origin evidence
|
|
131
|
+
|
|
132
|
+
Create a CST-to-AST loss ledger and a lowering entry for every concrete variant:
|
|
133
|
+
|
|
134
|
+
- input CST kind and accepted recovery states;
|
|
135
|
+
- output surface-AST kind and named fields;
|
|
136
|
+
- tokens, trivia, delimiters, and wrappers preserved by syntax reference;
|
|
137
|
+
- information intentionally consumed or normalized;
|
|
138
|
+
- diagnostics or error node produced when required evidence is missing;
|
|
139
|
+
- origin mapping for one-to-one, many-to-one, and one-to-many transformations;
|
|
140
|
+
- verifier expected before and after the transformation.
|
|
141
|
+
|
|
142
|
+
Do not lower irreversible semantic constructs inside parser callbacks. Publish a complete CST first,
|
|
143
|
+
then run a deterministic lowering pass whose inputs and outputs can be inspected independently.
|
|
144
|
+
Reject an unhandled concrete variant rather than silently returning null or a generic node.
|
|
145
|
+
|
|
146
|
+
For generated temporaries and expanded control flow, map the lowered nodes back to the originating
|
|
147
|
+
surface construct and material subexpressions. Preserve both a primary diagnostic origin and any
|
|
148
|
+
secondary origins needed to explain duplicated or reordered structure.
|
|
149
|
+
|
|
150
|
+
## Semantic-sensitive syntax
|
|
151
|
+
|
|
152
|
+
- Preserve parser decisions for contextual keywords, generic delimiters, patterns, and other forms
|
|
153
|
+
that cannot be reconstructed from token spelling alone.
|
|
154
|
+
- Preserve tuple, argument, sequence, grouping, and elision distinctions before discarding commas or
|
|
155
|
+
delimiters.
|
|
156
|
+
- Preserve statement boundaries and newline-sensitive decisions made by the grammar. Do not rebuild
|
|
157
|
+
them from a trivia-stripped token list.
|
|
158
|
+
- Carry raw spelling and exact language-defined literal representation until conversion has a
|
|
159
|
+
precise overflow, invalid-escape, suffix, and normalization contract.
|
|
160
|
+
- Keep pattern and assignment-target structure separate from expression structure when read, write,
|
|
161
|
+
delete, binding, default, and rest rules differ.
|
|
162
|
+
- Use the parser's already established precedence and associativity tree. Do not flatten operators
|
|
163
|
+
and re-fold them under a second, potentially divergent table.
|
|
164
|
+
|
|
165
|
+
## Evaluation order, scope, and reference semantics
|
|
166
|
+
|
|
167
|
+
- Lower compound assignment, optional access, logical assignment, comprehensions, iteration sugar,
|
|
168
|
+
async forms, and similar constructs with explicit temporaries that evaluate each material operand
|
|
169
|
+
the language-defined number of times and in the defined order.
|
|
170
|
+
- Preserve exceptions and side effects while introducing temporaries. Validate read, operation,
|
|
171
|
+
write, short-circuit, and cleanup order separately.
|
|
172
|
+
- Preserve receiver or reference identity when a member call differs from loading a function value
|
|
173
|
+
and calling it independently.
|
|
174
|
+
- Represent scope owners, binders, defaults, guards, and child evaluation regions explicitly. Do not
|
|
175
|
+
flatten a construct whose children execute in different scopes.
|
|
176
|
+
- Keep duplicate and ordered elements in source order when evaluation, override, reflection,
|
|
177
|
+
diagnostics, or tooling can observe them.
|
|
178
|
+
- Record desugaring decisions in the origin map so diagnostics point to user-written syntax rather
|
|
179
|
+
than invented temporaries or control-flow nodes.
|
|
180
|
+
|
|
181
|
+
## Identity, side tables, and snapshots
|
|
182
|
+
|
|
183
|
+
- Keep `NodeId`, source span, and structural hash distinct. A span is a location, a hash compares
|
|
184
|
+
content, and a node identity names one occurrence in a versioned tree.
|
|
185
|
+
- Exclude spans, trivia, and raw spelling from semantic structural equality when they do not affect
|
|
186
|
+
meaning. Maintain a separate syntax or source hash when exact spelling matters.
|
|
187
|
+
- Keep resolved symbols, inferred types, constants, control-flow facts, and other phase results in
|
|
188
|
+
generation-aware side tables keyed by node and snapshot identity. Do not replace syntax fields
|
|
189
|
+
with resolved objects in place.
|
|
190
|
+
- Reuse syntax identity after an edit only when the unchanged subtree and its parser context remain
|
|
191
|
+
valid. Invalidate dependent side-table entries by semantic dependency, not only by text overlap.
|
|
192
|
+
- Version syntax references and origin maps so a node cannot silently point into an obsolete source
|
|
193
|
+
snapshot.
|
|
194
|
+
- When nodes move without semantic change, preserve semantic comparability without claiming that the
|
|
195
|
+
old and new source occurrences are the same identity.
|
|
196
|
+
|
|
197
|
+
## Tree verification
|
|
198
|
+
|
|
199
|
+
Run a verifier after parsing and after every material lowering stage. Check:
|
|
200
|
+
|
|
201
|
+
- unique node identities within the declared identity scope;
|
|
202
|
+
- absence of structural cycles and illegal multi-parent ownership;
|
|
203
|
+
- child category, field cardinality, and source-order constraints;
|
|
204
|
+
- valid source ranges, delimiter ordering, and snapshot ownership;
|
|
205
|
+
- allowed missing, error, synthetic, and elided states for the current phase;
|
|
206
|
+
- complete lowering coverage and no parser-only wrapper in phases that forbid it;
|
|
207
|
+
- valid origin mapping for generated, merged, and split nodes;
|
|
208
|
+
- phase-specific rules such as no surface sugar after core lowering;
|
|
209
|
+
- side-table generation and node-snapshot compatibility.
|
|
210
|
+
|
|
211
|
+
Make verifier failures diagnostic and bounded. A malformed tree must not crash its printer, walker,
|
|
212
|
+
or diagnostic renderer before the verifier can identify the broken invariant.
|
|
213
|
+
|
|
214
|
+
## Test matrix
|
|
215
|
+
|
|
216
|
+
- Reconstruct exact original source from the CST for valid, invalid, incomplete, mixed-line-ending,
|
|
217
|
+
escaped, commented, and delimiter-heavy inputs.
|
|
218
|
+
- Assert surface-AST shape for punctuation-sensitive forms, operator pairs and triples, grouping,
|
|
219
|
+
contextual syntax, patterns, targets, scopes, and error nodes.
|
|
220
|
+
- Compare AST results across grammar refactors that change parser-only wrapper productions.
|
|
221
|
+
- Trace side effects and exceptions through sugar lowering to prove operand count, order, receiver,
|
|
222
|
+
scope, short-circuit, and cleanup behavior.
|
|
223
|
+
- Exercise every absence state and verify that missing or erroneous syntax never becomes an ordinary
|
|
224
|
+
executable value.
|
|
225
|
+
- Move and edit comments around empty containers, delimiters, preambles, and EOF; verify deterministic
|
|
226
|
+
trivia ownership and minimal unchanged-source edits.
|
|
227
|
+
- Compare incremental CST, AST, origin maps, and side-table invalidation with a fresh full pipeline
|
|
228
|
+
after edit sequences.
|
|
229
|
+
- Mutate each AST field and phase tag to prove the verifier rejects wrong categories, null required
|
|
230
|
+
fields, duplicate identities, cycles, stale origins, and forbidden phase nodes.
|
|
231
|
+
- Test both semantic equality and exact syntax equality so a source move or spelling change does not
|
|
232
|
+
accidentally poison semantic caches or disappear from source-aware tools.
|
|
233
|
+
|
|
234
|
+
## Failure matrix
|
|
235
|
+
|
|
236
|
+
| Symptom | Evidence to require |
|
|
237
|
+
| --- | --- |
|
|
238
|
+
| Formatter loses comments or whitespace. | Token gaps, trivia attachment, full spans, syntax references, and unchanged-slice reuse. |
|
|
239
|
+
| Grammar refactor changes public AST. | Concrete-variant lowering map, wrapper normalization rule, and AST golden diff. |
|
|
240
|
+
| Valid-looking AST came from malformed input. | Missing and unexpected CST nodes, category-specific error node, and execution gate. |
|
|
241
|
+
| Compound assignment evaluates a target twice. | Surface sugar node, temporary plan, evaluation trace, and origin map. |
|
|
242
|
+
| Rename or diagnostic points at the wrong text. | Snapshot identity, name span, raw token range, syntax reference, and origin generation. |
|
|
243
|
+
| Incremental analysis reuses stale facts. | Node and snapshot identity, changed semantic dependency, side-table generation, and full-pipeline differential. |
|
|
244
|
+
| Parentheses or commas change meaning after lowering. | Parser decision, structural discriminator, surface-AST shape, and semantic equality oracle. |
|
|
245
|
+
| Tree walker crashes after successful parse. | Constructor invariants, phase verifier, error-node schema, cycle and category checks. |
|
|
246
|
+
|
|
247
|
+
## Invariants and handoffs
|
|
248
|
+
|
|
249
|
+
- Every source unit is owned by the lossless syntax layer before any abstraction occurs.
|
|
250
|
+
- Every information loss names the owning lowering stage and a consumer contract that permits it.
|
|
251
|
+
- Every normal AST node represents written or explicitly synthetic meaning; recovery never forges a
|
|
252
|
+
user-written value.
|
|
253
|
+
- Every order-bearing construct remains ordered until a later phase proves order unobservable.
|
|
254
|
+
- Every generated node has an origin and every side-table fact has a snapshot generation.
|
|
255
|
+
- Every lowering stage has an input verifier, output verifier, and differential or semantic oracle.
|
|
256
|
+
- Use `parser-engineering-review` for CST, AST, recovery, source, and incremental ownership.
|
|
257
|
+
- Use `compiler-engineering-review` for HIR or IR semantic refinement after the parser boundary.
|
|
258
|
+
- Use `interpreter-engineering-review` when lowered nodes directly define runtime evaluation.
|
|
259
|
+
- Use `name-resolution-integrity-review` when bindings and symbol side tables are the disputed layer.
|
|
260
|
+
- Use `observability-debuggability-review` when durable tree or lowering diagnostics change.
|
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# Lexer and Tokenization Contract Checklist
|
|
2
|
+
|
|
3
|
+
Use this reference when `parser-engineering-review` reaches a lexer, tokenizer, token cache,
|
|
4
|
+
source-position layer, or incremental relexing boundary. Treat the examples as collision probes,
|
|
5
|
+
not as syntax that every language must accept. Freeze the language-specific decision before changing
|
|
6
|
+
implementation or tests.
|
|
7
|
+
|
|
8
|
+
## Contents
|
|
9
|
+
|
|
10
|
+
1. Token representation
|
|
11
|
+
2. Candidate selection and longest match
|
|
12
|
+
3. Identifiers and keywords
|
|
13
|
+
4. Operators, lexical modes, and goals
|
|
14
|
+
5. Encoding, Unicode, newlines, and positions
|
|
15
|
+
6. Strings and escapes
|
|
16
|
+
7. Numbers, comments, and malformed input
|
|
17
|
+
8. Streaming outcomes and recovery diagnostics
|
|
18
|
+
9. Incremental and large-input behavior
|
|
19
|
+
10. Hostile-input and resource budgets
|
|
20
|
+
11. Differential, fuzz, and property tests
|
|
21
|
+
12. Standards and implementation anchors
|
|
22
|
+
|
|
23
|
+
## 1. Token representation
|
|
24
|
+
|
|
25
|
+
Define one token contract before implementing scanner branches. Keep these concerns separate:
|
|
26
|
+
|
|
27
|
+
- `kind`: stable lexical classification, including explicit malformed or unterminated kinds when
|
|
28
|
+
callers need recovery.
|
|
29
|
+
- `span`: canonical half-open source range, normally `[startByte, endByte)` over the original byte
|
|
30
|
+
stream. Never make a decoded or normalized buffer the silent source of truth.
|
|
31
|
+
- `raw`: source slice identity or raw spelling. Avoid allocating a copied `rawText` for every token
|
|
32
|
+
when an immutable source buffer can provide the same lossless view.
|
|
33
|
+
- `cooked`: decoded escape, normalized identifier key, or literal value representation. Make an
|
|
34
|
+
invalid or unavailable cooked value explicit instead of overwriting raw source.
|
|
35
|
+
- `positions`: typed derived coordinates such as line index, UTF-16 offset, code-point offset, or
|
|
36
|
+
display column. Name the unit and conversion owner.
|
|
37
|
+
- `trivia`: whitespace and comments with raw spans plus applicable newline effects. Do not erase a
|
|
38
|
+
line break merely because the surrounding comment is skipped by the parser.
|
|
39
|
+
- `diagnostics`: stable code, severity, arguments, primary and related raw spans, fix-its, and
|
|
40
|
+
recovery information. Preserve a token boundary even when cooking fails, and keep message
|
|
41
|
+
rendering out of the scanner.
|
|
42
|
+
|
|
43
|
+
Require token and trivia spans to account for every original source byte exactly once, except for
|
|
44
|
+
declared zero-width synthetic insertions. Keep parser-inserted missing tokens separate from lexical
|
|
45
|
+
tokens that cover real input.
|
|
46
|
+
|
|
47
|
+
## 2. Candidate selection and longest match
|
|
48
|
+
|
|
49
|
+
Define selection as data, not rule-file folklore:
|
|
50
|
+
|
|
51
|
+
1. Start every candidate at the same input position.
|
|
52
|
+
2. Continue scanning while at least one candidate can progress.
|
|
53
|
+
3. Whenever a candidate accepts, record its last accepting rule, comparison end, actual token end,
|
|
54
|
+
and any capture state required to emit it.
|
|
55
|
+
4. When no candidate can progress, choose the greatest comparison end. Use an explicit, stable
|
|
56
|
+
priority only when comparison lengths tie.
|
|
57
|
+
5. Rewind to the chosen token end and emit. If no candidate ever accepted, consume one bounded
|
|
58
|
+
invalid source unit while preserving its raw byte range and emit an error token.
|
|
59
|
+
|
|
60
|
+
Keep `comparisonEnd` distinct from `tokenEnd` when lookahead or trailing context participates in
|
|
61
|
+
candidate comparison but must remain unconsumed. Reject equal-length, equal-priority overlaps during
|
|
62
|
+
grammar or table generation. Reordering declarations must not change output when explicit priority
|
|
63
|
+
is unchanged.
|
|
64
|
+
|
|
65
|
+
Build fixed operators and punctuators as a trie or equivalent DFA. Generate collision cases for
|
|
66
|
+
every prefix relation rather than maintaining hand-written `if` order. Include follower predicates
|
|
67
|
+
in the accepting condition when the next code point changes whether a candidate is lexically valid.
|
|
68
|
+
|
|
69
|
+
Examples to classify together include:
|
|
70
|
+
|
|
71
|
+
- `>`, `>=`, `>>`, `>>=`
|
|
72
|
+
- `=`, `==`, `===`, `=>`
|
|
73
|
+
- `1`, `1.`, `1.0`, `1e3`, `1e+3`
|
|
74
|
+
- `.5`, `1..2`, `1...2`, `1.foo`, `1._x`, `1.e2`
|
|
75
|
+
- a complete fixed token at EOF and the same token followed by each permitted token-start class
|
|
76
|
+
|
|
77
|
+
## 3. Identifiers and keywords
|
|
78
|
+
|
|
79
|
+
Scan the complete identifier before hard-keyword classification. Use an exact lookup on the
|
|
80
|
+
language-defined semantic spelling; never split a keyword prefix from a longer identifier.
|
|
81
|
+
|
|
82
|
+
Record these policy choices explicitly:
|
|
83
|
+
|
|
84
|
+
- hard keywords emitted as fixed token kinds;
|
|
85
|
+
- contextual keywords retained as identifiers or annotated with a parser-consumed hint;
|
|
86
|
+
- whether identifier escapes are accepted and whether lookup uses raw or cooked spelling;
|
|
87
|
+
- whether identifiers are normalized, rejected when non-normalized, or compared without
|
|
88
|
+
normalization;
|
|
89
|
+
- whether keyword matching is case-sensitive, ASCII-folded, or Unicode-folded;
|
|
90
|
+
- the pinned Unicode data version and the identifier profile, normally based on `XID_Start` and
|
|
91
|
+
`XID_Continue` plus a named set of additions or removals.
|
|
92
|
+
|
|
93
|
+
Do not call locale-dependent lowercase functions for language keywords. Do not normalize the whole
|
|
94
|
+
source buffer. Apply identifier normalization or folding only at the declared semantic-key boundary
|
|
95
|
+
while retaining raw spelling and byte spans.
|
|
96
|
+
|
|
97
|
+
Keep lexical validity separate from identifier-security diagnostics. Mixed-script, confusable,
|
|
98
|
+
bidirectional-control, and restricted-format checks belong to a named security pass unless the
|
|
99
|
+
language contract explicitly makes them lexical errors.
|
|
100
|
+
|
|
101
|
+
Probe at least `if`, `ifx`, `xif`, `while2`, `_return`, `return_`, escaped spellings that cook to a
|
|
102
|
+
keyword, normalized and decomposed equivalents, mixed scripts, and EOF immediately after an
|
|
103
|
+
identifier.
|
|
104
|
+
|
|
105
|
+
## 4. Operators, lexical modes, and goals
|
|
106
|
+
|
|
107
|
+
Make the current lexical mode physically restrict the candidate rule set. Use stack frames when a
|
|
108
|
+
mode can nest or must retain parameters such as delimiter count, interpolation brace depth, comment
|
|
109
|
+
depth, indentation state, or embedded-language identity.
|
|
110
|
+
|
|
111
|
+
Do not reduce nested strings or interpolation to one `insideString` boolean. Emit structural string
|
|
112
|
+
segments and ordinary expression tokens so the parser can see embedded expressions while preserving
|
|
113
|
+
raw text segments.
|
|
114
|
+
|
|
115
|
+
Recognize comment openers only in modes where comments can begin. Recognize string prefixes only
|
|
116
|
+
after the complete opener is confirmed; otherwise return to ordinary identifier or punctuation
|
|
117
|
+
rules. Preserve `/`, `//`, `/*`, and `/=` as competing candidates in code mode without applying
|
|
118
|
+
comment rules inside strings or comments.
|
|
119
|
+
|
|
120
|
+
When a token class depends on syntactic context, define a parser-supplied lexical goal or an
|
|
121
|
+
equivalent integrated scanner-parser contract. Do not infer division versus regular expression,
|
|
122
|
+
generic delimiter versus shift, or template tail versus right brace from a brittle previous-token
|
|
123
|
+
heuristic.
|
|
124
|
+
|
|
125
|
+
## 5. Encoding, Unicode, newlines, and positions
|
|
126
|
+
|
|
127
|
+
Separate raw-byte acquisition, decoding, lexical matching, and external position conversion:
|
|
128
|
+
|
|
129
|
+
- Decode using the declared source encoding while retaining a mapping from scanner code-point
|
|
130
|
+
boundaries to original byte offsets.
|
|
131
|
+
- On invalid encoding, preserve the exact failing byte range and guarantee progress. At an
|
|
132
|
+
uncommitted chunk boundary, distinguish an incomplete code-unit sequence that needs more input
|
|
133
|
+
from a sequence already proven invalid. Do not silently collapse distinct invalid byte sequences
|
|
134
|
+
into indistinguishable source.
|
|
135
|
+
- Recognize a BOM only at a contract-defined stream start. If an encoding declaration exists, sniff
|
|
136
|
+
only its bounded raw-byte prefix and define conflict behavior before full decoding.
|
|
137
|
+
- Pin the Unicode data version used by compiler, formatter, language server, and token cache. Treat a
|
|
138
|
+
Unicode version change as a compatibility change with identifier fixtures.
|
|
139
|
+
- Treat code points as lexical matching units unless the language explicitly says otherwise. Use
|
|
140
|
+
grapheme clusters and display width only for user-interface rendering.
|
|
141
|
+
- Define the accepted line terminator set. Count CRLF as one terminator sequence when supported and
|
|
142
|
+
distinguish physical lines from logical lines.
|
|
143
|
+
- Keep byte offsets, UTF-16 code-unit offsets, code-point offsets, line indices, and display columns
|
|
144
|
+
as distinct types or named conversions. Negotiate the external protocol position encoding instead
|
|
145
|
+
of assuming compiler byte columns equal editor columns.
|
|
146
|
+
|
|
147
|
+
Test multibyte identifiers, combining marks, emoji before diagnostics, CRLF and lone CR where
|
|
148
|
+
supported, mixed newline files, tabs, invalid encoding followed by valid syntax, and round trips
|
|
149
|
+
between the canonical byte span and every external position unit.
|
|
150
|
+
|
|
151
|
+
## 6. Strings and escapes
|
|
152
|
+
|
|
153
|
+
Scan strings with a state machine, not one lazy regular expression. Separate opener, ordinary text,
|
|
154
|
+
escape, interpolation opener, closing delimiter, forbidden newline, and EOF transitions.
|
|
155
|
+
|
|
156
|
+
- Consume an escape production atomically when its backslash is seen. Do not decide whether a quote
|
|
157
|
+
is escaped by inspecting only the immediately preceding character.
|
|
158
|
+
- Preserve raw spelling and compute cooked content separately. Keep a stable token or segment when
|
|
159
|
+
escape decoding fails.
|
|
160
|
+
- Store parameterized raw-string delimiter state from the opener and accept only an exactly matching
|
|
161
|
+
closer. Bound delimiter length according to the language contract.
|
|
162
|
+
- For interpolation, push an expression frame with its own brace depth. Permit nested strings and
|
|
163
|
+
interpolations by stacking frames rather than sharing one global depth.
|
|
164
|
+
- End an unterminated single-line string at its declared recovery boundary, usually before the
|
|
165
|
+
newline. Let multiline strings reach their declared closer or EOF. Emit an explicit unterminated
|
|
166
|
+
token or segment and leave the scanner in a progress-making state.
|
|
167
|
+
- Define every escape family: exact digit count or bounded variable count, valid scalar range,
|
|
168
|
+
surrogate rejection, unknown-escape policy, and whether line continuation contributes cooked
|
|
169
|
+
content.
|
|
170
|
+
|
|
171
|
+
Probe even and odd backslash runs before quotes, invalid escapes, escaped newlines, interpolation
|
|
172
|
+
with nested braces, nested interpolation, raw delimiters containing shorter false closers, prefixes
|
|
173
|
+
that are also valid identifier starts, newline recovery, and EOF after every opener state.
|
|
174
|
+
|
|
175
|
+
## 7. Numbers, comments, and malformed input
|
|
176
|
+
|
|
177
|
+
Keep unary signs outside numeric tokens unless the sign occurs in a grammar-defined exponent.
|
|
178
|
+
Specify numeric syntax independently from host-language conversion:
|
|
179
|
+
|
|
180
|
+
- base prefixes and the minimum digits after each prefix;
|
|
181
|
+
- digit classes per base;
|
|
182
|
+
- separator positions, repetition, and trailing policy;
|
|
183
|
+
- fraction, exponent marker, optional exponent sign, and required exponent digits;
|
|
184
|
+
- suffix start and allowed suffixes;
|
|
185
|
+
- dot follower restrictions and collisions with range or member-access tokens;
|
|
186
|
+
- forbidden followers after an otherwise valid numeric prefix;
|
|
187
|
+
- the recovery boundary for a malformed numeric token.
|
|
188
|
+
|
|
189
|
+
Lex numeric structure first and perform value conversion in a separate literal-semantic pass. Do not
|
|
190
|
+
let host `parseFloat`, fixed-width integer overflow, or locale parsing define lexical validity.
|
|
191
|
+
|
|
192
|
+
When the language wants one useful diagnostic, consume inputs such as `0xG`, `1e+foo`, `123abc`, or
|
|
193
|
+
invalid separator runs as one bounded malformed token instead of reporting a valid prefix followed
|
|
194
|
+
by misleading unrelated tokens. The exact malformed boundary is language policy and must be tested.
|
|
195
|
+
|
|
196
|
+
For malformed candidates, keep the accepted-language grammar narrow and define a separate bounded
|
|
197
|
+
candidate envelope for recovery. Record `firstFault`, `terminationReason`, and a capped
|
|
198
|
+
`secondaryFaultCount`; do not rescan the same token once per bad character. Keep these locations
|
|
199
|
+
separate:
|
|
200
|
+
|
|
201
|
+
- `primarySpan` or `faultOffset`: what the diagnostic should underline first;
|
|
202
|
+
- `recoverySpan`: all source consumed to regain a stable token boundary;
|
|
203
|
+
- `originSpan`: the opener or prefix that created the current lexical state; and
|
|
204
|
+
- a related termination span for newline, EOF, or a mismatched closer.
|
|
205
|
+
|
|
206
|
+
For an unterminated construct, the primary span normally points at the opener rather than an empty
|
|
207
|
+
EOF location. EOF or the forbidden newline can be a related span.
|
|
208
|
+
|
|
209
|
+
Preserve comments as trivia when formatting, documentation, source maps, or newline-sensitive syntax
|
|
210
|
+
needs them. Define whether block comments nest and whether a comment containing a line terminator has
|
|
211
|
+
newline semantics. At EOF, emit one unterminated-comment trivia item from opener to EOF.
|
|
212
|
+
|
|
213
|
+
## 8. Streaming outcomes and recovery diagnostics
|
|
214
|
+
|
|
215
|
+
Treat a buffer boundary, committed source EOF, malformed input, and resource exhaustion as different
|
|
216
|
+
outcomes. A streaming scanner should expose an equivalent of:
|
|
217
|
+
|
|
218
|
+
- `Token(token)`: emits a token that covers real input, or one declared bounded state-changing
|
|
219
|
+
insertion;
|
|
220
|
+
- `EndOfInput`: a terminal outcome observed once, not a repeatedly emitted zero-width token;
|
|
221
|
+
- `NeedMoreInput`: current bytes are a valid prefix of a candidate and source EOF is not yet known;
|
|
222
|
+
and
|
|
223
|
+
- `ResourceLimitExceeded(kind, offset, observed, limit)`: bounded termination with structured
|
|
224
|
+
evidence rather than an allocation failure or hang.
|
|
225
|
+
|
|
226
|
+
At committed EOF, emit an identifier, number, or fixed token when the current state accepts. Convert
|
|
227
|
+
an incomplete encoding sequence or open string, interpolation, raw delimiter, or comment to the
|
|
228
|
+
declared malformed or unterminated result. Do not return `NeedMoreInput` after EOF is known, and do
|
|
229
|
+
not emit the same zero-width error or EOF result twice.
|
|
230
|
+
|
|
231
|
+
Model buffer refill as a lexer state transition. Preserve or relocate every live position and state:
|
|
232
|
+
`cursor`, `limit`, `tokenStart`, last accepting marker and captures, trailing-context marker,
|
|
233
|
+
decoder partial state, mode stack, lexical goal, and EOF knowledge. A refill that keeps only the
|
|
234
|
+
cursor silently corrupts tokens spanning chunks.
|
|
235
|
+
|
|
236
|
+
Keep diagnostics as structured data, for example `code`, `severity`, `args`, `primarySpan`,
|
|
237
|
+
`relatedSpans`, `fixIts`, `recoverySpan`, `snapshotId`, and `mode`. The low-level scanner
|
|
238
|
+
should not localize or render a finished sentence.
|
|
239
|
+
|
|
240
|
+
Define synchronization by lexical mode. A code-mode invalid byte, string escape, interpolation
|
|
241
|
+
expression, raw string, and nested comment do not share one safe recovery delimiter. Coalesce
|
|
242
|
+
adjacent secondary failures into a contamination region, cap diagnostic volume, and emit one
|
|
243
|
+
aggregate omission diagnostic when the cap is reached.
|
|
244
|
+
|
|
245
|
+
Treat a fix-it as executable behavior. Apply it to a temporary immutable snapshot, lex again, and
|
|
246
|
+
require the intended token plus downstream token-and-state convergence. Reject a fix-it that only
|
|
247
|
+
makes the highlighted bytes look plausible while shifting the lexer into a different mode.
|
|
248
|
+
|
|
249
|
+
## 9. Incremental and large-input behavior
|
|
250
|
+
|
|
251
|
+
Checkpoint every state that can affect future candidates, including mode stack, lexical goal,
|
|
252
|
+
delimiter parameters, comment or interpolation depth, indentation or newline state, decoder partial
|
|
253
|
+
state, and any previous significant-token category required by the language contract. Checkpoint
|
|
254
|
+
density may be adaptive, but checkpoint contents must be complete.
|
|
255
|
+
|
|
256
|
+
Make checkpoint serialization a tested continuation contract: lexing a suffix after
|
|
257
|
+
serialize/deserialize must equal uninterrupted lexing. Restart before an edit at a checkpoint valid
|
|
258
|
+
for the new immutable snapshot. Stop only when canonical token kind, length, flags, and complete
|
|
259
|
+
outgoing state converge with the old snapshot at the same source position. A block hash is only a
|
|
260
|
+
fast inequality filter; verify actual fields after a hash match. Never use one equal token, a fixed
|
|
261
|
+
number of equal tokens, one line, or a fixed character radius as the correctness boundary.
|
|
262
|
+
|
|
263
|
+
Tie work and publication to `snapshotId`. Check cancellation or staleness at bounded work
|
|
264
|
+
intervals, discard partial results, and publish atomically only when the result still targets the
|
|
265
|
+
current snapshot. Arbitrary parallel chunks are unsafe unless each starts from a proven complete
|
|
266
|
+
state.
|
|
267
|
+
|
|
268
|
+
Keep the hot path narrow:
|
|
269
|
+
|
|
270
|
+
- use an ASCII fast path and a Unicode slow path whose results are identical at their boundary;
|
|
271
|
+
- if delimiter search is vectorized, test scalar tails and every chunk alignment;
|
|
272
|
+
- store source ranges in compact token records and move diagnostics, cooked values, and uncommon
|
|
273
|
+
payloads to side tables;
|
|
274
|
+
- defer unescaping, numeric conversion, normalization, and interning until a consumer requests them;
|
|
275
|
+
- compute line and display columns from a line-start index rather than updating every coordinate on
|
|
276
|
+
every byte; and
|
|
277
|
+
- align source and token blocks so edits replace bounded blocks, using relative offsets plus an
|
|
278
|
+
aggregate index instead of rewriting all following absolute positions.
|
|
279
|
+
|
|
280
|
+
Define snapshot lifetime and release policy. Zero-copy is not free if a ten-byte token retains an
|
|
281
|
+
obsolete multi-gigabyte snapshot; use chunk ownership or promote a small long-lived slice to owned
|
|
282
|
+
storage when that is cheaper.
|
|
283
|
+
|
|
284
|
+
Measure the editing product, not only clean-file throughput: `relexedBytesPerEdit`,
|
|
285
|
+
`reusedTokenRatio`, allocations per edit, diagnostic latency, peak live bytes, and p50/p95/p99 edit
|
|
286
|
+
latency. Keep counters available in tests so a wall-clock threshold is not the only complexity
|
|
287
|
+
oracle.
|
|
288
|
+
|
|
289
|
+
## 10. Hostile-input and resource budgets
|
|
290
|
+
|
|
291
|
+
Use one request-scoped multidimensional budget. Applicable counters include input bytes, raw token
|
|
292
|
+
bytes, cooked or decoded bytes, emitted token and trivia count, diagnostic count, nesting depth,
|
|
293
|
+
checkpoint count, retained source bytes, allocation bytes, and cooperative work units. Charge before
|
|
294
|
+
allocation or publication and return the exhausted dimension.
|
|
295
|
+
|
|
296
|
+
- Keep raw-token and cooked-value limits separate. Escape decoding, normalization, and conversion
|
|
297
|
+
can expand or allocate even when the raw spelling is bounded.
|
|
298
|
+
- Keep the recognition hot path linear. Do not hand hostile text to a backtracking regular-expression
|
|
299
|
+
engine or recursively descend once per nested comment opener.
|
|
300
|
+
- Track nested comments and interpolation with checked iterative counters. Bound retained opener
|
|
301
|
+
history instead of storing every nesting position.
|
|
302
|
+
- Scan a huge token as a range while updating only bounded metadata. Do not append every byte to a
|
|
303
|
+
builder or join all source chunks merely to classify the token.
|
|
304
|
+
- Bound output amplification: a small input must not create unbounded tiny tokens, diagnostics,
|
|
305
|
+
checkpoints, or interned identifiers. Coalesce compatible trivia and contamination regions.
|
|
306
|
+
- Treat NUL as input data unless the language forbids it. Keep EOF as separate state, and prove any
|
|
307
|
+
sentinel or padding cannot become a valid lexeme suffix or cause an out-of-bounds read.
|
|
308
|
+
- Use checked addition, multiplication, growth, and narrowing for positions, token-table sizes,
|
|
309
|
+
display-coordinate conversion, and allocation requests.
|
|
310
|
+
- Bound snapshot retention and identifier interning. Prefer request-local interning with a distinct
|
|
311
|
+
identifier budget and collision-resistant storage.
|
|
312
|
+
- Check cooperative cancellation after bounded bytes or state transitions, at refills and mode
|
|
313
|
+
changes, and inside very long tokens. Discard the incomplete snapshot result on cancellation.
|
|
314
|
+
|
|
315
|
+
## 11. Differential, fuzz, and property tests
|
|
316
|
+
|
|
317
|
+
Require applicable properties in addition to example fixtures:
|
|
318
|
+
|
|
319
|
+
- Raw token, trivia, skipped, and error spans are half-open, ordered, non-overlapping, and partition
|
|
320
|
+
the input without gaps; concatenating their raw slices reconstructs the exact input bytes.
|
|
321
|
+
- Every scanner step consumes source, reaches committed EOF, returns `NeedMoreInput`, or performs
|
|
322
|
+
one declared bounded state-changing insertion.
|
|
323
|
+
- No longer valid candidate exists at the chosen token start under the active mode and lexical goal.
|
|
324
|
+
- Equal-length selection follows explicit priority and remains stable when declaration order changes.
|
|
325
|
+
- Every fixed operator prefix pair receives generated surrounding-character and EOF cases.
|
|
326
|
+
- Hard keyword prefixes remain identifiers when the complete spelling is not an exact keyword.
|
|
327
|
+
- One-shot and chunked scanning agree for all short split positions and biased splits inside
|
|
328
|
+
multibyte encodings, escapes, numbers, comments, delimiters, and last-accept checkpoints.
|
|
329
|
+
- Full and incremental lexing agree after every edit in randomized edit sequences, including edits
|
|
330
|
+
that propagate string, comment, delimiter, indentation, or lexical-goal state.
|
|
331
|
+
- Checkpoint serialize/deserialize followed by suffix scanning equals uninterrupted scanning.
|
|
332
|
+
- Malformed-input scanning terminates within token, diagnostic, transition, revisit, allocation, and
|
|
333
|
+
retained-source budgets.
|
|
334
|
+
|
|
335
|
+
For differential testing, normalize each implementation to an observation such as
|
|
336
|
+
`(canonicalKind, rawStart, rawEnd, flags)`. Filter specification-permitted differences before
|
|
337
|
+
comparison, and treat disagreement as a candidate defect rather than majority proof. Keep an
|
|
338
|
+
intentionally slow reference lexer independent of production tables, character classifiers, and
|
|
339
|
+
candidate-selection helpers; sharing the same recognition code only reproduces the same bug twice.
|
|
340
|
+
|
|
341
|
+
Combine a grammar-aware generator with raw byte mutation. Bias lengths to zero, one, maximum minus
|
|
342
|
+
one, maximum, maximum plus one, powers of two, chunk size boundaries, delimiter lengths, and Unicode
|
|
343
|
+
sequence widths. Add metamorphic relations only with explicit preconditions, such as inserting
|
|
344
|
+
trivia where trivia is grammar-neutral or changing chunk partitions without changing bytes.
|
|
345
|
+
|
|
346
|
+
Instrument transitions, byte revisits, allocations, maximum stack or mode depth, and reprocessed
|
|
347
|
+
bytes. Use sanitizers or equivalent memory-safety instrumentation where supported. When shrinking a
|
|
348
|
+
failure, minimize not only input bytes but also edit history, chunk splits, checkpoint placement,
|
|
349
|
+
options, and the normalized mismatch while preserving the triggering phenomenon.
|
|
350
|
+
|
|
351
|
+
Keep minimized failures as regression seeds. Classify whether each seed proves a language-contract
|
|
352
|
+
decision, implementation defect, host-runtime disagreement, or unsupported input.
|
|
353
|
+
|
|
354
|
+
## 12. Standards and implementation anchors
|
|
355
|
+
|
|
356
|
+
Use these primary sources as examples of explicit lexical contracts, not as permission to copy one
|
|
357
|
+
language's decisions into another:
|
|
358
|
+
|
|
359
|
+
- [flex input matching](https://westes.github.io/flex/manual/Matching.html): longest input first,
|
|
360
|
+
then tie handling, including trailing-context comparison length.
|
|
361
|
+
- [ECMAScript lexical grammar](https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html):
|
|
362
|
+
longest input elements, numeric followers, line terminators, templates, and parser-selected
|
|
363
|
+
lexical goals.
|
|
364
|
+
- [Rust token grammar](https://doc.rust-lang.org/reference/tokens.html): raw delimiters, escapes,
|
|
365
|
+
identifier classes, and dot follower restrictions for floating literals.
|
|
366
|
+
- [ANTLR lexer rules](https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md): mode-specific
|
|
367
|
+
sublexers and lexer mode transitions.
|
|
368
|
+
- [Go language specification](https://go.dev/ref/spec): comment boundaries, comment newline effects,
|
|
369
|
+
numeric separators, and semicolon insertion inputs.
|
|
370
|
+
- [Python lexical analysis](https://docs.python.org/3/reference/lexical_analysis.html): source
|
|
371
|
+
decoding, bounded encoding declarations, physical and logical lines, strings, and indentation.
|
|
372
|
+
- [Unicode UAX #31](https://www.unicode.org/reports/tr31/): identifier profiles, `XID_Start`,
|
|
373
|
+
`XID_Continue`, normalization, and version-sensitive Unicode data.
|
|
374
|
+
- [Unicode UTS #39](https://www.unicode.org/reports/tr39/): identifier restriction and confusable
|
|
375
|
+
detection mechanisms that belong in a separately declared security policy.
|
|
376
|
+
- [Unicode UAX #29](https://www.unicode.org/reports/tr29/): grapheme boundaries for display and
|
|
377
|
+
cursor behavior rather than ordinary lexer grammar units.
|
|
378
|
+
- [Language Server Protocol 3.17](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/):
|
|
379
|
+
negotiated position encoding and the UTF-16 compatibility default.
|
|
380
|
+
- [Go `bufio.Scanner` source](https://go.dev/src/bufio/scan.go): partial-input split outcomes,
|
|
381
|
+
progress checks, invalid advance rejection, token-size limits, buffer relocation, and empty-token
|
|
382
|
+
termination guards.
|
|
383
|
+
- [Tree-sitter external scanners](https://tree-sitter.github.io/tree-sitter/creating-parsers/4-external-scanners.html):
|
|
384
|
+
complete scanner-state serialization, explicit EOF distinct from NUL, column-query cost, and
|
|
385
|
+
zero-width-token loop hazards.
|
|
386
|
+
- [re2c end-of-input and refill manual](https://re2c.org/manual/manual_d.html#eof):
|
|
387
|
+
cursor, limit, token start, markers, refill relocation, sentinel, padding, and bounds-check
|
|
388
|
+
invariants.
|
|
389
|
+
- [RE2](https://github.com/google/re2): linear-time matching, bounded memory, non-recursive
|
|
390
|
+
execution, and graceful budget exhaustion for untrusted patterns and text.
|
|
391
|
+
- [Clang diagnostics internals](https://clang.llvm.org/docs/InternalsManual.html#the-diagnostics-subsystem):
|
|
392
|
+
stable diagnostic IDs, typed arguments, source ranges, renderer separation, and executable fix-it
|
|
393
|
+
constraints.
|
|
394
|
+
- [Rust `rustc_lexer`](https://github.com/rust-lang/rust/blob/main/compiler/rustc_lexer/src/lib.rs):
|
|
395
|
+
compact token results that retain termination and malformed-literal state for later diagnosis.
|
|
396
|
+
- [LLVM libFuzzer](https://llvm.org/docs/LibFuzzer.html): deterministic and bounded fuzz targets,
|
|
397
|
+
structured mutators, corpus reduction, sanitizers, and memory or timeout failure oracles.
|