import type { FirstSet, Combinator } from '../types.ts'; /** * Resolve a NAMED cross-artifact rule reference (`g.Foo`) whose own thunk does not * resolve — the shared-shape hole, bound by name at fuse time. * * A shape module compiles `Ratio: sequence(g.Value, …)` without defining `Value`, so * that `lazy`'s thunk throws and every first-set through it degrades to `any`. Once * the shape is FUSED with a dialect that defines `Value`, the hole is bound — pass a * resolver over the fused winner map and the first-set is the real one. * * Only NAMED refs are resolvable: an unnamed `ref()` that was never `.define()`d * carries no name for anyone to bind, so it stays `any`. */ export type RefResolver = (name: string) => Combinator | undefined; /** Winner-resolved choice facts shared by table encoding and capability IR. */ export type FinalChoiceClassification = { readonly exclusive: boolean; readonly firstSets: readonly FirstSet[]; readonly nullable: readonly boolean[]; }; /** Resolve final arm winners before deciding whether a choice is exclusive. */ export declare function classifyFinalChoice(arms: readonly Combinator[], resolve?: RefResolver, activeTrivia?: Combinator | null): FinalChoiceClassification; export declare function union(a: FirstSet, b: FirstSet): FirstSet; export declare function intersects(a: FirstSet, b: FirstSet): boolean; export declare function fromChar(code: number): FirstSet; /** * True when `combinator`'s first set admits the code point at `input[pos]` (or its * first set is `any`). The runtime counterpart of codegen's `firstSetCond` guard — * used by the interpreter's first-set fail-fast in `optional`/`many`/`attempt`/ * `node` to reject a doomed sub-parse before doing any setup. Returns `false` at EOF. */ export declare function startsFirstSet(combinator: Combinator, input: string, pos: number): boolean; export declare function fromRange(lo: number, hi: number): FirstSet; export declare function any(): FirstSet; export declare function empty(): FirstSet; /** * Can this parser SUCCEED consuming zero characters (nullable / matches-empty)? * Used to compute a sound sequence first-set: a nullable leading term lets the * NEXT term's first chars start the whole sequence. MUST err toward `true` when * unsure — over-estimating nullability only widens the (over-approximated) first * set, which stays sound; under-estimating would drop valid start chars and make * first-char dispatch skip a matching arm. */ export declare function matchesEmpty(p: Combinator, seen?: Set>, resolve?: RefResolver): boolean; /** * A ZERO-WIDTH ASSERTION never consumes input, so it contributes NOTHING to a * sequence's first-set — the first consumed char comes from the following * non-nullable term. `not(X)` reports `firstSet: any()` (it cannot know what it * forbids), which would otherwise poison a sequence's first-set to `any` and kill * first-char dispatch of the whole arm. Skipping its contribution is SOUND: a * first-set used for dispatch gating must stay a correct SUPERSET of the rule's * true first chars, and `not(X) Y` can only start with a char in firstSet(Y) — the * assertion only NARROWS the language (it forbids a full match ahead), it never * widens the set of possible first chars beyond Y. So firstSet(Y) is a sound (and * tighter) superset. * * The POSITIVE lookahead `peek(X)` is zero-width too, but it is NOT in this * predicate: unlike `not`, it knows what it requires, so its first-set is a real * constraint that must be INTERSECTED into the sequence's set rather than dropped * (see `isPositiveLookahead` and `sequenceFirstSet`). */ export declare function isZeroWidthAssertion(p: Combinator): boolean; export declare function sequenceFirstSet(parsers: readonly Combinator[]): FirstSet; /** * Deep first-set that RESOLVES `lazy`/`ref` combinators to their targets. The * combinators bake `_meta.firstSet` at CONSTRUCTION, when a `ref()` still reads * `any()` (define() never updates it) — so a `choice`/`sequence` built over refs * caches a spuriously-`any` first-set and loses first-char dispatch. Recomputing * here, following refs, recovers the real set. Over-approximates on cycles / * unknown constructs (returns `any`) — always sound: a wider set only means "try * this arm for more first chars", never skips a real match. * * SOUND ONLY where refs are FINAL (monolithic compile). Under compose OVERRIDE a * referenced rule can be replaced with a WIDER first-set, so a baked deep set * would wrongly skip valid input — the compose path defers dispatch to fuse time. * * `resolve` binds NAMED cross-artifact holes (`g.Foo`) against a fused winner map — * see `RefResolver`. Diagnostic-only today: it is what lets the gating analysis ask * the question at the site where the hole actually HAS an answer. */ export declare function firstSetOf(p: Combinator, seen?: Set>, resolve?: RefResolver, activeTrivia?: Combinator | null): FirstSet; //# sourceMappingURL=first-set.d.ts.map