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
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
import type { ParseContext, ParseResult } from '../types.ts'
|
|
2
|
+
import { advanceTrivia, needsDeferredTriviaCommit, rollbackTrivia, saveTriviaMark, scanTrivia } from '../combinators/trivia-skip.ts'
|
|
3
|
+
import {
|
|
4
|
+
beginCstNodeCapture, cstCaptureActive, endCstNodeCapture, pushCstChild,
|
|
5
|
+
pushCstLeaf, rollbackCstCapture, saveCstMark, type CstRollbackMark,
|
|
6
|
+
} from '../cst/capture-buffer.ts'
|
|
7
|
+
import {
|
|
8
|
+
OP_CHOICE, OP_EMPTY, OP_GATE, OP_LEAF, OP_LIT, OP_NODE, OP_NOT, OP_OPT,
|
|
9
|
+
OP_PEEK, OP_REP, OP_REPV, OP_RULE, OP_RX, OP_SEQ, OP_SEQV, OP_XFORM,
|
|
10
|
+
OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_EXPECT,
|
|
11
|
+
} from './ops.ts'
|
|
12
|
+
import {
|
|
13
|
+
expandCompact, resolveTable,
|
|
14
|
+
type CompactProgram, type ResolvedClass, type ResolvedDispatch, type TableProgram, type TableRule,
|
|
15
|
+
} from './program.ts'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* THE SHARED DRIVER.
|
|
19
|
+
*
|
|
20
|
+
* One recognizer for every grammar, every rule and every variant — the thing
|
|
21
|
+
* codegen emits once PER RULE, and which therefore sets the per-rule byte floor.
|
|
22
|
+
* It uses the same zero-allocation protocol the emitted code uses (a sentinel
|
|
23
|
+
* for failure plus a shared end-position slot), so what it adds over open-coded
|
|
24
|
+
* recognition is the opcode read and the switch, not an allocation.
|
|
25
|
+
*
|
|
26
|
+
* The driver is instantiated ONCE PER RESOLVED TABLE, closing over that table's
|
|
27
|
+
* arrays. Instruction operands are then reads of context slots rather than
|
|
28
|
+
* property loads through an object, and — the point of G5 — an option can never
|
|
29
|
+
* be consulted here: two settings pairs are two tables, not two code paths.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/** Failure sentinel — identity-compared, never inspected. */
|
|
33
|
+
const FAIL: unique symbol = Symbol('pm.fail')
|
|
34
|
+
|
|
35
|
+
const EMPTY_TL: readonly number[] = Object.freeze([])
|
|
36
|
+
const EMPTY_FX: string[] = []
|
|
37
|
+
|
|
38
|
+
type Leaf = { _tag: 'leaf'; value: string; span: { start: number; end: number } }
|
|
39
|
+
|
|
40
|
+
function rawEntry(v: unknown, input: string, s: number, e: number): unknown {
|
|
41
|
+
if (typeof v === 'object' && v !== null) {
|
|
42
|
+
const t = (v as { _tag?: string })._tag
|
|
43
|
+
if (t === 'node' || t === 'leaf' || t === 'parseError') return v
|
|
44
|
+
}
|
|
45
|
+
return { _tag: 'leaf', value: typeof v === 'string' ? v : (typeof v === 'object' && v !== null ? input.slice(s, e) : ''), span: { start: s, end: e } }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Same semantics as `trackLinesInto` in `src/table/assemble.ts`. (Named for the
|
|
49
|
+
* source lowering before it, deleted in `37c57b5`.) */
|
|
50
|
+
function trackLines(ctx: ParseContext, input: string, end: number): void {
|
|
51
|
+
const from = ctx._lineScannedTo ?? 0
|
|
52
|
+
if (end <= from) return
|
|
53
|
+
const starts = ctx._lineStarts
|
|
54
|
+
if (starts === undefined) return
|
|
55
|
+
for (let i = from; i < end; i++) if (input.charCodeAt(i) === 10) starts.push(i + 1)
|
|
56
|
+
ctx._lineScannedTo = end
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Same semantics as `lineCol` in `src/table/run-support.ts`, which is where the
|
|
60
|
+
* live copy moved. (Named for the source lowering before it, deleted in `37c57b5`.) */
|
|
61
|
+
function lineCol(ctx: ParseContext, offset: number): [number, number] {
|
|
62
|
+
const starts = ctx._lineStarts ?? [0]
|
|
63
|
+
let lo = 0, hi = starts.length - 1
|
|
64
|
+
while (lo < hi) {
|
|
65
|
+
const mid = (lo + hi + 1) >> 1
|
|
66
|
+
if (starts[mid]! <= offset) lo = mid
|
|
67
|
+
else hi = mid - 1
|
|
68
|
+
}
|
|
69
|
+
return [lo + 1, offset - starts[lo]! + 1]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function spanLines(ctx: ParseContext, start: number, end: number): { start: number; end: number; startLine: number; startColumn: number; endLine: number; endColumn: number } {
|
|
73
|
+
const s = lineCol(ctx, start), e = lineCol(ctx, end)
|
|
74
|
+
return { start, end, startLine: s[0], startColumn: s[1], endLine: e[0], endColumn: e[1] }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function classHas(cls: ResolvedClass, code: number): boolean {
|
|
78
|
+
if (code < 0) return false
|
|
79
|
+
if (code < 128) return cls.ascii[code] === 1
|
|
80
|
+
const hi = cls.hi
|
|
81
|
+
for (let i = 0; i < hi.length; i += 2) if (code >= hi[i]! && code <= hi[i + 1]!) return true
|
|
82
|
+
return false
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
type Driver = {
|
|
86
|
+
exec: (ip: number, input: string, pos: number, ctx: ParseContext) => unknown
|
|
87
|
+
end: () => number
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function makeDriver(
|
|
91
|
+
code: Int32Array,
|
|
92
|
+
k: readonly unknown[],
|
|
93
|
+
fns: readonly unknown[],
|
|
94
|
+
cc: readonly ResolvedClass[],
|
|
95
|
+
fx: readonly (readonly string[])[],
|
|
96
|
+
disp: readonly ResolvedDispatch[],
|
|
97
|
+
): Driver {
|
|
98
|
+
/** Shared end-position out-parameter (`_pfEnd` in emitted code). */
|
|
99
|
+
let END = 0
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Capture goes through the runtime's own buffer (`src/cst/capture-buffer.ts`),
|
|
103
|
+
* not a hand-rolled copy: it is already the shared mechanism the interpreter
|
|
104
|
+
* uses, and a second implementation of it is precisely the duplication G5 is
|
|
105
|
+
* about removing.
|
|
106
|
+
*/
|
|
107
|
+
function pushLeaf(ctx: ParseContext, value: string, s: number, e: number): void {
|
|
108
|
+
const lf: Leaf = { _tag: 'leaf', value, span: { start: s, end: e } }
|
|
109
|
+
pushCstLeaf(ctx, lf)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Is there anything a failed branch could need to UNRECORD?
|
|
114
|
+
*
|
|
115
|
+
* `saveCstMark` allocates a 5-field object and `saveTriviaMark` allocates that
|
|
116
|
+
* plus a 7-field one; `rollbackTrivia` allocates a third to call through. In
|
|
117
|
+
* the driver those sat in the repetition and choice loops, so a parse
|
|
118
|
+
* allocated three-to-four objects PER ITEM that codegen never allocates (it
|
|
119
|
+
* emits scalar locals). That is a per-item cost, which is what the widening
|
|
120
|
+
* gap with input size was: +82% small, +275% large.
|
|
121
|
+
*
|
|
122
|
+
* When every sink either rollback touches is absent, nothing was recorded,
|
|
123
|
+
* so nothing needs unrecording and the mark need not exist. A grammar with no
|
|
124
|
+
* `node()` and no trivia log — json, csv — never allocates one.
|
|
125
|
+
*/
|
|
126
|
+
function rollbackNeeded(ctx: ParseContext): boolean {
|
|
127
|
+
return ctx._cstBuf !== undefined
|
|
128
|
+
|| ctx._cstLeaves !== undefined
|
|
129
|
+
|| ctx._cstRawChildren !== undefined
|
|
130
|
+
|| ctx._cstTriviaLog !== undefined
|
|
131
|
+
|| ctx._fields !== undefined
|
|
132
|
+
|| ctx._errors !== undefined
|
|
133
|
+
|| ctx._triviaLog !== undefined
|
|
134
|
+
|| ctx._rootTriviaLog !== undefined
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The lead character at `pos`, as the first-set tables index it.
|
|
139
|
+
*
|
|
140
|
+
* `charCodeAt` is the hot read; only a high surrogate needs the code-point
|
|
141
|
+
* decode, so that branch is paid on astral input and nowhere else.
|
|
142
|
+
*/
|
|
143
|
+
function skipTrivia(input: string, cur: number, ctx: ParseContext): number {
|
|
144
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
145
|
+
const scan = scanTrivia(input, cur, ctx)
|
|
146
|
+
scan.commit()
|
|
147
|
+
return scan.end
|
|
148
|
+
}
|
|
149
|
+
return advanceTrivia(input, cur, ctx)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function lead(input: string, pos: number): number {
|
|
153
|
+
if (pos >= input.length) return -1
|
|
154
|
+
const c = input.charCodeAt(pos)
|
|
155
|
+
if (c < 0xd800 || c > 0xdbff) return c
|
|
156
|
+
return input.codePointAt(pos) ?? c
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function exec(ip: number, input: string, pos: number, ctx: ParseContext): unknown {
|
|
160
|
+
switch (code[ip]) {
|
|
161
|
+
case OP_LIT: {
|
|
162
|
+
const s = k[code[ip + 1]!] as string
|
|
163
|
+
if (input.startsWith(s, pos)) {
|
|
164
|
+
const e = pos + s.length
|
|
165
|
+
if (cstCaptureActive(ctx)) pushLeaf(ctx, s, pos, e)
|
|
166
|
+
END = e
|
|
167
|
+
return s
|
|
168
|
+
}
|
|
169
|
+
ctx._fe = pos; ctx._fx = fx[code[ip + 2]!] as string[]
|
|
170
|
+
return FAIL
|
|
171
|
+
}
|
|
172
|
+
case OP_RX: {
|
|
173
|
+
const re = k[code[ip + 1]!] as RegExp
|
|
174
|
+
re.lastIndex = pos
|
|
175
|
+
const m = re.exec(input)
|
|
176
|
+
if (m !== null) {
|
|
177
|
+
const v = m[0]
|
|
178
|
+
const e = pos + v.length
|
|
179
|
+
if (cstCaptureActive(ctx)) pushLeaf(ctx, v, pos, e)
|
|
180
|
+
END = e
|
|
181
|
+
return v
|
|
182
|
+
}
|
|
183
|
+
ctx._fe = pos; ctx._fx = fx[code[ip + 2]!] as string[]
|
|
184
|
+
return FAIL
|
|
185
|
+
}
|
|
186
|
+
case OP_LIT_TRACK: {
|
|
187
|
+
const s = k[code[ip + 1]!] as string
|
|
188
|
+
if (input.startsWith(s, pos)) {
|
|
189
|
+
const e = pos + s.length
|
|
190
|
+
if (cstCaptureActive(ctx)) pushLeaf(ctx, s, pos, e)
|
|
191
|
+
trackLines(ctx, input, e)
|
|
192
|
+
END = e
|
|
193
|
+
return s
|
|
194
|
+
}
|
|
195
|
+
ctx._fe = pos; ctx._fx = fx[code[ip + 2]!] as string[]
|
|
196
|
+
return FAIL
|
|
197
|
+
}
|
|
198
|
+
case OP_RX_TRACK: {
|
|
199
|
+
const re = k[code[ip + 1]!] as RegExp
|
|
200
|
+
re.lastIndex = pos
|
|
201
|
+
const m = re.exec(input)
|
|
202
|
+
if (m !== null) {
|
|
203
|
+
const v = m[0]
|
|
204
|
+
const e = pos + v.length
|
|
205
|
+
if (cstCaptureActive(ctx)) pushLeaf(ctx, v, pos, e)
|
|
206
|
+
trackLines(ctx, input, e)
|
|
207
|
+
END = e
|
|
208
|
+
return v
|
|
209
|
+
}
|
|
210
|
+
ctx._fe = pos; ctx._fx = fx[code[ip + 2]!] as string[]
|
|
211
|
+
return FAIL
|
|
212
|
+
}
|
|
213
|
+
case OP_EMPTY:
|
|
214
|
+
END = pos
|
|
215
|
+
return ''
|
|
216
|
+
|
|
217
|
+
case OP_GATE: {
|
|
218
|
+
if (!classHas(cc[code[ip + 1]!]!, lead(input, pos))) {
|
|
219
|
+
ctx._fe = pos; ctx._fx = fx[code[ip + 3]!] as string[]
|
|
220
|
+
return FAIL
|
|
221
|
+
}
|
|
222
|
+
return exec(code[ip + 2]!, input, pos, ctx)
|
|
223
|
+
}
|
|
224
|
+
case OP_RULE:
|
|
225
|
+
return exec(code[ip + 1]!, input, pos, ctx)
|
|
226
|
+
|
|
227
|
+
case OP_EXPECT: {
|
|
228
|
+
const v = exec(code[ip + 1]!, input, pos, ctx)
|
|
229
|
+
if (v !== FAIL) return v
|
|
230
|
+
// Mirrors src/combinators/expect.ts:135-150 — succeed at zero width with
|
|
231
|
+
// a ParseError value, and record it in the flat sink when present.
|
|
232
|
+
const span = { start: pos, end: pos }
|
|
233
|
+
const err = { _tag: 'parseError' as const, span, expected: fx[code[ip + 2]!] as string[] }
|
|
234
|
+
ctx._errors?.push(err)
|
|
235
|
+
END = pos
|
|
236
|
+
return err
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
case OP_SCOPE: {
|
|
240
|
+
const ki = code[ip + 1]!
|
|
241
|
+
const saved = ctx.trivia
|
|
242
|
+
ctx.trivia = ki < 0 ? undefined : (k[ki] as ParseContext['trivia'])
|
|
243
|
+
const v = exec(code[ip + 2]!, input, pos, ctx)
|
|
244
|
+
ctx.trivia = saved
|
|
245
|
+
return v
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
case OP_SEQ:
|
|
249
|
+
case OP_SEQV: {
|
|
250
|
+
const n = code[ip + 1]!
|
|
251
|
+
const values: unknown[] | undefined = code[ip] === OP_SEQ ? [] : undefined
|
|
252
|
+
let cur = pos
|
|
253
|
+
for (let i = 0; i < n; i++) {
|
|
254
|
+
const child = code[ip + 2 + i]!
|
|
255
|
+
if (i > 0 && ctx.trivia !== undefined) {
|
|
256
|
+
const mark = rollbackNeeded(ctx) ? saveTriviaMark(ctx) : null
|
|
257
|
+
let scanEnd: number
|
|
258
|
+
if (needsDeferredTriviaCommit(ctx)) {
|
|
259
|
+
const scan = scanTrivia(input, cur, ctx)
|
|
260
|
+
scan.commit()
|
|
261
|
+
scanEnd = scan.end
|
|
262
|
+
} else {
|
|
263
|
+
scanEnd = advanceTrivia(input, cur, ctx)
|
|
264
|
+
}
|
|
265
|
+
const v = exec(child, input, scanEnd, ctx)
|
|
266
|
+
if (v === FAIL) return FAIL
|
|
267
|
+
if (END > scanEnd) cur = END
|
|
268
|
+
else if (mark !== null) rollbackTrivia(ctx, mark)
|
|
269
|
+
if (values !== undefined) values.push(v)
|
|
270
|
+
continue
|
|
271
|
+
}
|
|
272
|
+
// TERMINAL FAST PATH. Terminals are the majority of executed
|
|
273
|
+
// instructions, and reaching one through `exec` costs a JS call frame
|
|
274
|
+
// plus a switch dispatch that the emitted code does not pay. Running
|
|
275
|
+
// LIT/RX in place removes both. The duplication is in the DRIVER,
|
|
276
|
+
// which ships once for every grammar — the cost this design trades on.
|
|
277
|
+
const cop = code[child]
|
|
278
|
+
if (cop === OP_LIT) {
|
|
279
|
+
const lit = k[code[child + 1]!] as string
|
|
280
|
+
if (!input.startsWith(lit, cur)) {
|
|
281
|
+
ctx._fe = cur; ctx._fx = fx[code[child + 2]!] as string[]
|
|
282
|
+
return FAIL
|
|
283
|
+
}
|
|
284
|
+
const e = cur + lit.length
|
|
285
|
+
if (cstCaptureActive(ctx)) pushLeaf(ctx, lit, cur, e)
|
|
286
|
+
if (values !== undefined) values.push(lit)
|
|
287
|
+
cur = e
|
|
288
|
+
continue
|
|
289
|
+
}
|
|
290
|
+
if (cop === OP_RX) {
|
|
291
|
+
const re = k[code[child + 1]!] as RegExp
|
|
292
|
+
re.lastIndex = cur
|
|
293
|
+
const m = re.exec(input)
|
|
294
|
+
if (m === null) {
|
|
295
|
+
ctx._fe = cur; ctx._fx = fx[code[child + 2]!] as string[]
|
|
296
|
+
return FAIL
|
|
297
|
+
}
|
|
298
|
+
const mv = m[0]
|
|
299
|
+
const e = cur + mv.length
|
|
300
|
+
if (cstCaptureActive(ctx)) pushLeaf(ctx, mv, cur, e)
|
|
301
|
+
if (values !== undefined) values.push(mv)
|
|
302
|
+
cur = e
|
|
303
|
+
continue
|
|
304
|
+
}
|
|
305
|
+
const v = exec(child, input, cur, ctx)
|
|
306
|
+
if (v === FAIL) return FAIL
|
|
307
|
+
if (values !== undefined) values.push(v)
|
|
308
|
+
cur = END
|
|
309
|
+
}
|
|
310
|
+
END = cur
|
|
311
|
+
return values
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
case OP_CHOICE: {
|
|
315
|
+
const d = code[ip + 1]!
|
|
316
|
+
const base = ip + 3
|
|
317
|
+
if (d >= 0) {
|
|
318
|
+
const table = disp[d]!
|
|
319
|
+
const c = lead(input, pos)
|
|
320
|
+
let arm = -1
|
|
321
|
+
if (c >= 0 && c < 128) {
|
|
322
|
+
const a = table.ascii[c]!
|
|
323
|
+
if (a !== 0) arm = a - 1
|
|
324
|
+
} else if (c >= 128) {
|
|
325
|
+
const hi = table.hi
|
|
326
|
+
for (let i = 0; i < hi.length; i += 3) {
|
|
327
|
+
if (c >= hi[i]! && c <= hi[i + 1]!) { arm = hi[i + 2]!; break }
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (arm >= 0) {
|
|
331
|
+
const v = exec(code[base + arm]!, input, pos, ctx)
|
|
332
|
+
if (v !== FAIL) return v
|
|
333
|
+
}
|
|
334
|
+
const open = table.open
|
|
335
|
+
if (open.length === 0) return FAIL
|
|
336
|
+
const mark: CstRollbackMark | null = rollbackNeeded(ctx) ? saveCstMark(ctx) : null
|
|
337
|
+
if (mark !== null) rollbackCstCapture(ctx, mark)
|
|
338
|
+
for (let i = 0; i < open.length; i++) {
|
|
339
|
+
const v = exec(code[base + open[i]!]!, input, pos, ctx)
|
|
340
|
+
if (v !== FAIL) return v
|
|
341
|
+
if (mark !== null) rollbackCstCapture(ctx, mark)
|
|
342
|
+
}
|
|
343
|
+
return FAIL
|
|
344
|
+
}
|
|
345
|
+
const n = code[ip + 2]!
|
|
346
|
+
const mark: CstRollbackMark | null = rollbackNeeded(ctx) ? saveCstMark(ctx) : null
|
|
347
|
+
for (let i = 0; i < n; i++) {
|
|
348
|
+
const v = exec(code[base + i]!, input, pos, ctx)
|
|
349
|
+
if (v !== FAIL) return v
|
|
350
|
+
if (mark !== null) rollbackCstCapture(ctx, mark)
|
|
351
|
+
}
|
|
352
|
+
return FAIL
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
case OP_OPT: {
|
|
356
|
+
const mark: CstRollbackMark | null = rollbackNeeded(ctx) ? saveCstMark(ctx) : null
|
|
357
|
+
const v = exec(code[ip + 1]!, input, pos, ctx)
|
|
358
|
+
if (v === FAIL) {
|
|
359
|
+
if (mark !== null) rollbackCstCapture(ctx, mark)
|
|
360
|
+
END = pos
|
|
361
|
+
// NULL, not undefined. `optional()` yields `null` on no-match
|
|
362
|
+
// (src/combinators/repeat.ts:269,277) and grammars TEST for it:
|
|
363
|
+
// examples/lang's `call` reducer is `if (args === null) return callee`,
|
|
364
|
+
// so `undefined` there turned a bare identifier into a call node with
|
|
365
|
+
// `args: undefined`. The parse succeeded and only the tree moved.
|
|
366
|
+
return null
|
|
367
|
+
}
|
|
368
|
+
return v
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
case OP_REP:
|
|
372
|
+
case OP_REPV: {
|
|
373
|
+
const child = code[ip + 1]!
|
|
374
|
+
const min = code[ip + 2]!
|
|
375
|
+
const max = code[ip + 3]!
|
|
376
|
+
const sep = code[ip + 4]!
|
|
377
|
+
const out: unknown[] | undefined = code[ip] === OP_REP ? [] : undefined
|
|
378
|
+
const hasTrivia = ctx.trivia !== undefined
|
|
379
|
+
const needMark = rollbackNeeded(ctx)
|
|
380
|
+
let cur = pos
|
|
381
|
+
let count = 0
|
|
382
|
+
for (;;) {
|
|
383
|
+
if (max >= 0 && count >= max) break
|
|
384
|
+
// One mark pair for the whole loop when a rollback is even possible,
|
|
385
|
+
// refreshed per iteration rather than reallocated.
|
|
386
|
+
const cmark = needMark ? saveCstMark(ctx) : null
|
|
387
|
+
const tmark = needMark ? saveTriviaMark(ctx) : null
|
|
388
|
+
let itemStart = cur
|
|
389
|
+
if (sep >= 0 && count > 0) {
|
|
390
|
+
// separator, with trivia on BOTH sides — mirrors repeat.ts's sepBy loop
|
|
391
|
+
let sp = cur
|
|
392
|
+
if (hasTrivia) sp = skipTrivia(input, sp, ctx)
|
|
393
|
+
const sv = exec(sep, input, sp, ctx)
|
|
394
|
+
if (sv === FAIL) {
|
|
395
|
+
if (tmark !== null) rollbackTrivia(ctx, tmark)
|
|
396
|
+
if (cmark !== null) rollbackCstCapture(ctx, cmark)
|
|
397
|
+
break
|
|
398
|
+
}
|
|
399
|
+
itemStart = hasTrivia ? skipTrivia(input, END, ctx) : END
|
|
400
|
+
} else if (hasTrivia) {
|
|
401
|
+
// Trivia precedes EVERY item, the first included: `repItem` in
|
|
402
|
+
// repeat.ts does this, and skipping it only for later items dropped
|
|
403
|
+
// exactly one trivia-log entry per repetition — invisible in the
|
|
404
|
+
// parse, visible in a node's `triviaLog`.
|
|
405
|
+
itemStart = skipTrivia(input, itemStart, ctx)
|
|
406
|
+
}
|
|
407
|
+
// Nothing but trivia left: don't speculatively parse an item at EOF.
|
|
408
|
+
if (itemStart >= input.length) {
|
|
409
|
+
if (tmark !== null) rollbackTrivia(ctx, tmark)
|
|
410
|
+
if (cmark !== null) rollbackCstCapture(ctx, cmark)
|
|
411
|
+
break
|
|
412
|
+
}
|
|
413
|
+
const v = exec(child, input, itemStart, ctx)
|
|
414
|
+
if (v === FAIL) {
|
|
415
|
+
if (tmark !== null) rollbackTrivia(ctx, tmark)
|
|
416
|
+
if (cmark !== null) rollbackCstCapture(ctx, cmark)
|
|
417
|
+
break
|
|
418
|
+
}
|
|
419
|
+
if (END === itemStart) {
|
|
420
|
+
// Zero-width item: it cannot make progress, so stop without taking it.
|
|
421
|
+
if (tmark !== null) rollbackTrivia(ctx, tmark)
|
|
422
|
+
if (cmark !== null) rollbackCstCapture(ctx, cmark)
|
|
423
|
+
break
|
|
424
|
+
}
|
|
425
|
+
if (out !== undefined) out.push(v)
|
|
426
|
+
cur = END
|
|
427
|
+
count++
|
|
428
|
+
}
|
|
429
|
+
if (count < min) return FAIL
|
|
430
|
+
END = cur
|
|
431
|
+
return out
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
case OP_XFORM: {
|
|
435
|
+
const v = exec(code[ip + 2]!, input, pos, ctx)
|
|
436
|
+
if (v === FAIL) return FAIL
|
|
437
|
+
const fn = fns[code[ip + 1]!] as (value: unknown, span: { start: number; end: number }) => unknown
|
|
438
|
+
return fn(v, { start: pos, end: END })
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
case OP_LEAF: {
|
|
442
|
+
const v = exec(code[ip + 2]!, input, pos, ctx)
|
|
443
|
+
if (v === FAIL) return FAIL
|
|
444
|
+
const end = END
|
|
445
|
+
const fn = fns[code[ip + 1]!] as (value: unknown, span: { start: number; end: number }) => unknown
|
|
446
|
+
const out = fn(v, { start: pos, end })
|
|
447
|
+
END = end
|
|
448
|
+
return out
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
case OP_NODE:
|
|
452
|
+
case OP_NODE_TRACK: {
|
|
453
|
+
// `flags` bit 2 = the builder reads `triviaLog`. Decided by
|
|
454
|
+
// `src/table/encode.ts` from the reducer's arity — the SAME analysis
|
|
455
|
+
// codegen runs — and baked into the row, so the driver reads a bit
|
|
456
|
+
// rather than re-deriving anything.
|
|
457
|
+
const flags = code[ip + 3]!
|
|
458
|
+
const saved = beginCstNodeCapture(ctx)
|
|
459
|
+
if ((flags & 4) === 0) ctx.captureTrivia = false
|
|
460
|
+
const v = exec(code[ip + 2]!, input, pos, ctx)
|
|
461
|
+
const cap = endCstNodeCapture(ctx, saved)
|
|
462
|
+
if (v === FAIL) return FAIL
|
|
463
|
+
const end = END
|
|
464
|
+
const build = fns[code[ip + 1]!] as (
|
|
465
|
+
children: readonly unknown[], fields: undefined, span: { start: number; end: number },
|
|
466
|
+
rawChildren: readonly unknown[], triviaLog: readonly number[], state: unknown,
|
|
467
|
+
) => unknown
|
|
468
|
+
const st = (flags & 8) !== 0 && ctx.state !== undefined
|
|
469
|
+
? Object.assign({}, ctx.state as Record<string, unknown>)
|
|
470
|
+
: undefined
|
|
471
|
+
const nd = build(
|
|
472
|
+
cap.children, undefined,
|
|
473
|
+
code[ip] === OP_NODE_TRACK ? spanLines(ctx, pos, end) : { start: pos, end },
|
|
474
|
+
cap.rawChildren, (flags & 4) !== 0 ? cap.triviaLog : EMPTY_TL, st,
|
|
475
|
+
)
|
|
476
|
+
pushCstChild(ctx, nd, rawEntry(nd, input, pos, end))
|
|
477
|
+
END = end
|
|
478
|
+
return nd
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
case OP_NOT: {
|
|
482
|
+
const mark: CstRollbackMark | null = rollbackNeeded(ctx) ? saveCstMark(ctx) : null
|
|
483
|
+
const v = exec(code[ip + 1]!, input, pos, ctx)
|
|
484
|
+
if (mark !== null) rollbackCstCapture(ctx, mark)
|
|
485
|
+
if (v === FAIL) { END = pos; return null }
|
|
486
|
+
ctx._fe = pos
|
|
487
|
+
return FAIL
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
case OP_PEEK: {
|
|
491
|
+
const mark: CstRollbackMark | null = rollbackNeeded(ctx) ? saveCstMark(ctx) : null
|
|
492
|
+
const v = exec(code[ip + 1]!, input, pos, ctx)
|
|
493
|
+
if (mark !== null) rollbackCstCapture(ctx, mark)
|
|
494
|
+
if (v === FAIL) return FAIL
|
|
495
|
+
END = pos
|
|
496
|
+
return null
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
default:
|
|
500
|
+
throw new Error(`table driver: unknown opcode ${String(code[ip])} at ${ip}`)
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
return { exec, end: () => END }
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Turn a program into the rule map a compiled artifact exports.
|
|
509
|
+
*
|
|
510
|
+
* The entries have the SAME signature as codegen rule functions, so `run()`,
|
|
511
|
+
* the linker's public wrappers and every consumer are unchanged.
|
|
512
|
+
*/
|
|
513
|
+
export function execRulesBaseline(source: TableProgram | CompactProgram): Record<string, TableRule> {
|
|
514
|
+
const prog = expandCompact(source)
|
|
515
|
+
const t = resolveTable(prog)
|
|
516
|
+
const d = makeDriver(t.code, t.k, t.fns, t.cc, t.fx, t.disp)
|
|
517
|
+
const out: Record<string, TableRule> = {}
|
|
518
|
+
// Chosen ONCE, from table data, at rule-map construction. Not a per-parse
|
|
519
|
+
// branch on an option: a plain table never has this wrapper at all.
|
|
520
|
+
const lines = prog.lines === 1
|
|
521
|
+
for (const name of Object.keys(prog.rules)) {
|
|
522
|
+
const entry = prog.rules[name]!
|
|
523
|
+
out[name] = (input: string, pos: number, ctx: ParseContext): ParseResult<unknown> => {
|
|
524
|
+
ctx._fe = -1
|
|
525
|
+
ctx._fx = EMPTY_FX
|
|
526
|
+
if (lines && ctx._lineStarts === undefined) { ctx._lineStarts = [0]; ctx._lineScannedTo = 0 }
|
|
527
|
+
const v = d.exec(entry, input, pos, ctx)
|
|
528
|
+
if (v === FAIL) {
|
|
529
|
+
const fe = ctx._fe
|
|
530
|
+
const at = fe === undefined || fe < 0 ? pos : fe
|
|
531
|
+
return { ok: false, expected: (ctx._fx ?? EMPTY_FX) as string[], span: { start: at, end: at } }
|
|
532
|
+
}
|
|
533
|
+
return { ok: true, value: v, span: { start: pos, end: d.end() } }
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return out
|
|
537
|
+
}
|