UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

458 lines (457 loc) • 36.1 kB
/** * THE BINDING RULE — which shell names a command text binds, and to what, read off the one lexer's facts and the * program read model's roles. A word that expands a name (`"$F"`, `${F}`, a `~` reading `HOME`) names a path only * through what the text bound that name to; this module answers "what may `F` hold here", and nothing else. * * Two halves: * · {@link bindingEffectOf} — what ONE segment does to the names: binds a name to a value (an assignment statement, a * declaration builtin's `NAME=value`, a `for` list), makes a name unknown (a builtin whose operand role binds a name, * an assigning expansion `${N:=…}`, an arithmetic assignment, a code body that runs later), gives a name an ATTRIBUTE * (integer, a case change, an array, read-only: a later assignment to it stores something other than its text, or * nothing), or makes EVERY name unknown (a name reference, `eval`, `source`, a computed name, an unquoted * here-document `${`), and resets every name to the state it starts the text in (a function body: it runs at its * call, against that table); * · {@link BindingThread} — the effects threaded through the segments the way the plan threads the working directory * (`shell-read-plan.ts`), in their ORDERED state: a binding is one for a reader only where it may run before the * reader in the same shell — not one written after it, inside a subshell the reader is not in (a closed `( … )`, a * pipeline member that is not the last, a background job) or in a function body (it runs at a call: a call the plan * sees makes every name a body binds unknown from there). A value bound in a segment that may not have run before * a reader (an `&&` / `||` run, a branch, a loop body, the last pipeline member) joins the values the name held * before instead of replacing them. A reader in a function body loses every name another body binds — unless the * body declared it with a plain `local`. `PWD` / `OLDPWD` start from what the working-directory thread says. * An attribute and a name reference hold for every segment they may RUN before: a later one, one in a function body * (it runs at its call), one in the same loop body (a later beat). * * A name the text does not settle is UNKNOWN, and a word expanding an unknown name stays a word the shell rewrites (its * read cannot be established). `HOME` is an ordinary name whose state at the start of a text is the declared home. * The shell's own variables (the ones bash sets, holds read-only or evaluates itself) are never bound from text. */ import { type LexedRedirect, type LexedSegment, type LexedToken, type LexedWord } from "../../shell/lex.js"; import { type DeclaredAttribute } from "./program-read-model.js"; import { type BuiltinState } from "./shell-read-builtins.js"; /** A value a name may hold — the text the program receives ({@link spelled}: what a shell re-parsing it reads), literal * throughout, or a PATTERN whose matches are the values (a `for` list word the shell globs before the loop binds it; * `spelled` is then the pattern as the program receives it where it matches nothing): `glob`, with its `parts` — the * value in runs: a literal run (quoted or literal text, a settled value) and a pattern run (glob pieces as written, * quoting kept, and as a reader judges them — {@link WordExpansion.pattern}). The one producer is the piece walk * ({@link valueOf}). */ export type BoundValue = { readonly spelled: string; readonly glob?: never; readonly parts?: never; readonly fields?: readonly string[]; } | { readonly spelled: string; readonly glob: true; readonly parts: readonly ValuePart[]; readonly fields?: never; }; /** One run of a pattern {@link BoundValue}: literal text, or a pattern — the shell expands its characters — `text` as * written (what a shell re-reading it matches by), `judged` as a reader judges the names it matches. */ export type ValuePart = { readonly text: string; readonly pattern: false; } | { readonly text: string; readonly pattern: true; readonly judged: string; }; /** A spelling the deny judge alone reads ({@link Binding.floor}, {@link wordFloorValues}): a value, or a word as written * where its names are unknown — nothing re-reads it, so a pattern says no more than that it is one. */ export interface FloorValue { readonly spelled: string; readonly glob?: true; /** A pattern's spelling as a reader judges the names it matches, where it is not `spelled` ({@link judgedSpellingOf}). */ readonly pattern?: string; } /** A pattern value's names as a reader judges them, where that is not its spelling: its runs, a class the judge widens * as `?` (the lexer's `WordExpansion.pattern.judged`), a leading `~` the literal tilde it is. */ export declare function judgedSpellingOf(v: BoundValue): string | undefined; /** A value as a deny-floor spelling, its judged spelling with it. */ export declare function floorOf(v: BoundValue): FloorValue; /** The values a name may hold where the text settles it. */ export type NameValues = readonly BoundValue[]; /** What a name holds at one point of a text: its possible values, or `"unknown"`. (The values are a NAMED arm: the * release manifest reads a union that spells a word as a vocabulary, and a `readonly …[]` arm beside the word is a shape * it cannot enumerate — it would then publish the set unreadable.) */ export type NameState = NameValues | "unknown"; /** * The variables bash keeps itself — it sets them (`PWD`, `REPLY`, `OPTARG`, `BASH_REMATCH`, …), holds them read-only * (`SHELLOPTS`, `BASHOPTS`, `BASH_VERSINFO`: an assignment to one is refused), or evaluates every value assigned to them * as ARITHMETIC (the integer variables: `OPTIND`, `RANDOM`, `LINENO`, `HISTCMD`, `BASHPID`, …; the reference * implementation's table of them, `zsh`'s included, is read whole: a member that is not one in this shell costs a * question, never a read). Their value is never the text that bound it. */ export declare const SHELL_INTEGER_VARIABLES: ReadonlySet<string>; /** Is this a variable bash keeps itself ({@link SHELL_INTEGER_VARIABLES}, or one it sets)? The working-directory names * ({@link WORKING_DIRECTORY_NAMES}) are not: their value is the working-directory thread's ({@link WorkingDirectoryState}). */ export declare function shellKeepsName(name: string): boolean; /** The names bash sets when the working directory moves: `PWD` (where the shell stands, as the move spelled it) and * `OLDPWD` (the `PWD` it stood in before the last move — `cd -` goes there). A text may assign them too. */ export declare const WORKING_DIRECTORY_NAMES: readonly ["PWD", "OLDPWD"]; export type WorkingDirectoryName = (typeof WORKING_DIRECTORY_NAMES)[number]; /** What the working-directory thread (`shell-read-plan.ts`) says the two names hold at one segment, before anything the * text assigns them: the bases it may stand in (`PWD`) and the ones it stood in before its last move (`OLDPWD`) — * `unknown` where it lost track, the move's spelling is not the base (a physical move), or the shell inherited it. */ export type WorkingDirectoryState = { readonly [K in WorkingDirectoryName]: NameState; } & { /** The last segment before the reader whose move the thread applied or lost track at (-1: none in this text). */ readonly movedAt: number; }; /** The POSIX special builtins: a prefix assignment to one stays after it, and one runs before a function of its name * (in POSIX mode, which an inherited environment can turn on unseen). */ export declare const SPECIAL_BUILTINS: ReadonlySet<string>; export declare const functionKey: (name: string) => string; /** What a function name is at a reader: `defined` — it certainly is one; `absent` — it certainly is not; `maybe` — a branch, * a loop, a body that may not have run, a removal that may not have found it. */ export type FunctionState = "defined" | "maybe" | "absent"; /** One binding a segment makes: a name and what it now holds (`unknown` = made unknown). `prefix`: a binding that may or * may not take effect (a prefix assignment to a special builtin, which may or may not outlive its command; an `unset` of a * function, which a read-only function refuses). `loopVar`: a `for` loop's variable, held through its body. */ export interface Binding { readonly name: string; readonly state: NameState; readonly prefix?: true; readonly loopVar?: true; /** `local`: a plain `local NAME…` — in a function body the name is the body's own and never leaves it. `unread`: a * declaration builtin with an option word (`declare -g`, `local -p`, `local -r`): which scope it binds in is not * read, so it is neither the body's own name nor covered by an earlier `local`. */ readonly scope?: "local" | "unread"; /** Spellings the name may hold that the deny judge still reads where the name is otherwise unknown (an array's * elements: what `${A[k]}` expands to is one of them). */ readonly floor?: readonly FloorValue[]; } /** An attribute a declaration gives a name — or every name (`name` absent: the declaration computed it): a later * assignment to it is evaluated as arithmetic (`integer`), stores a case change or an array element (`transformed`), or * is refused (`frozen`) — it binds something other than its text. */ export interface NameAttribute { readonly name?: string; readonly kind: Exclude<DeclaredAttribute, "reference" | "unsettled">; } /** What ONE segment does to the names. `all`: every name made unknown (`unknown`), or reset to its state at the start * of the text (`reset` — a function body). `attributes`: the attributes it gives ({@link NameAttribute}). `references`: * a name reference was declared — from here on an assignment to any name may write through it, so no name holds what * the text assigned. `inFunction`: the builtin assigns only inside a function body (`local`) — outside one bash refuses * the command, and its bindings hold nothing the text says. */ export interface BindingEffect { readonly bindings: readonly Binding[]; readonly all?: "unknown" | "reset"; readonly attributes?: readonly NameAttribute[]; readonly references?: true; readonly inFunction?: true; } /** How one value word reads against the table, the earlier assignments of the same segment applied (bash assigns left * to right): its possible values, or `unknown`. */ export type ValueReader = (word: Pick<LexedWord, "pieces">, quoted: boolean, overlay: ReadonlyMap<string, NameState>) => NameState; /** The segment's shape the effect needs beside its words: the functions whose definition heads were dropped from it. */ export interface SegmentShape { readonly defines: readonly string[]; } /** The argv projection of a lexed segment: structure that names nothing that runs here is dropped — a subshell * parenthesis, a bare `{` / `}`, a function definition's head (`NAME ()`, and `function NAME [()]` with a name of * any spelling, {@link dropDefinitionHeads}), a `case` arm's pattern ({@link dropCasePattern}), and the block words * at the head. */ export interface ProjectedSegment extends SegmentShape { readonly argv: readonly LexedWord[]; readonly redirects: readonly LexedRedirect[]; readonly grouped: boolean; } export declare function projectSegment(segment: LexedSegment): ProjectedSegment; /** A function definition's head names nothing that runs here and is dropped from a segment's tokens, in place: * `NAME ( )` ({@link isDefinitionName}), and `function NAME [( )]` — a bare `function` at command position, a name of any * spelling. The lexer puts the body's compound command back at command position after the head, so a definition * nested in a body is dropped the same way; after a drop the token that moved up is looked at again. Answers where the * heads stood: entry `k` names the functions whose heads were dropped right before the token now at `k` (the last entry, * past the last token, a head whose body opens in a later segment). */ export declare function dropDefinitionHeads(tokens: LexedToken[]): readonly (readonly string[])[]; /** * What a word holds through the names it refers to — `$NAME`, `${NAME}`, a leading `~` (the value of `HOME`): `undefined` * where it refers to no name (it reads as written), else {@link valueOf}. `table.stateOf` is read after `overlay` (the * names the same segment bound earlier). */ export declare function wordValues(word: Pick<LexedWord, "pieces">, table: BindingTable | undefined, quoted: boolean, overlay?: ReadonlyMap<string, NameState>, split?: boolean): readonly BoundValue[] | "unknown" | undefined; /** The names a word's expansions read as values — a bare `$NAME` / `${NAME}`, and one written inside a bracket the shell * forms its class from after expanding it ({@link valueOf}) — in the order they stand. */ export declare function namesIn(word: Pick<LexedWord, "pieces">): string[]; /** * What a VALUE word holds (an assignment's value, a `for` list word, a word handed to a program) — THE piece walk, the one * producer of {@link BoundValue}s: every combination of the values its pieces take, each field's pattern formed once the * whole field has expanded ({@link formedField}) — a literal piece its text, a glob piece its pattern as written (a bracket * holding an expansion its brackets and its body, the body's names substituted in place), `~` and `$NAME` the values the * table gives: * · its values — a field the shell globs makes the value a pattern; * · `"unknown"` — a name it refers to is not settled here, it carries an expansion no name answers (a modifier, a * substitution, a brace list, `~user`), an UNQUOTED expansion's value is no {@link READABLE_VALUE} (or holds * whitespace outside `split`), `IFS` may have changed (`quoted` = the whole word is read as one value: an assignment's * value, which is never split), a field is not formed or a split one forms a pattern, or it would list more than * {@link WORD_VALUES_MAX} values. * `split` = the word is read as the ARGUMENTS it becomes: an unquoted value is split into its words on the default `IFS` * (a value then carries its {@link BoundValue} `fields`). */ export declare function valueOf(word: Pick<LexedWord, "pieces">, table: BindingTable | undefined, quoted: boolean, overlay?: ReadonlyMap<string, NameState>, split?: boolean): NameState; /** * The spellings a word the table leaves unknown may still take through the deny floors of the names it refers to * ({@link BindingTable.floorOf}) — `${A[k]}`, `${A[@]}`, `$A` reading an array's elements — or through their values where * known: for the deny judge alone. Empty where some name it refers to leaves neither. */ export declare function wordFloorValues(word: Pick<LexedWord, "pieces">, table: BindingTable | undefined): readonly FloorValue[]; /** Where a segment's argv heads a `for` / `select` loop: the index of that bare word, at the segment's start or past the * bare control words in front of it (`do for x in …`, `then for …` — a loop nested in a body or a branch); `undefined` * for any other segment. */ export declare function loopListHeadAt(argv: readonly LexedWord[]): number | undefined; /** * What ONE segment does to the names (see the module header). `argv` = the segment's argv projection (structure * dropped); `readValue` folds a value word against the table (a reader that answers `unknown` gives the names alone). * `shadow`: the word the shell looks up first is a function of the text where the segment stands (`named`: it is one, the * builtin of its name does not run — the call's effect is the body's; `maybe`: it may be one, so what the builtin binds is one * more value its names may hold). `availability`: whether the builtin of a name runs by it where the segment stands * ({@link BuiltinState}) — `disabled`: the word finds no command and binds nothing, `maybe`: as a function that may stand. */ export declare function bindingEffectOf(segment: LexedSegment, argv: readonly LexedWord[], shape: SegmentShape, readValue: ValueReader, shadow?: "named" | "maybe", availability?: (builtin: string) => BuiltinState): BindingEffect; /** * The names an ARITHMETIC text may assign: every identifier in a text that carries an assignment operator (`=` that is no * comparison, `+=` and its kin, `++`, `--`) — read whole, not parsed: a name only compared there is made unknown too. */ export declare function arithmeticAssignedNames(text: string): string[]; /** The names a text binds anywhere (every segment, every name the binding rule reads), or `all` where it may bind any * name — for a body that runs later. Unreadable text binds any. */ export declare function namesBoundIn(text: string, depth?: number): ReadonlySet<string> | "all"; /** * Does this text bind `HOME` anywhere (or every name)? — the question a reader that spells the declared home for `~` / * `$HOME` asks of a text it reads as ONE unit (the read-only classifier's segments). The read station asks the * threaded question instead ({@link BindingThread}). */ export declare function textBindsHome(text: string): boolean; /** What a name holds at one point of a text, asked by name ({@link BindingTable.stateOf}). */ export type NameReader = (name: string) => NameState; /** What holds for the names where a nested text starts, given by the text around it: the attributes * ({@link NameAttribute}) and whether a name reference was declared — a substitution body starts with what may run * before its segment, a text run later or elsewhere (a code body, `eval`'s text, a child shell's `-c`) with all the * text around it gives. */ export interface InheritedNames { readonly attributes: readonly NameAttribute[]; readonly references: boolean; /** The deny floors a name starts the text with ({@link BindingTable.floorOf}): what the words handing it this text as * written may name there — or, for a substitution body, the floors its segment reads. */ readonly floors?: ReadonlyMap<string, readonly FloorValue[]>; /** The names something before the nested text may have changed — a change that can reach where it starts, and the * names its own segment's command environment sets (`TMPDIR=… bash -c …`): there such a name no longer holds what the * shell provides ({@link BindingTable.providedByShell}). `all`: any name. Absent: none. */ readonly rebound?: ReadonlySet<string> | "all"; } /** The function and builtin keys of the shell a text runs in — a literal `eval` text, a substitution body (a fork): what each key * holds where the text starts (the outer table's answer for it), and the names a call to one of the outer functions may change. */ export interface InheritedFunctions { readonly start: (key: string) => NameState; readonly bound: ReadonlySet<string> | "all"; } /** Two rebound sets as one. */ export declare function joinRebound(a: ReadonlySet<string> | "all" | undefined, b: Iterable<string> | "all" | undefined): ReadonlySet<string> | "all"; /** What the thread answers for one reader: what a name may hold, and whether a name carries the integer attribute. */ export interface BindingTable { stateOf(name: string): NameState; /** Values assigned to this name are evaluated as arithmetic. */ isInteger(name: string): boolean; /** The text may have changed `IFS` before this point: an unquoted expansion is split on what the text does not say. */ readonly ifsTouched: boolean; /** `HOME` may hold something other than the declared home here. */ readonly homeTouched: boolean; /** Every spelling any binding of this name before here left for the deny judge alone ({@link Binding.floor}). */ floorOf(name: string): readonly FloorValue[]; /** What a substitution body here starts with. */ readonly inherited: InheritedNames; /** The names a change that can reach this point touched — a binding, or a name made unknown, that may run before it in * this shell (the thread's order: {@link BindingThread}) — and the names its start says were rebound; `all`: any. */ readonly rebound: ReadonlySet<string> | "all"; /** Does this name still hold what the shell provides here: no change that can reach this point touched it? */ providedByShell(name: string): boolean; /** What a function of this name is here: the one ordered rule that answers a variable's value answers it * ({@link FunctionState}). A name the text never defines is `absent` to the caller's own filter, not to this thread. */ functionState(name: string): FunctionState; /** Whether the builtin of this name runs by it here: the same ordered rule ({@link BuiltinState}). */ builtinState(name: string): BuiltinState; } /** * The effects of a text's segments, threaded the way the plan threads its working directory: a reader at segment `j` * sees the latest binding of a name, and, where that binding may not have run before `j`, the bindings before it too. * A binding is CERTAIN for `j` when no block holding it (a branch, a loop, a group) closes or switches branch between it * and `j` — a block it precedes may come and go — its segment is no pipeline member, background job or prefix * assignment, and — reached through `&&` / `||` — it lies in `j`'s own `&&` run (`andRunStart`: the same index the * working-directory thread reads). * * A binding exists for a reader only where it may run before the reader IN THE SAME SHELL — the ordered state: one * written after the reader, one inside a subshell the reader is not in (a `( … )` group that closed before it, a * pipeline member that is not the last, a background job — a substitution body is a text of its own) and one in a * function body is NOT a binding for it. A function body runs at its call: a call the plan can see (a program word * naming one of the text's functions, a code body a builtin runs later, which may name one) makes every name a body * binds unknown from that segment on ({@link functionBound}); a text the plan does not read (`eval`, `source`, a * computed program word) already makes every name unknown. The last member of a pipeline may or may not run in this * shell: its bindings join the values before them. A body's own readers follow its own order; a reader in another body * loses a name any other body binds ({@link Unreadable}). A name the body declares with a plain `local` (before the * binding, where the declaration certainly ran) never leaves it. * * An attribute ({@link NameAttribute}) and a name reference hold for every segment they may RUN before — a later one, * one in a function body, one in the same loop body: an assignment there binds something other than its text. */ export declare class BindingThread { private readonly segments; /** What each segment binds, its names alone (a value is the reader's to read). */ private readonly named; /** The state a name starts the text in (and is reset to by a function body): the declared home for `HOME`. */ private readonly initial; /** Names any segment of the text binds (a function body run later reads a `HOME` bound anywhere as unknown). */ private readonly boundAnywhere; /** Each loop head's segment and its matching `done`'s. */ private readonly loops; /** `HOME` may already hold something other than the declared home where the text starts (a substitution body * inside a text that bound it). */ private readonly homeStartsTouched; /** The functions the shell that runs this text (a literal `eval` text) already holds. */ private readonly inheritedFunctions?; private readonly entries; /** The `local` declarations the walk applied as certain ({@link apply}), each where it stands. */ private readonly localDeclarations; /** The attributes the text gives ({@link BindingEffect.attributes}), and where — read off its names alone, before any * reader: one given later in the text may run first. */ private readonly attributesAt; /** Names no assignment makes readable again ({@link Unreadable}). */ private readonly unreadable; /** The block nesting each segment moves ({@link blockStructure}). */ private readonly blocks; /** Segments that END in a pipe or a `&`: the command that closes them is a pipeline member that is not the last, or a * background job — a subshell of its own ({@link ownSubshellAt}: which of the segment's bindings that is). */ private readonly ownSubshell; /** The floors the names start the text with ({@link InheritedNames.floors}). */ private readonly startFloors; /** The names rebound where the text starts ({@link InheritedNames.rebound}). */ private readonly startRebound; /** Where a function body runs ({@link runsBodies}): the last segment that can call one, and the command environment of each call. */ private bodyRuns; constructor(segments: readonly LexedSegment[], /** What each segment binds, its names alone (a value is the reader's to read). */ named: readonly BindingEffect[], /** The state a name starts the text in (and is reset to by a function body): the declared home for `HOME`. */ initial: (name: string) => NameState, /** Names any segment of the text binds (a function body run later reads a `HOME` bound anywhere as unknown). */ boundAnywhere: (name: string) => boolean, /** Each loop head's segment and its matching `done`'s. */ loops: ReadonlyMap<number, number>, /** `HOME` may already hold something other than the declared home where the text starts (a substitution body * inside a text that bound it). */ homeStartsTouched?: boolean, /** What holds where the text starts: given before its first segment. */ inherited?: InheritedNames, /** The functions the shell that runs this text (a literal `eval` text) already holds. */ inheritedFunctions?: InheritedFunctions | undefined); /** What a text nested at segment `j` starts with ({@link InheritedNames}) — `j` absent: a text run later, which every * segment may run before (in whatever shell: a later text may run inside a subshell or a body, so every change * counts). */ inheritedAt(j?: number): InheritedNames; /** What a name holds where the text starts: a function name unbound, a builtin enabled (what the shell around an `eval` text, a * substitution body or a text run later holds, if it says); a variable as the plan says. */ private startOf; /** Does any segment of this text bind the name (or every name)? */ private bindsInText; /** What a text this one runs at some later point (a `trap` action) finds each function and builtin key: the point is not ordered * against the segments (it may fire after any of them, inside any body or subshell), so a key holds what the text starts it with * and every value any segment binds it ({@link InheritedFunctions}). */ heldAnywhere(): InheritedFunctions; /** Tell the thread where function bodies run: `runs[si]` — segment `si` may run one (a call, a text the plan does not * read); `atEnd` — a code body may run at the text's end or at any point (`trap`); `environment[si]` — what a call's own * command environment sets. A call inside a loop may run again after a later segment of the loop. The last run point * bounds what can precede a body: a binding after it never does. A name a body that makes a call binds — `local` too: * the shell's scope is dynamic, the callee runs inside it — is unreadable to a reader in any other body. */ runsBodies(runs: readonly boolean[], atEnd: boolean, environment: readonly (ReadonlySet<string> | "all" | undefined)[]): void; /** The names a reader that runs LATER than it stands may find rebound by segments after it: a reader in a function body * runs at each call, so every segment up to the last run point (and a call's own command environment) may run before it; * a text handed to run later (`j` absent) at any point. A reader that runs where it stands has none: the effects the walk * has applied so far are the ones that precede it. A `local` counts like any binding: it shortens a name's life, not the * view of a reader that runs inside its extent (a body called from there, a `trap` text it sets). */ private boundLater; /** Does a binding segment `at` makes, standing at `standing`, run in a subshell of its own — a pipeline member that is * not the last, a background job? A segment's closing pipe or `&` ends ITS LAST command, at the depth that command * stands: a binding that stands shallower (a function definition's head, in front of the block its body opens in the * same segment: `f(){ ls | head; … }`) is not that member — the pipe closes a command inside the body, and the * definition is the shell's own. */ private ownSubshellAt; /** Is a binding segment `at` makes one no later reader may count on as certain: made in a pipeline member (it follows a * `|`, or it is {@link ownSubshellAt}) or a background job? */ private detachedAt; /** Can a binding segment `at` makes exist for a reader at segment `j` (`j` absent: a reader at the text's end, outside * every body and subshell)? Not where `at` stands in a function body the reader is not in (the body runs at its call), * runs in a subshell of its own (a pipeline member that is not the last, a background job), or stands in a `( … )` * group the reader is not in. */ private visible; /** Where the binding `name` of segment `at` is made: the segment's own place, or — a function definition — where its head * stands. */ private standingOf; /** The names any of the text's function bodies binds — what a call to one of them may change — or `all` where a body * may bind any name. A name the body keeps `local` ({@link leavesBody}) stays in it. */ functionBound(): ReadonlySet<string> | "all"; /** The function body a binding segment `at` makes belongs to, where the name can outlive it: the body it stands in — a * plain `local NAME` is the body's own and never leaves it (an optioned declaration, `declare -g` / `local -p`, reads no * scope, so it can). What a reader in ANOTHER body loses ({@link unreadableBy}); a call to the body changes it unless a * declaration the body certainly ran covers the name ({@link functionBound}). */ private bodyBinding; /** Does segment `at` stand in a function body (it runs at a call, not here)? */ inFunctionBody(at: number): boolean; /** Does segment `at` run in a subshell (a `( … )` group, a pipeline member that is not the last, a background job) or a * function body — whatever it changes, the shell that runs the next segment may not see? */ runsApart(at: number): boolean; /** Segment `at` hands this shell a body it runs at ANY later point (a `trap` action, an alias value): every name the * body may bind (`all`: any) is unreadable to every reader after `at`, whatever is assigned to it in between. */ runsLater(at: number, names: ReadonlySet<string> | "all"): void; /** What segment `at` makes unreadable: in a function body, the names it binds (a plain `local` stays in it) — every name * where it may bind any; a name reference, every name. Read before any segment is applied, so it does not ask which * declarations certainly ran: a name a body assigns after its own `local` is lost to a reader in another body all the same * (more questions, never fewer). */ private unreadableBy; /** May segment `x` run before segment `e` runs (`x` being `e`: before a later run of it): `x` comes first in the text, * `e` stands in a function body (the body runs at its call, after any segment, and may run again), or both stand in * one loop's body (a later beat runs `x` again first). */ private mayRunBefore; /** Did the body certainly declare this name `local` before segment `at`: an earlier segment of the body, run on its own * (no `&&` / `||`, no pipeline member or background job), in a block still open at `at`, whose declaration the walk * APPLIED as certain — the shell ran its word as the builtin: no function of that name standing, no launcher, path or * redirection in the way, and the builtin enabled where the body runs (what {@link bindingEffectOf} concluded, the ordered * state of {@link BindingTable.functionState} and {@link BindingTable.builtinState}; recorded by {@link apply}). */ private declaredLocal; /** Does the block that holds a binding's words stay open (no closing word, no switch of branch) through `j`? */ private heldThrough; /** Apply segment `at`'s effect. `andRun`: the segment was reached through `&&` / `||`. `loopEnd`: for a loop variable, * the index of the loop's end. */ apply(at: number, effect: BindingEffect, andRun: boolean, loopEnd?: number): void; /** Does a reader at segment `j` lose the name `u` makes unreadable: past a name reference it may run after, or in a * function body other than the one that binds it? */ private lostAt; /** Make these names unknown from segment `at` on (a loop body that binds them may have run before any of its beats; a * call runs a body that binds them). */ kill(at: number, names: Iterable<string> | "all"): void; /** The table a reader at segment `j` sees; `andRunStart` = the first segment of `j`'s `&&` run; `where` = what the * working-directory thread says `PWD` / `OLDPWD` hold there (absent: it does not say — both unknown). */ tableAt(j: number, andRunStart: number, where?: WorkingDirectoryState): BindingTable; } /** A segment that opens with `((`: an arithmetic command (or a subshell in a subshell — the tokens are the same). */ export declare function isArithmeticCommand(segment: LexedSegment): boolean; /** The `[[` operators whose operands the arithmetic evaluator reads (`[[ x -eq y ]]`; `[` / `test` compare integers * without evaluating them). */ export declare const ARITHMETIC_TEST_OPERATORS: ReadonlySet<string>; /** The substitutions a parameter expansion's body hands the arithmetic evaluator: its subscript (`${a[…]}`) and the * offset and length of a substring expansion (`${x:off:len}` — the shell expands them, then evaluates them). */ export declare function parameterBodySubstitutions(name: string, body: string, table: BindingTable | undefined): string[]; /** * The substitutions the shell's ARITHMETIC evaluator runs while it evaluates `text`: every `$(…)`, backquote or process * substitution inside an array SUBSCRIPT of it (`a[$(…)]` — quoted or not: the evaluator re-reads the text it is * handed), and — for each name the text refers to whose value the table holds — the same of that value (the evaluator * evaluates a variable's value as arithmetic too, through any chain of names). A name the table does not settle * contributes the literal values its bindings left (an array's elements) and nothing else: any other value is data the * text does not hold. A name already on the chain is a cycle (bash refuses * it). Each body is shell text the evaluator re-enters; past the reader's budget of values the text itself is handed * back as a body, so the segment re-enters text it did not follow (unestablished, never silent). */ export declare function arithmeticSubstitutions(text: string, table: BindingTable | undefined, chain?: ReadonlySet<string>, budget?: { left: number; }): string[]; /** The text of every `[…]` subscript in an arithmetic text (nested brackets balanced; an unclosed one runs to the end). */ export declare function subscriptsOf(text: string): string[];