/** The dialect this lexer reads. The execution environment falls back to `sh` when no bash is found; a reader on
 *  that path must degrade every word carrying a {@link BashOnlyConstruct} to the conservative reading. */
export declare const SHELL_LEX_DIALECT = "bash";
/** What holds a character quoted: the four quote forms and the backslash escape, one reason each. */
export declare const QUOTE_KINDS: readonly ["'", "\"", "$'", "$\"", "\\"];
export type QuoteKind = (typeof QUOTE_KINDS)[number];
/** The expansions this lexer names. Extended globs are not among them: `extglob` is off when `bash -c` starts, where
 *  `?(…)` is a syntax error and `(` is a group token here — but a text may turn it on (`shopt -s extglob` on an earlier
 *  line), after which bash reads `pack@(age.json)` as one pattern. A reader that plans reads treats an unquoted opener
 *  as a pattern it does not expand (`extglobOpenerIn`, the read station's `unreadable` floor). */
export declare const EXPANSION_KINDS: readonly ["parameter", "command", "process", "arithmetic", "tilde", "brace", "glob"];
export type ExpansionKind = (typeof EXPANSION_KINDS)[number];
/** Why a word's value cannot be read off the text. Each member is a spelling whose value the text does not
 *  contain — never "the lexer did not look". */
export declare const UNRESOLVED_REASONS: readonly ["ansi_c_escape", "locale_string", "parameter_text", "subscript_text", "compound_array_value"];
export type UnresolvedReason = (typeof UNRESOLVED_REASONS)[number];
/** The sentence a consumer hands on for an unresolved word: every reason is one a face ASKS about (the locale
 *  string included — its translation is not in the text), and a deny row is still judged on the written spelling
 *  by the readers that keep the word beside the reason. */
export declare const UNRESOLVED_SENTENCE: {
    readonly ansi_c_escape: "an ANSI-C quoted word carries an escape this lexer does not fold";
    readonly locale_string: "a locale-translated string carries text this lexer does not read";
    readonly parameter_text: "a parameter expansion carries text this lexer does not read";
    readonly subscript_text: "a subscript carries text this lexer does not read";
    readonly compound_array_value: "a compound assignment value is a list this lexer does not read";
};
/** Why a command yields no segments: bash's own syntax errors and the two constructs this lexer cannot delimit. */
export declare const PARSE_FAILURE_REASONS: readonly ["unterminated_single_quote", "unterminated_double_quote", "unterminated_ansi_c", "unterminated_subscript", "unterminated_compound_value", "unterminated_command_substitution", "unterminated_process_substitution", "unterminated_parameter_expansion", "unterminated_heredoc", "undelimited_substitution", "redirect_without_target", "heredoc_without_delimiter", "heredoc_delimiter_expands"];
export type ParseFailureReason = (typeof PARSE_FAILURE_REASONS)[number];
export declare const PARSE_FAILURE_SENTENCE: {
    readonly unterminated_single_quote: "a single-quoted word never closes";
    readonly unterminated_double_quote: "a double-quoted word never closes";
    readonly unterminated_ansi_c: "an ANSI-C quoted word never closes";
    readonly unterminated_subscript: "a subscript never closes";
    readonly unterminated_compound_value: "a compound assignment value never closes";
    readonly unterminated_command_substitution: "a command substitution never terminates";
    readonly unterminated_process_substitution: "a process substitution never terminates";
    readonly unterminated_parameter_expansion: "a parameter expansion never terminates";
    readonly unterminated_heredoc: "a here-document body never terminates";
    readonly undelimited_substitution: "a command substitution carries a construct this lexer cannot delimit";
    readonly redirect_without_target: "a redirection names no target";
    readonly heredoc_without_delimiter: "a here-document operator names no delimiter";
    readonly heredoc_delimiter_expands: "a here-document delimiter is not a plain word";
};
/** The constructs of this dialect a POSIX `sh` reads as something else. */
export declare const BASH_ONLY_CONSTRUCTS: readonly ["ansi_c_quoting", "locale_string", "append_assignment", "subscript_assignment", "compound_assignment", "here_string", "process_substitution", "redirect_both", "pipe_both", "brace_expansion"];
export type BashOnlyConstruct = (typeof BASH_ONLY_CONSTRUCTS)[number];
/**
 * The ANSI-C escapes this lexer folds: the thirteen single-letter ones, whose byte is the same in every bash and
 * in the reference implementation's table. Numeric, control and unicode escapes are NOT here — their bytes differ
 * between bash 3.2 and 5.x (`\c?`, `\u`, `\U`) or truncate the region (NUL) — and a body carrying one is
 * `unresolved` rather than decoded. Admission to this table is a differential test against the real shells.
 */
