/**
 * The ONE reader of a segment's PROGRAM POSITION: which argv word names the program bash runs, and what stands in
 * front of it — bare control words with their declared options, environment assignments, a launcher chain.
 *
 * Every face that judges a command by its program (the compound walk, the single-command boundary face, the
 * refused-command whitelist, the poll loop's base-move check) reads this ONE function. A face that needs the
 * answer it cannot give reads {@link ProgramPosition.refusal}: a declarative record of why the program is not
 * readable, minted into one sentence by {@link programPositionRefusalSentence}. Reading less than this reader
 * does (an option skipped, a chain member missed) is how one face used to vouch for a program another refused.
 */
import { SHELL_CONTROL_PREFIXES, type LexedWord } from "../../shell/lex.js";
/** The verdict every unresolvable / out-of-root / unbounded finding ends on. The findings differ in what
 *  they found; the consequence is one consequence, and a copy that drifts reads as a second rule. */
export declare const NOT_AUTO_ALLOWED = "\u2014 not auto-allowed";
/** argv[0] as the program bash will resolve it: `/usr/bin/cat` and `cat` are one name. */
export declare function programBasename(word: string): string;
/**
 * The `NAME=` / `NAME+=` prefix as WRITTEN in a whitespace-split token. This is NOT the position reader's grammar
 * — the reader reads the lexer's {@link LexedWord.assignment} fact — but the one reader that still walks the
 * command TEXT rather than its words (the activity summary) reads it here. It retires with it.
 */
export declare const ASSIGNMENT_PREFIX: RegExp;
/** The prefix a whitespace-split token BEGINS with, or `undefined` — the text readers' view of
 *  {@link ASSIGNMENT_PREFIX}; `name` is the variable before any subscript, `settlesWholeName` false for an
 *  append and for a subscript. */
export declare function writtenAssignmentPrefix(token: string): {
    readonly prefix: string;
    readonly name: string;
    readonly appends: boolean;
    readonly settlesWholeName: boolean;
} | undefined;
/** The names a segment's COMMAND ENVIRONMENT sets for the program it starts: the assignment words in front of the
 *  program (the lexer's {@link LexedWord.assignment} fact, a launcher's `NAME=value` operand included) — or `all` where
 *  a launcher in front of it may set, clear or replace the environment (`env -u` / `-i`, `sudo`, `su`, …). */
export declare function commandEnvironmentNames(argv: readonly LexedWord[]): ReadonlySet<string> | "all";
export { SHELL_CONTROL_PREFIXES };
/** A control word is a keyword only when bash sees it BARE: `'if'` / `"do"` / `\\!` are command names (a program
 *  looked up on PATH, whose failure changes nothing), so a quoted or escaped spelling never counts as one. */
export declare function isBareControlWord(words: readonly LexedWord[], i: number, set: ReadonlySet<string>): boolean;
/** Does the shell read this word as syntax — a reserved word, a control word, `{`, `coproc` — of `set`? Only a word
 *  written BARE where bash reads a command's first word (the lexer's {@link LexedWord.atCommandPosition}): a quoted or
 *  escaped spelling is a command name, and a word an expansion produced (a value, a split field) is never syntax —
 *  bash parses the line before it expands it. The one reading every syntax reader of a command's words asks. */
export declare function isShellSyntaxWord(w: LexedWord | undefined, set: ReadonlySet<string>): boolean;
/** The words that head a loop over a list (`for NAME in …`, `select NAME in …`). */
export declare const LOOP_LIST_HEADS: ReadonlySet<string>;
/**
 * A word bash strips as an ASSIGNMENT before it chooses the program: the lexer's assignment fact, written BARE
 * (the name, the brackets and the operator unquoted — a quoted VALUE still assigns, a quoted operator is a
 * program name), read where bash accepts one (the lexer's own command-position state, which this reader's walk
 * over control words and earlier assignments re-traces). One fact, two readers that must agree.
 */
export declare function isLeadingAssignmentWord(words: readonly LexedWord[], i: number): boolean;
export declare const PROGRAM_POSITION_REFUSAL_KINDS: readonly ["option_at_program_position", "control_syntax_at_program_position"];
export type ProgramPositionRefusalKind = (typeof PROGRAM_POSITION_REFUSAL_KINDS)[number];
/** Why the program could not be read — a closed set, each member minted into one sentence. `owner` is the word
 *  that took the offending token: the control word or the first launcher of the chain. */
