/** * Grammar spec model — a small, notation-agnostic tree that both the EBNF * emitter and the railroad-diagram emitter consume. * * The model is produced by walking the SAME `_def` structure the interpreter * and macro compiler consume, so a generated spec cannot drift from what * actually parses. See `docs/proposals/grammar-spec-generation.md`. */ import type { Combinator } from '../types.ts'; /** A node in the grammar spec tree — one per syntactic construct. */ export type SpecNode = { kind: 'seq'; items: SpecNode[]; } | { kind: 'choice'; items: SpecNode[]; } /** `item*`, or `item{0,max}` when `many(…, { max })` bounded it. */ | { kind: 'star'; item: SpecNode; max?: number; } /** `item+`, or `item{min,max}` when `many(…, { min, max })` bounded it. `min` * defaults to 1 and is always >= 1 (a min-0 repeat is a `star`). */ | { kind: 'plus'; item: SpecNode; min?: number; max?: number; } | { kind: 'opt'; item: SpecNode; } /** * Separated repetition. `min`/`max` count ITEMS, not separators: `min: 0` is * `(item (sep item)*)?` — NULLABLE — and any `min >= 1` requires that many * items, so it is not. `trailing` mirrors `sepBy`'s option of the same name. */ | { kind: 'sepBy'; item: SpecNode; sep: SpecNode; min: number; max?: number; trailing?: 'allow'; } /** Reference to a named production (non-terminal). */ | { kind: 'ref'; name: string; } /** * A terminal. `literal` terminals are exact strings (rendered quoted); * non-literal terminals are patterns/prose (rendered as-is, e.g. a regex * or a caller-supplied display name). */ | { kind: 'terminal'; text: string; literal: boolean; } /** Negative lookahead (`not`). Rendered as an annotation, not consumed input. */ | { kind: 'not'; item: SpecNode; } /** Positive lookahead (`ahead`). Zero-width, like `not`. */ | { kind: 'peek'; item: SpecNode; } /** An out-of-band annotation (guards, error-recovery, unknowns). */ | { kind: 'annotation'; text: string; } /** Matches nothing (elided trivia / semantic-only wrappers). */ | { kind: 'empty'; }; /** One named production: `name ::= expr`. */ export type Production = { name: string; expr: SpecNode; /** True when the rule is trivia (whitespace/comment). Elided by default. */ trivia: boolean; }; export type SpecModel = { productions: Production[]; }; export type SpecOptions = { /** * How to order the emitted productions when neither `order` nor `root` is given: * - `'source'` (default) — the order the rules were **declared** in the * `rules()` factory. Predictable, includes every rule, and leads with the * entry rule (authors write it first). Internal-but-referenced helper rules * follow, in first-reference order. * - `'reachable'` — BFS from the entry rule: the first-declared rule leads, * then each rule appears the first time it is referenced; any rules not * reachable from the entry are appended in declaration order. * Ignored when `order` or `root` is set. */ sort?: 'source' | 'reachable'; /** * Explicit rule order (and subset). When given, only these rules are emitted, * in this order, plus any rules they reach. Overrides `sort`. */ order?: string[]; /** * Start rule(s). When given, only these and the rules they reach are emitted * (a pruned, reachability-ordered spec). Overrides `sort`. */ root?: string | string[]; /** Include trivia rules (whitespace/comment) in the output. Default: false. */ includeTrivia?: boolean; /** * Display names for terminals, keyed by rule name. When a rule whose body is a * single terminal (regex/literal/keywords) has an entry here, that whole rule * renders as the given terminal name instead of expanding — e.g. * `{ Ident: 'identifier' }`. */ terminals?: Record; /** * Best-effort rendering of a regex terminal to a readable form. Return * `undefined` to fall back to the default `/source/` rendering. */ regexDisplay?: (source: string, flags: string) => string | undefined; }; export type GrammarInput = Record> | Combinator; /** * The fixed string(s) a regex matches — the terminal its author actually wrote — * or `undefined` when the pattern has real structure. Handles the three shapes * that spell a keyword: a bare literal, a literal guarded by a trailing word * boundary (`word()` / `keywords()` and every hand-written copy of them), and a * `\b…\b`-anchored word. */ export declare function fixedStringsOfRegex(source: string): string[] | undefined; /** * Build the notation-agnostic spec model from a `rules()` grammar (or a single * combinator). Following every referenced named rule keeps the closure complete; * ordering is controlled by `order` / `root` / `sort` (see {@link SpecOptions}). */ export declare function buildSpecModel(grammar: GrammarInput, options?: SpecOptions): SpecModel; //# sourceMappingURL=model.d.ts.map