export declare const ANSI_C_ESCAPES: {
    readonly a: "\u0007";
    readonly b: "\b";
    readonly e: "\u001B";
    readonly E: "\u001B";
    readonly f: "\f";
    readonly n: "\n";
    readonly r: "\r";
    readonly t: "\t";
    readonly v: "\v";
    readonly "\\": "\\";
    readonly "'": "'";
    readonly '"': "\"";
    readonly "?": "?";
};
export interface WordPiece {
    /** Source offsets of the written text, `[start, end)`; a continuation between two pieces is nobody's. */
    readonly span: readonly [number, number];
    readonly quotedBy: QuoteKind | undefined;
    /** The text the program receives from this piece — absent for an expansion and for an unresolved piece. */
    readonly literal?: string;
    readonly expansion?: WordExpansion;
}
export interface WordExpansion {
    readonly kind: ExpansionKind;
    /** `"many"` where the result is word-split (an unquoted parameter or command substitution, a brace list, a glob). */
    readonly yields: "one" | "many";
    /** The text between the delimiters, where there is one (a substitution body, a brace list, a tilde-prefix). */
    readonly body?: string;
    /** The parameter name, where the expansion names one. */
    readonly name?: string;
    /** A glob's pattern — absent where an expansion stands inside it (its text is not the pattern): `folded`, what the
     *  program receives where it matches nothing — quotes removed, the spelling {@link LexedWord.folded} carries at its place
     *  (`[^.]`); `written`, as written, quoting kept (`[^\.]`, `["!"a]`) — the text a shell re-reading it matches by;
     *  `judged`, the spelling a reader judges the names it matches by — `folded`, save a class the judge reads as any one
     *  character: one holding a quoted or escaped character (its quote-removed text reads another class: `["!"a]` is not
     *  the negation `[!a]`) or a `[:…:]` / `[=…=]` / `[.….]` unit — spelled `?`, a superset of its members. */
    readonly pattern?: {
        readonly folded: string;
        readonly written: string;
        readonly judged: string;
    };
}
export interface QuotedSpan {
    /** Offsets into {@link LexedWord.raw}, `[start, end)`; the quote characters belong to their span. */
    readonly start: number;
    readonly end: number;
    readonly by: QuoteKind;
}
/** Bash's assignment fact for a word whose folded spelling is `NAME[subscript]?(+)?=value`, minted wherever the
 *  word stands. Whether bash STRIPS it before choosing the program is `bare && atCommandPosition`; whether the
 *  program that receives it reads it as an assignment is the program's own grammar. */
export interface AssignmentFact {
    readonly name: string;
    readonly op: "=" | "+=";
    readonly subscript?: {
        readonly raw: string;
        readonly folded: string;
        readonly expansions: readonly WordPiece[];
    };
    readonly value: {
        readonly raw: string;
        readonly folded: string;
        readonly pieces: readonly WordPiece[];
        readonly expansions: readonly WordPiece[];
        readonly unresolved?: UnresolvedReason;
    };
    /** The name, the brackets and the operator are written unquoted and unescaped — the subscript's CONTENT and the
     *  value may be quoted and still leave the word an assignment. */
    readonly bare: boolean;
    readonly form: "scalar" | "compound";
    /** `op === "="` with no subscript and a scalar value: the whole name is settled by this word's text. */
    readonly settlesWholeName: boolean;
}
/** An argv word. `raw` is what the SHELL sees (quotes, escapes and substitution text retained); `folded` is what
 *  the PROGRAM receives after quote removal, with every substitution replaced by {@link SUBSTITUTION_PLACEHOLDER},
 *  every other expansion left in its written spelling, and a literal leading tilde spelled `./~…`
 *  ({@link literalTildeSpelling}). Both are views of {@link LexedWord.pieces}. */