export type ProgramPositionRefusal = {
    readonly kind: "option_at_program_position";
    readonly owner: string;
    readonly option: string;
} | {
    readonly kind: "control_syntax_at_program_position";
    readonly owner: string;
    readonly word: string;
    /** Not a DECLINE ({@link programPositionRunsShell}): the row WAS read and a SHELL — or a program the launcher
     *  names by an option of its own (`su -s PROGRAM`) — stands at the program position, run by the launcher at argv
     *  index `launcher` and handed the words from index `from` on (none where `from` is the argv's end: `sudo -s`,
     *  `chroot DIR`), as that launcher's row composes them (`launchedCommands`, shell-reentry-text.ts). Absent ⇒
     *  genuine control syntax, which IS one. */
    readonly runsShell?: {
        readonly launcher: number;
        readonly from: number;
    };
};
export interface ProgramPosition {
    /** Indices of the bare control words stripped in front (`!`, `if`, `time`, …), in order; their declared options
     *  are skipped with them. */
    readonly controlWords: readonly number[];
    /** The first index past the control words and their options — the WRITTEN command word: an assignment, a
     *  launcher, or the program itself. `undefined` when nothing stands there. */
    readonly written: number | undefined;
    /** The leading `NAME=value` words at `written`. */
    readonly assignments: readonly number[];
    /** The launcher chain past the assignments, in order (basenames); empty when the written word is not a launcher. */
    readonly launchers: readonly {
        readonly index: number;
        readonly name: string;
    }[];
    /** Some chain member is an argv re-entry program: the program's operands arrive on a stream. */
    readonly argvFromStdin: boolean;
    /** The chain ends ON the re-entry program (nothing follows it), so it runs its default program. */
    readonly runsDefaultProgram: boolean;
    /** The program the stream-fed chain member runs when the chain names none (`xargs` runs `echo`). */
    readonly defaultProgram?: string;
    /** The program bash RUNS: the first word past the chain. `name` is the folded word as written, `basename` what
     *  bash resolves (`/usr/bin/cat` is `cat`). `undefined` when the chain names none (a lookup, `command -v git`, runs
     *  nothing) or the read was refused. */
    readonly program: {
        readonly index: number;
        readonly name: string;
        readonly basename: string;
    } | undefined;
    /** Why no program could be read; `undefined` beside `program: undefined` means the chain simply names none. */
    readonly refusal: ProgramPositionRefusal | undefined;
    /** A launcher of the chain moves the directory or the root the program runs in, or where its word is looked up
     *  (`env -C <dir>`, `sudo -R <dir>`, `env -P <dirs>`): the program is still the word it names, but where its path
     *  operands resolve is not the command line's working directory — each consumer reads that as it must. */
    readonly launcherMovesBase: boolean;
}
/**
 * Read the program position of one segment's argv words.
 *
 * In order: bare control words and the options their launcher rows declare; the written word; its leading
 * assignments; then either the program itself or a launcher chain — whose first member's declared options are read
 * too (it is the launcher the line names), and inside which an assignment, a bare number, a nested launcher and an
 * argv re-entry program are stepped over, an option-shaped word (a lone `-` included — `env - <program>` clears
 * the environment and the table does not say so) refuses, and shell control syntax refuses. An option-shaped
 * WRITTEN word (judged on its basename, as the program it names) refuses the same way: it is where the program
 * would be, and the word in front took an option no row explains.
 */
export declare function readProgramPosition(words: readonly LexedWord[]): ProgramPosition;
/** Does this program position hand a program operands the walk cannot see? True when the chain re-enters through
 *  stdin AND the program it runs is not one the caller accepts as a stream target. ONE reading, shared by every
 *  consumer; WHICH targets are accepted is the caller's declaration, not this reader's. */
export declare function argvReentryUnjudged(pos: ProgramPosition, acceptsTarget: (basename: string) => boolean): boolean;
/**
 * The two ways this reader DECLINES rather than judges — a CLOSED set (`docs/CLOSED-SETS.md`), because what a
 * seat does with a declined segment is a ROW of the shell read decision table (`shell-read-judge.ts`, the
 * `declined` row: the one row the seats disagree on), not a boolean buried in a caller.
 * `unreadable_program_position`: the walk cannot name the program bash will run (`env -- ls`).
 * `stream_fed_operands`: the operands arrive on a STREAM it never saw (`… | xargs cat`). Neither names a WORD.
 */
export declare const SHELL_SCAN_DECLINES: readonly ["unreadable_program_position", "stream_fed_operands"];
export type ShellScanDecline = (typeof SHELL_SCAN_DECLINES)[number];
/** Does a SHELL stand where this segment's program would be — as the program itself (`sh -c`), or as a launcher
 *  ROW handing its operands to one (`watch "…"`)? ONE predicate for the re-entry class, so the two spellings
 *  cannot be answered differently; which names are shells is the caller's declaration. Not a decline. */
export declare function programPositionRunsShell(pos: ProgramPosition, runsShell: (basename: string) => boolean): boolean;
/** Which decline, if any, this program position raises — ONE reading of the two facts above, so no consumer
 *  re-derives either. A refusal that says a SHELL runs is NOT one: it names what runs. */
export declare function shellScanDeclineOf(pos: ProgramPosition, acceptsStreamTarget: (basename: string) => boolean): ShellScanDecline | undefined;
/** ONE sentence per refusal kind, minted here and nowhere else. */
export declare function programPositionRefusalSentence(refusal: ProgramPositionRefusal): string;
