parseman 0.48.1 → 0.50.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/dist/analysis/commitment.d.ts +2 -1
- package/dist/analysis/commitment.d.ts.map +1 -1
- package/dist/analysis/diagnostics.js +1931 -861
- package/dist/analysis/diagnostics.js.map +3 -3
- package/dist/analysis/rebuild.d.ts.map +1 -1
- package/dist/cli/index.js +1236 -164
- package/dist/cli/index.js.map +3 -3
- package/dist/combinators/trivia-skip.d.ts +1 -1
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/compiler/build-arity.d.ts +16 -0
- package/dist/compiler/build-arity.d.ts.map +1 -1
- package/dist/compiler/degradation.d.ts +0 -2
- package/dist/compiler/degradation.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/compiler/token-alphabet.d.ts +11 -0
- package/dist/compiler/token-alphabet.d.ts.map +1 -1
- package/dist/compiler/token-capability.js +185 -20
- package/dist/compiler/token-capability.js.map +1 -1
- package/dist/cst/capture-buffer.d.ts +5 -1
- package/dist/cst/capture-buffer.d.ts.map +1 -1
- package/dist/index.js +1354 -278
- package/dist/index.js.map +3 -3
- package/dist/language-service/index.js +2 -1
- package/dist/language-service/index.js.map +1 -1
- package/dist/plugin/direct-builder-static.d.ts +20 -0
- package/dist/plugin/direct-builder-static.d.ts.map +1 -1
- package/dist/plugin/entry-supercompiler.d.ts +48 -0
- package/dist/plugin/entry-supercompiler.d.ts.map +1 -0
- package/dist/plugin/evaluator.d.ts +13 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +2118 -376
- package/dist/plugin/index.js.map +3 -3
- package/dist/run/index.js +2 -1
- package/dist/run/index.js.map +1 -1
- package/dist/spec/index.js +29 -7
- package/dist/spec/index.js.map +1 -1
- package/dist/table/assemble.d.ts.map +1 -1
- package/dist/table/compile-rule-map.d.ts +6 -5
- package/dist/table/compile-rule-map.d.ts.map +1 -1
- package/dist/table/emit-assembly.d.ts +6 -1
- package/dist/table/emit-assembly.d.ts.map +1 -1
- package/dist/table/encode.d.ts.map +1 -1
- package/dist/table/index.js +1298 -231
- package/dist/table/index.js.map +3 -3
- package/dist/table/ops.d.ts +3 -2
- package/dist/table/ops.d.ts.map +1 -1
- package/dist/table/program.d.ts +15 -1
- package/dist/table/program.d.ts.map +1 -1
- package/dist/table/scalar-terminal.d.ts +30 -0
- package/dist/table/scalar-terminal.d.ts.map +1 -1
- package/dist/table/site-labels.d.ts +8 -0
- package/dist/table/site-labels.d.ts.map +1 -1
- package/dist/types.d.ts +8 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/analysis/commitment.ts +19 -8
- package/src/analysis/rebuild.ts +1 -0
- package/src/combinators/trivia-skip.ts +2 -2
- package/src/compiler/build-arity.ts +50 -0
- package/src/compiler/degradation.ts +0 -6
- package/src/compiler/ir-serialize.ts +17 -3
- package/src/compiler/linker.ts +14 -1
- package/src/compiler/token-alphabet.ts +322 -28
- package/src/cst/capture-buffer.ts +34 -11
- package/src/plugin/direct-builder-static.ts +116 -12
- package/src/plugin/entry-supercompiler.ts +567 -0
- package/src/plugin/evaluator.ts +60 -2
- package/src/plugin/index.ts +147 -4
- package/src/table/assemble.ts +125 -42
- package/src/table/compile-rule-map.ts +8 -7
- package/src/table/compile.ts +7 -8
- package/src/table/emit-assembly.ts +646 -126
- package/src/table/emit.ts +1 -1
- package/src/table/encode.ts +132 -7
- package/src/table/ops.ts +3 -2
- package/src/table/program.ts +44 -3
- package/src/table/scalar-terminal.ts +213 -1
- package/src/table/site-labels.ts +22 -9
- package/src/types.ts +1 -1
- package/src/version.ts +1 -1
package/src/plugin/index.ts
CHANGED
|
@@ -23,13 +23,14 @@ import { createUnplugin } from 'unplugin'
|
|
|
23
23
|
import { parseSync } from 'oxc-parser'
|
|
24
24
|
import { ResolverFactory } from 'oxc-resolver'
|
|
25
25
|
import MagicString from 'magic-string'
|
|
26
|
-
import { evaluateExpr, evaluateCombinatorArray, evaluateParserFactory, evaluateStaticValue, evaluateWordFactory, evaluateWhenFactory, evaluateRefDeclaration, applyDefineStatement, referencesAny, setReducerResolver, propName, type Scope, type ScopeEntry } from './evaluator.ts'
|
|
26
|
+
import { evaluateExpr, evaluateCombinatorArray, evaluateParserFactory, evaluateStaticValue, evaluateWordFactory, evaluateWhenFactory, evaluateRefDeclaration, applyDefineStatement, referencesAny, setReducerResolver, setBuilderImportResolver, propName, type Scope, type ScopeEntry } from './evaluator.ts'
|
|
27
27
|
import { classifyRuleMap } from '../analysis/commitment.ts'
|
|
28
28
|
import { compile } from '../table/compile.ts'
|
|
29
29
|
import { compileRuleMap } from '../table/compile-rule-map.ts'
|
|
30
30
|
import { compileLinkableTable } from '../compiler/compile-linkable-table.ts'
|
|
31
31
|
import { createReducerResolver } from './reducer-resolver.ts'
|
|
32
32
|
import { findFreeIdentifiers } from './free-identifiers.ts'
|
|
33
|
+
import { supercompileRuleMapReplacement } from './entry-supercompiler.ts'
|
|
33
34
|
import {
|
|
34
35
|
beginDegradationCapture, endDegradationCapture, formatDegradation, formatDegradations,
|
|
35
36
|
resolveDegradationLevel, recordDegradation, degradationCaptureDepth, unwindDegradationCapture,
|
|
@@ -516,6 +517,7 @@ export function transformMacro(
|
|
|
516
517
|
return transformMacroImpl(code, id, moduleAliases, warnUnloweredRegex, recovery, grammarCoverage)
|
|
517
518
|
} finally {
|
|
518
519
|
setReducerResolver(null)
|
|
520
|
+
setBuilderImportResolver(null)
|
|
519
521
|
// Both are idempotent: on the success path the body already released them and these
|
|
520
522
|
// are no-ops. On an aborted transform they are what stops the leak.
|
|
521
523
|
for (const d of unwindDegradationCapture(depth)) console.warn(formatDegradation(d))
|
|
@@ -666,6 +668,10 @@ function transformMacroImpl(
|
|
|
666
668
|
*/
|
|
667
669
|
const reducerResolver = createReducerResolver(id, body as unknown[], code)
|
|
668
670
|
setReducerResolver(reducerResolver, code)
|
|
671
|
+
/* A direct builder's free name is rescuable when THIS module imported it — the
|
|
672
|
+
* artifact carries `{ source, imported }` and a downstream compose() re-emits the
|
|
673
|
+
* import (see the re-lower pass below). Module-private consts stay refusals. */
|
|
674
|
+
setBuilderImportResolver(name => importBindings.get(name) ?? null)
|
|
669
675
|
|
|
670
676
|
const topLevelFunction = (moduleBody: AnyNode[], name: string): AnyNode | null => {
|
|
671
677
|
for (const st of moduleBody) {
|
|
@@ -797,6 +803,69 @@ function transformMacroImpl(
|
|
|
797
803
|
* at the end of this transform is what proves it was actually emitted.
|
|
798
804
|
*/
|
|
799
805
|
let usedTableRuntime = false
|
|
806
|
+
/**
|
|
807
|
+
* `source` -> (local -> imported) for direct-builder free names that rode in on a
|
|
808
|
+
* carried piece's IR (a composed base grammar whose reducers call imported AST
|
|
809
|
+
* factories). Re-emitted as real imports into THIS module so the inlined builder
|
|
810
|
+
* source has bindings to resolve. A name this module already imports is skipped.
|
|
811
|
+
*/
|
|
812
|
+
const pendingBuilderImports = new Map<string, Map<string, string>>()
|
|
813
|
+
/**
|
|
814
|
+
* Harvest direct-builder import provenance off a MERGED rule graph so the re-lower
|
|
815
|
+
* pass re-emits those imports. `buildImports` rides on a `node()`'s `_def`, but a
|
|
816
|
+
* rule that ANOTHER rule references (`g.X`) is materialized in the evaluated map as
|
|
817
|
+
* a `lazy` proxy whose definition node sits behind `_def.thunk()` — never an own
|
|
818
|
+
* property. A generic `Object.values` descent therefore skips it entirely, silently
|
|
819
|
+
* dropping the imports of every cross-referenced rule (the css base's `VarCall`,
|
|
820
|
+
* referenced by its selector/value parents, is the canonical case: its `funcCall` /
|
|
821
|
+
* `isValueSlotValue` reads were lost and the fused downstream module threw "bound by
|
|
822
|
+
* nothing" / left a runtime compose()).
|
|
823
|
+
*
|
|
824
|
+
* The fused table encodes exactly the WINNER of each rule name and binds every
|
|
825
|
+
* reference BY NAME to that winner (`enc.winners`), so the imports it inlines are
|
|
826
|
+
* exactly the union over the winning rule bodies. Harvest that set: walk each rule
|
|
827
|
+
* entry's own body (following the entry lazy's thunk), and STOP at a named `lazy`
|
|
828
|
+
* reference inside a body — it resolves to a winner already covered as its own
|
|
829
|
+
* entry, so descending it would reach an OVERRIDDEN rule's shadowed original and
|
|
830
|
+
* re-emit a dead import. An anonymous `lazy` is inline recursion and is followed.
|
|
831
|
+
* One `seen` set is shared across every rule so a cyclic grammar terminates.
|
|
832
|
+
*/
|
|
833
|
+
const collectBuilderImports = (ruleMap: ReadonlyArray<readonly [string, Combinator<unknown>]>): void => {
|
|
834
|
+
const seen = new Set<unknown>()
|
|
835
|
+
const walk = (v: unknown): void => {
|
|
836
|
+
if (v === null || typeof v !== 'object' || seen.has(v)) return
|
|
837
|
+
seen.add(v)
|
|
838
|
+
const def = (v as { _def?: { tag?: string; thunk?: () => unknown; buildImports?: ReadonlyArray<{ local: string; source: string; imported: string }> } })._def
|
|
839
|
+
for (const bi of def?.buildImports ?? []) {
|
|
840
|
+
let m = pendingBuilderImports.get(bi.source)
|
|
841
|
+
if (!m) { m = new Map(); pendingBuilderImports.set(bi.source, m) }
|
|
842
|
+
m.set(bi.local, bi.imported)
|
|
843
|
+
}
|
|
844
|
+
// An ANONYMOUS lazy is inline recursion — follow the thunk. A NAMED lazy is a
|
|
845
|
+
// rule reference bound by name to a winner covered as its own entry; do not
|
|
846
|
+
// descend it (that path reaches an overridden rule's shadowed original).
|
|
847
|
+
if (def?.tag === 'lazy' && (v as { _ruleName?: string })._ruleName === undefined && typeof def.thunk === 'function') {
|
|
848
|
+
let target: unknown = null
|
|
849
|
+
try { target = def.thunk() } catch { /* external ref — no definition to walk */ }
|
|
850
|
+
walk(target)
|
|
851
|
+
}
|
|
852
|
+
for (const child of Object.values(v as Record<string, unknown>)) {
|
|
853
|
+
if (Array.isArray(child)) { for (const c of child) walk(c) } else walk(child)
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
for (const [, rule] of ruleMap) {
|
|
857
|
+
walk(rule)
|
|
858
|
+
// A referenced rule entry is a named lazy whose body node (with its builder
|
|
859
|
+
// imports) is behind the thunk; `walk` skips a named lazy's thunk, so follow
|
|
860
|
+
// the WINNER'S body explicitly here. A raw-node entry was already fully walked.
|
|
861
|
+
const def = rule._def as { tag?: string; thunk?: () => unknown }
|
|
862
|
+
if (def?.tag === 'lazy' && typeof def.thunk === 'function') {
|
|
863
|
+
let body: unknown = null
|
|
864
|
+
try { body = def.thunk() } catch { /* unresolved winner — nothing to walk */ }
|
|
865
|
+
walk(body)
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
800
869
|
/** Exported `rules()` factories, whose bodies are left verbatim. See the push site. */
|
|
801
870
|
const exportedFactories: Array<{ name: string; pos: number }> = []
|
|
802
871
|
let runtimeComposeFallback = false
|
|
@@ -1457,6 +1526,9 @@ function transformMacroImpl(
|
|
|
1457
1526
|
const merged = mergedCarriedRules(carried)
|
|
1458
1527
|
if (merged !== null) {
|
|
1459
1528
|
if (composing) applyComposingTrivia(merged.rules, composing)
|
|
1529
|
+
// Harvest the direct-builder import provenance carried on the merged graph so
|
|
1530
|
+
// the re-lower pass at the end of this transform re-emits those imports.
|
|
1531
|
+
collectBuilderImports(merged.rules)
|
|
1460
1532
|
const refusals: string[] = []
|
|
1461
1533
|
const compiled = compileRuleMap(merged.rules, {
|
|
1462
1534
|
...(composing ? { trivia: composing } : {}),
|
|
@@ -1625,9 +1697,12 @@ function transformMacroImpl(
|
|
|
1625
1697
|
if (compiled !== null) {
|
|
1626
1698
|
usedTableRuntime = true
|
|
1627
1699
|
return {
|
|
1628
|
-
replacement:
|
|
1629
|
-
|
|
1630
|
-
|
|
1700
|
+
replacement: supercompileRuleMapReplacement(
|
|
1701
|
+
compiled.prog,
|
|
1702
|
+
compiled.replacementWithMetadata(
|
|
1703
|
+
staticTableMetadataSource({ reflection: compiled.reflection, leaf: true }),
|
|
1704
|
+
{ precompileDefault: true },
|
|
1705
|
+
),
|
|
1631
1706
|
),
|
|
1632
1707
|
...(importedFactories.length ? { importedFactories } : {}),
|
|
1633
1708
|
}
|
|
@@ -2186,6 +2261,73 @@ function transformMacroImpl(
|
|
|
2186
2261
|
if (usedTableRuntime && applied.length > 0) {
|
|
2187
2262
|
ms.prepend(`import { tableRules } from ${JSON.stringify(TABLE_RUNTIME_SPECIFIER)}\n`)
|
|
2188
2263
|
}
|
|
2264
|
+
/* Re-bind the direct-builder free names carried in on composed IR: a base
|
|
2265
|
+
* grammar's reducer calls `dimension` from '@jesscss/core/ast', that provenance
|
|
2266
|
+
* rode in on the carried piece, and the fused table inlines the reducer source
|
|
2267
|
+
* here — so this module must import the same binding.
|
|
2268
|
+
*
|
|
2269
|
+
* The inlined builder source spells the free name VERBATIM, so a re-emitted import
|
|
2270
|
+
* cannot be aliased away: the local name is load-bearing. Two things therefore make
|
|
2271
|
+
* a carried import unsatisfiable, and both are refused rather than silently mis-bound
|
|
2272
|
+
* or emitted as a duplicate declaration:
|
|
2273
|
+
*
|
|
2274
|
+
* - the name is ALREADY BOUND in this module to something else — a named import
|
|
2275
|
+
* from a DIFFERENT source/symbol (the inlined builder would call the wrong
|
|
2276
|
+
* binding), a default/namespace import, or a top-level const/function/class
|
|
2277
|
+
* (re-emitting the import would be a redeclaration `SyntaxError`). The
|
|
2278
|
+
* free-identifier net below cannot catch either: a wrong-binding read is bound,
|
|
2279
|
+
* and a redeclaration is the opposite of an unbound read.
|
|
2280
|
+
* - two DISTINCT carried sources need the SAME local name (the map is keyed by
|
|
2281
|
+
* source, so each would emit its own `import { X } from …`).
|
|
2282
|
+
*
|
|
2283
|
+
* A name this module already imports from the SAME source under the SAME symbol is
|
|
2284
|
+
* the benign case — the exact import the builder needs is already present, so it is
|
|
2285
|
+
* skipped (no duplicate). */
|
|
2286
|
+
if (applied.length > 0 && pendingBuilderImports.size > 0) {
|
|
2287
|
+
// Every top-level binding of THIS module, not just its named imports.
|
|
2288
|
+
const boundLocally = new Set<string>()
|
|
2289
|
+
for (const stmt of body as Statement[]) {
|
|
2290
|
+
if (stmt.type === 'ImportDeclaration') {
|
|
2291
|
+
for (const sp of (stmt as unknown as ImportDeclaration).specifiers) boundLocally.add(sp.local.name)
|
|
2292
|
+
continue
|
|
2293
|
+
}
|
|
2294
|
+
const decl = stmt.type === 'ExportNamedDeclaration'
|
|
2295
|
+
? ((stmt as unknown as ExportNamedDeclaration).declaration as unknown as AnyNode | undefined)
|
|
2296
|
+
: (stmt as unknown as AnyNode)
|
|
2297
|
+
if (decl?.type === 'FunctionDeclaration' || decl?.type === 'ClassDeclaration') {
|
|
2298
|
+
const n = (decl as unknown as { id?: { name?: string } }).id?.name
|
|
2299
|
+
if (n) boundLocally.add(n)
|
|
2300
|
+
continue
|
|
2301
|
+
}
|
|
2302
|
+
const vd = unwrapVd(stmt)
|
|
2303
|
+
for (const d of vd?.declarations ?? []) {
|
|
2304
|
+
const n = (d.id as unknown as { name?: string }).name
|
|
2305
|
+
if (n) boundLocally.add(n)
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
const emitted = new Set<string>()
|
|
2309
|
+
for (const [source, locals] of pendingBuilderImports) {
|
|
2310
|
+
const needed: Array<[string, string]> = []
|
|
2311
|
+
for (const [local, imported] of locals) {
|
|
2312
|
+
const own = importBindings.get(local)
|
|
2313
|
+
// Exact same import already present: the builder's need is satisfied. Skip.
|
|
2314
|
+
if (own && own.source === source && own.imported === imported) continue
|
|
2315
|
+
if (boundLocally.has(local) || emitted.has(local)) {
|
|
2316
|
+
throw new Error(
|
|
2317
|
+
`${id} — parseman will not emit this module: a fused builder needs \`${imported}\` from `
|
|
2318
|
+
+ `${JSON.stringify(source)} bound as \`${local}\`, but this module already binds \`${local}\` `
|
|
2319
|
+
+ `to something else. The inlined builder source names \`${local}\` verbatim, so the import `
|
|
2320
|
+
+ `cannot be aliased; rename the conflicting local binding so the builder's import can be re-emitted.`,
|
|
2321
|
+
)
|
|
2322
|
+
}
|
|
2323
|
+
emitted.add(local)
|
|
2324
|
+
needed.push([local, imported])
|
|
2325
|
+
}
|
|
2326
|
+
if (needed.length === 0) continue
|
|
2327
|
+
const specs = needed.map(([local, imported]) => imported === local ? local : `${imported} as ${local}`)
|
|
2328
|
+
ms.prepend(`import { ${specs.join(', ')} } from ${JSON.stringify(source)}\n`)
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2189
2331
|
if (applied.length > 0) {
|
|
2190
2332
|
ms.prepend(
|
|
2191
2333
|
`// Generated by parseman v${PARSEMAN_VERSION} — DO NOT EDIT.\n` +
|
|
@@ -2259,6 +2401,7 @@ function transformMacroImpl(
|
|
|
2259
2401
|
// caller's config does not break; it is now inert.
|
|
2260
2402
|
|
|
2261
2403
|
setReducerResolver(null)
|
|
2404
|
+
setBuilderImportResolver(null)
|
|
2262
2405
|
// Every place the compiler chose a correct-but-slower path for this module. Reported
|
|
2263
2406
|
// on the ordinary warning channel and greppable on `[parseman] degraded`, so a
|
|
2264
2407
|
// consumer's build gate can assert zero of them the way jess's `check:macro` already
|
package/src/table/assemble.ts
CHANGED
|
@@ -125,11 +125,12 @@ import {
|
|
|
125
125
|
type SubtreeRef, type TableProgram, type TableRule,
|
|
126
126
|
} from './program.ts'
|
|
127
127
|
import { stampRuleMap } from './stamp.ts'
|
|
128
|
-
import { reachableSites } from './site-labels.ts'
|
|
128
|
+
import { computeSiteLabels, reachableSites } from './site-labels.ts'
|
|
129
129
|
import { refuseUnclassifiedRootScope } from '../cst/root-trivia-scope.ts'
|
|
130
130
|
import { captureError, firstSetSentinel, matchesAt, orSentinel, recoverScan } from '../recovery/scan.ts'
|
|
131
131
|
import {
|
|
132
|
-
|
|
132
|
+
leadingLiteralFamily, leadingScalarSequence, leadingScalarTerminal, makeScalarRecognizer, scalarTerminalNodeChild,
|
|
133
|
+
scalarTerminalNotChild, type ScalarRecognizer,
|
|
133
134
|
} from './scalar-terminal.ts'
|
|
134
135
|
|
|
135
136
|
/**
|
|
@@ -482,6 +483,16 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
482
483
|
return recognize
|
|
483
484
|
}
|
|
484
485
|
|
|
486
|
+
const labelExtraIps: number[] = []
|
|
487
|
+
for (const s of prog.scans ?? []) {
|
|
488
|
+
for (const r of s.skip) labelExtraIps.push(r[0])
|
|
489
|
+
if (s.sentinel !== undefined) labelExtraIps.push(s.sentinel[0])
|
|
490
|
+
}
|
|
491
|
+
for (const set of prog.scanSkip ?? []) for (const r of set) labelExtraIps.push(r[0])
|
|
492
|
+
const closureLabels = computeSiteLabels(
|
|
493
|
+
code, [...Object.values(prog.rules), ...labelExtraIps], hostCst,
|
|
494
|
+
)
|
|
495
|
+
|
|
485
496
|
/**
|
|
486
497
|
* The INSTALLED trivia scanner for the scope currently running.
|
|
487
498
|
*
|
|
@@ -818,7 +829,9 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
818
829
|
// has no single form. `rollbackNeeded` short-circuits true on a live buffer,
|
|
819
830
|
// so the other seven sinks are not consulted — as before.
|
|
820
831
|
const raw = b.raw
|
|
821
|
-
MRAW =
|
|
832
|
+
MRAW = b.noRaw === true
|
|
833
|
+
? b.rawLen ?? 0
|
|
834
|
+
: raw !== undefined ? raw.length : b.rawSingle !== undefined ? 1 : 0
|
|
822
835
|
const ch = b.ch
|
|
823
836
|
MLV = ch !== undefined ? ch.length : b.single !== undefined ? 1 : 0
|
|
824
837
|
const tl = b.tl
|
|
@@ -1004,6 +1017,33 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
1004
1017
|
return cur
|
|
1005
1018
|
}
|
|
1006
1019
|
|
|
1020
|
+
/** A non-first term at a site proven to run under an open node capture buffer. */
|
|
1021
|
+
function nextTermBuffered(child: Piece, input: string, cur: number, ctx: ParseContext): number {
|
|
1022
|
+
if (ctx.trivia === undefined) {
|
|
1023
|
+
const v = child(input, cur, ctx)
|
|
1024
|
+
if (v === FAIL) return -1
|
|
1025
|
+
TERMV = v
|
|
1026
|
+
return EC.e
|
|
1027
|
+
}
|
|
1028
|
+
const before = ctx._cstBuf!
|
|
1029
|
+
const beforeTl = before.tl
|
|
1030
|
+
const mTl = beforeTl === undefined ? 0 : beforeTl.length
|
|
1031
|
+
const mLog = ctx._triviaLog?.length ?? 0
|
|
1032
|
+
const mRoot = ctx._rootTriviaLog?.length ?? 0
|
|
1033
|
+
const scanEnd = skipTrivia(input, cur, ctx)
|
|
1034
|
+
const scanned = ctx._cstBuf!
|
|
1035
|
+
const scannedTl = scanned.tl
|
|
1036
|
+
const scanTl = scannedTl === undefined ? 0 : scannedTl.length
|
|
1037
|
+
const scanLog = ctx._triviaLog?.length ?? 0
|
|
1038
|
+
const scanRoot = ctx._rootTriviaLog?.length ?? 0
|
|
1039
|
+
const v = child(input, scanEnd, ctx)
|
|
1040
|
+
if (v === FAIL) return -1
|
|
1041
|
+
TERMV = v
|
|
1042
|
+
if (EC.e > scanEnd) return EC.e
|
|
1043
|
+
rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot)
|
|
1044
|
+
return cur
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1007
1047
|
function committed(c: ParseContext): boolean {
|
|
1008
1048
|
return c._fc === true
|
|
1009
1049
|
}
|
|
@@ -1288,7 +1328,16 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
1288
1328
|
const holder = { fwd, set: (p: Piece) => { target = p } }
|
|
1289
1329
|
inFlight.set(ip, holder)
|
|
1290
1330
|
|
|
1291
|
-
const
|
|
1331
|
+
const op = code[ip]
|
|
1332
|
+
// Match the emitted assembly's label-proven scope alias: rule entries in a
|
|
1333
|
+
// single ambient trivia scope otherwise reinstall and restore the exact
|
|
1334
|
+
// same trivia, labels and scanner on every call. Install the forwarding
|
|
1335
|
+
// holder first so a recursive child can still link back through this site.
|
|
1336
|
+
const piece = (op === OP_SCOPE_PLAIN || (op === OP_SCOPE && code[ip + 3]! === 0))
|
|
1337
|
+
&& code[ip + 1]! >= 0
|
|
1338
|
+
&& closureLabels.at(ip).tri === code[ip + 1]!
|
|
1339
|
+
? link(code[ip + 2]!)
|
|
1340
|
+
: lower(ip)
|
|
1292
1341
|
|
|
1293
1342
|
inFlight.delete(ip)
|
|
1294
1343
|
holder.set(piece)
|
|
@@ -2148,6 +2197,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2148
2197
|
const fn = fused && projection < 0
|
|
2149
2198
|
? fns[reducer] as (value: unknown, span: { start: number; end: number }) => unknown
|
|
2150
2199
|
: undefined
|
|
2200
|
+
const step = closureLabels.at(ip).buf ? nextTermBuffered : nextTerm
|
|
2151
2201
|
|
|
2152
2202
|
const runnerBlock = (
|
|
2153
2203
|
count: number,
|
|
@@ -2255,7 +2305,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2255
2305
|
const kid = link(kidIp)
|
|
2256
2306
|
return (input, cur, ctx, inherited) => {
|
|
2257
2307
|
ctx._sync = sync ?? inherited
|
|
2258
|
-
return
|
|
2308
|
+
return step(kid, input, cur, ctx)
|
|
2259
2309
|
}
|
|
2260
2310
|
}
|
|
2261
2311
|
const negated = code[kidIp + 1] === 1
|
|
@@ -2328,7 +2378,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2328
2378
|
const kidIp = code[base + i]!
|
|
2329
2379
|
if (code[kidIp] !== OP_ADJ) {
|
|
2330
2380
|
const kid = link(kidIp)
|
|
2331
|
-
return (input, cur, ctx) =>
|
|
2381
|
+
return (input, cur, ctx) => step(kid, input, cur, ctx)
|
|
2332
2382
|
}
|
|
2333
2383
|
const negated = code[kidIp + 1] === 1
|
|
2334
2384
|
const ki = code[kidIp + 2]!
|
|
@@ -2436,7 +2486,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2436
2486
|
return (input, pos, ctx) => {
|
|
2437
2487
|
const v0 = k0(input, pos, ctx)
|
|
2438
2488
|
if (v0 === FAIL) return FAIL
|
|
2439
|
-
const cur =
|
|
2489
|
+
const cur = step(k1, input, EC.e, ctx)
|
|
2440
2490
|
if (cur < 0) return FAIL
|
|
2441
2491
|
EC.e = cur
|
|
2442
2492
|
return projection === 0 ? v0
|
|
@@ -2448,7 +2498,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2448
2498
|
return (input, pos, ctx) => {
|
|
2449
2499
|
const v0 = k0(input, pos, ctx)
|
|
2450
2500
|
if (v0 === FAIL) return FAIL
|
|
2451
|
-
const cur =
|
|
2501
|
+
const cur = step(k1, input, EC.e, ctx)
|
|
2452
2502
|
if (cur < 0) return FAIL
|
|
2453
2503
|
EC.e = cur
|
|
2454
2504
|
return [v0, TERMV]
|
|
@@ -2457,7 +2507,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2457
2507
|
return (input, pos, ctx) => {
|
|
2458
2508
|
const v0 = k0(input, pos, ctx)
|
|
2459
2509
|
if (v0 === FAIL) return FAIL
|
|
2460
|
-
const cur =
|
|
2510
|
+
const cur = step(k1, input, EC.e, ctx)
|
|
2461
2511
|
if (cur < 0) return FAIL
|
|
2462
2512
|
EC.e = cur
|
|
2463
2513
|
return undefined
|
|
@@ -2470,10 +2520,10 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2470
2520
|
return (input, pos, ctx) => {
|
|
2471
2521
|
const v0 = k0(input, pos, ctx)
|
|
2472
2522
|
if (v0 === FAIL) return FAIL
|
|
2473
|
-
let cur =
|
|
2523
|
+
let cur = step(k1, input, EC.e, ctx)
|
|
2474
2524
|
if (cur < 0) return FAIL
|
|
2475
2525
|
const v1 = TERMV
|
|
2476
|
-
cur =
|
|
2526
|
+
cur = step(k2, input, cur, ctx)
|
|
2477
2527
|
if (cur < 0) return FAIL
|
|
2478
2528
|
EC.e = cur
|
|
2479
2529
|
return projection === 0 ? v0
|
|
@@ -2486,10 +2536,10 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2486
2536
|
return (input, pos, ctx) => {
|
|
2487
2537
|
const v0 = k0(input, pos, ctx)
|
|
2488
2538
|
if (v0 === FAIL) return FAIL
|
|
2489
|
-
let cur =
|
|
2539
|
+
let cur = step(k1, input, EC.e, ctx)
|
|
2490
2540
|
if (cur < 0) return FAIL
|
|
2491
2541
|
const v1 = TERMV
|
|
2492
|
-
cur =
|
|
2542
|
+
cur = step(k2, input, cur, ctx)
|
|
2493
2543
|
if (cur < 0) return FAIL
|
|
2494
2544
|
EC.e = cur
|
|
2495
2545
|
return [v0, v1, TERMV]
|
|
@@ -2498,9 +2548,9 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2498
2548
|
return (input, pos, ctx) => {
|
|
2499
2549
|
const v0 = k0(input, pos, ctx)
|
|
2500
2550
|
if (v0 === FAIL) return FAIL
|
|
2501
|
-
let cur =
|
|
2551
|
+
let cur = step(k1, input, EC.e, ctx)
|
|
2502
2552
|
if (cur < 0) return FAIL
|
|
2503
|
-
cur =
|
|
2553
|
+
cur = step(k2, input, cur, ctx)
|
|
2504
2554
|
if (cur < 0) return FAIL
|
|
2505
2555
|
EC.e = cur
|
|
2506
2556
|
return undefined
|
|
@@ -2516,43 +2566,43 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2516
2566
|
next: SequenceTermBlock | undefined,
|
|
2517
2567
|
): SequenceTermBlock => {
|
|
2518
2568
|
if (count === 1) return (input, cur, ctx, values) => {
|
|
2519
|
-
cur =
|
|
2569
|
+
cur = step(k0, input, cur, ctx)
|
|
2520
2570
|
if (cur < 0) return -1
|
|
2521
2571
|
if (values !== undefined) values.push(TERMV)
|
|
2522
2572
|
return next === undefined ? cur : next(input, cur, ctx, values)
|
|
2523
2573
|
}
|
|
2524
2574
|
if (count === 2) return (input, cur, ctx, values) => {
|
|
2525
|
-
cur =
|
|
2575
|
+
cur = step(k0, input, cur, ctx)
|
|
2526
2576
|
if (cur < 0) return -1
|
|
2527
2577
|
if (values !== undefined) values.push(TERMV)
|
|
2528
|
-
cur =
|
|
2578
|
+
cur = step(k1, input, cur, ctx)
|
|
2529
2579
|
if (cur < 0) return -1
|
|
2530
2580
|
if (values !== undefined) values.push(TERMV)
|
|
2531
2581
|
return next === undefined ? cur : next(input, cur, ctx, values)
|
|
2532
2582
|
}
|
|
2533
2583
|
if (count === 3) return (input, cur, ctx, values) => {
|
|
2534
|
-
cur =
|
|
2584
|
+
cur = step(k0, input, cur, ctx)
|
|
2535
2585
|
if (cur < 0) return -1
|
|
2536
2586
|
if (values !== undefined) values.push(TERMV)
|
|
2537
|
-
cur =
|
|
2587
|
+
cur = step(k1, input, cur, ctx)
|
|
2538
2588
|
if (cur < 0) return -1
|
|
2539
2589
|
if (values !== undefined) values.push(TERMV)
|
|
2540
|
-
cur =
|
|
2590
|
+
cur = step(k2, input, cur, ctx)
|
|
2541
2591
|
if (cur < 0) return -1
|
|
2542
2592
|
if (values !== undefined) values.push(TERMV)
|
|
2543
2593
|
return next === undefined ? cur : next(input, cur, ctx, values)
|
|
2544
2594
|
}
|
|
2545
2595
|
return (input, cur, ctx, values) => {
|
|
2546
|
-
cur =
|
|
2596
|
+
cur = step(k0, input, cur, ctx)
|
|
2547
2597
|
if (cur < 0) return -1
|
|
2548
2598
|
if (values !== undefined) values.push(TERMV)
|
|
2549
|
-
cur =
|
|
2599
|
+
cur = step(k1, input, cur, ctx)
|
|
2550
2600
|
if (cur < 0) return -1
|
|
2551
2601
|
if (values !== undefined) values.push(TERMV)
|
|
2552
|
-
cur =
|
|
2602
|
+
cur = step(k2, input, cur, ctx)
|
|
2553
2603
|
if (cur < 0) return -1
|
|
2554
2604
|
if (values !== undefined) values.push(TERMV)
|
|
2555
|
-
cur =
|
|
2605
|
+
cur = step(k3, input, cur, ctx)
|
|
2556
2606
|
if (cur < 0) return -1
|
|
2557
2607
|
if (values !== undefined) values.push(TERMV)
|
|
2558
2608
|
return next === undefined ? cur : next(input, cur, ctx, values)
|
|
@@ -2722,6 +2772,13 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2722
2772
|
if (n === 2 || n === 3) {
|
|
2723
2773
|
const a0 = link(code[base]!), a1 = link(code[base + 1]!)
|
|
2724
2774
|
const a2 = n === 3 ? link(code[base + 2]!) : undefined
|
|
2775
|
+
const predecide = !hostCst && !REC && !cfg.probe && !cfg.coverage && !cfg.trackLines
|
|
2776
|
+
const p0ip = predecide ? leadingScalarTerminal(code, code[base]!, 2, true, true) : -1
|
|
2777
|
+
const p1ip = predecide ? leadingScalarTerminal(code, code[base + 1]!, 2, true, true) : -1
|
|
2778
|
+
const p2ip = predecide && n === 3 ? leadingScalarTerminal(code, code[base + 2]!, 2, true, true) : -1
|
|
2779
|
+
const p0 = p0ip < 0 ? undefined : scalarFor(p0ip)
|
|
2780
|
+
const p1 = p1ip < 0 ? undefined : scalarFor(p1ip)
|
|
2781
|
+
const p2 = p2ip < 0 ? undefined : scalarFor(p2ip)
|
|
2725
2782
|
const e0 = fx[code[base + n]!] as string[]
|
|
2726
2783
|
const e1 = fx[code[base + n + 1]!] as string[]
|
|
2727
2784
|
const e2 = n === 3 ? fx[code[base + n + 2]!] as string[] : undefined
|
|
@@ -2751,7 +2808,10 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2751
2808
|
let acc: string[] | undefined
|
|
2752
2809
|
let best = pos
|
|
2753
2810
|
if (c < 128) {
|
|
2754
|
-
|
|
2811
|
+
let bits = mask[c < 0 ? 128 : c]!
|
|
2812
|
+
if ((bits & 1) !== 0 && p0 !== undefined && p0(input, pos) < 0) bits &= ~1
|
|
2813
|
+
if ((bits & 2) !== 0 && p1 !== undefined && p1(input, pos) < 0) bits &= ~2
|
|
2814
|
+
if ((bits & 4) !== 0 && p2 !== undefined && p2(input, pos) < 0) bits &= ~4
|
|
2755
2815
|
let prev = 0
|
|
2756
2816
|
if ((bits & 1) !== 0) {
|
|
2757
2817
|
ctx._fc = false
|
|
@@ -2796,7 +2856,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2796
2856
|
return FAIL
|
|
2797
2857
|
}
|
|
2798
2858
|
|
|
2799
|
-
if (g0 === null || classHas(g0, c)) {
|
|
2859
|
+
if ((g0 === null || classHas(g0, c)) && (p0 === undefined || p0(input, pos) >= 0)) {
|
|
2800
2860
|
ctx._fc = false
|
|
2801
2861
|
const v = a0(input, pos, ctx)
|
|
2802
2862
|
if (v !== FAIL) return v
|
|
@@ -2806,7 +2866,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2806
2866
|
if (committed(ctx)) { if (acc !== undefined) ctx._fx = acc; return FAIL }
|
|
2807
2867
|
if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot)
|
|
2808
2868
|
} else if (best === pos) acc = accSet(e0, acc)
|
|
2809
|
-
if (g1 === null || classHas(g1, c)) {
|
|
2869
|
+
if ((g1 === null || classHas(g1, c)) && (p1 === undefined || p1(input, pos) >= 0)) {
|
|
2810
2870
|
ctx._fc = false
|
|
2811
2871
|
const v = a1(input, pos, ctx)
|
|
2812
2872
|
if (v !== FAIL) return v
|
|
@@ -2817,7 +2877,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2817
2877
|
if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot)
|
|
2818
2878
|
} else if (best === pos) acc = accSet(e1, acc)
|
|
2819
2879
|
if (n === 3) {
|
|
2820
|
-
if (g2 === null || classHas(g2, c)) {
|
|
2880
|
+
if ((g2 === null || classHas(g2, c)) && (p2 === undefined || p2(input, pos) >= 0)) {
|
|
2821
2881
|
ctx._fc = false
|
|
2822
2882
|
const v = a2!(input, pos, ctx)
|
|
2823
2883
|
if (v !== FAIL) return v
|
|
@@ -3432,6 +3492,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3432
3492
|
// grammar collapse form and the host collapse predicate.
|
|
3433
3493
|
const keepChildren = !structural || cfg.hostReadsChildren !== false || collapse || unwrap
|
|
3434
3494
|
const rawOnly = !keepChildren
|
|
3495
|
+
const omitsRaw = !hostCst && build !== undefined && proj < 0 && (flags & 2) !== 0
|
|
3435
3496
|
return (input, pos, ctx) => {
|
|
3436
3497
|
const host = HOST
|
|
3437
3498
|
// `beginCstNodeCapture`/`endCstNodeCapture` INLINED, and the two objects
|
|
@@ -3444,17 +3505,12 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3444
3505
|
// allocations a parse that the compiled engine (which inlines its own
|
|
3445
3506
|
// capture prologue and epilogue) never makes.
|
|
3446
3507
|
const sCh = ctx._cstChildren
|
|
3447
|
-
const sLv = ctx._cstLeaves
|
|
3448
|
-
const sRaw = ctx._cstRawChildren
|
|
3449
|
-
const sTl = ctx._cstTriviaLog
|
|
3450
3508
|
const sCap = ctx.captureTrivia
|
|
3451
3509
|
const sBuf = ctx._cstBuf
|
|
3452
|
-
const buf: CstCaptureBuf = rawOnly
|
|
3510
|
+
const buf: CstCaptureBuf = rawOnly
|
|
3511
|
+
? { rawOnly: true }
|
|
3512
|
+
: omitsRaw ? { noRaw: true, rawLen: 0 } : {}
|
|
3453
3513
|
ctx._cstBuf = buf
|
|
3454
|
-
ctx._cstChildren = undefined
|
|
3455
|
-
ctx._cstLeaves = undefined
|
|
3456
|
-
ctx._cstRawChildren = undefined
|
|
3457
|
-
ctx._cstTriviaLog = undefined
|
|
3458
3514
|
// `begin` sets this true and the caller immediately cleared it when the
|
|
3459
3515
|
// node does not capture wide. Net: the flag IS `captureWide`, a const.
|
|
3460
3516
|
ctx.captureTrivia = captureWide
|
|
@@ -3476,13 +3532,11 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3476
3532
|
if (structural) ctx._triviaCaptureMask = savedMask
|
|
3477
3533
|
const kids = rawOnly ? EMPTY_CH : buf.ch ?? (buf.single !== undefined ? [buf.single] : EMPTY_CH)
|
|
3478
3534
|
const hostKids = kids
|
|
3479
|
-
const rawKids =
|
|
3535
|
+
const rawKids = omitsRaw
|
|
3536
|
+
? EMPTY_CH
|
|
3537
|
+
: buf.raw ?? (buf.rawSingle !== undefined ? [buf.rawSingle] : EMPTY_CH)
|
|
3480
3538
|
const tlog = buf.tl ?? EMPTY_TLOG
|
|
3481
3539
|
ctx._cstBuf = sBuf
|
|
3482
|
-
ctx._cstChildren = sCh
|
|
3483
|
-
ctx._cstLeaves = sLv
|
|
3484
|
-
ctx._cstRawChildren = sRaw
|
|
3485
|
-
ctx._cstTriviaLog = sTl
|
|
3486
3540
|
ctx.captureTrivia = sCap
|
|
3487
3541
|
if (v === FAIL) return FAIL
|
|
3488
3542
|
const end = EC.e
|
|
@@ -3620,6 +3674,35 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3620
3674
|
rawScalarSpecs.add(code[child + 1]!)
|
|
3621
3675
|
scalarFor(child)
|
|
3622
3676
|
}
|
|
3677
|
+
} else if (code[ip] === OP_CHOICE && !disp[code[ip + 1]!]!.exclusive) {
|
|
3678
|
+
const n = code[ip + 2]!
|
|
3679
|
+
for (let i = 0; i < n; i++) {
|
|
3680
|
+
const armIp = code[ip + 4 + i]!
|
|
3681
|
+
const child = leadingScalarTerminal(code, armIp, 2, true, true)
|
|
3682
|
+
if (n === 2 || n === 3) {
|
|
3683
|
+
if (child >= 0) scalarFor(child)
|
|
3684
|
+
continue
|
|
3685
|
+
}
|
|
3686
|
+
if (child >= 0) {
|
|
3687
|
+
const spec = k[code[child + 1]!]
|
|
3688
|
+
if (code[child] === OP_LIT && typeof spec === 'string' && spec.length >= 2) {
|
|
3689
|
+
scalarFor(child)
|
|
3690
|
+
continue
|
|
3691
|
+
}
|
|
3692
|
+
}
|
|
3693
|
+
const family = leadingLiteralFamily(code, k, armIp)
|
|
3694
|
+
if (family !== undefined && family.length >= 2 && family.every(terminal => {
|
|
3695
|
+
const value = k[code[terminal + 1]!]
|
|
3696
|
+
return typeof value === 'string' && value.length >= 2
|
|
3697
|
+
})) {
|
|
3698
|
+
for (const terminal of family) scalarFor(terminal)
|
|
3699
|
+
}
|
|
3700
|
+
const sequence = leadingScalarSequence(code, armIp)
|
|
3701
|
+
if (sequence !== undefined && (sequence.trivia < 0
|
|
3702
|
+
|| triviaScan[sequence.trivia] != null)) {
|
|
3703
|
+
for (const terminal of sequence.terminals) scalarFor(terminal)
|
|
3704
|
+
}
|
|
3705
|
+
}
|
|
3623
3706
|
}
|
|
3624
3707
|
}
|
|
3625
3708
|
const notChild = scalarTerminalNotChild(code, ip)
|
|
@@ -116,16 +116,17 @@ export type CompiledRuleMapTable = {
|
|
|
116
116
|
hostBranchElided: boolean
|
|
117
117
|
reflection: GrammarReflection
|
|
118
118
|
/**
|
|
119
|
-
* The RUNNABLE map, which the source lowering has no counterpart for — it
|
|
119
|
+
* The LIVE RUNNABLE map, which the source lowering has no counterpart for — it
|
|
120
120
|
* hands back text and nothing else, because its artifact only exists once the
|
|
121
121
|
* emitted source is evaluated. A table exists as data before it is printed, so
|
|
122
122
|
* the same call that produces the replacement can also hand back the parser.
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
123
|
+
* It may use runtime assembly specialisation; `prog` and `replacement` remain
|
|
124
|
+
* serialized closure artifacts. That is what makes a differential against the
|
|
125
|
+
* interpreter possible without `eval`, and it is why the table-vs-interpreter
|
|
126
|
+
* test can compare `expected` sets rather than only accept/reject.
|
|
126
127
|
*/
|
|
127
128
|
rules: Record<string, TableRule>
|
|
128
|
-
/** The
|
|
129
|
+
/** The closure-stamped wire program, for a caller that wants to fold or inspect it. */
|
|
129
130
|
prog: TableProgram
|
|
130
131
|
/**
|
|
131
132
|
* The coverage DENOMINATOR — every id this map can hit — present only under
|
|
@@ -237,7 +238,7 @@ export function compileRuleMapRunnable(
|
|
|
237
238
|
hostBranchElided: hostMode === 'ast' && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
238
239
|
reflection: collectGrammarReflection(ruleMap),
|
|
239
240
|
...(plan === undefined ? {} : { coverageDefinitions: plan.definitions }),
|
|
240
|
-
rules: tableRules(
|
|
241
|
+
rules: tableRules(prog),
|
|
241
242
|
prog: artifact,
|
|
242
243
|
}
|
|
243
244
|
}
|
|
@@ -348,7 +349,7 @@ export function compileRuleMap(
|
|
|
348
349
|
hostBranchElided: hostMode === 'ast' && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
349
350
|
reflection: collectGrammarReflection(ruleMap),
|
|
350
351
|
...(plan === undefined ? {} : { coverageDefinitions: plan.definitions }),
|
|
351
|
-
rules: tableRules(
|
|
352
|
+
rules: tableRules(prog),
|
|
352
353
|
prog: artifact,
|
|
353
354
|
}
|
|
354
355
|
}
|
package/src/table/compile.ts
CHANGED
|
@@ -156,17 +156,16 @@ function compileImpl<T>(
|
|
|
156
156
|
// this is the same guard on the single-root entry point.
|
|
157
157
|
const { prog, fnSrcs } = encodeTableProgram({ [ENTRY]: combinator as Combinator<unknown> }, settings)
|
|
158
158
|
/**
|
|
159
|
-
*
|
|
159
|
+
* LIVE parsers may assemble the encoded program into specialised functions.
|
|
160
|
+
* `tableRules` falls back to closure assembly when dynamic construction is not
|
|
161
|
+
* available, so this remains runnable under a restrictive CSP.
|
|
160
162
|
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
* canonical: both paths carry an explicit empty inventory and use the shared
|
|
165
|
-
* closure assembler. Static factories remain an opt-in experiment until they
|
|
166
|
-
* can satisfy both semantic identity and the size budget.
|
|
163
|
+
* PRINTED artifacts are different: they must not require `new Function` after
|
|
164
|
+
* import. Give the emitters the canonical explicit-empty assembly inventory,
|
|
165
|
+
* while the parser returned by this call runs the raw program's fast path.
|
|
167
166
|
*/
|
|
168
167
|
const artifact = closureArtifact(prog)
|
|
169
|
-
const entry = tableRules(
|
|
168
|
+
const entry = tableRules(prog)[ENTRY]!
|
|
170
169
|
|
|
171
170
|
// Captured-first, supplied-as-fill-in. The encoder records a source per author
|
|
172
171
|
// callback from the def (`fnSrc` / `buildSrc` / `predSrc` / `gateSrcs`), which the
|