export interface LexedWord {
    readonly kind: "word";
    readonly raw: string;
    readonly folded: string;
    /** The spelling a reader judges the word's names by, where it is not `folded`: each bracket class holding a quoted or
     *  escaped character or a `[:…:]` / `[=…=]` / `[.….]` unit spelled `?` (`["!"a]*`, `[[:alpha:]]*` ⇒ `?*`,
     *  {@link WordExpansion.pattern}). */
    readonly judged?: string;
    readonly pieces: readonly WordPiece[];
    readonly quotedSpans: readonly QuotedSpan[];
    /** The pieces that carry an expansion, in order. */
    readonly expansions: readonly WordPiece[];
    readonly assignment?: AssignmentFact;
    /** The first reason, in reading order, that a value in this word cannot be read off the text. */
    readonly unresolved?: UnresolvedReason;
    /** The word was read where bash accepts an assignment or a command name: at a segment's start, after a bare
     *  assignment word, after a bare control-prefix word, or after a leading redirection list. */
    readonly atCommandPosition: boolean;
}
/** A redirection and the word it takes. A descriptor duplication (`>&2`, `<&0`, `>&-`, `>&1-`) takes none: its
 *  operand is `dup`, the descriptor (or `-`, or a descriptor followed by `-`) as written. `fd` is the descriptor
 *  number written in front of the operator (`2>f`, `3>&0`); absent when none was (bash's default, `1` for an
 *  output form and `0` for an input form, is the reader's to apply). */
export interface LexedRedirect {
    readonly kind: "redirect";
    readonly op: "<" | ">" | ">>" | "<<<" | "&>" | "&>>" | ">&" | "<&";
    readonly fd?: number;
    readonly target?: LexedWord;
    readonly dup?: string;
}
/** A here-document: the body is DATA the program reads on stdin, never command text. `quoted` records whether
 *  the delimiter word carried a quote or an escape, which is bash's rule for "the body does not expand". */
export interface LexedHeredoc {
    readonly kind: "heredoc";
    readonly delimiter: string;
    readonly quoted: boolean;
    readonly body: string;
}
/** A subshell parenthesis, standing alone: structure, not a word. */
export interface LexedGroup {
    readonly kind: "group";
    readonly op: "(" | ")";
}
export type LexedToken = LexedWord | LexedRedirect | LexedHeredoc | LexedGroup;
/** The connector bash ran a segment through — `"start"` for the first one. A closed set, because the read
 *  boundary distinguishes all four: `&&` is the only one under which the previous segment is known to have
 *  exited ZERO, `||` is the only one under which the previous segment may have been SKIPPED ENTIRELY, `|`
 *  puts the segment in a subshell whose directory changes never reach the parent, and `;` is plain sequence. */
export type ShellSegmentConnector = "start" | ";" | "&&" | "||" | "|";
/** The two boundaries the read boundary does not distinguish from a plain sequence: a backgrounding `&` and a
 *  line break. */
export type LenientConnector = ShellSegmentConnector | "&" | "\n";
export interface LexedSegment {
    /** The segment's text exactly as written (surrounding whitespace included). Here-document bodies are not part
     *  of any segment's text. */
    readonly text: string;
    readonly connector: LenientConnector;
    /** The `|` was spelled `|&`: the previous segment's standard error is piped too (bash 4+; a syntax error on
     *  bash 3.2, so a reader on the fail-closed side treats the pipe as real). */
    readonly pipesStderr?: true;
    readonly tokens: readonly LexedToken[];
    /** The bodies of the substitutions found in THIS segment (its words and its redirection targets), in order. */
    readonly substitutions: readonly string[];
}
export interface LexedCommand {
    readonly segments: readonly LexedSegment[];
    /** Every substitution body of the command, in order (the per-segment lists concatenated). */
    readonly substitutions: readonly string[];
}
export interface LexParseFailure {
    readonly parseFailure: {
        readonly reason: ParseFailureReason;
        readonly at: number;
    };
}
/** A command: its segments, or the one reason it has none. */
export type ShellLex = LexedCommand | LexParseFailure;
/** One segment's argv words in both spellings, index-aligned by construction (folding is strictly per word — it
 *  never splits or joins). The one shape every downstream arm of the classifier reads. */
