import type { Combinator, ParseContext } from '../types.ts'; export type ScanToOptions = { /** * Per-call opaque-unit skippers (balanced parens/brackets, dialect * interpolation, …). These EXTEND the grammar-level ambient default: ambient * trivia (comments/ws) and ambient `scanSkip` (strings) are applied too, unless * `raw`. So a site only needs to list the extra units its scan requires. */ skip?: Combinator[]; /** * Hard opt-out: skip NOTHING ambiently — no trivia, no scanSkip, and (with no * per-call `skip`) a pure raw byte-walk. For the rare site that intends to scan * literally through comments/strings. */ raw?: boolean; /** * If true, reaching EOF without finding the sentinel is a success — returns * everything consumed so far. Default false (fail at EOF). */ orEOF?: boolean; /** * `balanced()` only. Make an unmatched close a genuine FAILURE instead of a * recovered one. * * By default `balanced()` wraps its close in `expect()`, which never fails: on * a miss it returns a ParseError, records it on `ctx._errors`, and reports a * zero-width span. So the combinator is UNFAILABLE once its opener is consumed * — the rejection is computed and recorded, but a caller cannot branch on it. * `choice()` cannot fall through to another arm, `not()` cannot negate it, and * a `sequence()` around it proceeds as if the group closed. * * With `strict: true` the close is required, so an unmatched or missing close * fails the whole group and rolls back to the opener — the ordinary combinator * contract. Nested groups inherit strictness (the interior recurses into the * same combinator). * * Opt-in: the default is unchanged, because recovery is what a tolerant * document parse wants, and existing grammars are built on it. */ strict?: boolean; }; /** * Resolve the effective ordered skipper list for a scan, folding grammar-level * ambient trivia + scanSkip in FRONT of the per-call `skip` (explicit skip * EXTENDS the ambient default). Shared by the interpreter `scanTo`/`balanced`; * the compiled path bakes the identical list in codegen. * * raw → [] (no trivia, no scanSkip, no skip) * else → [ ...trivia?, ...scanSkip?, ...skip ] * * The ambient trivia (comments/ws) leads so a sentinel hidden in a comment is * never matched, then ambient strings, then the site's extra units. The sentinel * itself is still checked before any skipper, so a sentinel that also starts a * skip region wins (unchanged priority). */ export declare function resolveScanSkip(explicitSkip: Combinator[], raw: boolean, ctx: ParseContext): Combinator[]; /** * Consume input up to (but not including) the sentinel, skipping over any * "hole" patterns in order so their contents are never mistaken for the sentinel. * * Returns the consumed text as a string. The sentinel is NOT consumed. * Fails if the sentinel is never found (unless orEOF is true). * * const selector = scanTo(literal('{'), { * skip: [cssComment, stringLit, balanced('(', ')'), balanced('[', ']')], * }) */ export declare function scanTo(sentinel: Combinator, { skip, raw, orEOF }?: ScanToOptions): Combinator; /** Codegen marker: a balanced combinator that must re-resolve ambient scanSkip * into its interior at emit time (the compiled mirror of the interpreter wrapper). */ export type BalancedAmbient = Combinator & { _balancedAmbient?: { open: string; close: string; ownSkip: Combinator[]; strict?: boolean; }; }; /** * Marker: this combinator IS a balanced interior — its delimiters, and the fact * that everything between them is a scan rather than authored structure. * * Set by `buildBalancedInterior`, so EVERY balanced carries it: the ambient one, * the `raw` one, and each interior the ambient cache rebuilds. `_balancedAmbient` * cannot serve this purpose — it is absent on `raw`, and it means "re-resolve * ambient scanSkip", which is a different claim. * * Read by the spec/railroad emitter, which renders a balanced as its delimiters * around an opaque interior. That is not a simplification: the delimiters are * FIXED at construction and the interior genuinely is a delimiter scan, so the * rendering states exactly what the construct is. Expanding the lowered shape * instead would print the content-run regex and the `self` back-edge, which are * emitter machinery, not language. */ export type BalancedMarked = Combinator & { _balanced?: { open: string; close: string; }; }; /** * The table lowering's marker, on the object `balanced()` RETURNS. * * Deliberately not `_balancedAmbient`, and deliberately on the OUTER combinator. * `_balancedAmbient` means "rebuild my interior with the ambient scanSkip", which * is false for `raw`, and it sits on the INNER combinator because that is the one * codegen's dedup and the interior `self` back-edge address. Reading `_def` (or * the ambient marker) off the outer object gets the wrong thing — a structural * encoder made exactly that mistake and lowered the wrong parser, silently. * * This marker instead records the CONSTRUCTOR ARGUMENTS, so an encoder can carry * a `balanced()` as data and let `balanced()` itself rebuild it. It is present on * every `balanced()`, `raw` included. */ export type BalancedSpec = Combinator & { _balancedSpec?: { open: string; close: string; ownSkip: Combinator[]; strict: boolean; raw: boolean; }; }; /** * Match a balanced open/close pair, skipping over any holes inside. * Returns the full matched text including delimiters. * * const parenGroup = balanced('(', ')', { skip: [comment, stringLit] }) * * With no per-call `skip`, a balanced under a grammar that declares * `rules({ scanSkip })` consults that ambient opaque-unit set in its INTERIOR too, * so a delimiter hidden inside a string/bracket run never closes the balance * early — the same footgun closure `scanTo` gets. `raw: true` opts out. * * By DEFAULT an unmatched close is RECOVERED, not failed: the close is wrapped in * `expect()`, so the group always succeeds and records a ParseError instead. Pass * `strict: true` to make it fail and roll back — see `ScanToOptions.strict`. */ export declare function balanced(open: string, close: string, options?: ScanToOptions): Combinator; /** Build a balanced open/close interior for a FIXED skip set (no ambient). */ export declare function buildBalancedInterior(open: string, close: string, skips: Combinator[], strict?: boolean): Combinator; //# sourceMappingURL=scanTo.d.ts.map