parseman 0.45.0 → 0.47.0
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/README.md +8 -3
- package/dist/analysis/choice-cost-gate.d.ts +158 -0
- package/dist/analysis/choice-cost-gate.d.ts.map +1 -0
- package/dist/analysis/choice-cost-render.d.ts +96 -0
- package/dist/analysis/choice-cost-render.d.ts.map +1 -0
- package/dist/analysis/choice-cost.d.ts +383 -0
- package/dist/analysis/choice-cost.d.ts.map +1 -0
- package/dist/analysis/commitment.d.ts +131 -0
- package/dist/analysis/commitment.d.ts.map +1 -0
- package/dist/analysis/corpus.d.ts +73 -0
- package/dist/analysis/corpus.d.ts.map +1 -0
- package/dist/analysis/diagnose-render.d.ts +65 -0
- package/dist/analysis/diagnose-render.d.ts.map +1 -0
- package/dist/analysis/diagnose.d.ts +15 -0
- package/dist/analysis/diagnose.d.ts.map +1 -1
- package/dist/analysis/diagnostics.cjs +13736 -0
- package/dist/analysis/diagnostics.cjs.map +6 -0
- package/dist/analysis/diagnostics.d.ts +27 -0
- package/dist/analysis/diagnostics.d.ts.map +1 -0
- package/dist/analysis/diagnostics.js +13713 -0
- package/dist/analysis/diagnostics.js.map +6 -0
- package/dist/analysis/duplication.d.ts.map +1 -1
- package/dist/analysis/fix-render.d.ts +43 -0
- package/dist/analysis/fix-render.d.ts.map +1 -0
- package/dist/analysis/fix.d.ts +172 -0
- package/dist/analysis/fix.d.ts.map +1 -0
- package/dist/analysis/format-number.d.ts +23 -0
- package/dist/analysis/format-number.d.ts.map +1 -0
- package/dist/analysis/gating.d.ts +47 -2
- package/dist/analysis/gating.d.ts.map +1 -1
- package/dist/analysis/rebuild.d.ts +61 -0
- package/dist/analysis/rebuild.d.ts.map +1 -0
- package/dist/analysis/terminal.d.ts +145 -0
- package/dist/analysis/terminal.d.ts.map +1 -0
- package/dist/cli/index.cjs +14837 -0
- package/dist/cli/index.cjs.map +6 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +14814 -0
- package/dist/cli/index.js.map +6 -0
- package/dist/combinators/adjacency.d.ts +100 -0
- package/dist/combinators/adjacency.d.ts.map +1 -0
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/completions.d.ts.map +1 -1
- package/dist/combinators/dispatch.d.ts +8 -1
- package/dist/combinators/dispatch.d.ts.map +1 -1
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/gate.d.ts.map +1 -1
- package/dist/combinators/grammar.d.ts +22 -0
- package/dist/combinators/grammar.d.ts.map +1 -1
- package/dist/combinators/literal.d.ts +8 -0
- package/dist/combinators/literal.d.ts.map +1 -1
- package/dist/combinators/map.d.ts +0 -1
- package/dist/combinators/map.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +13 -3
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/combinators/parser.d.ts +1 -1
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/combinators/ref.d.ts.map +1 -1
- package/dist/combinators/regex.d.ts +1 -16
- package/dist/combinators/regex.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts +30 -2
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/combinators/scanTo.d.ts +71 -1
- package/dist/combinators/scanTo.d.ts.map +1 -1
- package/dist/combinators/sequence.d.ts.map +1 -1
- package/dist/combinators/token.d.ts.map +1 -1
- package/dist/combinators/trivia-boundary.d.ts +26 -0
- package/dist/combinators/trivia-boundary.d.ts.map +1 -0
- package/dist/combinators/trivia-skip.d.ts +40 -1
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/combinators/withCtx.d.ts.map +1 -1
- package/dist/compiler/build-arity.d.ts.map +1 -1
- package/dist/compiler/compile-linkable-table.d.ts +104 -0
- package/dist/compiler/compile-linkable-table.d.ts.map +1 -0
- package/dist/compiler/degradation.d.ts +0 -2
- package/dist/compiler/degradation.d.ts.map +1 -1
- package/dist/compiler/fields.d.ts +13 -0
- package/dist/compiler/fields.d.ts.map +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts +5 -5
- package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +79 -47
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/compiler/token-alphabet.d.ts +81 -0
- package/dist/compiler/token-alphabet.d.ts.map +1 -0
- package/dist/compiler/token-dispatch.d.ts +95 -0
- package/dist/compiler/token-dispatch.d.ts.map +1 -0
- package/dist/compiler/token-scanner.d.ts +53 -0
- package/dist/compiler/token-scanner.d.ts.map +1 -0
- package/dist/compiler/value-usage.d.ts.map +1 -1
- package/dist/coverage.d.ts +1 -1
- package/dist/coverage.d.ts.map +1 -1
- package/dist/cst/capture-buffer.d.ts +35 -0
- package/dist/cst/capture-buffer.d.ts.map +1 -1
- package/dist/cst/reflection-attach.d.ts +8 -0
- package/dist/cst/reflection-attach.d.ts.map +1 -0
- package/dist/cst/reflection-symbols.d.ts +10 -0
- package/dist/cst/reflection-symbols.d.ts.map +1 -0
- package/dist/cst/reflection.d.ts +2 -4
- package/dist/cst/reflection.d.ts.map +1 -1
- package/dist/cst/root-trivia-scope.d.ts +26 -0
- package/dist/cst/root-trivia-scope.d.ts.map +1 -0
- package/dist/cst/trivia-charscan.d.ts +18 -0
- package/dist/cst/trivia-charscan.d.ts.map +1 -0
- package/dist/cst/trivia-kinds.d.ts +19 -0
- package/dist/cst/trivia-kinds.d.ts.map +1 -1
- package/dist/functional/doc.d.ts.map +1 -1
- package/dist/functional/run-tabled.d.ts +12 -0
- package/dist/functional/run-tabled.d.ts.map +1 -0
- package/dist/functional/run.d.ts +25 -42
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/grammar-metadata.d.ts +3 -0
- package/dist/grammar-metadata.d.ts.map +1 -0
- package/dist/index.cjs +10499 -7478
- package/dist/index.cjs.map +3 -4
- package/dist/index.d.ts +24 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10499 -7478
- package/dist/index.js.map +3 -4
- package/dist/language-service/index.cjs +311 -121
- package/dist/language-service/index.cjs.map +3 -4
- package/dist/language-service/index.js +311 -121
- package/dist/language-service/index.js.map +3 -4
- package/dist/oracle/index.cjs.map +0 -1
- package/dist/oracle/index.js.map +0 -1
- package/dist/parse-context.d.ts +49 -0
- package/dist/parse-context.d.ts.map +1 -0
- package/dist/plugin/evaluator.d.ts +41 -2
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/free-identifiers.d.ts +23 -0
- package/dist/plugin/free-identifiers.d.ts.map +1 -0
- package/dist/plugin/index.cjs +11381 -9442
- package/dist/plugin/index.cjs.map +3 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +11381 -9442
- package/dist/plugin/index.js.map +3 -4
- package/dist/plugin/reducer-resolver.d.ts +17 -1
- package/dist/plugin/reducer-resolver.d.ts.map +1 -1
- package/dist/regex/classes.d.ts +28 -0
- package/dist/regex/classes.d.ts.map +1 -1
- package/dist/regex/first-set.d.ts +14 -0
- package/dist/regex/first-set.d.ts.map +1 -1
- package/dist/run/index.cjs +136 -51
- package/dist/run/index.cjs.map +2 -3
- package/dist/run/index.js +136 -51
- package/dist/run/index.js.map +2 -3
- package/dist/spec/index.cjs +2898 -1622
- package/dist/spec/index.cjs.map +3 -4
- package/dist/spec/index.js +2898 -1622
- package/dist/spec/index.js.map +3 -4
- package/dist/spec/model.d.ts +8 -0
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/table/assemble.d.ts +307 -0
- package/dist/table/assemble.d.ts.map +1 -0
- package/dist/table/cell.d.ts +42 -0
- package/dist/table/cell.d.ts.map +1 -0
- package/dist/table/child-slots.d.ts +30 -0
- package/dist/table/child-slots.d.ts.map +1 -0
- package/dist/table/compile-rule-map.d.ts +136 -0
- package/dist/table/compile-rule-map.d.ts.map +1 -0
- package/dist/table/compile.d.ts +56 -0
- package/dist/table/compile.d.ts.map +1 -0
- package/dist/table/duplication-hook.d.ts +32 -0
- package/dist/table/duplication-hook.d.ts.map +1 -0
- package/dist/table/emit-assembly.d.ts +139 -0
- package/dist/table/emit-assembly.d.ts.map +1 -0
- package/dist/table/emit.d.ts +113 -0
- package/dist/table/emit.d.ts.map +1 -0
- package/dist/table/encode-baseline.d.ts +16 -0
- package/dist/table/encode-baseline.d.ts.map +1 -0
- package/dist/table/encode.d.ts +71 -0
- package/dist/table/encode.d.ts.map +1 -0
- package/dist/table/exec-baseline.d.ts +9 -0
- package/dist/table/exec-baseline.d.ts.map +1 -0
- package/dist/table/exec.d.ts +72 -0
- package/dist/table/exec.d.ts.map +1 -0
- package/dist/table/fold.d.ts +25 -0
- package/dist/table/fold.d.ts.map +1 -0
- package/dist/table/index.cjs +11375 -0
- package/dist/table/index.cjs.map +6 -0
- package/dist/table/index.d.ts +100 -0
- package/dist/table/index.d.ts.map +1 -0
- package/dist/table/index.js +11352 -0
- package/dist/table/index.js.map +6 -0
- package/dist/table/inspect.d.ts +17 -0
- package/dist/table/inspect.d.ts.map +1 -0
- package/dist/table/ops.d.ts +446 -0
- package/dist/table/ops.d.ts.map +1 -0
- package/dist/table/program.d.ts +493 -0
- package/dist/table/program.d.ts.map +1 -0
- package/dist/table/run-support.d.ts +38 -0
- package/dist/table/run-support.d.ts.map +1 -0
- package/dist/{compiler/scannable-run.d.ts → table/scan-shapes.d.ts} +14 -13
- package/dist/table/scan-shapes.d.ts.map +1 -0
- package/dist/table/site-labels.d.ts +58 -0
- package/dist/table/site-labels.d.ts.map +1 -0
- package/dist/table/stamp.d.ts +70 -0
- package/dist/table/stamp.d.ts.map +1 -0
- package/dist/types.d.ts +80 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +41 -3
- package/src/analysis/choice-cost-gate.ts +359 -0
- package/src/analysis/choice-cost-render.ts +293 -0
- package/src/analysis/choice-cost.ts +1008 -0
- package/src/analysis/commitment.ts +557 -0
- package/src/analysis/corpus.ts +130 -0
- package/src/analysis/diagnose-render.ts +625 -0
- package/src/analysis/diagnose.ts +317 -0
- package/src/analysis/diagnostics.ts +33 -0
- package/src/analysis/duplication.ts +1955 -0
- package/src/analysis/fix-render.ts +217 -0
- package/src/analysis/fix.ts +669 -0
- package/src/analysis/format-number.ts +31 -0
- package/src/analysis/gating.ts +792 -0
- package/src/analysis/grammar.ts +72 -0
- package/src/analysis/rebuild.ts +287 -0
- package/src/analysis/terminal.ts +336 -0
- package/src/cli/index.ts +413 -0
- package/src/combinators/adjacency.ts +171 -0
- package/src/combinators/attempt.ts +41 -0
- package/src/combinators/case-fold.ts +90 -0
- package/src/combinators/choice.ts +466 -0
- package/src/combinators/completions.ts +64 -0
- package/src/combinators/dispatch.ts +358 -0
- package/src/combinators/expect.ts +159 -0
- package/src/combinators/first-set.ts +322 -0
- package/src/combinators/gate.ts +50 -0
- package/src/combinators/grammar.ts +272 -0
- package/src/combinators/keywords.ts +145 -0
- package/src/combinators/literal.ts +102 -0
- package/src/combinators/map.ts +106 -0
- package/src/combinators/node.ts +345 -0
- package/src/combinators/not.ts +55 -0
- package/src/combinators/parser.ts +266 -0
- package/src/combinators/peek.ts +63 -0
- package/src/combinators/probe.ts +25 -0
- package/src/combinators/ref.ts +109 -0
- package/src/combinators/regex.ts +170 -0
- package/src/combinators/repeat.ts +561 -0
- package/src/combinators/scanTo.ts +393 -0
- package/src/combinators/sequence.ts +221 -0
- package/src/combinators/token.ts +120 -0
- package/src/combinators/trivia-boundary.ts +48 -0
- package/src/combinators/trivia-skip.ts +821 -0
- package/src/combinators/withCtx.ts +45 -0
- package/src/compiler/build-arity.ts +330 -0
- package/src/compiler/compile-linkable-table.ts +209 -0
- package/src/compiler/degradation.ts +266 -0
- package/src/compiler/fields.ts +191 -0
- package/src/compiler/grammar-coverage-ids.ts +129 -0
- package/src/compiler/ir-serialize.ts +615 -0
- package/src/compiler/linker.ts +954 -0
- package/src/compiler/token-alphabet.ts +209 -0
- package/src/compiler/token-dispatch.ts +353 -0
- package/src/compiler/token-scanner.ts +318 -0
- package/src/compiler/value-usage.ts +147 -0
- package/src/coverage.ts +383 -0
- package/src/cst/capture-buffer.ts +297 -0
- package/src/cst/host-mode.ts +69 -0
- package/src/cst/reflection-attach.ts +11 -0
- package/src/cst/reflection-symbols.ts +9 -0
- package/src/cst/reflection.ts +149 -0
- package/src/cst/relative-spans.ts +207 -0
- package/src/cst/root-trivia-scope.ts +30 -0
- package/src/cst/trivia-charscan.ts +312 -0
- package/src/cst/trivia-entries.ts +285 -0
- package/src/cst/trivia-index.ts +131 -0
- package/src/cst/trivia-kinds.ts +358 -0
- package/src/cst/types.ts +76 -0
- package/src/cst/walk.ts +101 -0
- package/src/functional/doc.ts +959 -0
- package/src/functional/run-tabled.ts +153 -0
- package/src/functional/run.ts +558 -0
- package/src/grammar-metadata.ts +2 -0
- package/src/index.ts +189 -0
- package/src/language-service/index.ts +221 -0
- package/src/line-index.ts +131 -0
- package/src/oracle/digest.ts +620 -0
- package/src/oracle/index.ts +55 -0
- package/src/parse-context.ts +91 -0
- package/src/plugin/direct-builder-static.ts +102 -0
- package/src/plugin/evaluator.ts +1505 -0
- package/src/plugin/free-identifiers.ts +338 -0
- package/src/plugin/index.ts +2281 -0
- package/src/plugin/reducer-resolver.ts +606 -0
- package/src/recovery/scan.ts +155 -0
- package/src/regex/classes.ts +183 -0
- package/src/regex/first-set.ts +316 -0
- package/src/run/index.ts +31 -0
- package/src/spec/ebnf.ts +128 -0
- package/src/spec/index.ts +54 -0
- package/src/spec/model.ts +636 -0
- package/src/spec/railroad-lib.ts +559 -0
- package/src/spec/railroad.ts +256 -0
- package/src/table/assemble.ts +2994 -0
- package/src/table/cell.ts +42 -0
- package/src/table/child-slots.ts +113 -0
- package/src/table/compile-rule-map.ts +336 -0
- package/src/table/compile.ts +244 -0
- package/src/table/duplication-hook.ts +89 -0
- package/src/table/emit-assembly.ts +1766 -0
- package/src/table/emit.ts +418 -0
- package/src/table/encode-baseline.ts +340 -0
- package/src/table/encode.ts +1569 -0
- package/src/table/exec-baseline.ts +537 -0
- package/src/table/exec.ts +1672 -0
- package/src/table/fold.ts +38 -0
- package/src/table/index.ts +108 -0
- package/src/table/inspect.ts +52 -0
- package/src/table/ops.ts +459 -0
- package/src/table/program.ts +855 -0
- package/src/table/run-support.ts +66 -0
- package/src/table/scan-shapes.ts +1578 -0
- package/src/table/site-labels.ts +228 -0
- package/src/table/stamp.ts +229 -0
- package/src/types.ts +563 -0
- package/src/version.ts +16 -0
- package/dist/compiler/codegen.d.ts +0 -334
- package/dist/compiler/codegen.d.ts.map +0 -1
- package/dist/compiler/inline-build.d.ts +0 -11
- package/dist/compiler/inline-build.d.ts.map +0 -1
- package/dist/compiler/inline-callback.d.ts +0 -21
- package/dist/compiler/inline-callback.d.ts.map +0 -1
- package/dist/compiler/line-index.d.ts +0 -2
- package/dist/compiler/line-index.d.ts.map +0 -1
- package/dist/compiler/scannable-run.d.ts.map +0 -1
- package/dist/compiler/scannable-terminal.d.ts +0 -23
- package/dist/compiler/scannable-terminal.d.ts.map +0 -1
- package/dist/compiler/trivia-fast-path.d.ts +0 -38
- package/dist/compiler/trivia-fast-path.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -11,7 +11,8 @@ usually mean grammar files, generated code, and extra tooling. Parséman is a co
|
|
|
11
11
|
library with an optional compiler, and it gives you both.
|
|
12
12
|
|
|
13
13
|
**Parsing to JS values, the macro build is the fastest general-purpose JS parser in the
|
|
14
|
-
suite** — ahead of every other library measured, at every grammar and every input size
|
|
14
|
+
suite** — ahead of every other library measured, at every grammar and every input size in
|
|
15
|
+
that suite.
|
|
15
16
|
Every parser in the suite builds real output: objects, row arrays, AST nodes. On a 7.7 kB
|
|
16
17
|
GraphQL document Parséman takes **131 µs**; Peggy takes 328 µs. Only a purpose-built native
|
|
17
18
|
edges it out, `JSON.parse` on JSON.
|
|
@@ -138,8 +139,9 @@ See **[The three modes](https://matthew-dean.github.io/parseman/guide/modes)**.
|
|
|
138
139
|
coverage ("which rules and choice arms ran?") and trace ("what did it try, select, and
|
|
139
140
|
backtrack through?").
|
|
140
141
|
- 🚦 **[First-char gating diagnostics](https://matthew-dean.github.io/parseman/guide/first-char-gating)** —
|
|
141
|
-
|
|
142
|
-
and says how to fix it.
|
|
142
|
+
`diagnoseGrammar()` tells you which `choice` lost its O(1) dispatch, names the
|
|
143
|
+
overlapping arms, and says how to fix it. Run it in a test or a CI job — compiling
|
|
144
|
+
reports nothing.
|
|
143
145
|
- 📈 **[Performance guide](https://matthew-dean.github.io/parseman/guide/performance)** —
|
|
144
146
|
the levers that actually move a grammar, and [how regexes lower](https://matthew-dean.github.io/parseman/guide/regex-lowering).
|
|
145
147
|
|
|
@@ -161,6 +163,9 @@ GraphQL **131 µs** vs Peggy's 328 µs, JSON **133 µs** vs Chevrotain's 241 µs
|
|
|
161
163
|
**75.3 µs** vs Peggy's 420 µs. Native `JSON.parse` does JSON large in 51.6 µs. On the CST
|
|
162
164
|
chart, macro build runs 174 µs against Lezer's 594 µs parse-only.
|
|
163
165
|
|
|
166
|
+
Those are the committed charts, regenerated at 0.29.0 (2026-07-22) on an M4 Pro, measuring
|
|
167
|
+
the JS-codegen lowering that `compile()` and the macro build emit.
|
|
168
|
+
|
|
164
169
|

|
|
165
170
|
|
|
166
171
|

|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CHOICE COST — the policy layer.
|
|
3
|
+
* ===============================
|
|
4
|
+
*
|
|
5
|
+
* Analysis says what the grammar costs. This says which of those numbers fail a build.
|
|
6
|
+
* They are separate because they have different consumers and different lifetimes: a
|
|
7
|
+
* developer wants the ranked list on every run, CI wants one bit, and the threshold
|
|
8
|
+
* that produces that bit is a decision the owner makes once and writes down.
|
|
9
|
+
*
|
|
10
|
+
* This module is PURE — it takes a report and a baseline and returns a verdict. It
|
|
11
|
+
* reads no files, spawns nothing, and prints nothing, so it is testable without a
|
|
12
|
+
* fixture checkout and cannot be the reason a gate is flaky.
|
|
13
|
+
*
|
|
14
|
+
* THE BASELINE IS ABSOLUTE, NOT DIFFERENTIAL
|
|
15
|
+
* ------------------------------------------
|
|
16
|
+
* Gating each commit against its parent lets +2% per commit land forever: every
|
|
17
|
+
* individual step is under tolerance and the total is unbounded. So the committed
|
|
18
|
+
* baseline records the ACTUAL byte counts, and drift is measured against those
|
|
19
|
+
* numbers, not against yesterday's.
|
|
20
|
+
*
|
|
21
|
+
* A baseline is committed DATA, reviewed like any other diff. Nothing here writes one.
|
|
22
|
+
* Rebaselining is a deliberate act with a reviewable artifact and owner sign-off; there
|
|
23
|
+
* is no automatic refresh, because a gate that rebaselines itself is a gate that
|
|
24
|
+
* records regressions rather than catching them.
|
|
25
|
+
*
|
|
26
|
+
* AND IT IS TWO-SIDED — A WIN MUST BE BANKED
|
|
27
|
+
* ------------------------------------------
|
|
28
|
+
* Growth past the committed number fails, and so does an unbanked IMPROVEMENT. This is
|
|
29
|
+
* the half usually left to a comment asking a human politely, and it is the half that
|
|
30
|
+
* rots: `bench/grammar-density/config.json` and `bench/workloads/config.json` each
|
|
31
|
+
* carried exactly such a comment and sat unbumped for TEN releases. If a reorder takes
|
|
32
|
+
* a site from 7,846 wasted bytes to 2,000 and the baseline does not move with it, 5,846
|
|
33
|
+
* bytes of fresh headroom silently become budget for the next regression — and the gate
|
|
34
|
+
* that was supposed to catch that regression reads green through the whole of it.
|
|
35
|
+
*
|
|
36
|
+
* So the committed number is a BAND, not a floor: leaving it in either direction fails,
|
|
37
|
+
* and only the remedy differs. Raising a number needs owner sign-off; lowering one is
|
|
38
|
+
* mandatory. Both are the same one-line rebaseline and the same reviewable diff.
|
|
39
|
+
*
|
|
40
|
+
* `bench/size-guard.ts` is the shape this follows — it earned the tightness in 0.45 by
|
|
41
|
+
* catching +0.14% moves a 1% tolerance would have waved through.
|
|
42
|
+
*
|
|
43
|
+
* A BASELINE CANNOT LAUNDER A CEILING
|
|
44
|
+
* -----------------------------------
|
|
45
|
+
* If a ceiling is configured, a baseline that records a number ABOVE it is rejected as
|
|
46
|
+
* invalid rather than honoured. Otherwise the ceiling would be waivable by rebaselining,
|
|
47
|
+
* which makes it a suggestion. (`bench/size-guard.ts` validates its own baseline for
|
|
48
|
+
* exactly this reason; this follows it.)
|
|
49
|
+
*
|
|
50
|
+
* FAILS CLOSED
|
|
51
|
+
* ------------
|
|
52
|
+
* Every way of not having measured is a failure, never a pass: a missing baseline, a
|
|
53
|
+
* baseline of the wrong shape, an empty baseline, a report over zero corpus files, a
|
|
54
|
+
* report where no site was instrumentable, a report whose grammar walk was incomplete
|
|
55
|
+
* (`unresolvedRoots` non-empty), a baselined key that no longer exists, and a measured
|
|
56
|
+
* key with no baseline entry. This repo already contains the alternative — `ratio:
|
|
57
|
+
* ordered.length === 0 ? 1` in src/coverage.ts reports 100% covered when nothing was
|
|
58
|
+
* analysable — and the whole point of a gate is to not be that.
|
|
59
|
+
*/
|
|
60
|
+
import type { WastedWorkReport } from './choice-cost.ts';
|
|
61
|
+
export type WastedWorkBaseline = {
|
|
62
|
+
readonly schema: 'parseman.wasted-work-baseline/1';
|
|
63
|
+
/** Informational: which revision produced the numbers. Never compared. */
|
|
64
|
+
gitRev: string;
|
|
65
|
+
/** Informational, `YYYY-MM-DD`. Never compared — comparing it would make the
|
|
66
|
+
* verdict depend on the clock. */
|
|
67
|
+
updatedAt: string;
|
|
68
|
+
/**
|
|
69
|
+
* Absolute per-corpus totals, keyed by corpus id.
|
|
70
|
+
*
|
|
71
|
+
* `totalWastedBytes` is the INTERPRETED column, and that is deliberate even though
|
|
72
|
+
* `WastedWorkReport` names `totalGatedWastedBytes` as the headline. For BYTES the two
|
|
73
|
+
* are the same number, structurally: the modelled first-char guard is derived from the
|
|
74
|
+
* arm's first SET, which over-approximates what the arm can start with, so wherever the
|
|
75
|
+
* guard rejects, the arm's own leading terminal would have rejected at the same position
|
|
76
|
+
* having consumed nothing. Measured over four dialect grammars, zero arms differ (see the
|
|
77
|
+
* header of `choice-cost.ts`). What the guard removes is ATTEMPTS, not rescanned bytes —
|
|
78
|
+
* so `gatedAttempts`, `gatedFailures` and the inversion ranking DO read the gated columns,
|
|
79
|
+
* and only the byte totals are recorded from the interpreted one, where it is additionally
|
|
80
|
+
* the conservative UPPER bound of the two.
|
|
81
|
+
*
|
|
82
|
+
* That identity is not enforced anywhere it could be relied on silently: `checkWastedWork`
|
|
83
|
+
* judges the compiled column against this same band wherever the two columns part, so a
|
|
84
|
+
* divergence goes red instead of unnoticed.
|
|
85
|
+
*/
|
|
86
|
+
totals: Record<string, {
|
|
87
|
+
corpusBytes: number;
|
|
88
|
+
totalWastedBytes: number;
|
|
89
|
+
instrumentedSites: number;
|
|
90
|
+
}>;
|
|
91
|
+
/** Absolute per-site wasted bytes, keyed by `<corpus>::<siteKey>`. Interpreted column,
|
|
92
|
+
* for the reason given on `totals` above. */
|
|
93
|
+
sites: Record<string, number>;
|
|
94
|
+
};
|
|
95
|
+
export type WastedWorkPolicy = {
|
|
96
|
+
/**
|
|
97
|
+
* Maximum wasted bytes per corpus byte. A hard ceiling no rebaseline can waive.
|
|
98
|
+
* Omit for drift-only gating; a project should set it once it knows its own number.
|
|
99
|
+
*/
|
|
100
|
+
ceilingRatio?: number;
|
|
101
|
+
/**
|
|
102
|
+
* Half-width of the band around each committed number, as a percentage. Default 1.
|
|
103
|
+
*
|
|
104
|
+
* SYMMETRIC: a measurement more than this ABOVE its baseline is a regression, and a
|
|
105
|
+
* measurement more than this BELOW it is an unbanked win. Both fail.
|
|
106
|
+
*
|
|
107
|
+
* This is not a noise allowance — the metric is a deterministic count of input bytes,
|
|
108
|
+
* so its noise floor is exactly zero and any non-zero value here is pure headroom.
|
|
109
|
+
* It exists only so incidental one-byte churn does not thrash the baseline in both
|
|
110
|
+
* directions. Set it as near zero as the corpus permits; `bench/choice-cost-guard.ts`
|
|
111
|
+
* runs at 0.1, matching `bench/size-guard.ts`'s ratchet slack.
|
|
112
|
+
*/
|
|
113
|
+
driftTolerancePct?: number;
|
|
114
|
+
/**
|
|
115
|
+
* Fail on an ordering inversion — an arm that failed every one of its attempts while
|
|
116
|
+
* a later arm at the same site matched. Off by default: on an existing grammar this
|
|
117
|
+
* fires immediately, and a gate that is red on arrival for a pre-existing condition
|
|
118
|
+
* gets disabled rather than fixed. Turn it on once the backlog is empty, to keep it
|
|
119
|
+
* empty.
|
|
120
|
+
*/
|
|
121
|
+
failOnInversions?: boolean;
|
|
122
|
+
};
|
|
123
|
+
export type GateBreach = {
|
|
124
|
+
/** `drift` is growth past the band; `shrank` is an improvement that was not banked.
|
|
125
|
+
* Both are failures, and the `detail` says which remedy applies. */
|
|
126
|
+
kind: 'ceiling' | 'drift' | 'shrank' | 'unbaselined' | 'stale' | 'inversion' | 'unmeasurable' | 'invalid-baseline';
|
|
127
|
+
key: string;
|
|
128
|
+
/** One line. Says what happened and what number to look at — never advice. */
|
|
129
|
+
detail: string;
|
|
130
|
+
};
|
|
131
|
+
export type GateVerdict = {
|
|
132
|
+
readonly schema: 'parseman.wasted-work-verdict/1';
|
|
133
|
+
ok: boolean;
|
|
134
|
+
/** Ascending by (kind, key). Deterministic, so a verdict is diffable. */
|
|
135
|
+
breaches: readonly GateBreach[];
|
|
136
|
+
checkedCorpora: number;
|
|
137
|
+
checkedSites: number;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Judge one or more measured corpora against a committed baseline.
|
|
141
|
+
*
|
|
142
|
+
* `reports` is keyed by corpus id — a grammar is usually gated over more than one body
|
|
143
|
+
* of input, and a single blended number would let a regression on one hide behind an
|
|
144
|
+
* improvement on another.
|
|
145
|
+
*/
|
|
146
|
+
export declare function checkWastedWork(reports: Readonly<Record<string, WastedWorkReport>>, baseline: unknown, policy?: WastedWorkPolicy): GateVerdict;
|
|
147
|
+
/**
|
|
148
|
+
* Build the baseline a passing measurement would record.
|
|
149
|
+
*
|
|
150
|
+
* Deliberately NOT called by the gate. It exists so a rebaseline is one explicit
|
|
151
|
+
* command whose output is a file in the diff — the reviewable record — rather than
|
|
152
|
+
* something the gate can do to itself on a red run.
|
|
153
|
+
*/
|
|
154
|
+
export declare function buildWastedWorkBaseline(reports: Readonly<Record<string, WastedWorkReport>>, meta: {
|
|
155
|
+
gitRev: string;
|
|
156
|
+
updatedAt: string;
|
|
157
|
+
}): WastedWorkBaseline;
|
|
158
|
+
//# sourceMappingURL=choice-cost-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choice-cost-gate.d.ts","sourceRoot":"","sources":["../../src/analysis/choice-cost-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAExD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,MAAM,EAAE,iCAAiC,CAAA;IAClD,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAA;IACd;uCACmC;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACpG;kDAC8C;IAC9C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;;;;;OAWG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB;yEACqE;IACrE,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,aAAa,GAAG,OAAO,GAAG,WAAW,GAAG,cAAc,GAAG,kBAAkB,CAAA;IAClH,GAAG,EAAE,MAAM,CAAA;IACX,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,MAAM,EAAE,gCAAgC,CAAA;IACjD,EAAE,EAAE,OAAO,CAAA;IACX,yEAAyE;IACzE,QAAQ,EAAE,SAAS,UAAU,EAAE,CAAA;IAC/B,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAQD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,EACnD,QAAQ,EAAE,OAAO,EACjB,MAAM,GAAE,gBAAqB,GAC5B,WAAW,CAkLb;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,EACnD,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC1C,kBAAkB,CAWpB"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CHOICE COST — the human layer.
|
|
3
|
+
* ==============================
|
|
4
|
+
*
|
|
5
|
+
* Three layers, not two:
|
|
6
|
+
*
|
|
7
|
+
* ANALYSIS src/analysis/choice-cost.ts — what the sites are and what they cost.
|
|
8
|
+
* POLICY bench/choice-cost-guard.ts — which of those numbers fail a build.
|
|
9
|
+
* RENDERING this file — how a person reads either of them.
|
|
10
|
+
*
|
|
11
|
+
* The structured report is the source of truth. Nothing here computes a finding, and
|
|
12
|
+
* nothing here decides pass or fail; a gate consumes the data and never this text. If
|
|
13
|
+
* a number appears below that is not in the report, that is a bug in this file.
|
|
14
|
+
*
|
|
15
|
+
* WHAT A PARSER GENERATOR CAN SHOW THAT A COMPILER CANNOT
|
|
16
|
+
* -------------------------------------------------------
|
|
17
|
+
* A type error has one source to point at. A wasted-work finding has TWO, and relating
|
|
18
|
+
* them is the whole diagnostic:
|
|
19
|
+
*
|
|
20
|
+
* - the GRAMMAR site — the ordered choice whose arm ordering costs the time
|
|
21
|
+
* - the COST — measured, over a real corpus, per alternative
|
|
22
|
+
*
|
|
23
|
+
* So the ordering is printed WITH its measured cost beside each arm, which makes the
|
|
24
|
+
* fix self-evident without a paragraph explaining it:
|
|
25
|
+
*
|
|
26
|
+
* StylesheetAtRule › dispatch[0] 1.31 MB rescanned
|
|
27
|
+
* 0 RoutedAtRuleStatement failed 4,182 / 4,271 1.31 MB
|
|
28
|
+
* 1 RoutedLayerBlock matched 4,182
|
|
29
|
+
*
|
|
30
|
+
* Reading that, nobody needs to be told what to do.
|
|
31
|
+
*
|
|
32
|
+
* QUIET BY DEFAULT
|
|
33
|
+
* ----------------
|
|
34
|
+
* Nothing in this module prints. It returns strings. There is no console call and no
|
|
35
|
+
* process-wide default-on channel, deliberately: importing `examples/css/parser.ts`
|
|
36
|
+
* already emits roughly sixty lines of gating advice before any user code runs, and a
|
|
37
|
+
* beautiful diagnostic that nobody reads because it is buried in build noise is not
|
|
38
|
+
* beautiful. This one is available on request — from the CLI gate, or by calling it —
|
|
39
|
+
* and silent otherwise.
|
|
40
|
+
*
|
|
41
|
+
* DETERMINISM BINDS THE RENDERING TOO
|
|
42
|
+
* -----------------------------------
|
|
43
|
+
* The rendering is diffable: it preserves the report's ordering, contains no timings,
|
|
44
|
+
* no dates, no absolute paths, and colour is opt-in rather than auto-detected, so the
|
|
45
|
+
* same report always renders to the same bytes. A renderer that sniffed `isTTY` would
|
|
46
|
+
* produce two different outputs from one report and break exactly that.
|
|
47
|
+
*/
|
|
48
|
+
import type { ChoiceInventoryReport, ChoiceInventoryEntry, WastedWorkReport } from './choice-cost.ts';
|
|
49
|
+
import { groupDigits } from './format-number.ts';
|
|
50
|
+
export type RenderOptions = {
|
|
51
|
+
/** Rows to show. Default 20. The report always holds all of them. */
|
|
52
|
+
limit?: number;
|
|
53
|
+
/**
|
|
54
|
+
* ANSI colour. Default false — NOT auto-detected from `isTTY`, because a renderer
|
|
55
|
+
* whose bytes depend on where it is piped cannot be diffed or snapshotted.
|
|
56
|
+
*/
|
|
57
|
+
color?: boolean;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Deterministic thousands grouping. `toLocaleString()` is locale-dependent and
|
|
61
|
+
* would make the output differ between machines — the one thing a gateable
|
|
62
|
+
* rendering cannot do.
|
|
63
|
+
*
|
|
64
|
+
* DEFINED IN `./format-number.ts` and re-exported here because this module's own
|
|
65
|
+
* callers import it from here. It was a byte-identical second copy: `./terminal.ts`
|
|
66
|
+
* declared one, this file declared another, and the two were one edit away from
|
|
67
|
+
* disagreeing about how a report reads on two different screens.
|
|
68
|
+
*/
|
|
69
|
+
export { groupDigits };
|
|
70
|
+
/** Byte counts at a glance. Binary units, fixed to one decimal, so 1,376,256 renders
|
|
71
|
+
* as `1.3 MB` on every machine. */
|
|
72
|
+
export declare function bytes(n: number): string;
|
|
73
|
+
/**
|
|
74
|
+
* The combinator source a left-factoring would produce, ready to paste.
|
|
75
|
+
*
|
|
76
|
+
* Offered ONLY for the shape where it is mechanical and total: every arm of the choice
|
|
77
|
+
* in one group. A partial group needs the author to decide which arms move and in what
|
|
78
|
+
* order — an ordering decision that changes what the grammar accepts, which no
|
|
79
|
+
* generated rewrite may make silently.
|
|
80
|
+
*
|
|
81
|
+
* This is a PREVIEW. It is not applied, and — until the digest-verification loop
|
|
82
|
+
* described in `docs/` is wired — it is not yet proven behaviour-preserving, so it is
|
|
83
|
+
* labelled a candidate rather than offered as a fix. An unverified rewrite presented
|
|
84
|
+
* as verified is worse than no suggestion at all.
|
|
85
|
+
*/
|
|
86
|
+
export declare function leftFactorPreview(e: ChoiceInventoryEntry): string | null;
|
|
87
|
+
export declare function renderChoiceInventory(r: ChoiceInventoryReport, opts?: RenderOptions): string;
|
|
88
|
+
/**
|
|
89
|
+
* The ranked list, with each top site expanded into its arm ordering.
|
|
90
|
+
*
|
|
91
|
+
* The expansion is the point. A ranked list of site keys tells you WHERE; the arm
|
|
92
|
+
* breakdown beside it tells you WHY, and "arm 0 failed 4,182 of 4,271 times" is an
|
|
93
|
+
* argument for moving arm 0 that needs no prose attached.
|
|
94
|
+
*/
|
|
95
|
+
export declare function renderWastedWork(r: WastedWorkReport, opts?: RenderOptions): string;
|
|
96
|
+
//# sourceMappingURL=choice-cost-render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choice-cost-render.d.ts","sourceRoot":"","sources":["../../src/analysis/choice-cost-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,OAAO,KAAK,EACV,qBAAqB,EAAE,oBAAoB,EAAE,gBAAgB,EAC9D,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD,MAAM,MAAM,aAAa,GAAG;IAC1B,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAID;;;;;;;;;GASG;AACH,OAAO,EAAE,WAAW,EAAE,CAAA;AAEtB;oCACoC;AACpC,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIvC;AA8CD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,oBAAoB,GAAG,MAAM,GAAG,IAAI,CAOxE;AAID,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,qBAAqB,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CA0ChG;AAID;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAmEtF"}
|