import type { Combinator } from '../types.ts'; import type { HostMode } from '../cst/host-mode.ts'; import { type GrammarReflection } from '../cst/reflection.ts'; import { type TableRuleMapOptions } from '../table/compile-rule-map.ts'; import type { TableProgram, TableRule } from '../table/program.ts'; /** * `compileLinkable()` FOR THE TABLE LOWERING — `linkable()` produces TABLES too. * * ── WHAT `compileLinkable` ACTUALLY RETURNS, AND WHY NONE OF IT TRANSFERS ───── * `LinkablePieces` is `prelude` / `ruleFns` / `wrappers` / `firstSets` / * `firstSetRecipes` / `nullable` / `deps` / `needsEmptyTl` — every field of it is * SOURCE TEXT or an input to resolving source text. It exists because * source-lowering composition is a TEXTUAL splice: `fusedBody()` concatenates * namespaced preludes, picks a winning `_r_` per name, and substitutes * `@FS:` dispatch placeholders with the winner's first-set condition. A table has * no text to splice and no placeholders to resolve, so porting those fields would * be porting the mechanism rather than the capability. * * The capability is: a piece must be RUNNABLE on its own, and COMPOSABLE with * other pieces. This artifact carries exactly those two things. * * `prog` / `rules` — the piece AS A TABLE. Present whenever the piece is * self-contained. This is the ruling: a `linkable()` * artifact is a table, not a bag of compiled functions. * `ir` — the piece's combinator graph, serialized. This is the * composable half, and it is NOT new machinery: the plugin * already carries pieces as IR (`plugin/index.ts:1772`) and * the linker already re-lowers them (`linker.ts:640`, * `compileLinkable(evalRuleMapIR(p.ir), …)`). * * ── WHY THAT MAKES COMPOSITION THE EASY KIND ───────────────────────────────── * The open question was whether table-to-table composition has to merge two * ALREADY-ENCODED programs — relocating code offsets and merging const, fn, * class, expected and dispatch pools. It does not, as long as every piece * carries its IR: the composer evaluates each piece's IR back to a rule map, * merges the maps (later pieces overriding earlier names, which is what * `compose()` means), and calls `encodeTable` ONCE over the merged map. One * encode, no relocation, and the result is byte-for-byte the table the merged * grammar would have produced if it had been written as one `rules()` call. * * The relocation route is only forced for a piece with NO IR, which is why `ir` * being null is reported here as a first-class fact rather than folded into a * bare `null` return. * * ── THE HOLE CASE IS NOT REFUSED ───────────────────────────────────────────── * A piece that references a rule it does not define (`g.Value` with no * `.define()` — `hasExternalRuleRef`'s SHARED-SHAPE signature) cannot be encoded * standalone: `encodeTable` resolves a `lazy` by calling its thunk, and that * thunk throws. Such a piece gets `prog: null` and `rules: null` and keeps its * `ir`, which is the correct answer rather than a refusal: a shape with a hole * is not a parser in ANY lowering, and it composes through the merge above, * where the hole is filled by whichever piece supplies the name. */ export type LinkableTableOptions = Omit; export type LinkableTable = { /** * The parseman version that produced this artifact — the same ARTIFACT VERSION * LOCK `LinkablePieces.v` carries, for the same reason: artifacts are * version-locked and the format has no back-compat read path. */ v: string; ns: string; /** Local rule names, external (undefined) entries already dropped. */ keys: string[]; /** Rule names this piece REFERENCES but does not define. */ external: string[]; /** The piece as a table — null when it has holes (see `external`). */ prog: TableProgram | null; /** The runnable form of `prog` — null for the same reason. */ rules: Record | null; /** The emitted expression for `prog`, or null when there is no `prog`. */ replacement: string | null; /** * The piece's combinator graph, serialized — the COMPOSABLE half. Null when * the map cannot be faithfully serialized (a callback with no captured * source); a null here is what would force composition to merge encoded * programs instead of merging rule maps. */ ir: string | null; /** * The piece's rule map as LIVE COMBINATORS — present only for an in-process * artifact, never serialized. * * `ir` is the portable composable half, and a grammar BUILT AT RUNTIME often has no * `ir` at all (a live callback has no recoverable source). Such a piece still has to * compose, and in-process it can: the combinators themselves are right there. Without * this the runtime `compose([linkable(g)])` refused a grammar the source lowering * composed happily. */ ruleMap: ReadonlyArray]>; hostMode: HostMode; hostBranchElided: boolean; /** * Whether any rule carries a DIRECT builder, and whether the piece is free of * semantic reduction. `composeLeaf` gates on both, and they are predicates over the * combinator graph rather than products of lowering it — so they belong on the * artifact regardless of which lowering produced it. */ hasDirectBuilders: boolean; isRecognitionOnly: boolean; reflection: GrammarReflection; }; export declare function compileLinkableTable(ruleMapArg: ReadonlyArray]>, ns: string, opts?: LinkableTableOptions): LinkableTable | null; //# sourceMappingURL=compile-linkable-table.d.ts.map