import type { Combinator } from '../types.ts'; import type { HostMode } from '../cst/host-mode.ts'; import { type GrammarReflection } from '../cst/reflection.ts'; import type { TableProgram, TableRule } from './program.ts'; import { type GrammarCoverageDefinition } from '../compiler/grammar-coverage-ids.ts'; import { type DuplicationOption } from './duplication-hook.ts'; /** * `compileRuleMap()` FOR THE TABLE LOWERING — the counterpart that did not exist. * * `compile` covered `compile()`, the SINGLE-ROOT entry point, which the * plugin uses only for standalone combinators (`plugin/index.ts:1693`, `:1870`). * The main path — every `rules()` grammar — goes through `compileRuleMap`, and * with no table counterpart there was nothing for the macro build to point at. * This is that function, and it is the EASY direction: `encodeTable` takes a * named rule map natively, so nothing here adapts a shape. `compile` is the * one that adapts (it wraps a root as `{ Entry: root }`). * * ── THE CONTRACT IT MATCHES ────────────────────────────────────────────────── * `compileRuleMap` returns ONE `replacement` string: a self-contained expression * that the plugin splices over the whole `rules(factory)` call-expression * (`plugin/index.ts:1753`, and as an initialiser at `:1941`), evaluating ONCE to * the `{ name: fn, … }` map. `keys` is the entry list, for the caller to check * against the source's own keys. `hostMode` / `hostBranchElided` are what the * macro stamps the emitted map with. `reflection` is per-grammar CST node * reflection. It returns `null`, all-or-nothing, when the map cannot be inlined. * * Every one of those is reproduced here, with ONE stated divergence, the same * one `compile` documents: the expression references `tableRules` and is * therefore NOT self-contained. That reference is the entire reason a table * artifact is small; inlining the driver per grammar rebuilds exactly the size * this lowering exists to remove. The consumer owns the import. * * ── WHY `emitTableModule` WAS NOT ENOUGH ───────────────────────────────────── * It emits a whole rule map as one module — `import` line, `export const` — and * the plugin has no module to write; it has an expression slot inside an * existing file. `emitTableExpression` was the right emitter and needed one * thing: `entry: null`, meaning "the map itself" rather than one rule out of it. * That is a two-line change to an existing emitter, not a new one. */ export type TableRuleMapOptions = { /** Grammar-level ambient trivia, as `rules({ trivia }, …)` declares it. */ readonly trivia?: Combinator; /** Grammar-level ambient scan-skip, as `rules({ scanSkip }, …)` declares it. */ readonly scanSkip?: Combinator[]; readonly recovery?: boolean; readonly hostMode?: HostMode; readonly trackLines?: boolean; /** * GRAMMAR-COVERAGE COUNTERS. This is the MACRO's path — `plugin/index.ts` passes * `coverage: grammarCoverage` here for every `rules()` grammar — so this is what * makes `{ grammarCoverage: true }` a working build under the table lowering. * * COUNTERS ONLY, per the owner ruling recorded in `notes/RELEASE-0.48-TARGET.md` * §1; `_grammarTrace` parity is 0.48 work. The plugin's coverage path needs the * DEFINITIONS STAMP and the HITS, and both are here. */ readonly coverage?: boolean; /** Identifier the emitted expression expects `tableRules` to be bound to. */ readonly runtimeRef?: string; /** * Reducer sources in `prog.fns` order, for a caller that holds them OUT OF * BAND — the same escape `compile(combinator, mapFnSources?)` provides. * * The encoder captures a source per callback from the def (`fnSrc` / * `buildSrc` / `predSrc` / `gateSrcs`), which the macro evaluator sets and a * runtime-built combinator does not have. Supplying them here is what lets a * grammar constructed at runtime still PRINT; it does not override captured * ones, it fills in for a pool that has none. */ readonly fnSources?: readonly string[]; /** * WHY THIS REFUSED, filled in on the `null` return. * * `null` means "leave this grammar interpreted", which is ~79 ms against ~14 ms * on `benchmark.less` — a ~5x regression that produces no test failure and no * warning content beyond "couldn't be inlined". The reasons exist inside the * encoder (`prog.runtimeOnly`) and simply had no way out; this is that way out, * so the plugin's warning can name the construct instead of the outcome. * * An out-parameter rather than a changed return type: every existing caller * checks for `null` and that contract is unchanged. */ readonly refusals?: string[]; /** * The structural duplication diagnostic. Ran inside the source lowering; it runs * here for the same reason, so a build that asked for it keeps getting it. */ readonly duplication?: DuplicationOption; }; export type CompiledRuleMapTable = { /** Every entry this saw, in order — same use as `compileRuleMap`'s `keys`. */ keys: string[]; /** The expression that replaces the whole `rules(factory)` call. */ replacement: string; /** Re-emit the same table call with construction-time artifact metadata. */ replacementWithMetadata(metadataSource: string, options?: { readonly precompileDefault?: boolean; }): string; hostMode: HostMode; hostBranchElided: boolean; reflection: GrammarReflection; /** * The LIVE RUNNABLE map, which the source lowering has no counterpart for — it * hands back text and nothing else, because its artifact only exists once the * emitted source is evaluated. A table exists as data before it is printed, so * the same call that produces the replacement can also hand back the parser. * It may use runtime assembly specialisation; `prog` and `replacement` remain * serialized closure artifacts. That is what makes a differential against the * interpreter possible without `eval`, and it is why the table-vs-interpreter * test can compare `expected` sets rather than only accept/reject. */ rules: Record; /** The closure-stamped wire program, for a caller that wants to fold or inspect it. */ prog: TableProgram; /** * The coverage DENOMINATOR — every id this map can hit — present only under * `{ coverage: true }`. Same field and same meaning as `compileRuleMap`'s, so * the plugin's stamp site needs no branch on which lowering produced it. */ coverageDefinitions?: readonly GrammarCoverageDefinition[]; }; /** * ENCODE FOR RUNNING, with no printability requirement. * * `compileRuleMap` refuses a map whose author callbacks have no captured SOURCE, * because PRINTING one would emit `() => {}` and the parse would return the wrong tree. * That gate is right for the macro, which prints, and wrong for every caller that only * ever RUNS the result: a grammar built at runtime has live callbacks and no sources by * construction, and `encodeTableProgram` parks the live function in the pool where the * driver calls it perfectly well. * * Conflating the two is the single defect this project has now hit three times — a * runtime `compose()`, `linkable()`, and the fuse — each presenting as "this grammar * cannot be compiled" for a grammar that runs. The split lives here, once, so the next * caller inherits the right answer instead of rediscovering it. */ export declare function compileRuleMapRunnable(ruleMap: ReadonlyArray]>, opts?: TableRuleMapOptions): Omit | null; export declare function compileRuleMap(ruleMap: ReadonlyArray]>, opts?: TableRuleMapOptions): CompiledRuleMapTable | null; //# sourceMappingURL=compile-rule-map.d.ts.map