@sema-agent/core 7.45.0 → 7.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +298 -1
- package/dist/agents/extra-tool-names.d.ts +65 -0
- package/dist/agents/extra-tool-names.js +124 -0
- package/dist/agents/subagent.d.ts +17 -5
- package/dist/agents/subagent.js +33 -25
- package/dist/agents/tool-filter.d.ts +17 -1
- package/dist/agents/tool-filter.js +7 -0
- package/dist/core/agent-config-dir.d.ts +20 -0
- package/dist/core/agent-config-dir.js +49 -0
- package/dist/core/allow-entry.d.ts +6 -4
- package/dist/core/allow-entry.js +6 -5
- package/dist/core/ask-origin.d.ts +35 -12
- package/dist/core/ask-origin.js +24 -7
- package/dist/core/checkpoint-store.d.ts +39 -2
- package/dist/core/effective-path-target.d.ts +136 -4
- package/dist/core/effective-path-target.js +110 -2
- package/dist/core/engine-notice.d.ts +12 -4
- package/dist/core/gate-fold.js +5 -2
- package/dist/core/gate-lanes.js +11 -4
- package/dist/core/gate-outcome.d.ts +4 -2
- package/dist/core/gate-outcome.js +2 -2
- package/dist/core/governance-codes.d.ts +3 -1
- package/dist/core/governance-codes.js +3 -0
- package/dist/core/hooks.d.ts +3 -0
- package/dist/core/path-rule-binding.d.ts +65 -0
- package/dist/core/path-rule-binding.js +99 -0
- package/dist/core/permission-rule-model.d.ts +59 -24
- package/dist/core/permission-rule-model.js +48 -44
- package/dist/core/permission-rule-provider.d.ts +7 -0
- package/dist/core/permission-rule-provider.js +10 -3
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +6 -2
- package/dist/core/permission-rule-sync.js +2 -2
- package/dist/core/permission-rules.d.ts +26 -45
- package/dist/core/permission-rules.js +77 -57
- package/dist/core/runner/child-tree.d.ts +97 -0
- package/dist/core/runner/child-tree.js +104 -0
- package/dist/core/runner/construction-doors.d.ts +5 -0
- package/dist/core/runner/construction-doors.js +6 -0
- package/dist/core/runner/contracts.d.ts +46 -0
- package/dist/core/runner/gate-exit.d.ts +4 -1
- package/dist/core/runner/gate-exit.js +5 -1
- package/dist/core/runner/permission-rule-lanes.d.ts +34 -25
- package/dist/core/runner/permission-rule-lanes.js +18 -12
- package/dist/core/runner/persisted-path-rows.d.ts +31 -7
- package/dist/core/runner/persisted-path-rows.js +31 -12
- package/dist/core/runner/prepare-ask-lane.d.ts +4 -0
- package/dist/core/runner/prepare-ask-lane.js +4 -2
- package/dist/core/runner/prepare-execution-env.d.ts +5 -2
- package/dist/core/runner/prepare-execution-env.js +10 -3
- package/dist/core/runner/prepare-gate-stations.d.ts +3 -0
- package/dist/core/runner/prepare-gate-stations.js +2 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +8 -4
- package/dist/core/runner/prepare-hands-readface.js +11 -11
- package/dist/core/runner/prepare-inherited-gate.d.ts +8 -1
- package/dist/core/runner/prepare-inherited-gate.js +8 -2
- package/dist/core/runner/prepare-park-ask.d.ts +3 -0
- package/dist/core/runner/prepare-park-ask.js +5 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +14 -2
- package/dist/core/runner/prepare-policy-chain.js +13 -5
- package/dist/core/runner/prepare-suspend-saga.d.ts +10 -0
- package/dist/core/runner/prepare-suspend-saga.js +7 -1
- package/dist/core/runner/prepare-task.js +37 -18
- package/dist/core/runner/prepare-turn-wiring.d.ts +2 -0
- package/dist/core/runner/prepare-turn-wiring.js +2 -1
- package/dist/core/runner/prepare-workspace-restore.d.ts +3 -0
- package/dist/core/runner/prepare-workspace-restore.js +1 -0
- package/dist/core/runner/resume-apply.js +17 -3
- package/dist/core/runner/resume-checkpoint-screen.js +13 -0
- package/dist/core/runner/run-leg.js +5 -1
- package/dist/core/runner/runtask.js +2 -2
- package/dist/core/runner/sub-agent-deny-lists.d.ts +1 -1
- package/dist/core/runner/write-protection-station.d.ts +3 -2
- package/dist/core/runner/write-protection-station.js +1 -0
- package/dist/core/runner-deps.d.ts +14 -0
- package/dist/core/sensitive-path-policy.d.ts +8 -0
- package/dist/core/sensitive-path-policy.js +18 -2
- package/dist/core/shell-wrapper-projection.d.ts +11 -0
- package/dist/core/shell-wrapper-projection.js +56 -0
- package/dist/core/shell-wrapper-table.d.ts +144 -34
- package/dist/core/shell-wrapper-table.js +40 -20
- package/dist/core/synthetic-read-verdict.d.ts +3 -0
- package/dist/core/synthetic-read-verdict.js +3 -1
- package/dist/core/tool-catalog-entries.d.ts +21 -0
- package/dist/core/tool-catalog-entries.js +12 -2
- package/dist/core/tool-face.d.ts +10 -1
- package/dist/core/tool-name-readings.d.ts +8 -0
- package/dist/core/tool-name-readings.js +2 -0
- package/dist/core/tool-policy.d.ts +40 -17
- package/dist/core/tool-policy.js +11 -9
- package/dist/core/tool-registry.d.ts +9 -0
- package/dist/core/tool-registry.js +10 -0
- package/dist/core/tool-spec.d.ts +3 -2
- package/dist/core/write-protect.d.ts +14 -3
- package/dist/core/write-protect.js +41 -10
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -3
- package/dist/orchestration/run-spec.js +8 -7
- package/dist/orchestration/workflow.js +1 -1
- package/dist/shell/lex.d.ts +22 -0
- package/dist/shell/lex.js +75 -13
- package/dist/tools/fs/bash-program-position.d.ts +14 -90
- package/dist/tools/fs/bash-program-position.js +41 -74
- package/dist/tools/fs/bash-readonly-classifier.d.ts +17 -444
- package/dist/tools/fs/bash-readonly-classifier.js +169 -1225
- package/dist/tools/fs/index.d.ts +3 -2
- package/dist/tools/fs/program-read-model.d.ts +711 -0
- package/dist/tools/fs/program-read-model.js +1259 -0
- package/dist/tools/fs/program-read-model.rows.d.ts +18 -0
- package/dist/tools/fs/program-read-model.rows.js +624 -0
- package/dist/tools/fs/read-deny-home.d.ts +19 -1
- package/dist/tools/fs/read-deny-home.js +62 -24
- package/dist/tools/fs/read-deny.d.ts +54 -14
- package/dist/tools/fs/read-deny.js +104 -50
- package/dist/tools/fs/removal-targets.d.ts +7 -6
- package/dist/tools/fs/removal-targets.js +34 -24
- package/dist/tools/fs/safety.d.ts +3 -0
- package/dist/tools/fs/safety.js +10 -3
- package/dist/tools/fs/shell-read-argv.d.ts +86 -0
- package/dist/tools/fs/shell-read-argv.js +388 -0
- package/dist/tools/fs/shell-read-bindings.d.ts +300 -0
- package/dist/tools/fs/shell-read-bindings.js +755 -0
- package/dist/tools/fs/shell-read-check.js +23 -15
- package/dist/tools/fs/shell-read-establish.js +82 -8
- package/dist/tools/fs/shell-read-judge.d.ts +11 -1
- package/dist/tools/fs/shell-read-judge.js +9 -1
- package/dist/tools/fs/shell-read-plan.d.ts +33 -8
- package/dist/tools/fs/shell-read-plan.js +309 -407
- package/dist/tools/fs/shell-read-word.d.ts +60 -26
- package/dist/tools/fs/shell-read-word.js +47 -37
- package/dist/tools/fs/shell-read-write-targets.d.ts +15 -64
- package/dist/tools/fs/shell-read-write-targets.js +85 -137
- package/dist/tools/fs/shell-reentry-text.d.ts +136 -6
- package/dist/tools/fs/shell-reentry-text.js +203 -53
- package/dist/tools/monitor.d.ts +3 -3
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +25 -5
- package/wire-changes/core@7.46.0.json +1522 -0
- package/wire-changes/core@7.47.0.json +412 -0
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { lexShell, PARSE_FAILURE_SENTENCE, substitutionsInHeredocBody, literalTildeSpelling, } from "../../shell/lex.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { lexShell, PARSE_FAILURE_SENTENCE, substitutionsInHeredocBody, literalTextOf, literalTildeSpelling, } from "../../shell/lex.js";
|
|
2
|
+
import { programTextOf, readOfText, readsOf, renamed, rewritten, settledFieldsOf, spelledWithHome, isArithmeticBody, unreadableSentenceOf } from "./shell-read-word.js";
|
|
3
|
+
import { assignmentArithmetic, bare, listedVerbCandidates, pathSubcommandOf, programTextSentence, pushAssignment, roleReads, subscriptOnly, unlistedWords } from "./shell-read-argv.js";
|
|
4
|
+
import { ARITHMETIC_TEST_OPERATORS, BindingThread, arithmeticSubstitutions, isArithmeticCommand, bindingEffectOf, parameterBodySubstitutions, projectSegment, valueOf, } from "./shell-read-bindings.js";
|
|
5
|
+
import { programBasename, programPositionRunsShell, readProgramPosition, shellScanDeclineOf, } from "./bash-program-position.js";
|
|
6
|
+
import { POLL_LOOP_MAX_BEATS, attachedOptionPayloads, resolveOperandLexically, isPathShapedToken, programTextSlotFiles, } from "./bash-readonly-classifier.js";
|
|
7
|
+
import { BLOCK_WORD_NAMES, commandLineOptionSpellings, declaredAttributes, isDeclarationBuiltin, isInertBuiltin, launcherOptionPathRole, launcherOptionStep, readOptionRole, programLanguageOf, programTextOpensOf, selectedOptions, movesBaseUnfollowed, opensNoOperand, programDelivery, programRow, readArgRoles, runsShellText, } from "./program-read-model.js";
|
|
5
8
|
import { isAbsolutePathForm } from "./safety.js";
|
|
6
|
-
import { codeBodies, reentryText } from "./shell-reentry-text.js";
|
|
9
|
+
import { codeBodies, launchedInput, pipedTextOf, reentryText, scriptFileAt, stdinTextsOf } from "./shell-reentry-text.js";
|
|
7
10
|
export const READ_CANDIDATE_PROVENANCES = Object.freeze([
|
|
8
11
|
"operand",
|
|
9
12
|
"option_value",
|
|
@@ -15,28 +18,52 @@ export const READ_CANDIDATE_PROVENANCES = Object.freeze([
|
|
|
15
18
|
"cd_target",
|
|
16
19
|
"program_path",
|
|
17
20
|
"script_slot_file",
|
|
21
|
+
"mount_source",
|
|
22
|
+
"object_path",
|
|
18
23
|
]);
|
|
19
24
|
const NESTING_MAX = 4;
|
|
20
25
|
const BASE_CANDIDATE_MAX = 256;
|
|
21
|
-
export function planShellReads(command, decl, depth = 0,
|
|
26
|
+
export function planShellReads(command, decl, depth = 0, start) {
|
|
22
27
|
const shape = { grouped: false, backgrounded: false, strayRedirection: false };
|
|
23
28
|
if (depth > NESTING_MAX)
|
|
24
29
|
return { segments: [], unreadable: `command text nested more than ${NESTING_MAX} levels deep`, shape };
|
|
25
30
|
const lexed = lexShell(command);
|
|
26
31
|
if ("parseFailure" in lexed)
|
|
27
32
|
return { segments: [], unreadable: PARSE_FAILURE_SENTENCE[lexed.parseFailure.reason], shape };
|
|
28
|
-
const
|
|
29
|
-
const unreadable = unreadableSentenceOf(lexed, command, !arithmetic);
|
|
30
|
-
const nestedPlan = (text, arithmetic = false) => planShellReads(text, decl, depth + 1, home === undefined, arithmetic);
|
|
33
|
+
const unreadable = unreadableSentenceOf(lexed, command);
|
|
31
34
|
const projected = lexed.segments.map((segment) => projectSegment(segment));
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
35
|
+
const named = projected.map((p, si) => bindingEffectOf(lexed.segments[si], p.argv, p, () => "unknown"));
|
|
36
|
+
const boundHere = (name) => named.some((e) => e.all === "unknown" || e.bindings.some((b) => b.name === name));
|
|
37
|
+
const boundAnywhere = (name) => boundHere(name) || start?.boundAnywhere(name) === true;
|
|
38
|
+
const declaredHome = decl.homeDir !== undefined ? [{ spelled: decl.homeDir }] : "unknown";
|
|
39
|
+
const initial = start?.initial ?? ((name) => (name === "HOME" ? declaredHome : "unknown"));
|
|
40
|
+
const loopShapes = projected.map((p) => loopShapeOf(p));
|
|
41
|
+
const loopEndOf = new Map();
|
|
42
|
+
{
|
|
43
|
+
const open = [];
|
|
44
|
+
loopShapes.forEach((l, si) => {
|
|
45
|
+
if (l === "head")
|
|
46
|
+
open.push(si);
|
|
47
|
+
else if (l === "end") {
|
|
48
|
+
const h = open.pop();
|
|
49
|
+
if (h !== undefined)
|
|
50
|
+
loopEndOf.set(h, si);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const names = new BindingThread(lexed.segments, named, initial, boundAnywhere, loopEndOf, start?.homeTouched === true, start?.inherited);
|
|
55
|
+
const laterStart = { initial: (name) => (name === "HOME" && !boundAnywhere("HOME") ? declaredHome : "unknown"), boundAnywhere, homeTouched: boundAnywhere("HOME"), inherited: names.inheritedAt() };
|
|
56
|
+
const nestedPlanner = (table) => (text, kind) => planShellReads(text, decl, depth + 1, kind === "substitution" ? { initial: (name) => table.stateOf(name), boundAnywhere, homeTouched: table.homeTouched, inherited: table.inherited } : laterStart);
|
|
57
|
+
const empty = lexed.segments.map((segment, si) => segmentIsEmpty(segment, projected[si]));
|
|
58
|
+
const facts = projected.map(() => undefined);
|
|
59
|
+
const tables = projected.map(() => undefined);
|
|
60
|
+
const factsAt = (si, table) => {
|
|
61
|
+
tables[si] ??= table;
|
|
62
|
+
const piped = si > 0 && lexed.segments[si].connector === "|" ? pipedTextOf(lexed.segments[si - 1], projected[si - 1].argv) : undefined;
|
|
63
|
+
return (facts[si] ??= segmentFacts(lexed.segments[si], projected[si], decl, table, nestedPlanner(table), piped));
|
|
64
|
+
};
|
|
65
|
+
const basesOf = projected.map(() => new Set());
|
|
66
|
+
const unmodelled = projected.map(() => false);
|
|
40
67
|
let candidates = [{ base: decl.cwd, skippedCd: -1 }];
|
|
41
68
|
let baseLost = false;
|
|
42
69
|
let floorBases;
|
|
@@ -48,22 +75,25 @@ export function planShellReads(command, decl, depth = 0, homeRebound = false, ar
|
|
|
48
75
|
let crossedAllAnd = true;
|
|
49
76
|
let crossedAnyOr = false;
|
|
50
77
|
let previousEmitted = -1;
|
|
51
|
-
const reaches =
|
|
78
|
+
const reaches = projected.map(() => undefined);
|
|
52
79
|
const loops = [];
|
|
53
80
|
const thread = (si, replay) => {
|
|
54
|
-
const
|
|
81
|
+
const connector = lexed.segments[si].connector;
|
|
55
82
|
if (previousEmitted >= 0) {
|
|
56
|
-
const connector = f.connector;
|
|
57
83
|
if (replay || connector !== "&&")
|
|
58
84
|
crossedAllAnd = false;
|
|
59
85
|
if (!replay && connector === "||")
|
|
60
86
|
crossedAnyOr = true;
|
|
61
87
|
}
|
|
62
|
-
if (
|
|
88
|
+
if (empty[si]) {
|
|
89
|
+
if (!replay)
|
|
90
|
+
factsAt(si, names.tableAt(si, andRunStart));
|
|
63
91
|
return;
|
|
92
|
+
}
|
|
64
93
|
if (previousEmitted >= 0 && !crossedAllAnd)
|
|
65
94
|
andRunStart = crossedAnyOr ? si + 1 : si;
|
|
66
|
-
const
|
|
95
|
+
const f = replay ? facts[si] : factsAt(si, names.tableAt(si, andRunStart));
|
|
96
|
+
const pipeFed = f.connector === "|" || lexed.segments[si + 1]?.connector === "|";
|
|
67
97
|
reaches[si] ??= { andJoined: previousEmitted >= 0 && crossedAllAnd, orBroken: !crossedAllAnd && crossedAnyOr, moveProvable: f.moveProvable && !replay && !pipeFed };
|
|
68
98
|
crossedAllAnd = true;
|
|
69
99
|
crossedAnyOr = false;
|
|
@@ -107,46 +137,67 @@ export function planShellReads(command, decl, depth = 0, homeRebound = false, ar
|
|
|
107
137
|
else
|
|
108
138
|
candidates = next;
|
|
109
139
|
};
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
140
|
+
const bind = (si) => {
|
|
141
|
+
const table = tables[si];
|
|
142
|
+
if (table === undefined)
|
|
143
|
+
return;
|
|
144
|
+
const end = loopEndOf.get(si);
|
|
145
|
+
if (end !== undefined) {
|
|
146
|
+
const body = named.slice(si + 1, end);
|
|
147
|
+
names.kill(si, body.some((e) => e.all === "unknown") ? "all" : body.flatMap((e) => e.bindings.map((b) => b.name)));
|
|
148
|
+
}
|
|
149
|
+
const segment = lexed.segments[si];
|
|
150
|
+
const effect = bindingEffectOf(segment, projected[si].argv, projected[si], (w, quoted, overlay) => valueOf(w, table, quoted, overlay));
|
|
151
|
+
const { all, ...rest } = effect;
|
|
152
|
+
names.apply(si, all === "reset" ? rest : effect, segment.connector === "&&" || segment.connector === "||", end);
|
|
153
|
+
};
|
|
154
|
+
for (let si = 0; si < projected.length; si++) {
|
|
155
|
+
const shapeOfLoop = loopShapes[si];
|
|
156
|
+
if (named[si].all === "reset")
|
|
157
|
+
names.apply(si, { bindings: [], all: "reset" }, false);
|
|
158
|
+
thread(si, false);
|
|
159
|
+
bind(si);
|
|
160
|
+
if (shapeOfLoop === "head") {
|
|
161
|
+
loops.push({ bodyStart: si + 1, beats: facts[si].loopHead?.beats });
|
|
115
162
|
continue;
|
|
116
163
|
}
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
for (let beat = 1; beat < frame.beats && !baseLost; beat++) {
|
|
133
|
-
for (let k = frame.bodyStart; k < si; k++)
|
|
134
|
-
thread(k, true);
|
|
135
|
-
}
|
|
164
|
+
if (shapeOfLoop !== "end")
|
|
165
|
+
continue;
|
|
166
|
+
const frame = loops.pop();
|
|
167
|
+
if (frame === undefined)
|
|
168
|
+
continue;
|
|
169
|
+
const body = facts.slice(frame.bodyStart, si);
|
|
170
|
+
const moves = body.some((b) => b?.baseMove !== undefined);
|
|
171
|
+
if (!moves)
|
|
172
|
+
continue;
|
|
173
|
+
if (frame.beats === undefined) {
|
|
174
|
+
for (let k = frame.bodyStart; k < si; k++)
|
|
175
|
+
unmodelled[k] = true;
|
|
176
|
+
loseBase(candidates.filter((c) => c.skippedCd < andRunStart));
|
|
136
177
|
continue;
|
|
137
178
|
}
|
|
138
|
-
|
|
179
|
+
for (let beat = 1; beat < frame.beats && !baseLost; beat++) {
|
|
180
|
+
for (let k = frame.bodyStart; k < si; k++)
|
|
181
|
+
thread(k, true);
|
|
182
|
+
}
|
|
139
183
|
}
|
|
184
|
+
const planned = facts.map((f) => f);
|
|
185
|
+
const inert = depth === 0 && unreadable === undefined && planned.every(segmentOpensNothing);
|
|
186
|
+
const settled = inert ? planned.map((f) => ({ ...f, reads: f.reads.filter((c) => c.provenance !== "env_assignment") })) : planned;
|
|
187
|
+
shape.grouped = projected.some((p) => p.grouped);
|
|
188
|
+
shape.backgrounded = lexed.segments.some((s) => s.connector === "&") || settled.some((f) => f.backgrounds === true);
|
|
189
|
+
shape.strayRedirection = projected.some((p) => p.argv.length === 0 && p.redirects.length > 0);
|
|
140
190
|
const segments = [];
|
|
141
|
-
for (let si = 0; si <
|
|
142
|
-
const f =
|
|
191
|
+
for (let si = 0; si < settled.length; si++) {
|
|
192
|
+
const f = settled[si];
|
|
143
193
|
if (f.empty)
|
|
144
194
|
continue;
|
|
145
195
|
const bases = unmodelled[si] ? "unmodelled" : [...basesOf[si]];
|
|
146
196
|
const floor = unmodelled[si] && floorBases !== undefined && floorBases.length > 0 ? floorBases : undefined;
|
|
147
197
|
const withBases = (c) => {
|
|
148
198
|
const relative = relativeSpelling(c.spelled);
|
|
149
|
-
|
|
199
|
+
const here = c.provenance === "object_path" && bases !== "unmodelled" ? [...new Set(bases.flatMap(ancestorsOf))] : bases;
|
|
200
|
+
return { ...c, bases: relative ? here : [], ...(relative && floor !== undefined ? { floorBases: floor } : {}) };
|
|
150
201
|
};
|
|
151
202
|
segments.push({
|
|
152
203
|
text: f.text,
|
|
@@ -156,6 +207,7 @@ export function planShellReads(command, decl, depth = 0, homeRebound = false, ar
|
|
|
156
207
|
...(f.verb !== undefined ? { verb: f.verb } : {}),
|
|
157
208
|
...(f.reentry !== undefined ? { reentry: f.reentry } : {}),
|
|
158
209
|
...(f.unreadProgramText !== undefined ? { unreadProgramText: f.unreadProgramText } : {}),
|
|
210
|
+
...(f.stdin !== undefined ? { stdin: f.stdin } : {}),
|
|
159
211
|
declines: f.declines,
|
|
160
212
|
reads: dedupe(f.reads).map(withBases),
|
|
161
213
|
redirects: f.redirects.map((r) => (r.target === undefined ? { op: r.op, direction: r.direction } : { op: r.op, direction: r.direction, target: withBases(r.target) })),
|
|
@@ -167,57 +219,88 @@ export function planShellReads(command, decl, depth = 0, homeRebound = false, ar
|
|
|
167
219
|
}
|
|
168
220
|
return { segments, shape, ...(unreadable !== undefined ? { unreadable } : {}) };
|
|
169
221
|
}
|
|
222
|
+
function ancestorsOf(dir) {
|
|
223
|
+
const out = [dir];
|
|
224
|
+
for (let d = dir, up = parentOf(d); up !== d; d = up, up = parentOf(d))
|
|
225
|
+
out.push(up);
|
|
226
|
+
return out;
|
|
227
|
+
}
|
|
228
|
+
function parentOf(dir) {
|
|
229
|
+
return resolveOperandLexically(dir, "..", undefined) ?? dir;
|
|
230
|
+
}
|
|
231
|
+
function loopShapeOf(p) {
|
|
232
|
+
const head = p.argv[0];
|
|
233
|
+
if (head === undefined)
|
|
234
|
+
return undefined;
|
|
235
|
+
if (head.raw === head.folded && (head.folded === "for" || head.folded === "select") && BLOCK_WORD_NAMES.has(head.folded))
|
|
236
|
+
return "head";
|
|
237
|
+
if (head.raw === head.folded && head.folded === "done" && BLOCK_WORD_NAMES.has(head.folded))
|
|
238
|
+
return "end";
|
|
239
|
+
const pos = readProgramPosition(p.argv);
|
|
240
|
+
return pos.controlWords.some((i) => p.argv[i].folded === "while" || p.argv[i].folded === "until") ? "head" : undefined;
|
|
241
|
+
}
|
|
242
|
+
function segmentIsEmpty(segment, p) {
|
|
243
|
+
if (p.argv.length > 0 || p.redirects.length > 0 || segment.substitutions.length > 0)
|
|
244
|
+
return false;
|
|
245
|
+
return !segment.tokens.some((t) => t.kind === "heredoc" && !t.quoted && (substitutionsInHeredocBody(t.body)?.length ?? 1) > 0);
|
|
246
|
+
}
|
|
170
247
|
function segmentOpensNothing(f) {
|
|
171
248
|
if (f.empty)
|
|
172
249
|
return true;
|
|
173
250
|
const program = f.verb;
|
|
174
251
|
const at = program === undefined ? -1 : f.argv.findIndex((w) => w.folded === program.name);
|
|
175
|
-
const inertProgram = program === undefined || (program.name === program.basename &&
|
|
252
|
+
const inertProgram = program === undefined || (program.name === program.basename && isInertBuiltin(program.basename) && !(isDeclarationBuiltin(program.basename) && f.argv.slice(at + 1).some((w) => /^[-+]/.test(w.folded))));
|
|
176
253
|
return inertProgram && f.argv.every((w) => !/[[\]$`]/.test(w.raw)) && f.nested.length === 0 && f.reentry === undefined && f.declines.length === 0 && f.launcherChain.length === 0 && f.redirects.every((r) => r.direction !== "in") && f.reads.every((c) => c.provenance === "env_assignment");
|
|
177
254
|
}
|
|
178
|
-
function
|
|
179
|
-
const
|
|
180
|
-
let grouped = tokens.some((t) => t.kind === "group");
|
|
181
|
-
dropDefinitionHeads(tokens);
|
|
182
|
-
const words = tokens.filter((t) => {
|
|
183
|
-
if (t.kind !== "word")
|
|
184
|
-
return false;
|
|
185
|
-
if (t.raw === t.folded && (t.folded === "{" || t.folded === "}")) {
|
|
186
|
-
grouped = true;
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
return true;
|
|
190
|
-
});
|
|
191
|
-
return {
|
|
192
|
-
argv: words,
|
|
193
|
-
redirects: tokens.filter((t) => t.kind === "redirect"),
|
|
194
|
-
grouped,
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
function segmentFacts(segment, p, decl, home, nestedPlan) {
|
|
198
|
-
const facts = segmentFactsRead(segment, p, decl, home, nestedPlan);
|
|
255
|
+
function segmentFacts(segment, p, decl, table, nestedPlan, piped) {
|
|
256
|
+
const facts = segmentFactsRead(segment, p, decl, table, nestedPlan, piped);
|
|
199
257
|
const unresolvedRaw = new Set();
|
|
200
258
|
for (const t of segment.tokens) {
|
|
201
259
|
const w = t.kind === "word" ? t : t.kind === "redirect" ? t.target : undefined;
|
|
202
260
|
if (w !== undefined && w.pieces.some((p) => p.literal === undefined && p.expansion === undefined))
|
|
203
261
|
unresolvedRaw.add(w.raw);
|
|
204
262
|
}
|
|
205
|
-
const homeWithheld =
|
|
206
|
-
const floor = (c) => {
|
|
263
|
+
const homeWithheld = decl.homeDir !== undefined && table.stateOf("HOME") === "unknown";
|
|
264
|
+
const floor = (c) => {
|
|
265
|
+
if (c.floorSpelled !== undefined)
|
|
266
|
+
return c;
|
|
267
|
+
const f = (c.expands === "unresolvable" || c.spelled.startsWith("./~")) && decl.homeDir !== undefined ? spelledWithHome(c.spelled, c.raw, decl.homeDir) : undefined;
|
|
268
|
+
return f === undefined ? c : { ...c, floorSpelled: f };
|
|
269
|
+
};
|
|
207
270
|
const unsettle = (c) => floor((unresolvedRaw.has(c.raw) || (homeWithheld && c.spelled.startsWith("~"))) && c.expands !== "unresolvable" ? { ...c, expands: "unresolvable" } : c);
|
|
271
|
+
const each = (c) => {
|
|
272
|
+
const { alternatives, floors, ...one } = c;
|
|
273
|
+
const shadows = (floors ?? []).map((v) => ({ spelled: v.spelled, raw: one.raw, provenance: one.provenance, expands: v.glob === true ? "glob" : false, denyOnly: true }));
|
|
274
|
+
return [...[one, ...(alternatives ?? []).map((a) => ({ ...renamed(one, a.spelled), ...a }))].map(unsettle), ...shadows];
|
|
275
|
+
};
|
|
208
276
|
const move = facts.baseMove;
|
|
209
277
|
return {
|
|
210
278
|
...facts,
|
|
211
|
-
reads: facts.reads.
|
|
212
|
-
|
|
279
|
+
reads: facts.reads.flatMap(each),
|
|
280
|
+
redirects: facts.redirects.map((r) => (r.target === undefined ? r : { ...r, target: unsettle(r.target) })),
|
|
281
|
+
...(move !== undefined && typeof move.target !== "string" ? { baseMove: { target: unsettle(move.target.alternatives !== undefined ? { ...each(move.target)[0], expands: "unresolvable" } : move.target) } } : {}),
|
|
213
282
|
};
|
|
214
283
|
}
|
|
215
|
-
function segmentFactsRead(segment, p, decl,
|
|
284
|
+
function segmentFactsRead(segment, p, decl, table, nestedPlan, piped) {
|
|
216
285
|
const nested = [];
|
|
286
|
+
const ctx = { table, reentered: [], programTextSeen: false };
|
|
217
287
|
const arithmetic = segment.tokens.flatMap((t) => (t.kind === "word" ? t : t.kind === "redirect" ? t.target : undefined)?.pieces ?? []).flatMap((q) => (q.expansion?.kind === "arithmetic" && q.expansion.body !== undefined && isArithmeticBody(q.expansion.body) ? [q.expansion.body] : []));
|
|
218
288
|
const count = (list, body) => list.filter((b) => b === body).length;
|
|
219
|
-
|
|
220
|
-
|
|
289
|
+
const arithmeticBody = (body) => {
|
|
290
|
+
const l = lexShell(body);
|
|
291
|
+
if ("parseFailure" in l)
|
|
292
|
+
nested.push(nestedPlan(body, "substitution"));
|
|
293
|
+
else
|
|
294
|
+
for (const s of l.segments.flatMap((sg) => sg.substitutions))
|
|
295
|
+
nested.push(nestedPlan(s, "substitution"));
|
|
296
|
+
ctx.reentered.push(...arithmeticSubstitutions(body, table));
|
|
297
|
+
};
|
|
298
|
+
for (const body of segment.substitutions) {
|
|
299
|
+
if (count(arithmetic, body) > 0 && count(arithmetic, body) === count(segment.substitutions, body))
|
|
300
|
+
arithmeticBody(body);
|
|
301
|
+
else
|
|
302
|
+
nested.push(nestedPlan(body, "substitution"));
|
|
303
|
+
}
|
|
221
304
|
let unreadableHeredoc = false;
|
|
222
305
|
for (const t of segment.tokens) {
|
|
223
306
|
if (t.kind !== "heredoc" || t.quoted)
|
|
@@ -227,12 +310,24 @@ function segmentFactsRead(segment, p, decl, home, nestedPlan) {
|
|
|
227
310
|
unreadableHeredoc = true;
|
|
228
311
|
continue;
|
|
229
312
|
}
|
|
230
|
-
for (const s of inner)
|
|
231
|
-
|
|
313
|
+
for (const s of inner) {
|
|
314
|
+
if (s.kind === "arithmetic" && isArithmeticBody(s.body))
|
|
315
|
+
arithmeticBody(s.body);
|
|
316
|
+
else
|
|
317
|
+
nested.push(nestedPlan(s.body, "substitution"));
|
|
318
|
+
}
|
|
232
319
|
}
|
|
233
320
|
if (unreadableHeredoc)
|
|
234
321
|
nested.push({ segments: [], unreadable: "a here-document body carries a substitution this lexer cannot delimit", shape: { grouped: false, backgrounded: false, strayRedirection: false } });
|
|
235
|
-
|
|
322
|
+
if (isArithmeticCommand(segment))
|
|
323
|
+
ctx.reentered.push(...arithmeticSubstitutions(p.argv.map((w) => w.folded).join(" "), table));
|
|
324
|
+
for (const t of segment.tokens) {
|
|
325
|
+
const w = t.kind === "word" ? t : t.kind === "redirect" ? t.target : undefined;
|
|
326
|
+
for (const q of w?.pieces ?? [])
|
|
327
|
+
if (q.expansion?.kind === "parameter" && q.expansion.name !== undefined && q.expansion.body !== undefined)
|
|
328
|
+
ctx.reentered.push(...parameterBodySubstitutions(q.expansion.name, q.expansion.body, table));
|
|
329
|
+
}
|
|
330
|
+
const redirects = p.redirects.map((r) => redirectFact(r, table, decl.homeDir));
|
|
236
331
|
const reads = [];
|
|
237
332
|
for (const r of redirects)
|
|
238
333
|
if (r.direction === "in" && r.target !== undefined)
|
|
@@ -244,42 +339,60 @@ function segmentFactsRead(segment, p, decl, home, nestedPlan) {
|
|
|
244
339
|
redirects,
|
|
245
340
|
nested,
|
|
246
341
|
};
|
|
247
|
-
const toks = readsOf(p.argv,
|
|
342
|
+
const toks = readsOf(p.argv, table, decl.homeDir);
|
|
343
|
+
const done = (f) => {
|
|
344
|
+
const reentered = [...new Set(ctx.reentered)];
|
|
345
|
+
for (const body of reentered)
|
|
346
|
+
nested.push(nestedPlan(body, "later"));
|
|
347
|
+
return {
|
|
348
|
+
...base,
|
|
349
|
+
...f,
|
|
350
|
+
...(reentered.length > 0 ? { reentry: "shell" } : {}),
|
|
351
|
+
...(f.unreadProgramText === undefined && ctx.programText !== undefined ? { unreadProgramText: ctx.programText } : {}),
|
|
352
|
+
};
|
|
353
|
+
};
|
|
248
354
|
const head = toks[0]?.folded;
|
|
249
355
|
if (head === "coproc" && toks[0].raw === head && toks.length > 1) {
|
|
250
|
-
const tail = (from) => ({ argv: p.argv.slice(from)
|
|
251
|
-
const first = segmentFacts(segment, tail(1), decl,
|
|
356
|
+
const tail = (from) => ({ ...p, argv: p.argv.slice(from) });
|
|
357
|
+
const first = segmentFacts(segment, tail(1), decl, table, nestedPlan, piped);
|
|
252
358
|
if (toks.length < 3)
|
|
253
359
|
return { ...first, backgrounds: true };
|
|
254
|
-
const second = segmentFacts(segment, tail(2), decl,
|
|
360
|
+
const second = segmentFacts(segment, tail(2), decl, table, nestedPlan, piped);
|
|
255
361
|
const seen = new Set(first.nested.map((n) => JSON.stringify(n.segments.map((sg) => sg.text))));
|
|
256
362
|
const extraNested = second.nested.filter((n) => !seen.has(JSON.stringify(n.segments.map((sg) => sg.text))));
|
|
257
363
|
return { ...first, ...(second.reentry === "shell" ? { reentry: second.reentry } : {}), reads: [...first.reads, ...second.reads], nested: [...first.nested, ...extraNested], backgrounds: true };
|
|
258
364
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
365
|
+
const loop = loopShapeOf(p);
|
|
366
|
+
if (head !== undefined && toks[0].raw === head && BLOCK_WORD_NAMES.has(head)) {
|
|
367
|
+
if (loop === "head")
|
|
368
|
+
return done({ empty: false, launcherChain: [], declines: [], reads, moveProvable: false, loopHead: { beats: literalBeats(toks) } });
|
|
369
|
+
if (head === "[[") {
|
|
370
|
+
toks.forEach((r, i) => {
|
|
371
|
+
if (ARITHMETIC_TEST_OPERATORS.has(toks[i - 1]?.folded ?? "") || ARITHMETIC_TEST_OPERATORS.has(toks[i + 1]?.folded ?? "") || toks[i - 1]?.folded === "-v")
|
|
372
|
+
ctx.reentered.push(...arithmeticSubstitutions(r.folded, table));
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
return done({ empty: false, launcherChain: [], declines: [], reads, moveProvable: false });
|
|
265
376
|
}
|
|
266
377
|
const pos = readProgramPosition(p.argv);
|
|
267
378
|
const written = pos.written;
|
|
268
379
|
if (written === undefined)
|
|
269
|
-
return {
|
|
270
|
-
const loopHead =
|
|
380
|
+
return done({ empty: segmentIsEmpty(segment, p), launcherChain: [], declines: [], reads, moveProvable: false });
|
|
381
|
+
const loopHead = loop === "head" ? { beats: undefined } : undefined;
|
|
271
382
|
const launcherChain = pos.launchers.map((l) => l.name);
|
|
272
383
|
const launcherIndices = new Set(pos.launchers.map((l) => l.index));
|
|
273
384
|
const declines = [];
|
|
274
|
-
const decline = shellScanDeclineOf(pos,
|
|
385
|
+
const decline = shellScanDeclineOf(pos, opensNoOperand);
|
|
275
386
|
if (decline !== undefined)
|
|
276
387
|
declines.push(decline);
|
|
277
388
|
const program = pos.program;
|
|
278
389
|
const basename = program?.basename;
|
|
279
390
|
const listed = basename !== undefined && (decl.readers.has(basename) || basename === "cd");
|
|
280
391
|
const verb = program === undefined ? undefined : { name: program.name, basename: program.basename, listed };
|
|
281
|
-
for (const k of pos.assignments)
|
|
392
|
+
for (const k of pos.assignments) {
|
|
282
393
|
pushAssignment(reads, toks[k].word, "env_assignment");
|
|
394
|
+
assignmentArithmetic(toks[k].word, table.isInteger(toks[k].word.assignment?.name ?? ""), ctx);
|
|
395
|
+
}
|
|
283
396
|
for (const l of pos.launchers) {
|
|
284
397
|
const r = toks[l.index];
|
|
285
398
|
if (isPathShapedToken(r.folded))
|
|
@@ -290,19 +403,30 @@ function segmentFactsRead(segment, p, decl, home, nestedPlan) {
|
|
|
290
403
|
const assignmentIndices = new Set(pos.assignments);
|
|
291
404
|
const chainEnd = pos.program?.index ?? toks.length;
|
|
292
405
|
const launcherValueIndices = new Set();
|
|
406
|
+
const launcherPathValues = new Map();
|
|
293
407
|
for (const l of pos.launchers) {
|
|
294
|
-
const row =
|
|
295
|
-
if (row === undefined)
|
|
408
|
+
const row = programRow(programBasename(l.name));
|
|
409
|
+
if (row?.launcher === undefined)
|
|
296
410
|
continue;
|
|
297
411
|
for (let j = l.index + 1; j < chainEnd; j++) {
|
|
298
412
|
const w = toks[j].folded;
|
|
299
413
|
if (!w.startsWith("-") || w === "-")
|
|
300
414
|
break;
|
|
301
|
-
const
|
|
302
|
-
if (
|
|
415
|
+
const step = launcherOptionStep(row, w);
|
|
416
|
+
if (step === undefined)
|
|
303
417
|
break;
|
|
304
|
-
if (
|
|
305
|
-
|
|
418
|
+
if (step === 2) {
|
|
419
|
+
const role = launcherOptionPathRole(row, w);
|
|
420
|
+
if (role === undefined)
|
|
421
|
+
launcherValueIndices.add(j + 1);
|
|
422
|
+
else
|
|
423
|
+
launcherPathValues.set(j + 1, { value: toks[j + 1].folded, role });
|
|
424
|
+
j++;
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
const own = readOptionRole(row, w);
|
|
428
|
+
if (own.form === "attached" && own.role?.kind === "path")
|
|
429
|
+
launcherPathValues.set(j, { value: literalTildeSpelling(own.value), role: own.role });
|
|
306
430
|
}
|
|
307
431
|
}
|
|
308
432
|
for (let j = 0; j < chainEnd; j++) {
|
|
@@ -310,6 +434,11 @@ function segmentFactsRead(segment, p, decl, home, nestedPlan) {
|
|
|
310
434
|
continue;
|
|
311
435
|
const r = toks[j];
|
|
312
436
|
const word = r.folded;
|
|
437
|
+
const pathValue = launcherPathValues.get(j);
|
|
438
|
+
if (pathValue !== undefined) {
|
|
439
|
+
reads.push(...roleReads(r, "option_value", pathValue.value, pathValue.role, "literal", ctx));
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
313
442
|
if (word.startsWith("-") && word !== "-") {
|
|
314
443
|
for (const payload of attachedOptionPayloads(word))
|
|
315
444
|
reads.push(bare(r, "unlisted_word", payload));
|
|
@@ -331,75 +460,79 @@ function segmentFactsRead(segment, p, decl, home, nestedPlan) {
|
|
|
331
460
|
let reentry;
|
|
332
461
|
if (pos.argvFromStdin)
|
|
333
462
|
reentry = "argv";
|
|
463
|
+
const reenterShell = (verb, argvs) => {
|
|
464
|
+
const stdin = stdinTextsOf(segment, piped);
|
|
465
|
+
const scripts = argvs.flatMap(({ shell, texts: t, args: a }) => [reentryText(shell, t), reentryText(shell, a), ...stdin.map((s) => (s.literal === undefined ? undefined : reentryText(shell, t, s.literal)))]);
|
|
466
|
+
for (const t of new Set(scripts))
|
|
467
|
+
if (t !== undefined)
|
|
468
|
+
nested.push(nestedPlan(t, "later"));
|
|
469
|
+
for (const { shell, args: a, words } of argvs) {
|
|
470
|
+
const at = shell === "source" || shell === "." ? a.findIndex((w) => !w.startsWith("-") || w === "-") : scriptFileAt(shell, a);
|
|
471
|
+
const file = at === undefined ? undefined : words[at];
|
|
472
|
+
if (file !== undefined)
|
|
473
|
+
reads.push(bare(file, "operand"));
|
|
474
|
+
}
|
|
475
|
+
return done({ empty: false, launcherChain, verb, reentry: "shell", declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}), ...(stdin.length > 0 ? { stdin } : {}) });
|
|
476
|
+
};
|
|
334
477
|
if (pos.refusal !== undefined) {
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const text = commandStringValue(row.commandString, toks, pos.refusal.option);
|
|
478
|
+
const commandLine = commandLineOptionSpellings(programRow(programBasename(pos.refusal.owner)));
|
|
479
|
+
if (pos.refusal.kind === "option_at_program_position" && commandLine.length > 0) {
|
|
480
|
+
const text = commandStringValue(commandLine, toks, pos.refusal.option);
|
|
339
481
|
if (text !== undefined) {
|
|
340
|
-
nested.push(nestedPlan(text.value));
|
|
482
|
+
nested.push(nestedPlan(text.value, "later"));
|
|
341
483
|
reentry = "shell";
|
|
342
|
-
unlistedWords(reads, toks, text.next, launcherIndices, "unlisted_word");
|
|
343
|
-
return {
|
|
484
|
+
unlistedWords(reads, toks, text.next, launcherIndices, "unlisted_word", ctx);
|
|
485
|
+
return done({ empty: false, launcherChain, ...(verb !== undefined ? { verb } : {}), reentry, declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}) });
|
|
344
486
|
}
|
|
345
487
|
}
|
|
346
|
-
if (programPositionRunsShell(pos,
|
|
347
|
-
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
488
|
+
if (programPositionRunsShell(pos, runsShellText)) {
|
|
489
|
+
const launched = launchedInput(p.argv, pos, { text: (k) => literalTextOf(toks[k].word.pieces) ?? programTextOf(toks[k]), folded: (k) => programTextOf(toks[k]), values: (k) => settledFieldsOf(toks[k]) });
|
|
490
|
+
for (const k of launched.programWords)
|
|
491
|
+
if (isPathShapedToken(toks[k].folded))
|
|
492
|
+
reads.push(bare(toks[k], "program_path"));
|
|
493
|
+
for (const text of launched.lines)
|
|
494
|
+
nested.push(nestedPlan(text, "substitution"));
|
|
495
|
+
const argvs = launched.shells.map((a) => ({ ...a, words: a.words.map((k) => (k === undefined ? undefined : toks[k])) }));
|
|
496
|
+
if (argvs.length === 0)
|
|
497
|
+
return done({ empty: false, launcherChain, reentry: "shell", declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}) });
|
|
498
|
+
return reenterShell({ name: argvs[0].shell, basename: argvs[0].shell, listed: decl.readers.has(argvs[0].shell) }, argvs);
|
|
353
499
|
}
|
|
354
500
|
const from = pos.launchers[0]?.index ?? written;
|
|
355
|
-
unlistedWords(reads, toks, from, launcherIndices, "unlisted_word");
|
|
356
|
-
return {
|
|
501
|
+
unlistedWords(reads, toks, from, launcherIndices, "unlisted_word", ctx);
|
|
502
|
+
return done({ empty: false, launcherChain, ...(verb !== undefined ? { verb } : {}), ...(reentry !== undefined ? { reentry } : {}), declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}) });
|
|
357
503
|
}
|
|
358
504
|
if (program === undefined) {
|
|
359
505
|
if (pos.launchers.length > 0)
|
|
360
|
-
unlistedWords(reads, toks, pos.launchers[0].index, launcherIndices, "unlisted_word");
|
|
361
|
-
return {
|
|
506
|
+
unlistedWords(reads, toks, pos.launchers[0].index, launcherIndices, "unlisted_word", ctx);
|
|
507
|
+
return done({ empty: false, launcherChain, ...(reentry !== undefined ? { reentry } : {}), declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}) });
|
|
362
508
|
}
|
|
363
509
|
const argReads = toks.slice(program.index + 1);
|
|
364
|
-
const args = argReads.map(
|
|
365
|
-
const texts = argReads.map((r) => (r.word.pieces
|
|
510
|
+
const args = argReads.map(programTextOf);
|
|
511
|
+
const texts = argReads.map((r) => literalTextOf(r.word.pieces) ?? programTextOf(r));
|
|
366
512
|
const programRead = toks[program.index];
|
|
367
513
|
if (rewritten(programRead) || isPathShapedToken(programRead.folded))
|
|
368
514
|
reads.push(bare(programRead, "program_path"));
|
|
369
|
-
if (
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
nested.push(nestedPlan(t));
|
|
375
|
-
if (basename === "source" || basename === ".") {
|
|
376
|
-
const file = argReads.find((a) => !a.folded.startsWith("-") || a.folded === "-");
|
|
377
|
-
if (file !== undefined)
|
|
378
|
-
reads.push(bare(file, "operand"));
|
|
379
|
-
}
|
|
380
|
-
else if (text === undefined) {
|
|
381
|
-
const file = argReads.find((a) => !a.folded.startsWith("-") || a.folded === "-");
|
|
382
|
-
if (file !== undefined && file.folded !== "-")
|
|
383
|
-
reads.push(bare(file, "operand"));
|
|
384
|
-
}
|
|
385
|
-
return { ...base, empty: false, launcherChain, verb: verb, reentry, declines, reads, moveProvable: false, ...(loopHead !== undefined ? { loopHead } : {}), loopEnd: false };
|
|
386
|
-
}
|
|
387
|
-
const interpreter = INTERPRETER_INLINE_PROGRAMS.get(interpreterKey(basename));
|
|
388
|
-
if (interpreter !== undefined && inlineProgramClause(interpreter, args) !== undefined)
|
|
515
|
+
if (runsShellText(basename))
|
|
516
|
+
return reenterShell(verb, [{ shell: basename, texts, args, words: argReads }]);
|
|
517
|
+
const row = programRow(basename);
|
|
518
|
+
const delivery = programDelivery(row, args);
|
|
519
|
+
if (delivery !== undefined)
|
|
389
520
|
reentry = "interpreter";
|
|
390
521
|
const moveProvable = pos.controlWords.length === 0 && pos.launchers.length === 0 && pos.assignments.length === 0 && program.name === basename;
|
|
391
522
|
let baseMove;
|
|
392
523
|
if (basename === "cd") {
|
|
393
524
|
baseMove = cdMove(argReads, reads);
|
|
394
525
|
}
|
|
395
|
-
else if (
|
|
526
|
+
else if (movesBaseUnfollowed(basename)) {
|
|
396
527
|
baseMove = { target: "unmodelled" };
|
|
397
|
-
unlistedWords(reads, toks, program.index, launcherIndices, "unlisted_word", program);
|
|
528
|
+
unlistedWords(reads, toks, program.index, launcherIndices, "unlisted_word", ctx, program);
|
|
398
529
|
}
|
|
399
530
|
else if (listed) {
|
|
400
|
-
listedVerbCandidates(basename, argReads, reads);
|
|
531
|
+
listedVerbCandidates(basename, argReads, reads, ctx);
|
|
401
532
|
}
|
|
402
|
-
else if (
|
|
533
|
+
else if (isDeclarationBuiltin(basename) && program.name === basename) {
|
|
534
|
+
const integer = declaredAttributes(row, args).has("integer");
|
|
535
|
+
const asWritten = row?.operands?.rest?.kind === "binds-name" && row.operands.rest.asWritten === true;
|
|
403
536
|
for (const r of argReads) {
|
|
404
537
|
const a = r.word.assignment;
|
|
405
538
|
if (a !== undefined && (r.expands !== "unresolvable" || a.value.expansions.length > 0))
|
|
@@ -408,20 +541,39 @@ function segmentFactsRead(segment, p, decl, home, nestedPlan) {
|
|
|
408
541
|
reads.push(bare(r, "unlisted_word"));
|
|
409
542
|
pushAssignment(reads, r.word, "unlisted_word");
|
|
410
543
|
}
|
|
544
|
+
assignmentArithmetic(r.word, integer || (a !== undefined && table.isInteger(a.name)), ctx, asWritten);
|
|
411
545
|
}
|
|
412
546
|
}
|
|
413
547
|
else {
|
|
414
|
-
unlistedWords(reads, toks, program.index, launcherIndices, "unlisted_word", program);
|
|
548
|
+
unlistedWords(reads, toks, program.index, launcherIndices, "unlisted_word", ctx, program);
|
|
549
|
+
}
|
|
550
|
+
for (const e of row === undefined ? [] : readArgRoles(row, args)) {
|
|
551
|
+
const role = e.kind === "value" || e.kind === "operand" ? e.role : e.kind === "option" && typeof e.reading === "object" ? e.reading.role : undefined;
|
|
552
|
+
if (role?.kind !== "binds-name" || role.asWritten === true)
|
|
553
|
+
continue;
|
|
554
|
+
const text = e.kind === "option" && typeof e.reading === "object" ? e.reading.attached : args[e.at];
|
|
555
|
+
ctx.reentered.push(...arithmeticSubstitutions(subscriptOnly(text), table));
|
|
415
556
|
}
|
|
557
|
+
const language = programLanguageOf(row);
|
|
558
|
+
if (language !== undefined && (delivery === "stdin" || (delivery === "text" && !ctx.programTextSeen))) {
|
|
559
|
+
const opens = programTextOpensOf(language);
|
|
560
|
+
if (opens === "any" || typeof opens !== "string")
|
|
561
|
+
ctx.programText ??= delivery === "stdin" ? `reads the ${language} program it runs from its standard input, which this station does not read` : programTextSentence(language);
|
|
562
|
+
}
|
|
563
|
+
const effectSub = pathSubcommandOf(row, args);
|
|
564
|
+
const effectRow = effectSub?.row ?? row;
|
|
565
|
+
const effectArgs = effectSub === undefined ? args : args.slice(effectSub.at + 1);
|
|
566
|
+
if (effectRow !== undefined && selectedOptions(effectRow, effectArgs).some((o) => o.effect === "executes"))
|
|
567
|
+
reentry = "shell";
|
|
416
568
|
let unreadProgramText;
|
|
417
|
-
|
|
418
|
-
|
|
569
|
+
const slot = row === undefined ? undefined : programTextSlotFiles(row, args);
|
|
570
|
+
if (slot !== undefined) {
|
|
419
571
|
for (const f of slot.reads)
|
|
420
572
|
reads.push(bare(readOfText(f), "script_slot_file"));
|
|
421
573
|
for (const f of slot.writes)
|
|
422
574
|
reads.push(bare(readOfText(f), "write_redirect_target"));
|
|
423
575
|
for (const c of slot.commands)
|
|
424
|
-
nested.push(nestedPlan(c));
|
|
576
|
+
nested.push(nestedPlan(c, "later"));
|
|
425
577
|
if (slot.commands.length > 0 || slot.executesPatternSpace)
|
|
426
578
|
reentry = "shell";
|
|
427
579
|
unreadProgramText = slot.unread;
|
|
@@ -430,9 +582,8 @@ function segmentFactsRead(segment, p, decl, home, nestedPlan) {
|
|
|
430
582
|
if (bodies.size > 0)
|
|
431
583
|
reentry = "shell";
|
|
432
584
|
for (const body of bodies)
|
|
433
|
-
nested.push(nestedPlan(body));
|
|
434
|
-
return {
|
|
435
|
-
...base,
|
|
585
|
+
nested.push(nestedPlan(body, "later"));
|
|
586
|
+
return done({
|
|
436
587
|
empty: false,
|
|
437
588
|
launcherChain,
|
|
438
589
|
verb: verb,
|
|
@@ -443,8 +594,7 @@ function segmentFactsRead(segment, p, decl, home, nestedPlan) {
|
|
|
443
594
|
...(baseMove !== undefined ? { baseMove } : {}),
|
|
444
595
|
moveProvable,
|
|
445
596
|
...(loopHead !== undefined ? { loopHead } : {}),
|
|
446
|
-
|
|
447
|
-
};
|
|
597
|
+
});
|
|
448
598
|
}
|
|
449
599
|
function rebasePlan(plan, from, to) {
|
|
450
600
|
if (to !== "unmodelled" && to.length === 1 && to[0] === from)
|
|
@@ -490,165 +640,20 @@ function dedupe(reads) {
|
|
|
490
640
|
}
|
|
491
641
|
return out;
|
|
492
642
|
}
|
|
493
|
-
function bare(r, provenance, spelled = r.folded) {
|
|
494
|
-
return { spelled, raw: r.raw, provenance, expands: r.expands };
|
|
495
|
-
}
|
|
496
643
|
function relativeSpelling(spelled) {
|
|
497
644
|
return !(isAbsolutePathForm(spelled) || spelled.startsWith("~"));
|
|
498
645
|
}
|
|
499
646
|
function joinBase(base, target, homeDir) {
|
|
500
647
|
return resolveOperandLexically(base, target, homeDir);
|
|
501
648
|
}
|
|
502
|
-
function redirectFact(r,
|
|
649
|
+
function redirectFact(r, table, homeDir) {
|
|
503
650
|
if (r.target === undefined)
|
|
504
651
|
return { op: r.op, direction: "dup" };
|
|
505
652
|
if (r.op === "<")
|
|
506
|
-
return { op: r.op, direction: "in", target: bare(readsOf([r.target],
|
|
653
|
+
return { op: r.op, direction: "in", target: bare(readsOf([r.target], table, homeDir)[0], "stdin_redirect") };
|
|
507
654
|
if (r.op === "<<<")
|
|
508
655
|
return { op: r.op, direction: "in" };
|
|
509
|
-
return { op: r.op, direction: "out", target: bare(readsOf([r.target],
|
|
510
|
-
}
|
|
511
|
-
function pushAssignment(reads, w, provenance) {
|
|
512
|
-
const a = w.assignment;
|
|
513
|
-
if (a === undefined)
|
|
514
|
-
return;
|
|
515
|
-
const expandsTilde = a.value.expansions.some((p) => p.expansion?.kind === "tilde");
|
|
516
|
-
const value = expandsTilde ? a.value.folded : literalTildeSpelling(a.value.folded);
|
|
517
|
-
const settled = a.op === "=" && !expandsTilde;
|
|
518
|
-
const named = a.value.folded === "" || (a.op === "+=" ? expandsTilde : !settled) ? undefined : value;
|
|
519
|
-
if (a.value.folded === "" && settled)
|
|
520
|
-
return;
|
|
521
|
-
const v = { spelled: value, raw: a.bare ? a.value.raw : w.raw, provenance };
|
|
522
|
-
const unsettled = provenance !== "env_assignment" ? { ...v, expands: "unresolvable" } : v.spelled.startsWith("~") && !v.spelled.includes(":") ? { ...v, expands: expandsOf(a.value) } : undefined;
|
|
523
|
-
if (!settled && unsettled !== undefined)
|
|
524
|
-
reads.push(unsettled);
|
|
525
|
-
const substitutes = a.value.expansions.some((p) => p.expansion?.kind === "command" || p.expansion?.kind === "process" || p.expansion?.kind === "arithmetic");
|
|
526
|
-
if (named !== undefined && !substitutes)
|
|
527
|
-
reads.push({ spelled: named, raw: w.raw, provenance, expands: expandsOf(w) });
|
|
528
|
-
if (a.value.folded.includes(":"))
|
|
529
|
-
for (const m of a.value.folded.split(":"))
|
|
530
|
-
if (m !== "") {
|
|
531
|
-
const r = readOfText(m);
|
|
532
|
-
reads.push({ spelled: r.folded, raw: r.raw, provenance, expands: r.expands, denyOnly: true });
|
|
533
|
-
}
|
|
534
|
-
if (a.form === "compound")
|
|
535
|
-
for (const e of compoundArrayElements(a.value))
|
|
536
|
-
reads.push({ spelled: e.folded, raw: e.raw, provenance, expands: e.expands, ...(e.denyOnly === true ? { denyOnly: true } : {}) });
|
|
537
|
-
}
|
|
538
|
-
function unlistedWords(reads, toks, from, launcherIndices, provenance, program) {
|
|
539
|
-
const argv = program !== undefined ? { program: program.basename, from: program.index } : argvProgramOf(toks.map((r) => r.word));
|
|
540
|
-
const argvStart = argv?.from ?? toks.length;
|
|
541
|
-
const slotVerb = argv?.program;
|
|
542
|
-
const message = slotVerb === undefined || argv === undefined ? new Set() : messageSlotWords(slotVerb, toks, argvStart);
|
|
543
|
-
const declaredNotPaths = ASSIGNMENT_VALUE_NOT_PATHS.has(slotVerb ?? "");
|
|
544
|
-
const noPathOperands = slotVerb !== undefined && NO_PATH_OPERAND_COMMANDS.has(slotVerb);
|
|
545
|
-
const permutes = slotVerb === undefined || !verbOptionsArePositionIndependent(slotVerb);
|
|
546
|
-
const expanding = new Set();
|
|
547
|
-
for (let j = from; j < toks.length; j++) {
|
|
548
|
-
if (launcherIndices.has(j))
|
|
549
|
-
continue;
|
|
550
|
-
if (noPathOperands && j > argvStart && !NO_PATH_OPERAND_EVALUATORS.has(slotVerb))
|
|
551
|
-
break;
|
|
552
|
-
if (toks[j].expands !== "unresolvable")
|
|
553
|
-
continue;
|
|
554
|
-
expanding.add(j);
|
|
555
|
-
reads.push(bare(toks[j], j === argvStart ? "program_path" : provenance));
|
|
556
|
-
if (j < argvStart)
|
|
557
|
-
pushAssignment(reads, toks[j].word, "env_assignment");
|
|
558
|
-
else if (j > argvStart && !declaredNotPaths)
|
|
559
|
-
pushAssignment(reads, toks[j].word, provenance);
|
|
560
|
-
}
|
|
561
|
-
const positional = [];
|
|
562
|
-
let stdinOperand = false;
|
|
563
|
-
let endOfOptions = false;
|
|
564
|
-
let sawArgvOperand = false;
|
|
565
|
-
for (let j = from; j < toks.length; j++) {
|
|
566
|
-
if (launcherIndices.has(j) || expanding.has(j) || message.has(j))
|
|
567
|
-
continue;
|
|
568
|
-
const r = toks[j];
|
|
569
|
-
const word = r.folded;
|
|
570
|
-
if (j > from && !endOfOptions && word === "--") {
|
|
571
|
-
endOfOptions = true;
|
|
572
|
-
continue;
|
|
573
|
-
}
|
|
574
|
-
if (noPathOperands && j >= argvStart)
|
|
575
|
-
break;
|
|
576
|
-
if (j === argvStart && !isPathShapedToken(word))
|
|
577
|
-
continue;
|
|
578
|
-
const optionShaped = !endOfOptions && word.startsWith("-") && word !== "-";
|
|
579
|
-
if (optionShaped && j > argvStart) {
|
|
580
|
-
const slot = slotVerb === undefined ? undefined : readVerbOptionSlot(slotVerb, word);
|
|
581
|
-
if (sawArgvOperand && permutes) {
|
|
582
|
-
reads.push(bare(r, provenance));
|
|
583
|
-
if (slot !== undefined && slot.form === "separated") {
|
|
584
|
-
const ahead = toks[j + 1];
|
|
585
|
-
if (ahead !== undefined && ahead.expands !== "unresolvable")
|
|
586
|
-
for (const c of slotValueCandidates(ahead.folded, slot.kind))
|
|
587
|
-
reads.push(bare(ahead, "option_value", c));
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
if (slot !== undefined && slot.form !== "unexplained" && !(slot.form === "separated" && sawArgvOperand && permutes)) {
|
|
591
|
-
if (slot.form === "attached") {
|
|
592
|
-
for (const c of slotValueCandidates(literalTildeSpelling(slot.value), slot.kind))
|
|
593
|
-
reads.push(bare(r, "option_value", c));
|
|
594
|
-
}
|
|
595
|
-
else if (slot.form === "separated") {
|
|
596
|
-
j++;
|
|
597
|
-
const value = toks[j];
|
|
598
|
-
if (value !== undefined && !expanding.has(j)) {
|
|
599
|
-
const named = slotValueCandidates(value.folded, slot.kind);
|
|
600
|
-
for (const c of named)
|
|
601
|
-
reads.push(bare(value, "option_value", c));
|
|
602
|
-
if (named.length > 0)
|
|
603
|
-
positional.push(value);
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
continue;
|
|
607
|
-
}
|
|
608
|
-
for (const payload of attachedOptionPayloads(word))
|
|
609
|
-
reads.push(bare(r, provenance, payload));
|
|
610
|
-
if (isPathShapedToken(word))
|
|
611
|
-
reads.push(bare(r, provenance));
|
|
612
|
-
continue;
|
|
613
|
-
}
|
|
614
|
-
if (optionShaped) {
|
|
615
|
-
for (const payload of attachedOptionPayloads(word))
|
|
616
|
-
reads.push(bare(r, provenance, payload));
|
|
617
|
-
if (isPathShapedToken(word))
|
|
618
|
-
reads.push(bare(r, provenance));
|
|
619
|
-
continue;
|
|
620
|
-
}
|
|
621
|
-
if (j > argvStart) {
|
|
622
|
-
sawArgvOperand = true;
|
|
623
|
-
if (word === "-") {
|
|
624
|
-
const m = slotVerb === undefined ? undefined : RECURSIVE_READ_FORMS[slotVerb];
|
|
625
|
-
if (m === undefined || m.dashIsStdin === true)
|
|
626
|
-
stdinOperand = true;
|
|
627
|
-
else
|
|
628
|
-
positional.push(r);
|
|
629
|
-
}
|
|
630
|
-
else
|
|
631
|
-
positional.push(r);
|
|
632
|
-
}
|
|
633
|
-
reads.push(bare(r, j === argvStart ? "program_path" : provenance));
|
|
634
|
-
if (j < argvStart)
|
|
635
|
-
pushAssignment(reads, r.word, "env_assignment");
|
|
636
|
-
else if (!declaredNotPaths)
|
|
637
|
-
pushAssignment(reads, r.word, provenance);
|
|
638
|
-
}
|
|
639
|
-
if (slotVerb !== undefined && argv !== undefined && segmentSelectsRecursiveRead(slotVerb, toks.slice(argvStart + 1).map((x) => x.folded))) {
|
|
640
|
-
const roots = positional.length > 0 ? positional : stdinOperand ? [] : [readOfText(".")];
|
|
641
|
-
for (const root of roots)
|
|
642
|
-
reads.push(bare(root, "traversal_root"));
|
|
643
|
-
}
|
|
644
|
-
for (let j = from; j < toks.length; j++) {
|
|
645
|
-
if (launcherIndices.has(j) || j === argvStart)
|
|
646
|
-
continue;
|
|
647
|
-
if (noPathOperands && j > argvStart)
|
|
648
|
-
break;
|
|
649
|
-
if (toks[j].expands === "glob")
|
|
650
|
-
reads.push(bare(toks[j], provenance));
|
|
651
|
-
}
|
|
656
|
+
return { op: r.op, direction: "out", target: bare(readsOf([r.target], table, homeDir)[0], "write_redirect_target") };
|
|
652
657
|
}
|
|
653
658
|
function commandStringValue(options, toks, option) {
|
|
654
659
|
const at = toks.findIndex((r) => r.folded === option);
|
|
@@ -656,7 +661,7 @@ function commandStringValue(options, toks, option) {
|
|
|
656
661
|
return undefined;
|
|
657
662
|
for (const spelling of options) {
|
|
658
663
|
if (option === spelling) {
|
|
659
|
-
const value = toks[at + 1]
|
|
664
|
+
const value = toks[at + 1] === undefined ? undefined : programTextOf(toks[at + 1]);
|
|
660
665
|
return value === undefined ? undefined : { value, next: at + 2 };
|
|
661
666
|
}
|
|
662
667
|
if (spelling.startsWith("--") && option.startsWith(`${spelling}=`))
|
|
@@ -696,106 +701,3 @@ function cdMove(args, reads) {
|
|
|
696
701
|
reads.push(c);
|
|
697
702
|
return { target: c };
|
|
698
703
|
}
|
|
699
|
-
function listedVerbCandidates(name, argReads, reads) {
|
|
700
|
-
if (NO_PATH_OPERAND_COMMANDS.has(name))
|
|
701
|
-
return;
|
|
702
|
-
const args = argReads.map((r) => r.folded);
|
|
703
|
-
const expanding = new Set();
|
|
704
|
-
argReads.forEach((r, k) => {
|
|
705
|
-
if (!rewritten(r))
|
|
706
|
-
return;
|
|
707
|
-
expanding.add(k);
|
|
708
|
-
reads.push({ spelled: r.folded, raw: r.raw, provenance: "operand", expands: "unresolvable" });
|
|
709
|
-
});
|
|
710
|
-
const eoo = args.indexOf("--");
|
|
711
|
-
const firstOperandSlot = verbFirstOperandSlot(name);
|
|
712
|
-
const firstOperandSuppliedByFlag = firstOperandSlot !== undefined && (eoo === -1 ? args : args.slice(0, eoo)).some((t) => suppliesFirstOperandSlot(firstOperandSlot, t));
|
|
713
|
-
const positional = [];
|
|
714
|
-
let sawOperand = false;
|
|
715
|
-
let stdinOperand = false;
|
|
716
|
-
let endOfOptions = false;
|
|
717
|
-
const permutes = !verbOptionsArePositionIndependent(name);
|
|
718
|
-
const push = (k, text, provenance) => {
|
|
719
|
-
reads.push(bare(argReads[k], provenance, text));
|
|
720
|
-
};
|
|
721
|
-
for (let k = 0; k < args.length; k++) {
|
|
722
|
-
const t = args[k];
|
|
723
|
-
if (expanding.has(k))
|
|
724
|
-
continue;
|
|
725
|
-
if (!endOfOptions) {
|
|
726
|
-
if (t === "--") {
|
|
727
|
-
endOfOptions = true;
|
|
728
|
-
continue;
|
|
729
|
-
}
|
|
730
|
-
if (t.startsWith("-") && t !== "-") {
|
|
731
|
-
const slot = readVerbOptionSlot(name, t);
|
|
732
|
-
if (sawOperand && permutes) {
|
|
733
|
-
push(k, t, "operand");
|
|
734
|
-
if (slot !== undefined && slot.form === "separated") {
|
|
735
|
-
const ahead = args[k + 1];
|
|
736
|
-
if (ahead !== undefined && !expanding.has(k + 1))
|
|
737
|
-
for (const c of slotValueCandidates(ahead, slot.kind))
|
|
738
|
-
push(k + 1, c, "option_value");
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
if (slot !== undefined && slot.form !== "unexplained" && !(slot.form === "separated" && sawOperand && permutes)) {
|
|
742
|
-
if (slot.form === "attached") {
|
|
743
|
-
for (const c of slotValueCandidates(literalTildeSpelling(slot.value), slot.kind))
|
|
744
|
-
push(k, c, "option_value");
|
|
745
|
-
}
|
|
746
|
-
else if (slot.form === "separated") {
|
|
747
|
-
const value = args[++k];
|
|
748
|
-
if (value !== undefined && !expanding.has(k)) {
|
|
749
|
-
const named = slotValueCandidates(value, slot.kind);
|
|
750
|
-
for (const c of named)
|
|
751
|
-
push(k, c, "option_value");
|
|
752
|
-
if (named.length > 0)
|
|
753
|
-
positional.push(argReads[k]);
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
continue;
|
|
757
|
-
}
|
|
758
|
-
for (const payload of attachedOptionPayloads(t))
|
|
759
|
-
push(k, payload, "option_value");
|
|
760
|
-
continue;
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
const inFirstOperandSlot = firstOperandSlot !== undefined && !firstOperandSuppliedByFlag && !sawOperand;
|
|
764
|
-
sawOperand = true;
|
|
765
|
-
if (t === "-") {
|
|
766
|
-
if (inFirstOperandSlot)
|
|
767
|
-
continue;
|
|
768
|
-
const m = RECURSIVE_READ_FORMS[name];
|
|
769
|
-
if (m === undefined || m.dashIsStdin === true) {
|
|
770
|
-
stdinOperand = true;
|
|
771
|
-
continue;
|
|
772
|
-
}
|
|
773
|
-
positional.push(argReads[k]);
|
|
774
|
-
continue;
|
|
775
|
-
}
|
|
776
|
-
if (inFirstOperandSlot) {
|
|
777
|
-
const named = slotValueCandidates(t, firstOperandSlot.kind);
|
|
778
|
-
for (const c of named)
|
|
779
|
-
push(k, c, "operand");
|
|
780
|
-
if (named.length > 0)
|
|
781
|
-
positional.push(argReads[k]);
|
|
782
|
-
continue;
|
|
783
|
-
}
|
|
784
|
-
positional.push(argReads[k]);
|
|
785
|
-
push(k, t, "operand");
|
|
786
|
-
if (!ASSIGNMENT_VALUE_NOT_PATHS.has(name)) {
|
|
787
|
-
pushAssignment(reads, argReads[k].word, "operand");
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
for (let k = 0; k < args.length; k++) {
|
|
791
|
-
if (expanding.has(k))
|
|
792
|
-
continue;
|
|
793
|
-
if (argReads[k].expands === "glob")
|
|
794
|
-
reads.push(bare(argReads[k], "operand"));
|
|
795
|
-
}
|
|
796
|
-
if (segmentSelectsRecursiveRead(name, args)) {
|
|
797
|
-
const roots = positional.length > 0 ? positional : stdinOperand ? [] : [readOfText(".")];
|
|
798
|
-
for (const root of roots)
|
|
799
|
-
reads.push(bare(root, "traversal_root"));
|
|
800
|
-
}
|
|
801
|
-
}
|