export interface SegmentTokens {
    readonly folded: readonly string[];
    readonly raw: readonly string[];
}
/** What a substitution leaves in a word's FOLDED spelling: a marker no argv word can spell, so a consumer that
 *  judges words sees "this word carries text the shell computes" rather than the computing text itself. */
export declare const SUBSTITUTION_PLACEHOLDER = " subst";
/** Shell control words that stand BEFORE a command: transparent for the boundary walk (the command behind them is
 *  judged), and a position after which bash still accepts an assignment word. */
export declare const SHELL_CONTROL_PREFIXES: ReadonlySet<string>;
/**
 * Does the `$` at `at` OPEN a quote form (`$'…'` / `$"…"`)? ONE question, asked by every walker that has to
 * answer it. Escaped means an ODD run of backslashes in front of it: `\$'y'` is a literal `$`, while `x\\$'y'`
 * is a literal backslash followed by a real ANSI-C quote. Counting the run is what a one-character peek behind
 * cannot do.
 */
export declare function dollarOpensQuote(text: string, at: number): boolean;
/** The `'` that CLOSES the ANSI-C quote opened at `open`, or `undefined` when none does. `\'` does not close
 *  one — the single place a quote region honours a backslash. */
export declare function ansiCQuoteClose(source: string, open: number): number | undefined;
/** The ONE spelling of a LITERAL leading tilde — `./~…`, the relative path it is — for every position bash does not
 *  expand it in; a word without a leading tilde is returned as is. */
export declare function literalTildeSpelling(word: string): string;
/** The argv words of a segment: redirections, here-documents and groups are not words the program receives (bash
 *  removes them before exec). */
export declare function argvOf(segment: LexedSegment): readonly LexedWord[];
/** The two-spelling view of {@link argvOf}, for the readers that compare spellings. */
export declare function wordsOf(segment: LexedSegment): SegmentTokens;
/** The substitution bodies of an UNQUOTED here-document body: `$(…)` and backticks are live there, quotes are
 *  ordinary characters, a backslash protects the next character. `undefined` when a substitution never closes. */
export declare function substitutionsInHeredocBody(body: string): {
    readonly body: string;
    readonly kind: "command" | "arithmetic";
}[] | undefined;
/** The text a word's pieces hand the program when every piece is literal; `undefined` when one is an expansion or
 *  unresolved. */
export declare function literalTextOf(pieces: readonly WordPiece[]): string | undefined;
/** The text an UNQUOTED here-document body delivers when the shell expands nothing in it: a backslash before `$`, a
 *  backquote or a backslash is removed (a line continuation was joined when the body was read), every other character
 *  stands. `undefined` when an unescaped `$` or backquote stands in it: the program reads what the expansion makes. */
export declare function literalHeredocBody(body: string): string | undefined;
/** Lex a command: its segments, or the one reason bash (or this lexer) cannot delimit them. */
export declare function lexShell(source: string): ShellLex;
/**
 * The refused-reading view of {@link lexShell}: a parse failure, and any word whose value cannot be read off the
 * text, become the one `{ reject }` sentence a consumer's unreadable arm already takes. A reader that keeps the
 * other words (the read station) reads {@link lexShell} and the word's {@link LexedWord.unresolved} instead.
 */
export declare function lexShellText(source: string): LexedCommand | {
    reject: string;
};
/** The constructs of this dialect the command leans on — what a POSIX `sh` would read as something else. Empty
 *  when the command reads the same under either shell's word grammar. */
export declare function bashOnlyConstructsOf(command: LexedCommand): readonly BashOnlyConstruct[];
