@poe-platform/safe-bash 0.1.736 → 0.1.738
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/dist/safe-bash/chunks/{chunk-ZFV5FGGH.js → chunk-E2FTAYLG.js} +15 -16
- package/dist/safe-bash/chunks/{chunk-ZFV5FGGH.js.map → chunk-E2FTAYLG.js.map} +2 -2
- package/dist/safe-bash/chunks/{chunk-DFNSXDHP.js → chunk-JNHKE26E.js} +2 -2
- package/dist/safe-bash/chunks/{chunk-N3RTTKMA.js → chunk-JTKTBT3B.js} +2 -2
- package/dist/safe-bash/command-assets/git_rust-NOIGQE52.wasm +0 -0
- package/dist/safe-bash/command-chunks/{chunk-L6GGCZOK.js → chunk-5EOMWWKN.js} +16 -15
- package/dist/safe-bash/command-chunks/chunk-5EOMWWKN.js.map +7 -0
- package/dist/safe-bash/command-chunks/{chunk-YXAPLUY4.js → chunk-WFMUMKBQ.js} +2 -2
- package/dist/safe-bash/core.browser.js +928 -218
- package/dist/safe-bash/core.browser.js.map +3 -3
- package/dist/safe-bash/shell/arithmetic.d.ts.map +1 -1
- package/dist/safe-bash/shell/arithmetic.js +10 -1
- package/dist/safe-bash/shell/arithmetic.js.map +1 -1
- package/dist/safe-bash/shell/getopts.d.ts +1 -0
- package/dist/safe-bash/shell/getopts.d.ts.map +1 -1
- package/dist/safe-bash/shell/getopts.js +71 -0
- package/dist/safe-bash/shell/getopts.js.map +1 -1
- package/dist/safe-bash/shell/runtime.d.ts +5 -0
- package/dist/safe-bash/shell/runtime.d.ts.map +1 -1
- package/dist/safe-bash/shell/runtime.js +1043 -247
- package/dist/safe-bash/shell/runtime.js.map +1 -1
- package/dist/safe-bash-command-git/index.js +1 -1
- package/dist/safe-bash-regex-engine/index.js +2 -2
- package/dist/safe-bash-regex-engine/text/regex.js +2 -2
- package/dist/safe-bash-regex-engine/text/replacement-buffer.js +1 -1
- package/package.json +2 -2
- package/dist/safe-bash/command-assets/git_rust-VC5UCZXR.wasm +0 -0
- package/dist/safe-bash/command-chunks/chunk-L6GGCZOK.js.map +0 -7
- /package/dist/safe-bash/chunks/{chunk-DFNSXDHP.js.map → chunk-JNHKE26E.js.map} +0 -0
- /package/dist/safe-bash/chunks/{chunk-N3RTTKMA.js.map → chunk-JTKTBT3B.js.map} +0 -0
- /package/dist/safe-bash/command-chunks/{chunk-YXAPLUY4.js.map → chunk-WFMUMKBQ.js.map} +0 -0
|
@@ -63,7 +63,7 @@ export const customRegisteredCommands = new WeakSet();
|
|
|
63
63
|
export const customRegisteredRegistries = new WeakSet();
|
|
64
64
|
import { defaultPredicateExecutors, tryFastPredicate } from "../commands/predicates.js";
|
|
65
65
|
import { builtInDirectContextExecutors, pathOf, RESOLVED_EXIT_ONE, RESOLVED_EXIT_ZERO, UsageError } from "../commands/internal.js";
|
|
66
|
-
import { cloneGetoptsState, createGetoptsInput, createGetoptsState, GetoptsError, getoptsInputAllocationSize, scanGetopts, withGetoptsIndex } from "./getopts.js";
|
|
66
|
+
import { cloneGetoptsState, createGetoptsInput, createGetoptsState, GetoptsError, getoptsInputAllocationSize, scanGetopts, scanGetoptsSync, withGetoptsIndex } from "./getopts.js";
|
|
67
67
|
import { activateChildCancellation, admitCancellationSubscriptionCapacity, prepareChildCancellation, selectRuntimeCancellationOutcome, subscribeCancellationOwner, unsubscribeCancellationOwner, } from "./cancellation.js";
|
|
68
68
|
import { variablePresence } from "../commands/variable-presence.js";
|
|
69
69
|
import { getArrayAssignment, getArraySelector, copyArraySelector, numericIndex, literalIndex, stringIndex, isQuoteMarker, prefixNameQuoteGroups, setArraySelector } from "./arrays/syntax.js";
|
|
@@ -2098,6 +2098,32 @@ function hasActiveVariableAttributes(state) {
|
|
|
2098
2098
|
}
|
|
2099
2099
|
return false;
|
|
2100
2100
|
}
|
|
2101
|
+
function hasNonNamerefAttributes(state) {
|
|
2102
|
+
const attrs = state.variableAttributes;
|
|
2103
|
+
if (!attrs || attrs.size === 0)
|
|
2104
|
+
return false;
|
|
2105
|
+
for (const [k, val] of attrs.entries()) {
|
|
2106
|
+
if (val.length === 0)
|
|
2107
|
+
continue;
|
|
2108
|
+
if (val !== "n")
|
|
2109
|
+
return true;
|
|
2110
|
+
const ref = state.variables[k];
|
|
2111
|
+
if (!ref || !isShellIdentifier(ref) || ref === k || attrs.get(ref))
|
|
2112
|
+
return true;
|
|
2113
|
+
}
|
|
2114
|
+
return false;
|
|
2115
|
+
}
|
|
2116
|
+
function resolveSyncNameref(state, name) {
|
|
2117
|
+
const attrs = state.variableAttributes;
|
|
2118
|
+
if (!attrs || attrs.size === 0)
|
|
2119
|
+
return name;
|
|
2120
|
+
if (attrs.get(name) === "n") {
|
|
2121
|
+
const ref = state.variables[name];
|
|
2122
|
+
if (ref && isShellIdentifier(ref) && ref !== name && !attrs.get(ref))
|
|
2123
|
+
return ref;
|
|
2124
|
+
}
|
|
2125
|
+
return name;
|
|
2126
|
+
}
|
|
2101
2127
|
function publishVariable(state, name, value) {
|
|
2102
2128
|
const monitor = stateMonitor(state);
|
|
2103
2129
|
if (monitor) {
|
|
@@ -3408,6 +3434,7 @@ function resolveSimpleArithOperand(tok, rawState, monitor, activeArrayStore, syn
|
|
|
3408
3434
|
}
|
|
3409
3435
|
tok = c1 === 123 ? tok.slice(2, -1) : tok.slice(1);
|
|
3410
3436
|
}
|
|
3437
|
+
tok = resolveSyncNameref(rawState, tok);
|
|
3411
3438
|
if (rawState.nounset || activeArrayStore?.bindings.has(tok) || monitor?.hasOverlay(tok) || activeArrayStore?.watches.has(tok))
|
|
3412
3439
|
return undefined;
|
|
3413
3440
|
const raw = rawState.variables[tok];
|
|
@@ -4218,8 +4245,12 @@ export class Runtime {
|
|
|
4218
4245
|
return {
|
|
4219
4246
|
isSync: true, resolve: (variable, subscript) => {
|
|
4220
4247
|
this.signal.throwIfAborted();
|
|
4221
|
-
if (this._syncArithState.variableAttributes?.get(variable)?.includes("n"))
|
|
4222
|
-
|
|
4248
|
+
if (this._syncArithState.variableAttributes?.get(variable)?.includes("n")) {
|
|
4249
|
+
const resolved = resolveSyncNameref(this._syncArithState, variable);
|
|
4250
|
+
if (resolved === variable)
|
|
4251
|
+
throw new ArrayFailure("nameref in sync arithmetic");
|
|
4252
|
+
variable = resolved;
|
|
4253
|
+
}
|
|
4223
4254
|
if (subscript !== undefined) {
|
|
4224
4255
|
let resolvedSub = subscript;
|
|
4225
4256
|
if (resolvedSub.charCodeAt(0) === 36 && /^\$[a-zA-Z_][a-zA-Z_0-9]*$/.test(resolvedSub)) {
|
|
@@ -4242,6 +4273,15 @@ export class Runtime {
|
|
|
4242
4273
|
resolvedSub = rawSub === undefined || rawSub === "" ? "0" : shellValueText(stateMonitor(st)?.values.get(resolvedSub, rawSub) ?? rawSub);
|
|
4243
4274
|
}
|
|
4244
4275
|
}
|
|
4276
|
+
else {
|
|
4277
|
+
const st = this._syncArithState;
|
|
4278
|
+
const binding = arrayStore(st)?.get(variable);
|
|
4279
|
+
if (!binding || !binding.associative) {
|
|
4280
|
+
const subStr = tryEvalSimpleExpandedArith(resolvedSub, st, stateMonitor(st), arrayStore(st), this._syncArithRawWriteOnly ? this._syncArithTouched : undefined);
|
|
4281
|
+
if (subStr !== undefined && !subStr.startsWith("-"))
|
|
4282
|
+
resolvedSub = subStr;
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4245
4285
|
if (resolvedSub.length === 0 || resolvedSub.length > 128 || !/^[a-zA-Z0-9_.\-/:@]+$/.test(resolvedSub))
|
|
4246
4286
|
throw new ArrayFailure("complex subscript in sync arithmetic");
|
|
4247
4287
|
return `[idx]${variable}:${resolvedSub}`;
|
|
@@ -4393,15 +4433,33 @@ export class Runtime {
|
|
|
4393
4433
|
}
|
|
4394
4434
|
}
|
|
4395
4435
|
canSyncArithmeticOperands(tree, state, line, depth = 0) {
|
|
4396
|
-
if (!tree || depth > 128 ||
|
|
4436
|
+
if (!tree || depth > 128 || hasNonNamerefAttributes(state) || state.readonlyVariables?.size)
|
|
4397
4437
|
return false;
|
|
4398
4438
|
switch (tree.kind) {
|
|
4399
4439
|
case "literal": return true;
|
|
4400
4440
|
case "name": {
|
|
4401
|
-
|
|
4441
|
+
const effName = resolveSyncNameref(state, tree.name);
|
|
4442
|
+
if (effName === "OPTIND" || effName === "PIPESTATUS")
|
|
4402
4443
|
return false;
|
|
4403
4444
|
const monitor = stateMonitor(state);
|
|
4404
|
-
if (monitor?.hasOverlay(
|
|
4445
|
+
if (monitor?.hasOverlay(effName) || monitor?.store?.watches.has(effName))
|
|
4446
|
+
return false;
|
|
4447
|
+
if (tree.subscript !== undefined) {
|
|
4448
|
+
if (state.nounset || hasUnpreparedLocal(state, tree.name))
|
|
4449
|
+
return false;
|
|
4450
|
+
const binding = arrayStore(state)?.get(tree.name);
|
|
4451
|
+
if (!binding)
|
|
4452
|
+
return false;
|
|
4453
|
+
if (binding.associative) {
|
|
4454
|
+
if (/^\$[a-zA-Z_][a-zA-Z_0-9]*$/.test(tree.subscript)) {
|
|
4455
|
+
const sv = tree.subscript.slice(1);
|
|
4456
|
+
return !arrayStore(state)?.get(sv) && !monitor?.hasOverlay(sv);
|
|
4457
|
+
}
|
|
4458
|
+
return /^[a-zA-Z0-9_.\-/:@]+$/.test(tree.subscript);
|
|
4459
|
+
}
|
|
4460
|
+
return /^(?:0|[1-9][0-9]{0,6})$/.test(tree.subscript) || /^\$?[a-zA-Z_][a-zA-Z_0-9]*$/.test(tree.subscript) || /^\s*[a-zA-Z_][a-zA-Z_0-9]*\s*(?:[-+*]\s*(?:0|[1-9][0-9]{0,6})|[/%]\s*[1-9][0-9]{0,6})\s*$/.test(tree.subscript);
|
|
4461
|
+
}
|
|
4462
|
+
if (arrayStore(state)?.get(tree.name))
|
|
4405
4463
|
return false;
|
|
4406
4464
|
const value = state.variables[tree.name]
|
|
4407
4465
|
?? (tree.name === "LINENO" ? String(line ?? 1)
|
|
@@ -4702,6 +4760,8 @@ export class Runtime {
|
|
|
4702
4760
|
const binding = arrayStore(state)?.get(name);
|
|
4703
4761
|
if (binding)
|
|
4704
4762
|
return binding.get(binding.associative ? binding.keys.get("30")?.index ?? -1 : 0);
|
|
4763
|
+
if (name === "DIRSTACK")
|
|
4764
|
+
return state.cwd;
|
|
4705
4765
|
if (name === "FUNCNAME" && state.variables.FUNCNAME === undefined)
|
|
4706
4766
|
return state.functionNames?.[0];
|
|
4707
4767
|
if (name === "_" && state.variables._ === undefined)
|
|
@@ -4709,27 +4769,55 @@ export class Runtime {
|
|
|
4709
4769
|
return state.variables[name];
|
|
4710
4770
|
}
|
|
4711
4771
|
async variablePresent(state, name, io) {
|
|
4772
|
+
const simple = this.tryVariablePresentSync(state, name);
|
|
4773
|
+
if (simple !== undefined)
|
|
4774
|
+
return simple;
|
|
4712
4775
|
name = this.referenceName(state, name);
|
|
4713
4776
|
const bracket = name.indexOf("[");
|
|
4714
4777
|
const base = bracket < 0 ? name : name.slice(0, bracket);
|
|
4715
|
-
const validName = base.length > 0 && [...base].every((character, index) => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_".includes(character)
|
|
4716
|
-
|| index > 0 && "0123456789".includes(character));
|
|
4717
|
-
if (!validName || bracket >= 0 && !name.endsWith("]"))
|
|
4718
|
-
return false;
|
|
4719
4778
|
const resolved = this.referenceName(state, base);
|
|
4720
4779
|
const binding = arrayStore(state)?.get(resolved);
|
|
4721
|
-
if (bracket < 0)
|
|
4722
|
-
return this.variable(state, base) !== undefined;
|
|
4723
4780
|
const selector = name.slice(bracket + 1, -1);
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
const
|
|
4727
|
-
if (
|
|
4728
|
-
return
|
|
4729
|
-
const index = await this.arrayIndex(binding, { decimal: selector, source: selector }, state, io, store.owner);
|
|
4781
|
+
const entries = this.presenceArrayEntries(state, resolved);
|
|
4782
|
+
const store = requireArrays(state);
|
|
4783
|
+
const index = await this.arrayIndex(binding, { decimal: selector, source: selector }, state, io, store.owner, false, entries ? entries.length - 1 : binding?.maximum ?? (this.variable(state, base) === undefined ? -1 : 0));
|
|
4784
|
+
if (entries)
|
|
4785
|
+
return index !== undefined && entries[index] !== undefined;
|
|
4730
4786
|
return index !== undefined && (binding ? binding.getValue(index) !== undefined
|
|
4731
4787
|
: index === 0 && this.variable(state, base) !== undefined);
|
|
4732
4788
|
}
|
|
4789
|
+
presenceArrayEntries(state, name) {
|
|
4790
|
+
if (name === "DIRSTACK")
|
|
4791
|
+
return [state.cwd, ...state.directoryStack?.entries ?? []];
|
|
4792
|
+
if (name === "FUNCNAME" && state.variables.FUNCNAME === undefined && !arrayStore(state)?.get(name))
|
|
4793
|
+
return state.functionNames ?? [];
|
|
4794
|
+
return undefined;
|
|
4795
|
+
}
|
|
4796
|
+
tryVariablePresentSync(state, name) {
|
|
4797
|
+
name = this.referenceName(state, name);
|
|
4798
|
+
const bracket = name.indexOf("[");
|
|
4799
|
+
const base = bracket < 0 ? name : name.slice(0, bracket);
|
|
4800
|
+
if (!isShellIdentifier(base) || bracket >= 0 && !name.endsWith("]"))
|
|
4801
|
+
return false;
|
|
4802
|
+
const resolved = this.referenceName(state, base);
|
|
4803
|
+
const binding = arrayStore(state)?.get(resolved);
|
|
4804
|
+
const entries = this.presenceArrayEntries(state, resolved);
|
|
4805
|
+
if (bracket < 0)
|
|
4806
|
+
return entries ? entries[0] !== undefined : this.variable(state, base) !== undefined;
|
|
4807
|
+
const selector = name.slice(bracket + 1, -1);
|
|
4808
|
+
if (binding?.associative) {
|
|
4809
|
+
if (selector.length === 0 || selector.length > 4096 || [...selector].some(character => "$`\\\"'".includes(character)))
|
|
4810
|
+
return undefined;
|
|
4811
|
+
const key = binding.keys.get(fastStringHexIdentity(selector));
|
|
4812
|
+
return key !== undefined && binding.getValue(key.index) !== undefined;
|
|
4813
|
+
}
|
|
4814
|
+
if (selector === "@" || selector === "*")
|
|
4815
|
+
return entries ? entries.length > 0 : binding ? binding.values.size > 0 : this.variable(state, base) !== undefined;
|
|
4816
|
+
if (selector.length === 0 || selector.length > 9 || [...selector].some(character => !"0123456789".includes(character)) || selector.length > 1 && selector[0] === "0")
|
|
4817
|
+
return undefined;
|
|
4818
|
+
const index = Number(selector);
|
|
4819
|
+
return entries ? entries[index] !== undefined : binding ? binding.getValue(index) !== undefined : index === 0 && this.variable(state, base) !== undefined;
|
|
4820
|
+
}
|
|
4733
4821
|
requireParameter(value, name, state, io, line) {
|
|
4734
4822
|
if (value === undefined && state.nounset)
|
|
4735
4823
|
throw new NounsetFailure(`${name}: unbound variable`, io.diagnosticLine ?? line);
|
|
@@ -5187,24 +5275,162 @@ export class Runtime {
|
|
|
5187
5275
|
}
|
|
5188
5276
|
}
|
|
5189
5277
|
}
|
|
5278
|
+
canSyncArrayMembersWord(w, rawState) {
|
|
5279
|
+
if (rawState.nounset)
|
|
5280
|
+
return false;
|
|
5281
|
+
const p0 = w.parts.length === 1 ? w.parts[0] : (w.parts.length === 2 && w.parts[0].kind === "text" && w.parts[0].value === "" ? w.parts[1] : undefined);
|
|
5282
|
+
if (!p0)
|
|
5283
|
+
return false;
|
|
5284
|
+
if (p0.kind !== "variable" || !p0.quoted || p0.indirect || p0.prefixNames || p0.length || p0.transform || p0.operator !== undefined)
|
|
5285
|
+
return false;
|
|
5286
|
+
const sel0 = getArraySelector(p0);
|
|
5287
|
+
if (!sel0 || (sel0.kind !== "members" && sel0.kind !== "keys") || sel0.separator !== "@")
|
|
5288
|
+
return false;
|
|
5289
|
+
if (p0.substring) {
|
|
5290
|
+
if (sel0.kind !== "members" || p0.keys)
|
|
5291
|
+
return false;
|
|
5292
|
+
const b = stateMonitor(rawState)?.store?.get(resolveSyncNameref(rawState, p0.name));
|
|
5293
|
+
if (b && b.associative)
|
|
5294
|
+
return false;
|
|
5295
|
+
if (!this.isPureSyncValueWord(p0.substring.offset, rawState))
|
|
5296
|
+
return false;
|
|
5297
|
+
if (p0.substring.length && !this.isPureSyncValueWord(p0.substring.length, rawState))
|
|
5298
|
+
return false;
|
|
5299
|
+
}
|
|
5300
|
+
return true;
|
|
5301
|
+
}
|
|
5302
|
+
tryExpandSyncArrayMembersWord(w, rawState, io, diagnosticLine) {
|
|
5303
|
+
if (rawState.nounset)
|
|
5304
|
+
return undefined;
|
|
5305
|
+
const p0 = w.parts.length === 1 ? w.parts[0] : (w.parts.length === 2 && w.parts[0].kind === "text" && w.parts[0].value === "" ? w.parts[1] : undefined);
|
|
5306
|
+
if (!p0)
|
|
5307
|
+
return undefined;
|
|
5308
|
+
if (p0.kind !== "variable" || !p0.quoted || p0.indirect || p0.prefixNames || p0.length || p0.transform || p0.operator !== undefined)
|
|
5309
|
+
return undefined;
|
|
5310
|
+
const sel0 = getArraySelector(p0);
|
|
5311
|
+
if (!sel0 || (sel0.kind !== "members" && sel0.kind !== "keys") || sel0.separator !== "@")
|
|
5312
|
+
return undefined;
|
|
5313
|
+
const monitor = stateMonitor(rawState);
|
|
5314
|
+
const activeStore = monitor?.store ?? arrayStore(rawState);
|
|
5315
|
+
const resolvedName = resolveSyncNameref(rawState, p0.name);
|
|
5316
|
+
const b = activeStore?.get(resolvedName);
|
|
5317
|
+
if (p0.substring) {
|
|
5318
|
+
if (sel0.kind !== "members" || p0.keys || (b && b.associative))
|
|
5319
|
+
return undefined;
|
|
5320
|
+
if (b && b.maximum >= 4096)
|
|
5321
|
+
return undefined;
|
|
5322
|
+
const evalSliceInt = (sw) => {
|
|
5323
|
+
if (sw.parts.length === 0)
|
|
5324
|
+
return 0;
|
|
5325
|
+
let expanded;
|
|
5326
|
+
try {
|
|
5327
|
+
expanded = this.fastValueWord(sw, rawState, io, false, false, false, false, undefined, diagnosticLine);
|
|
5328
|
+
}
|
|
5329
|
+
catch {
|
|
5330
|
+
return undefined;
|
|
5331
|
+
}
|
|
5332
|
+
if (typeof expanded !== "string")
|
|
5333
|
+
return undefined;
|
|
5334
|
+
const trimmed = expanded.trim();
|
|
5335
|
+
if (trimmed.length === 0)
|
|
5336
|
+
return 0;
|
|
5337
|
+
const syncTouched = this._syncArithRawWriteOnly ? this._syncArithTouched : undefined;
|
|
5338
|
+
const directOp = resolveSimpleArithOperand(trimmed, rawState, monitor, activeStore, syncTouched);
|
|
5339
|
+
if (directOp !== undefined)
|
|
5340
|
+
return directOp;
|
|
5341
|
+
const simpleExpr = tryEvalSimpleExpandedArith(trimmed, rawState, monitor, activeStore, syncTouched);
|
|
5342
|
+
if (simpleExpr !== undefined)
|
|
5343
|
+
return Number(simpleExpr);
|
|
5344
|
+
return undefined;
|
|
5345
|
+
};
|
|
5346
|
+
const offNum = evalSliceInt(p0.substring.offset);
|
|
5347
|
+
if (offNum === undefined)
|
|
5348
|
+
return undefined;
|
|
5349
|
+
let maxCount = Infinity;
|
|
5350
|
+
if (p0.substring.length) {
|
|
5351
|
+
const lenNum = evalSliceInt(p0.substring.length);
|
|
5352
|
+
if (lenNum === undefined || lenNum < 0)
|
|
5353
|
+
return undefined;
|
|
5354
|
+
maxCount = lenNum;
|
|
5355
|
+
}
|
|
5356
|
+
if (!b) {
|
|
5357
|
+
const sv = rawState.variables[resolvedName];
|
|
5358
|
+
if (sv === undefined)
|
|
5359
|
+
return [];
|
|
5360
|
+
const mv = (this._syncArithRawWriteOnly && this._syncArithTouched?.has(resolvedName)) ? sv : (monitor?.values.get(resolvedName, sv) ?? sv);
|
|
5361
|
+
if (typeof mv !== "string")
|
|
5362
|
+
return undefined;
|
|
5363
|
+
const startIdx = offNum < 0 ? 1 + offNum : offNum;
|
|
5364
|
+
if (startIdx < 0 || startIdx > 0 || maxCount === 0)
|
|
5365
|
+
return [];
|
|
5366
|
+
return [mv];
|
|
5367
|
+
}
|
|
5368
|
+
if (b.values.size === 0 || maxCount === 0)
|
|
5369
|
+
return [];
|
|
5370
|
+
const startIdx = offNum < 0 ? b.maximum + 1 + offNum : offNum;
|
|
5371
|
+
if (startIdx < 0)
|
|
5372
|
+
return [];
|
|
5373
|
+
const out = [];
|
|
5374
|
+
for (let k = startIdx; k <= b.maximum && out.length < maxCount; k++) {
|
|
5375
|
+
const slot = b.values.get(k);
|
|
5376
|
+
if (!slot)
|
|
5377
|
+
continue;
|
|
5378
|
+
const v = slot.text.shellValue;
|
|
5379
|
+
if (typeof v !== "string")
|
|
5380
|
+
return undefined;
|
|
5381
|
+
out.push(v);
|
|
5382
|
+
}
|
|
5383
|
+
return out;
|
|
5384
|
+
}
|
|
5385
|
+
const isKeys = sel0.kind === "keys" || p0.keys === true;
|
|
5386
|
+
if (b) {
|
|
5387
|
+
if (b.maximum >= 4096)
|
|
5388
|
+
return undefined;
|
|
5389
|
+
const out = [];
|
|
5390
|
+
for (let k = 0; k <= b.maximum; k++) {
|
|
5391
|
+
const slot = b.values.get(k);
|
|
5392
|
+
if (!slot)
|
|
5393
|
+
continue;
|
|
5394
|
+
const v = isKeys ? (b.associative ? b.keys.get(b.keyByIndex.get(k))?.text.shellValue : String(k)) : slot.text.shellValue;
|
|
5395
|
+
if (typeof v !== "string")
|
|
5396
|
+
return undefined;
|
|
5397
|
+
out.push(v);
|
|
5398
|
+
}
|
|
5399
|
+
return out;
|
|
5400
|
+
}
|
|
5401
|
+
const sv = rawState.variables[resolvedName];
|
|
5402
|
+
if (sv === undefined)
|
|
5403
|
+
return [];
|
|
5404
|
+
if (isKeys)
|
|
5405
|
+
return ["0"];
|
|
5406
|
+
const mv = (this._syncArithRawWriteOnly && this._syncArithTouched?.has(resolvedName)) ? sv : (monitor?.values.get(resolvedName, sv) ?? sv);
|
|
5407
|
+
if (typeof mv !== "string")
|
|
5408
|
+
return undefined;
|
|
5409
|
+
return [mv];
|
|
5410
|
+
}
|
|
5190
5411
|
tryFastArrayAssignmentSync(assignment, state, io, diagnosticLine, declaration, associative, ignoreYield = false) {
|
|
5191
5412
|
if (!ignoreYield && hasYieldCheckpoint(this.signal))
|
|
5192
5413
|
return false;
|
|
5193
5414
|
if (declaration)
|
|
5194
5415
|
return false;
|
|
5416
|
+
const monitor = stateMonitor(state);
|
|
5417
|
+
const rawState = monitor ? monitor.raw : state;
|
|
5195
5418
|
// Array writes must prepare scope observers before creating or mutating bindings.
|
|
5196
|
-
const name = assignment.name;
|
|
5419
|
+
const name = resolveSyncNameref(rawState, assignment.name);
|
|
5197
5420
|
if (hasUnpreparedLocal(state, name))
|
|
5198
5421
|
return false;
|
|
5199
5422
|
this._syncArithTouched?.delete(name);
|
|
5200
|
-
const monitor = stateMonitor(state);
|
|
5201
|
-
const rawState = monitor ? monitor.raw : state;
|
|
5202
5423
|
if (rawState.readonlyVariables?.has(name) || rawState.variableAttributes?.get(name) || rawState.exported.has(name) || controlNames.has(name)) {
|
|
5203
5424
|
return false;
|
|
5204
5425
|
}
|
|
5205
5426
|
// Cold activation belongs to normal command handling, which maps array refusals.
|
|
5206
|
-
const store = monitor?.store ?? (monitor &&
|
|
5427
|
+
const store = monitor?.store ?? (monitor && (this.budget.limits.maxExpansionBytes === Infinity && this.budget.limits.maxExpansionFields === Infinity) ? requireArrays(rawState) : undefined);
|
|
5207
5428
|
let current = store?.get(name);
|
|
5429
|
+
if (assignment.kind === "compound" && !(associative ?? current?.associative) && state.braceexpand !== false && assignment.entries.some(entry => {
|
|
5430
|
+
const original = compoundEntryWords.get(entry);
|
|
5431
|
+
return entry.index !== undefined && original?.parts.some(part => part.kind === "text" && !part.quoted && part.value.includes("{"));
|
|
5432
|
+
}))
|
|
5433
|
+
return false;
|
|
5208
5434
|
if (!monitor || !store || store.watches.has(name) || monitor.hasOverlay(name) || (current && (current.references !== 1 || (associative !== undefined && current.associative !== associative))) || (!current && rawState.variables[name] !== undefined)) {
|
|
5209
5435
|
return false;
|
|
5210
5436
|
}
|
|
@@ -5253,7 +5479,7 @@ export class Runtime {
|
|
|
5253
5479
|
let val = "";
|
|
5254
5480
|
if (entry.value.parts.length > 0) {
|
|
5255
5481
|
try {
|
|
5256
|
-
val = this.fastValueWord(entry.value, rawState, io, false, false, false, false, undefined, diagnosticLine);
|
|
5482
|
+
val = this.fastValueWord(entry.value, rawState, io, false, false, false, false, entry.index === undefined ? undefined : 0, diagnosticLine);
|
|
5257
5483
|
}
|
|
5258
5484
|
catch {
|
|
5259
5485
|
return false;
|
|
@@ -5301,6 +5527,8 @@ export class Runtime {
|
|
|
5301
5527
|
const entry = assignment.entries[i];
|
|
5302
5528
|
if (entry.append)
|
|
5303
5529
|
return false;
|
|
5530
|
+
if (rawState.braceexpand !== false && entry.value.parts.some(p => !p.quoted && p.kind === "text" && p.value.includes("{")))
|
|
5531
|
+
return false;
|
|
5304
5532
|
let explicitIdx;
|
|
5305
5533
|
if (entry.index !== undefined) {
|
|
5306
5534
|
const kSrc = (entry.index.source ?? entry.index.decimal).trim();
|
|
@@ -5308,13 +5536,26 @@ export class Runtime {
|
|
|
5308
5536
|
return false;
|
|
5309
5537
|
explicitIdx = Number(kSrc);
|
|
5310
5538
|
}
|
|
5311
|
-
else
|
|
5312
|
-
|
|
5539
|
+
else {
|
|
5540
|
+
const expandedArr = this.tryExpandSyncArrayMembersWord(entry.value, rawState, io, diagnosticLine);
|
|
5541
|
+
if (expandedArr !== undefined) {
|
|
5542
|
+
for (let mIdx = 0; mIdx < expandedArr.length; mIdx++) {
|
|
5543
|
+
const mVal = expandedArr[mIdx];
|
|
5544
|
+
const bLen = shellValueByteLength(mVal);
|
|
5545
|
+
if (bLen > this.budget.limits.maxExpansionBytes)
|
|
5546
|
+
return false;
|
|
5547
|
+
items.push({ explicitIdx: undefined, val: mVal, bLen });
|
|
5548
|
+
}
|
|
5549
|
+
continue;
|
|
5550
|
+
}
|
|
5551
|
+
if (entry.value.parts.length === 0 || !entry.value.parts.every(p => p.quoted || (p.kind === "text" && p.value.length > 0 && !p.value.includes(" ") && !p.value.includes("\t") && !p.value.includes("\n") && !p.value.includes("{") && !hasGlobOrEscape(p.value, true)))) {
|
|
5552
|
+
return false;
|
|
5553
|
+
}
|
|
5313
5554
|
}
|
|
5314
5555
|
let val = "";
|
|
5315
5556
|
if (entry.value.parts.length > 0) {
|
|
5316
5557
|
try {
|
|
5317
|
-
val = this.fastValueWord(entry.value, rawState, io, false, false, false, false, undefined, diagnosticLine);
|
|
5558
|
+
val = this.fastValueWord(entry.value, rawState, io, false, false, false, false, entry.index === undefined ? undefined : 0, diagnosticLine);
|
|
5318
5559
|
}
|
|
5319
5560
|
catch {
|
|
5320
5561
|
return false;
|
|
@@ -5723,7 +5964,7 @@ export class Runtime {
|
|
|
5723
5964
|
continue;
|
|
5724
5965
|
}
|
|
5725
5966
|
const index = entry.index ? (await this.arrayIndex(targetBinding, entry.index, state, io, operation, true)) : undefined;
|
|
5726
|
-
const fields = await this.valueWord(entry.value, state, io, entry.index === undefined);
|
|
5967
|
+
const fields = await this.valueWord(entry.value, state, io, entry.index === undefined, false, false, false, undefined, false, entry.index === undefined, entry.index === undefined ? undefined : 0);
|
|
5727
5968
|
if (index !== undefined) {
|
|
5728
5969
|
const value = await join(fields);
|
|
5729
5970
|
await insert(index, value, entry.append);
|
|
@@ -6240,6 +6481,9 @@ export class Runtime {
|
|
|
6240
6481
|
if (!watch.valid())
|
|
6241
6482
|
throw new ArrayFailure("binding changed during writer admission");
|
|
6242
6483
|
prepared.validate();
|
|
6484
|
+
// Clearing an indexed destination is an assignment even without elements.
|
|
6485
|
+
if (clear)
|
|
6486
|
+
prepared.binding.assigned = true;
|
|
6243
6487
|
let retirement;
|
|
6244
6488
|
monitor.publish(prepared.tickets, name, () => {
|
|
6245
6489
|
delete state.variables[name];
|
|
@@ -8145,14 +8389,14 @@ export class Runtime {
|
|
|
8145
8389
|
const r0 = command.redirects[0];
|
|
8146
8390
|
const rOp = r0.operator;
|
|
8147
8391
|
const isDevNull = (r0.descriptor === undefined || r0.descriptor === 1) && !r0.move && !r0.document && (rOp === ">" || rOp === ">>" || rOp === ">|") && r0.target.plain === "/dev/null";
|
|
8148
|
-
const isReadCmd = w0Plain === "read" || (command.words[1]?.plain === "read" && w0.parts[0]?.kind === "text" && w0.parts[0].value.startsWith("IFS="));
|
|
8392
|
+
const isReadCmd = w0Plain === "read" || w0Plain === "mapfile" || w0Plain === "readarray" || (command.words[1]?.plain === "read" && w0.parts[0]?.kind === "text" && w0.parts[0].value.startsWith("IFS="));
|
|
8149
8393
|
if (!isDevNull && w0Plain !== "echo" && w0Plain !== "printf" && !(isReadCmd && rOp === "<<<")) {
|
|
8150
8394
|
pipeline._skipTrySync = true;
|
|
8151
8395
|
return undefined;
|
|
8152
8396
|
}
|
|
8153
8397
|
}
|
|
8154
8398
|
else if (wordsLen >= 2) {
|
|
8155
|
-
if (w0Plain !== "echo" && w0Plain !== "printf" && w0Plain !== "[" && w0Plain !== "test" && w0Plain !== "mkdir" && w0Plain !== "rm" && w0Plain !== "local" && w0Plain !== "declare" && w0Plain !== "typeset" && w0Plain !== "return" && w0Plain !== "break" && w0Plain !== "continue" && w0Plain !== "shift" && w0Plain !== "read" && w0Plain !== "eval" && w0Plain !== "unset" && w0Plain !== "export" && w0Plain !== "let" && !(command.words[1]?.plain === "read" && w0.parts[0]?.kind === "text" && w0.parts[0].value.startsWith("IFS=")) && !(w0Plain !== undefined && state.functions.has(w0Plain))) {
|
|
8399
|
+
if (w0Plain !== ":" && w0Plain !== "true" && w0Plain !== "false" && w0Plain !== "getopts" && w0Plain !== "echo" && w0Plain !== "printf" && w0Plain !== "[" && w0Plain !== "test" && w0Plain !== "mkdir" && w0Plain !== "rm" && w0Plain !== "local" && w0Plain !== "declare" && w0Plain !== "typeset" && w0Plain !== "return" && w0Plain !== "break" && w0Plain !== "continue" && w0Plain !== "shift" && w0Plain !== "read" && w0Plain !== "eval" && w0Plain !== "unset" && w0Plain !== "export" && w0Plain !== "let" && !(command.words[1]?.plain === "read" && w0.parts[0]?.kind === "text" && w0.parts[0].value.startsWith("IFS=")) && !(w0Plain !== undefined && state.functions.has(w0Plain))) {
|
|
8156
8400
|
return undefined;
|
|
8157
8401
|
}
|
|
8158
8402
|
}
|
|
@@ -8214,6 +8458,8 @@ export class Runtime {
|
|
|
8214
8458
|
return true;
|
|
8215
8459
|
}
|
|
8216
8460
|
}
|
|
8461
|
+
// mapfile can require the asynchronous path as its input or binding
|
|
8462
|
+
// changes. Never speculate across a loop that has already made writes.
|
|
8217
8463
|
}
|
|
8218
8464
|
return false;
|
|
8219
8465
|
}
|
|
@@ -8238,7 +8484,7 @@ export class Runtime {
|
|
|
8238
8484
|
const fnBody = rawState.functions.get(w0Plain);
|
|
8239
8485
|
return fnBody.kind === "group" && fnBody.redirects.length === 0 && this.canSyncScriptCompound(fnBody.body, rawState, depth + 1);
|
|
8240
8486
|
}
|
|
8241
|
-
const st = stateMonitor(rawState)?.store ?? (stateMonitor(rawState) &&
|
|
8487
|
+
const st = stateMonitor(rawState)?.store ?? (stateMonitor(rawState) && (this.budget.limits.maxExpansionBytes === Infinity && this.budget.limits.maxExpansionFields === Infinity) ? requireArrays(rawState) : undefined);
|
|
8242
8488
|
const arrayAssign = getArrayAssignment(w0);
|
|
8243
8489
|
if (arrayAssign) {
|
|
8244
8490
|
if (!st)
|
|
@@ -8247,7 +8493,7 @@ export class Runtime {
|
|
|
8247
8493
|
return false;
|
|
8248
8494
|
}
|
|
8249
8495
|
if (arrayAssign.kind === "compound") {
|
|
8250
|
-
const isAssoc = Boolean(st?.get(arrayAssign.name)?.associative);
|
|
8496
|
+
const isAssoc = Boolean(st?.get(resolveSyncNameref(rawState, arrayAssign.name))?.associative);
|
|
8251
8497
|
return (arrayAssign.entries.length <= 32 && arrayAssign.entries.every(e => {
|
|
8252
8498
|
if (e.append)
|
|
8253
8499
|
return false;
|
|
@@ -8259,13 +8505,15 @@ export class Runtime {
|
|
|
8259
8505
|
const kSrc = (e.index.source ?? e.index.decimal).trim();
|
|
8260
8506
|
return /^(?:0|[1-9][0-9]{0,8})$/.test(kSrc) && isNoBraceSyncAssignWord(e.value);
|
|
8261
8507
|
}
|
|
8508
|
+
if (this.canSyncArrayMembersWord(e.value, rawState))
|
|
8509
|
+
return true;
|
|
8262
8510
|
return isNoBraceSyncWord(e.value) && e.value.parts.length > 0 && e.value.parts.every(p => p.quoted || (p.kind === "text" && p.value.length > 0 && !p.value.includes(" ") && !p.value.includes("\t") && !p.value.includes("\n") && !p.value.includes("{") && !hasGlobOrEscape(p.value, true)));
|
|
8263
8511
|
}));
|
|
8264
8512
|
}
|
|
8265
8513
|
return isNoBraceSyncAssignWord(arrayAssign.value);
|
|
8266
8514
|
}
|
|
8267
8515
|
const assignment = this.assignment(w0);
|
|
8268
|
-
return Boolean(assignment && assignment.name !== "OPTIND" && assignment.name !== "PIPESTATUS" && !assignment.name.includes("[") && !rawState.readonlyVariables?.has(assignment.name) && (!st?.get(assignment.name) || (!assignment.append && !hasUnpreparedLocal(rawState, assignment.name) && !rawState.exported.has(assignment.name))) && isNoBraceSyncAssignWord(assignment.value));
|
|
8516
|
+
return Boolean(assignment && (assignment.name !== "OPTIND" || (!assignment.append && !rawState.variableAttributes?.get("OPTIND"))) && assignment.name !== "PIPESTATUS" && !assignment.name.includes("[") && !rawState.readonlyVariables?.has(assignment.name) && (!st?.get(assignment.name) || (!assignment.append && !hasUnpreparedLocal(rawState, assignment.name) && !rawState.exported.has(assignment.name))) && isNoBraceSyncAssignWord(assignment.value));
|
|
8269
8517
|
}
|
|
8270
8518
|
if (w0Plain !== undefined && command.words.length <= 64 && rawState.functions.has(w0Plain) && this.firstInternalDiscovery(w0Plain, rawState, false) === "function" && !hasActiveExtensions(rawState)) {
|
|
8271
8519
|
const fnBody = rawState.functions.get(w0Plain);
|
|
@@ -8292,7 +8540,7 @@ export class Runtime {
|
|
|
8292
8540
|
}
|
|
8293
8541
|
if (command.words.length >= 2 && command.words.length <= 16) {
|
|
8294
8542
|
if (w0Plain === "unset" &&
|
|
8295
|
-
rawState.locals.length === 0 &&
|
|
8543
|
+
depth === 0 && rawState.locals.length === 0 &&
|
|
8296
8544
|
!hasShellFunction(rawState, "unset") &&
|
|
8297
8545
|
!rawState.extensions?.builtins.has("unset")) {
|
|
8298
8546
|
const uStart = command.words[1]?.plain === "-v" ? 2 : 1;
|
|
@@ -8316,6 +8564,7 @@ export class Runtime {
|
|
|
8316
8564
|
}
|
|
8317
8565
|
if (w0Plain === "export" &&
|
|
8318
8566
|
rawState.locals.length === 0 &&
|
|
8567
|
+
depth === 0 &&
|
|
8319
8568
|
!hasShellFunction(rawState, "export") &&
|
|
8320
8569
|
!rawState.extensions?.builtins.has("export")) {
|
|
8321
8570
|
let allOk = true;
|
|
@@ -8382,17 +8631,19 @@ export class Runtime {
|
|
|
8382
8631
|
// Array locals require the typed declaration and restoration lifecycle.
|
|
8383
8632
|
if (command.words[1]?.plain === "-a" || command.words[1]?.plain === "-A")
|
|
8384
8633
|
return false;
|
|
8634
|
+
const isNamerefDecl = command.words[1]?.plain === "-n" && (rawState.locals.length > 0 || depth > 0) && command.words.length >= 3;
|
|
8635
|
+
const isGlobalDecl = command.words[1]?.plain === "-g" && (w0Plain === "declare" || w0Plain === "typeset") && command.words.length >= 3;
|
|
8385
8636
|
let allValidLocal = true;
|
|
8386
|
-
for (let idx = 1; idx < command.words.length; idx++) {
|
|
8637
|
+
for (let idx = (isNamerefDecl || isGlobalDecl) ? 2 : 1; idx < command.words.length; idx++) {
|
|
8387
8638
|
const wArg = command.words[idx];
|
|
8388
8639
|
const assignment = !getArrayAssignment(wArg) ? this.assignment(wArg) : undefined;
|
|
8389
8640
|
if (assignment) {
|
|
8390
|
-
if (assignment.name === "OPTIND" || assignment.name === "PIPESTATUS" || assignment.name.includes("[") || !isNoBraceSyncAssignWord(assignment.value)) {
|
|
8641
|
+
if ((!isNamerefDecl && rawState.variableAttributes?.get(assignment.name)) || (assignment.name === "OPTIND" && (assignment.append || rawState.variableAttributes?.get("OPTIND"))) || assignment.name === "PIPESTATUS" || assignment.name.includes("[") || !isNoBraceSyncAssignWord(assignment.value)) {
|
|
8391
8642
|
allValidLocal = false;
|
|
8392
8643
|
break;
|
|
8393
8644
|
}
|
|
8394
8645
|
}
|
|
8395
|
-
else if (!wArg.plain || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(wArg.plain) || wArg.plain === "OPTIND" || wArg.plain === "PIPESTATUS") {
|
|
8646
|
+
else if (!wArg.plain || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(wArg.plain) || (wArg.plain === "OPTIND" && rawState.variableAttributes?.get("OPTIND")) || wArg.plain === "PIPESTATUS") {
|
|
8396
8647
|
allValidLocal = false;
|
|
8397
8648
|
break;
|
|
8398
8649
|
}
|
|
@@ -8400,6 +8651,13 @@ export class Runtime {
|
|
|
8400
8651
|
if (allValidLocal)
|
|
8401
8652
|
return true;
|
|
8402
8653
|
}
|
|
8654
|
+
if ((w0Plain === ":" || w0Plain === "true" || w0Plain === "false") && command.words.length <= 16 && !hasShellFunction(rawState, w0Plain) && !rawState.extensions?.builtins.has(w0Plain) && command.words.slice(1).every(isNoBraceSyncWord)) {
|
|
8655
|
+
return true;
|
|
8656
|
+
}
|
|
8657
|
+
// The scanner may require diagnostics or exceed its synchronous bounds.
|
|
8658
|
+
// Falling back after an earlier loop iteration would replay its effects.
|
|
8659
|
+
if (w0Plain === "getopts")
|
|
8660
|
+
return false;
|
|
8403
8661
|
if (w0Plain === "echo" && !hasShellFunction(rawState, "echo") && !rawState.extensions?.builtins.has("echo")) {
|
|
8404
8662
|
const w1Plain = command.words[1]?.plain;
|
|
8405
8663
|
if (w1Plain === undefined || !w1Plain.startsWith("-") || w1Plain === "-n" || w1Plain === "-e" || w1Plain === "-ne" || w1Plain === "-en")
|
|
@@ -8430,7 +8688,17 @@ export class Runtime {
|
|
|
8430
8688
|
}
|
|
8431
8689
|
if (w0Plain !== undefined && rawState.functions.has(w0Plain) && command.words.slice(1).every(isNoBraceSyncWord)) {
|
|
8432
8690
|
const fnBody = rawState.functions.get(w0Plain);
|
|
8433
|
-
|
|
8691
|
+
if (fnBody.kind !== "group" || fnBody.redirects.length !== 0)
|
|
8692
|
+
return false;
|
|
8693
|
+
rawState.locals.push(new Map());
|
|
8694
|
+
rawState.functionDepth++;
|
|
8695
|
+
try {
|
|
8696
|
+
return this.canSyncScriptCompound(fnBody.body, rawState, depth + 1);
|
|
8697
|
+
}
|
|
8698
|
+
finally {
|
|
8699
|
+
rawState.functionDepth--;
|
|
8700
|
+
rawState.locals.pop();
|
|
8701
|
+
}
|
|
8434
8702
|
}
|
|
8435
8703
|
return false;
|
|
8436
8704
|
}
|
|
@@ -8458,8 +8726,35 @@ export class Runtime {
|
|
|
8458
8726
|
return this.isPureSyncValueWord(e.operand, rawState);
|
|
8459
8727
|
if (e.kind === "unary")
|
|
8460
8728
|
return (e.operator === "-n" || e.operator === "-z" || e.operator === "-v") && this.isPureSyncValueWord(e.operand, rawState);
|
|
8461
|
-
if (e.kind === "binary")
|
|
8729
|
+
if (e.kind === "binary") {
|
|
8730
|
+
if (e.operator === "=~") {
|
|
8731
|
+
if (!this.isPureSyncValueWord(e.left, rawState) || !this.extractSimpleErePattern(e.right) || rawState.readonlyVariables?.has("BASH_REMATCH") || rawState.exported.has("BASH_REMATCH") || hasUnpreparedLocal(rawState, "BASH_REMATCH"))
|
|
8732
|
+
return false;
|
|
8733
|
+
const mon = stateMonitor(rawState);
|
|
8734
|
+
if (!mon || (this.budget.limits.maxExpansionBytes !== Infinity || this.budget.limits.maxExpansionFields !== Infinity) || mon.hasOverlay("BASH_REMATCH"))
|
|
8735
|
+
return false;
|
|
8736
|
+
const st = mon.store ?? requireArrays(rawState);
|
|
8737
|
+
if (st.watches.has("BASH_REMATCH"))
|
|
8738
|
+
return false;
|
|
8739
|
+
let rem = st.get("BASH_REMATCH");
|
|
8740
|
+
if (!rem) {
|
|
8741
|
+
if (rawState.variables.BASH_REMATCH !== undefined)
|
|
8742
|
+
return false;
|
|
8743
|
+
const created = IndexedBinding.create(st.owner, false);
|
|
8744
|
+
const prepared = st.prepareExistingName("BASH_REMATCH", 12, st.owner, this.signal);
|
|
8745
|
+
if (!prepared) {
|
|
8746
|
+
void created.release();
|
|
8747
|
+
return false;
|
|
8748
|
+
}
|
|
8749
|
+
const initTickets = st.owner.charge({ generation: true, version: true, epoch: true, work: 8 });
|
|
8750
|
+
st.publish("BASH_REMATCH", created, initTickets, prepared, false, st.owner);
|
|
8751
|
+
mon.epoch = initTickets.epoch;
|
|
8752
|
+
rem = created;
|
|
8753
|
+
}
|
|
8754
|
+
return !rem.associative && rem.references === 1;
|
|
8755
|
+
}
|
|
8462
8756
|
return this.isPureSyncValueWord(e.left, rawState) && (e.operator === "==" || e.operator === "=" || e.operator === "!=" ? this.canSyncPatternWordParts(e.right, rawState) : this.isPureSyncValueWord(e.right, rawState));
|
|
8757
|
+
}
|
|
8463
8758
|
if (e.kind === "not")
|
|
8464
8759
|
return checkCondNoFile(e.operand);
|
|
8465
8760
|
if (e.kind === "and" || e.kind === "or")
|
|
@@ -8497,13 +8792,13 @@ export class Runtime {
|
|
|
8497
8792
|
const sel0 = p0?.kind === "variable" ? getArraySelector(p0) : undefined;
|
|
8498
8793
|
const isArrAt = Boolean(p0?.kind === "variable" && p0.quoted && !p0.indirect && !p0.prefixNames && !p0.length && !p0.substring && !p0.transform && p0.operator === undefined && (sel0?.kind === "members" || sel0?.kind === "keys") && sel0.separator === "@");
|
|
8499
8794
|
const isBraceRange = Boolean(p0?.kind === "text" && !p0.quoted && /^\{-?\d+\.\.-?\d+(?:\.\.-?\d+)?\}$/.test(p0.value));
|
|
8500
|
-
if (!isArrAt && !isBraceRange && !(this.isPureSyncValueWord(w0, rawState) && w0.parts.every(p => p.quoted || (p.kind === "text" && !p.value.includes(" ") && !p.value.includes("\t") && !p.value.includes("\n") && !p.value.includes("{") && !hasGlobOrEscape(p.value, true)))))
|
|
8795
|
+
if (!isArrAt && !isBraceRange && !this.canSyncArrayMembersWord(w0, rawState) && !(this.isPureSyncValueWord(w0, rawState) && w0.parts.every(p => p.quoted || (p.kind === "text" && !p.value.includes(" ") && !p.value.includes("\t") && !p.value.includes("\n") && !p.value.includes("{") && !hasGlobOrEscape(p.value, true)))))
|
|
8501
8796
|
return false;
|
|
8502
8797
|
}
|
|
8503
8798
|
else {
|
|
8504
8799
|
for (let i = 0; i < command.words.length; i++) {
|
|
8505
8800
|
const w = command.words[i];
|
|
8506
|
-
if (!this.isPureSyncValueWord(w, rawState) || !w.parts.every(p => p.quoted || (p.kind === "text" && !p.value.includes(" ") && !p.value.includes("\t") && !p.value.includes("\n") && !p.value.includes("{") && !hasGlobOrEscape(p.value, true))))
|
|
8801
|
+
if (!this.canSyncArrayMembersWord(w, rawState) && (!this.isPureSyncValueWord(w, rawState) || !w.parts.every(p => p.quoted || (p.kind === "text" && !p.value.includes(" ") && !p.value.includes("\t") && !p.value.includes("\n") && !p.value.includes("{") && !hasGlobOrEscape(p.value, true)))))
|
|
8507
8802
|
return false;
|
|
8508
8803
|
}
|
|
8509
8804
|
}
|
|
@@ -8610,7 +8905,9 @@ export class Runtime {
|
|
|
8610
8905
|
}
|
|
8611
8906
|
else if (wp0 === "local" || wp0 === "declare" || wp0 === "typeset") {
|
|
8612
8907
|
const isArrDecl = c.words[1]?.plain === "-a" || c.words[1]?.plain === "-A";
|
|
8613
|
-
|
|
8908
|
+
const isNameref = c.words[1]?.plain === "-n";
|
|
8909
|
+
const isGlobal = c.words[1]?.plain === "-g";
|
|
8910
|
+
for (let k = (isArrDecl || isNameref || isGlobal) ? 2 : 1; k < c.words.length; k++) {
|
|
8614
8911
|
const wk = c.words[k];
|
|
8615
8912
|
const aa = getArrayAssignment(wk);
|
|
8616
8913
|
if (aa) {
|
|
@@ -8627,6 +8924,9 @@ export class Runtime {
|
|
|
8627
8924
|
if (wp0 === "local" || d > 0)
|
|
8628
8925
|
localArrayVars.add(nm);
|
|
8629
8926
|
}
|
|
8927
|
+
else if (isNameref) {
|
|
8928
|
+
localArrayVars.add(nm);
|
|
8929
|
+
}
|
|
8630
8930
|
else {
|
|
8631
8931
|
scalarVars.add(nm);
|
|
8632
8932
|
const pv = asg?.value.plain;
|
|
@@ -8637,8 +8937,8 @@ export class Runtime {
|
|
|
8637
8937
|
}
|
|
8638
8938
|
}
|
|
8639
8939
|
}
|
|
8640
|
-
else if (wp0 === "printf" && c.words[1]?.plain === "-v" && c.words[2]?.plain) {
|
|
8641
|
-
const target = c.words[2].plain;
|
|
8940
|
+
else if (wp0 === "printf" && c.words[1]?.plain === "-v" && (c.words[2]?.plain || c.words[2]?.parts[0]?.kind === "text")) {
|
|
8941
|
+
const target = c.words[2].plain ?? c.words[2].parts[0].value;
|
|
8642
8942
|
const br = target.indexOf("[");
|
|
8643
8943
|
if (br > 0)
|
|
8644
8944
|
arrayVars.add(target.slice(0, br));
|
|
@@ -8647,6 +8947,19 @@ export class Runtime {
|
|
|
8647
8947
|
nonIntScalarVars.add(target);
|
|
8648
8948
|
}
|
|
8649
8949
|
}
|
|
8950
|
+
else if (wp0 === "mapfile" || wp0 === "readarray") {
|
|
8951
|
+
arrayVars.add(c.words[2]?.plain ?? "MAPFILE");
|
|
8952
|
+
}
|
|
8953
|
+
else if (wp0 === "getopts") {
|
|
8954
|
+
const ov = c.words[2]?.plain;
|
|
8955
|
+
if (ov && isShellIdentifier(ov)) {
|
|
8956
|
+
scalarVars.add(ov);
|
|
8957
|
+
nonIntScalarVars.add(ov);
|
|
8958
|
+
}
|
|
8959
|
+
scalarVars.add("OPTIND");
|
|
8960
|
+
scalarVars.add("OPTARG");
|
|
8961
|
+
nonIntScalarVars.add("OPTARG");
|
|
8962
|
+
}
|
|
8650
8963
|
else if (wp0 === "read" || (c.words[1]?.plain === "read")) {
|
|
8651
8964
|
for (let k = 1; k < c.words.length; k++) {
|
|
8652
8965
|
const vp = c.words[k]?.plain;
|
|
@@ -8828,36 +9141,8 @@ export class Runtime {
|
|
|
8828
9141
|
if (expr.operator === "-z")
|
|
8829
9142
|
return val.length === 0 ? 0 : 1;
|
|
8830
9143
|
if (expr.operator === "-v") {
|
|
8831
|
-
const
|
|
8832
|
-
|
|
8833
|
-
if (!isShellIdentifier(val))
|
|
8834
|
-
return 1;
|
|
8835
|
-
const b = store?.get(val);
|
|
8836
|
-
if (b)
|
|
8837
|
-
return b.get(b.associative ? b.keys.get("30")?.index ?? -1 : 0) !== undefined ? 0 : 1;
|
|
8838
|
-
return this.variable(rawState, val) !== undefined ? 0 : 1;
|
|
8839
|
-
}
|
|
8840
|
-
if (!val.endsWith("]"))
|
|
8841
|
-
return 1;
|
|
8842
|
-
const base = val.slice(0, bracket);
|
|
8843
|
-
if (!isShellIdentifier(base))
|
|
8844
|
-
return 1;
|
|
8845
|
-
const sub = val.slice(bracket + 1, -1);
|
|
8846
|
-
const b = store?.get(base);
|
|
8847
|
-
if (!b?.associative && (sub === "@" || sub === "*")) {
|
|
8848
|
-
return (b ? b.values.size > 0 : this.variable(rawState, base) !== undefined) ? 0 : 1;
|
|
8849
|
-
}
|
|
8850
|
-
if (b?.associative) {
|
|
8851
|
-
if (sub.length === 0 || sub.length > 4096 || /[$\x60\\"']/.test(sub))
|
|
8852
|
-
return undefined;
|
|
8853
|
-
const ek = b.keys.get(fastStringHexIdentity(sub));
|
|
8854
|
-
return (ek !== undefined && b.getValue(ek.index) !== undefined) ? 0 : 1;
|
|
8855
|
-
}
|
|
8856
|
-
if (/^(?:0|[1-9][0-9]{0,8})$/.test(sub)) {
|
|
8857
|
-
const idx = Number(sub);
|
|
8858
|
-
return (b ? b.getValue(idx) !== undefined : idx === 0 && this.variable(rawState, base) !== undefined) ? 0 : 1;
|
|
8859
|
-
}
|
|
8860
|
-
return undefined;
|
|
9144
|
+
const present = this.tryVariablePresentSync(rawState, val);
|
|
9145
|
+
return present === undefined ? undefined : present ? 0 : 1;
|
|
8861
9146
|
}
|
|
8862
9147
|
if (syncConditionalFileUnaryOps.has(expr.operator)) {
|
|
8863
9148
|
const fileRes = this.tryEvalFastMemoryFileUnary(expr.operator, val, rawState);
|
|
@@ -9016,7 +9301,24 @@ export class Runtime {
|
|
|
9016
9301
|
}
|
|
9017
9302
|
return undefined;
|
|
9018
9303
|
}
|
|
9019
|
-
|
|
9304
|
+
setSyncPipeStatusCell(existing, status) {
|
|
9305
|
+
const cell = existing.values.get(0);
|
|
9306
|
+
if (cell && cell.text.references === 1 && cell.text.bytes === status.length) {
|
|
9307
|
+
cell.text.shellValue = status;
|
|
9308
|
+
}
|
|
9309
|
+
else {
|
|
9310
|
+
existing.owner.chargeWork(status.length);
|
|
9311
|
+
const token = new OwnedText(status, status.length, existing.owner.reserve({ payload: status.length, metadata: 32, work: 4 }));
|
|
9312
|
+
try {
|
|
9313
|
+
existing.insert(0, token);
|
|
9314
|
+
}
|
|
9315
|
+
catch (error) {
|
|
9316
|
+
token.release();
|
|
9317
|
+
throw error;
|
|
9318
|
+
}
|
|
9319
|
+
}
|
|
9320
|
+
}
|
|
9321
|
+
finishSyncPipeStatus(rawState, monitor, store, existing, _elem0, scope, finalStatus, restEpoch) {
|
|
9020
9322
|
if (!existing) {
|
|
9021
9323
|
if (store) {
|
|
9022
9324
|
if (publishPipelineStatus(rawState, finalStatus === 0 ? singleStatusZero : singleStatusOne, this.signal, scope))
|
|
@@ -9028,7 +9330,7 @@ export class Runtime {
|
|
|
9028
9330
|
}
|
|
9029
9331
|
}
|
|
9030
9332
|
else {
|
|
9031
|
-
(
|
|
9333
|
+
this.setSyncPipeStatusCell(existing, finalStatus === 0 ? "0" : "1");
|
|
9032
9334
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
9033
9335
|
}
|
|
9034
9336
|
rawState.status = finalStatus;
|
|
@@ -9050,7 +9352,7 @@ export class Runtime {
|
|
|
9050
9352
|
return undefined;
|
|
9051
9353
|
const rawState = monitor.raw;
|
|
9052
9354
|
const gArrays = guestArrays(rawState);
|
|
9053
|
-
if (io.terminal || io.asyncDefaultInput || hasActiveExtensions(rawState) ||
|
|
9355
|
+
if (io.terminal || io.asyncDefaultInput || hasActiveExtensions(rawState) || hasNonNamerefAttributes(rawState) || (gArrays && gArrays.watches.size > 0))
|
|
9054
9356
|
return undefined;
|
|
9055
9357
|
if (((this.budget.commands + 1) & 127) === 0) {
|
|
9056
9358
|
if (hasYieldCheckpoint(this.signal) || (this._syncReturnDepth === 0 && ((this.budget.commands + 1) & 8191) === 0))
|
|
@@ -9067,7 +9369,7 @@ export class Runtime {
|
|
|
9067
9369
|
let existing = store?.get("PIPESTATUS");
|
|
9068
9370
|
if (store && !existing) {
|
|
9069
9371
|
const initTarget = pipelineStatusTarget(rawState);
|
|
9070
|
-
if (
|
|
9372
|
+
if ((this.budget.limits.maxExpansionBytes === Infinity && this.budget.limits.maxExpansionFields === Infinity) &&
|
|
9071
9373
|
(initTarget === "indexed" || initTarget === "absent") &&
|
|
9072
9374
|
!store.watches.has("PIPESTATUS") &&
|
|
9073
9375
|
!monitor.hasOverlay("PIPESTATUS") &&
|
|
@@ -9093,10 +9395,10 @@ export class Runtime {
|
|
|
9093
9395
|
return undefined;
|
|
9094
9396
|
}
|
|
9095
9397
|
const elem0 = existing?.values.get(0);
|
|
9096
|
-
if (existing &&
|
|
9398
|
+
if (existing && !elem0)
|
|
9097
9399
|
return undefined;
|
|
9098
9400
|
const canMutatePipeStatus = !existing || (existing.references === 1 && elem0.text.references === 1);
|
|
9099
|
-
const diagnosticLine = io.diagnosticCommandLines?.get(command) ?? (command.line ?? 1) + (io.diagnosticOffset ?? 0);
|
|
9401
|
+
const diagnosticLine = io.diagnosticCommandLines?.get(command) ?? io.substitutionDiagnosticLines?.get(command) ?? (command.line ?? 1) + (io.diagnosticOffset ?? 0);
|
|
9100
9402
|
if (command.kind === "function") {
|
|
9101
9403
|
if (pipeline.negate || !canMutatePipeStatus || command.redirects.length > 0 || rawState.readonlyFunctions?.has(command.name) || (rawState.profile === "sh" && (specialBuiltinNames.has(command.name) || rawState.extensions?.builtins.get(command.name)?.special))) {
|
|
9102
9404
|
return undefined;
|
|
@@ -9159,7 +9461,7 @@ export class Runtime {
|
|
|
9159
9461
|
}
|
|
9160
9462
|
}
|
|
9161
9463
|
else {
|
|
9162
|
-
|
|
9464
|
+
this.setSyncPipeStatusCell(activeExisting, finalStatus === 0 ? "0" : "1");
|
|
9163
9465
|
activeStore.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
9164
9466
|
}
|
|
9165
9467
|
rawState.status = finalStatus;
|
|
@@ -9265,13 +9567,13 @@ export class Runtime {
|
|
|
9265
9567
|
}
|
|
9266
9568
|
const scalarMutMatch = fastSrc.length <= 64 ? SIMPLE_SCALAR_MUT_RE.exec(fastSrc) : null;
|
|
9267
9569
|
if (scalarMutMatch) {
|
|
9268
|
-
const varName = scalarMutMatch[1];
|
|
9570
|
+
const varName = resolveSyncNameref(rawState, scalarMutMatch[1]);
|
|
9269
9571
|
const binOp = scalarMutMatch[2];
|
|
9270
9572
|
const rhs1 = Number(scalarMutMatch[3]);
|
|
9271
9573
|
const rhsOp = scalarMutMatch[4];
|
|
9272
9574
|
const rhs2 = scalarMutMatch[5] !== undefined ? Number(scalarMutMatch[5]) : 0;
|
|
9273
9575
|
const rhsNum = rhsOp === "+" ? rhs1 + rhs2 : rhsOp === "-" ? rhs1 - rhs2 : rhsOp === "*" ? rhs1 * rhs2 : rhs1;
|
|
9274
|
-
if (varName !== "OPTIND" && varName !== "PIPESTATUS" && !store?.get(varName) && !
|
|
9576
|
+
if (varName !== "OPTIND" && varName !== "PIPESTATUS" && !store?.get(varName) && !hasNonNamerefAttributes(rawState)) {
|
|
9275
9577
|
const curVal = (this._syncArithRawWriteOnly && this._syncArithTouched?.has(varName))
|
|
9276
9578
|
? (rawState.variables[varName] ?? "0")
|
|
9277
9579
|
: (monitor.values.get(varName, rawState.variables[varName] ?? "0") ?? rawState.variables[varName] ?? "0");
|
|
@@ -9353,7 +9655,15 @@ export class Runtime {
|
|
|
9353
9655
|
}
|
|
9354
9656
|
const dynProg = prepareArithmetic(fastSrc, this.budget.parsing);
|
|
9355
9657
|
if (!dynProg.error && isSafeSmiProgram(dynProg) && this.canSyncArithmeticWithoutFault(dynProg.tree, rawState, diagnosticLine)) {
|
|
9356
|
-
|
|
9658
|
+
let nonZero;
|
|
9659
|
+
try {
|
|
9660
|
+
nonZero = this.syncShellArithmeticNonZero(dynProg, rawState, diagnosticLine);
|
|
9661
|
+
}
|
|
9662
|
+
catch (err) {
|
|
9663
|
+
if (err instanceof ArrayFailure)
|
|
9664
|
+
return undefined;
|
|
9665
|
+
throw err;
|
|
9666
|
+
}
|
|
9357
9667
|
if (rawState.extensions && !rawState.extensions.eventDepth)
|
|
9358
9668
|
publishCommandSpelling(rawState, commandSpelling(command));
|
|
9359
9669
|
const restEpoch = monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets).epoch;
|
|
@@ -9366,7 +9676,15 @@ export class Runtime {
|
|
|
9366
9676
|
}
|
|
9367
9677
|
}
|
|
9368
9678
|
if (!expr.error && isSafeSmiProgram(expr) && this.canSyncArithmeticWithoutFault(expr.tree, rawState, diagnosticLine)) {
|
|
9369
|
-
|
|
9679
|
+
let nonZero;
|
|
9680
|
+
try {
|
|
9681
|
+
nonZero = this.syncShellArithmeticNonZero(expr, rawState, diagnosticLine);
|
|
9682
|
+
}
|
|
9683
|
+
catch (err) {
|
|
9684
|
+
if (err instanceof ArrayFailure)
|
|
9685
|
+
return undefined;
|
|
9686
|
+
throw err;
|
|
9687
|
+
}
|
|
9370
9688
|
if (rawState.extensions && !rawState.extensions.eventDepth)
|
|
9371
9689
|
publishCommandSpelling(rawState, commandSpelling(command));
|
|
9372
9690
|
const restEpoch = monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets).epoch;
|
|
@@ -9425,9 +9743,12 @@ export class Runtime {
|
|
|
9425
9743
|
}
|
|
9426
9744
|
return res;
|
|
9427
9745
|
}
|
|
9428
|
-
|
|
9429
|
-
|
|
9430
|
-
|
|
9746
|
+
if (!command._skipTrySyncLoop) {
|
|
9747
|
+
const fastLoopRes = this.trySyncLoop(command, pipeline, rawState, monitor, store, existing, elem0, canMutatePipeStatus, io, diagnosticLine);
|
|
9748
|
+
if (fastLoopRes !== undefined)
|
|
9749
|
+
return fastLoopRes;
|
|
9750
|
+
command._skipTrySyncLoop = true;
|
|
9751
|
+
}
|
|
9431
9752
|
}
|
|
9432
9753
|
if (command.kind === "group" || command.kind === "if" || command.kind === "case" || command.kind === "while" || command.kind === "until" || command.kind === "for" || command.kind === "arithmetic-for") {
|
|
9433
9754
|
if (command.redirects.length !== 0 || pipeline.negate || !canMutatePipeStatus || (!ignored && rawState.errexit) || rawState.nounset || rawState.readonlyVariables?.size || hasYieldCheckpoint(this.signal) || (this._syncReturnDepth === 0 && (((this.budget.commands + 32) & 8191) < 32 || !this.canSyncCommandCompound(command, rawState, 0, rawState.loopDepth)))) {
|
|
@@ -9488,6 +9809,12 @@ export class Runtime {
|
|
|
9488
9809
|
if (command.kind === "while" || command.kind === "until") {
|
|
9489
9810
|
this.budget.tick();
|
|
9490
9811
|
let lastStatus = 0;
|
|
9812
|
+
const enableBatchRawWrite = !this._syncArithRawWriteOnly && !hasActiveExtensions(rawState) && !hasActiveVariableAttributes(rawState) && !rawState.readonlyVariables?.size && !rawState.allexport;
|
|
9813
|
+
const batchTouched = enableBatchRawWrite ? new Set() : undefined;
|
|
9814
|
+
if (enableBatchRawWrite) {
|
|
9815
|
+
this._syncArithRawWriteOnly = true;
|
|
9816
|
+
this._syncArithTouched = batchTouched;
|
|
9817
|
+
}
|
|
9491
9818
|
rawState.loopDepth++;
|
|
9492
9819
|
this._syncReturnDepth++;
|
|
9493
9820
|
try {
|
|
@@ -9544,6 +9871,17 @@ export class Runtime {
|
|
|
9544
9871
|
finally {
|
|
9545
9872
|
this._syncReturnDepth--;
|
|
9546
9873
|
rawState.loopDepth--;
|
|
9874
|
+
if (enableBatchRawWrite && batchTouched) {
|
|
9875
|
+
this._syncArithRawWriteOnly = false;
|
|
9876
|
+
this._syncArithTouched = undefined;
|
|
9877
|
+
for (const vName of batchTouched) {
|
|
9878
|
+
const vVal = rawState.variables[vName];
|
|
9879
|
+
if (typeof vVal === "string")
|
|
9880
|
+
monitor.publishStringVariable(vName, vVal);
|
|
9881
|
+
else if (vVal === undefined)
|
|
9882
|
+
delete monitor.proxy.variables[vName];
|
|
9883
|
+
}
|
|
9884
|
+
}
|
|
9547
9885
|
}
|
|
9548
9886
|
rawState.status = lastStatus;
|
|
9549
9887
|
return lastStatus;
|
|
@@ -9554,12 +9892,18 @@ export class Runtime {
|
|
|
9554
9892
|
return undefined;
|
|
9555
9893
|
}
|
|
9556
9894
|
this.budget.tick();
|
|
9557
|
-
|
|
9558
|
-
|
|
9895
|
+
const enableBatchRawWrite = !this._syncArithRawWriteOnly && !hasActiveExtensions(rawState) && !hasActiveVariableAttributes(rawState) && !rawState.readonlyVariables?.size && !rawState.allexport;
|
|
9896
|
+
const batchTouched = enableBatchRawWrite ? new Set() : undefined;
|
|
9897
|
+
if (enableBatchRawWrite) {
|
|
9898
|
+
this._syncArithRawWriteOnly = true;
|
|
9899
|
+
this._syncArithTouched = batchTouched;
|
|
9900
|
+
}
|
|
9559
9901
|
let lastStatus = 0;
|
|
9560
9902
|
rawState.loopDepth++;
|
|
9561
9903
|
this._syncReturnDepth++;
|
|
9562
9904
|
try {
|
|
9905
|
+
if (e0)
|
|
9906
|
+
this.syncShellArithmeticNonZero(e0, rawState, diagnosticLine);
|
|
9563
9907
|
let iter = 0;
|
|
9564
9908
|
while (true) {
|
|
9565
9909
|
if (++iter > 4096)
|
|
@@ -9603,6 +9947,17 @@ export class Runtime {
|
|
|
9603
9947
|
finally {
|
|
9604
9948
|
this._syncReturnDepth--;
|
|
9605
9949
|
rawState.loopDepth--;
|
|
9950
|
+
if (enableBatchRawWrite && batchTouched) {
|
|
9951
|
+
this._syncArithRawWriteOnly = false;
|
|
9952
|
+
this._syncArithTouched = undefined;
|
|
9953
|
+
for (const vName of batchTouched) {
|
|
9954
|
+
const vVal = rawState.variables[vName];
|
|
9955
|
+
if (typeof vVal === "string")
|
|
9956
|
+
monitor.publishStringVariable(vName, vVal);
|
|
9957
|
+
else if (vVal === undefined)
|
|
9958
|
+
delete monitor.proxy.variables[vName];
|
|
9959
|
+
}
|
|
9960
|
+
}
|
|
9606
9961
|
}
|
|
9607
9962
|
rawState.status = lastStatus;
|
|
9608
9963
|
return lastStatus;
|
|
@@ -9615,10 +9970,10 @@ export class Runtime {
|
|
|
9615
9970
|
}
|
|
9616
9971
|
else if (command.words.length === 1) {
|
|
9617
9972
|
const w0 = command.words[0];
|
|
9618
|
-
|
|
9619
|
-
const p0 =
|
|
9973
|
+
items = this.tryExpandSyncArrayMembersWord(w0, rawState, io, diagnosticLine);
|
|
9974
|
+
const p0 = items ? undefined : (w0.parts.length === 1 ? w0.parts[0] : (w0.parts.length === 2 && w0.parts[0].kind === "text" && w0.parts[0].value === "" ? w0.parts[1] : undefined));
|
|
9620
9975
|
const sel0 = p0?.kind === "variable" ? getArraySelector(p0) : undefined;
|
|
9621
|
-
if (p0?.kind === "variable" && p0.quoted && (sel0?.kind === "members" || sel0?.kind === "keys") && sel0.separator === "@") {
|
|
9976
|
+
if (p0?.kind === "variable" && p0.quoted && !p0.substring && (sel0?.kind === "members" || sel0?.kind === "keys") && sel0.separator === "@") {
|
|
9622
9977
|
const b = monitor.store?.get(p0.name);
|
|
9623
9978
|
items = [];
|
|
9624
9979
|
if (b) {
|
|
@@ -9657,6 +10012,12 @@ export class Runtime {
|
|
|
9657
10012
|
if (!items && command.words) {
|
|
9658
10013
|
items = [];
|
|
9659
10014
|
for (let i = 0; i < command.words.length; i++) {
|
|
10015
|
+
const expandedArr = this.tryExpandSyncArrayMembersWord(command.words[i], rawState, io, diagnosticLine);
|
|
10016
|
+
if (expandedArr !== undefined) {
|
|
10017
|
+
for (let mIdx = 0; mIdx < expandedArr.length; mIdx++)
|
|
10018
|
+
items.push(expandedArr[mIdx]);
|
|
10019
|
+
continue;
|
|
10020
|
+
}
|
|
9660
10021
|
let fv;
|
|
9661
10022
|
try {
|
|
9662
10023
|
fv = this.fastValueWord(command.words[i], rawState, io, false, false, false, false, undefined, diagnosticLine);
|
|
@@ -9673,6 +10034,12 @@ export class Runtime {
|
|
|
9673
10034
|
return undefined;
|
|
9674
10035
|
this.budget.tick();
|
|
9675
10036
|
let lastStatus = 0;
|
|
10037
|
+
const enableBatchRawWrite = !this._syncArithRawWriteOnly && !hasActiveExtensions(rawState) && !hasActiveVariableAttributes(rawState) && !rawState.readonlyVariables?.size && !rawState.allexport;
|
|
10038
|
+
const batchTouched = enableBatchRawWrite ? new Set() : undefined;
|
|
10039
|
+
if (enableBatchRawWrite) {
|
|
10040
|
+
this._syncArithRawWriteOnly = true;
|
|
10041
|
+
this._syncArithTouched = batchTouched;
|
|
10042
|
+
}
|
|
9676
10043
|
rawState.loopDepth++;
|
|
9677
10044
|
this._syncReturnDepth++;
|
|
9678
10045
|
try {
|
|
@@ -9683,7 +10050,12 @@ export class Runtime {
|
|
|
9683
10050
|
runYieldCheckpoint(this.signal);
|
|
9684
10051
|
}
|
|
9685
10052
|
this.budget.loop();
|
|
9686
|
-
|
|
10053
|
+
if (this._syncArithRawWriteOnly && this._syncArithTouched) {
|
|
10054
|
+
rawState.variables[command.name] = items[idx];
|
|
10055
|
+
this._syncArithTouched.add(command.name);
|
|
10056
|
+
}
|
|
10057
|
+
else
|
|
10058
|
+
monitor.publishStringVariable(command.name, items[idx]);
|
|
9687
10059
|
if (rawState.allexport)
|
|
9688
10060
|
rawState.exported.add(command.name);
|
|
9689
10061
|
const bodyRes = this.trySyncScript(command.body, state, io, ignored);
|
|
@@ -9709,6 +10081,17 @@ export class Runtime {
|
|
|
9709
10081
|
finally {
|
|
9710
10082
|
this._syncReturnDepth--;
|
|
9711
10083
|
rawState.loopDepth--;
|
|
10084
|
+
if (enableBatchRawWrite && batchTouched) {
|
|
10085
|
+
this._syncArithRawWriteOnly = false;
|
|
10086
|
+
this._syncArithTouched = undefined;
|
|
10087
|
+
for (const vName of batchTouched) {
|
|
10088
|
+
const vVal = rawState.variables[vName];
|
|
10089
|
+
if (typeof vVal === "string")
|
|
10090
|
+
monitor.publishStringVariable(vName, vVal);
|
|
10091
|
+
else if (vVal === undefined)
|
|
10092
|
+
delete monitor.proxy.variables[vName];
|
|
10093
|
+
}
|
|
10094
|
+
}
|
|
9712
10095
|
}
|
|
9713
10096
|
rawState.status = lastStatus;
|
|
9714
10097
|
return lastStatus;
|
|
@@ -9837,7 +10220,7 @@ export class Runtime {
|
|
|
9837
10220
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
9838
10221
|
}
|
|
9839
10222
|
else {
|
|
9840
|
-
|
|
10223
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
9841
10224
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
9842
10225
|
}
|
|
9843
10226
|
const finalStatus = pipeline.negate ? 1 : 0;
|
|
@@ -9934,7 +10317,7 @@ export class Runtime {
|
|
|
9934
10317
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
9935
10318
|
}
|
|
9936
10319
|
else {
|
|
9937
|
-
|
|
10320
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
9938
10321
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
9939
10322
|
}
|
|
9940
10323
|
const finalStatus = pipeline.negate ? 1 : 0;
|
|
@@ -9950,8 +10333,6 @@ export class Runtime {
|
|
|
9950
10333
|
if (w0Plain === "return" && (rawState.functionDepth > 0 || rawState.sourceDepth) && !hasActiveExtensions(rawState) && !hasShellFunction(rawState, "return") && !rawState.extensions?.builtins.has("return") && !pipeline.negate && canMutatePipeStatus) {
|
|
9951
10334
|
const retStatus = rawState.status;
|
|
9952
10335
|
const statusStr = retStatus === 0 ? "0" : retStatus === 1 ? "1" : String(retStatus);
|
|
9953
|
-
if (existing && elem0.text.bytes !== statusStr.length)
|
|
9954
|
-
return undefined;
|
|
9955
10336
|
const restEpoch = monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets).epoch;
|
|
9956
10337
|
this.budget.tick();
|
|
9957
10338
|
rawState.substitutionStatus = 0;
|
|
@@ -9965,7 +10346,7 @@ export class Runtime {
|
|
|
9965
10346
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
9966
10347
|
}
|
|
9967
10348
|
else {
|
|
9968
|
-
|
|
10349
|
+
this.setSyncPipeStatusCell(existing, statusStr);
|
|
9969
10350
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
9970
10351
|
}
|
|
9971
10352
|
rawState.status = retStatus;
|
|
@@ -9997,7 +10378,7 @@ export class Runtime {
|
|
|
9997
10378
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
9998
10379
|
}
|
|
9999
10380
|
else {
|
|
10000
|
-
|
|
10381
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
10001
10382
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
10002
10383
|
}
|
|
10003
10384
|
rawState.status = 0;
|
|
@@ -10029,7 +10410,7 @@ export class Runtime {
|
|
|
10029
10410
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
10030
10411
|
}
|
|
10031
10412
|
else {
|
|
10032
|
-
|
|
10413
|
+
this.setSyncPipeStatusCell(existing, statusChar);
|
|
10033
10414
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
10034
10415
|
}
|
|
10035
10416
|
rawState.status = finalStatus;
|
|
@@ -10070,7 +10451,7 @@ export class Runtime {
|
|
|
10070
10451
|
}
|
|
10071
10452
|
}
|
|
10072
10453
|
else {
|
|
10073
|
-
|
|
10454
|
+
this.setSyncPipeStatusCell(activeExisting, "0");
|
|
10074
10455
|
activeStore.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
10075
10456
|
}
|
|
10076
10457
|
const finalStatus = pipeline.negate ? 1 : 0;
|
|
@@ -10082,14 +10463,15 @@ export class Runtime {
|
|
|
10082
10463
|
}
|
|
10083
10464
|
const assignment = this.assignment(w0);
|
|
10084
10465
|
if (assignment) {
|
|
10466
|
+
const targetAssignName = resolveSyncNameref(rawState, assignment.name);
|
|
10085
10467
|
const hasSubPart = assignment.value.parts.some(part => part.kind === "substitution");
|
|
10086
|
-
const existingArrAssign = store?.get(
|
|
10087
|
-
if (assignment.
|
|
10088
|
-
|
|
10089
|
-
|
|
10468
|
+
const existingArrAssign = store?.get(targetAssignName);
|
|
10469
|
+
if ((targetAssignName === "OPTIND" && (assignment.append || rawState.variableAttributes?.get("OPTIND"))) ||
|
|
10470
|
+
targetAssignName === "PIPESTATUS" ||
|
|
10471
|
+
targetAssignName.includes("[") ||
|
|
10090
10472
|
(hasSubPart && !this.isPureSyncValueWord(assignment.value, rawState)) ||
|
|
10091
|
-
rawState.readonlyVariables?.has(
|
|
10092
|
-
(existingArrAssign && (assignment.append || hasUnpreparedLocal(rawState,
|
|
10473
|
+
rawState.readonlyVariables?.has(targetAssignName) ||
|
|
10474
|
+
(existingArrAssign && (assignment.append || hasUnpreparedLocal(rawState, targetAssignName) || rawState.exported.has(targetAssignName)))) {
|
|
10093
10475
|
return undefined;
|
|
10094
10476
|
}
|
|
10095
10477
|
if (rawState.extensions && !rawState.extensions.eventDepth)
|
|
@@ -10103,8 +10485,14 @@ export class Runtime {
|
|
|
10103
10485
|
}
|
|
10104
10486
|
if (typeof fastAssigned !== "string")
|
|
10105
10487
|
return undefined;
|
|
10488
|
+
if (targetAssignName === "OPTIND") {
|
|
10489
|
+
const trimmedOptind = fastAssigned.trim();
|
|
10490
|
+
if (!/^[0-9]{1,6}$/.test(trimmedOptind))
|
|
10491
|
+
return undefined;
|
|
10492
|
+
fastAssigned = String(Number(trimmedOptind));
|
|
10493
|
+
}
|
|
10106
10494
|
if (existingArrAssign) {
|
|
10107
|
-
if (!this.tryFastArraySubscriptWriteSync(rawState,
|
|
10495
|
+
if (!this.tryFastArraySubscriptWriteSync(rawState, targetAssignName, "0", fastAssigned))
|
|
10108
10496
|
return undefined;
|
|
10109
10497
|
const restEpoch = monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets).epoch;
|
|
10110
10498
|
this.budget.tick();
|
|
@@ -10128,7 +10516,7 @@ export class Runtime {
|
|
|
10128
10516
|
}
|
|
10129
10517
|
}
|
|
10130
10518
|
else {
|
|
10131
|
-
|
|
10519
|
+
this.setSyncPipeStatusCell(activeExisting, "0");
|
|
10132
10520
|
activeStore.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
10133
10521
|
}
|
|
10134
10522
|
const finalStatus = pipeline.negate ? 1 : 0;
|
|
@@ -10140,8 +10528,8 @@ export class Runtime {
|
|
|
10140
10528
|
}
|
|
10141
10529
|
let finalAssigned = fastAssigned;
|
|
10142
10530
|
if (assignment.append) {
|
|
10143
|
-
const curRaw = rawState.variables[
|
|
10144
|
-
const curStr = curRaw === undefined ? "" : (monitor.values.get(
|
|
10531
|
+
const curRaw = rawState.variables[targetAssignName];
|
|
10532
|
+
const curStr = curRaw === undefined ? "" : (monitor.values.get(targetAssignName, curRaw) ?? curRaw);
|
|
10145
10533
|
if (typeof curStr !== "string")
|
|
10146
10534
|
return undefined;
|
|
10147
10535
|
finalAssigned = curStr + finalAssigned;
|
|
@@ -10152,17 +10540,21 @@ export class Runtime {
|
|
|
10152
10540
|
this.budget.tick();
|
|
10153
10541
|
if (!hasSubPart)
|
|
10154
10542
|
rawState.substitutionStatus = 0;
|
|
10155
|
-
if (
|
|
10543
|
+
if (targetAssignName !== "_" && rawState.variables._ !== undefined)
|
|
10156
10544
|
delete rawState.variables._;
|
|
10157
10545
|
rawState.lastArgument = "";
|
|
10158
10546
|
if (this._syncArithRawWriteOnly && this._syncArithTouched) {
|
|
10159
|
-
rawState.variables[
|
|
10160
|
-
this._syncArithTouched.add(
|
|
10547
|
+
rawState.variables[targetAssignName] = finalAssigned;
|
|
10548
|
+
this._syncArithTouched.add(targetAssignName);
|
|
10161
10549
|
}
|
|
10162
10550
|
else
|
|
10163
|
-
monitor.publishStringVariable(
|
|
10551
|
+
monitor.publishStringVariable(targetAssignName, finalAssigned);
|
|
10552
|
+
if (targetAssignName === "OPTIND") {
|
|
10553
|
+
rawState.variables.OPTIND = finalAssigned;
|
|
10554
|
+
this.syncGetopts(rawState);
|
|
10555
|
+
}
|
|
10164
10556
|
if (rawState.allexport)
|
|
10165
|
-
monitor.proxy.exported.add(
|
|
10557
|
+
monitor.proxy.exported.add(targetAssignName);
|
|
10166
10558
|
if (io.assignmentDiagnosticContext)
|
|
10167
10559
|
io.assignmentDiagnosticContext.name = undefined;
|
|
10168
10560
|
if (!existing) {
|
|
@@ -10170,7 +10562,7 @@ export class Runtime {
|
|
|
10170
10562
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
10171
10563
|
}
|
|
10172
10564
|
else {
|
|
10173
|
-
|
|
10565
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
10174
10566
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
10175
10567
|
}
|
|
10176
10568
|
const finalStatus = pipeline.negate ? 1 : 0;
|
|
@@ -10186,60 +10578,234 @@ export class Runtime {
|
|
|
10186
10578
|
if (command.words.length >= 1) {
|
|
10187
10579
|
const w0Plain = command.words[0].plain;
|
|
10188
10580
|
if (this.budget.limits.maxExpansionFields === Infinity && command.words.length >= 4 && w0Plain === "printf" && command.words[1]?.plain === "-v" && command.redirects.length === 0 && canMutatePipeStatus && (!pipeline.negate || ignored || !rawState.errexit) && !hasShellFunction(rawState, "printf") && !rawState.extensions?.builtins.has("printf")) {
|
|
10189
|
-
const targetVar = command.words[2]?.plain;
|
|
10190
10581
|
const def = this.commands.get("printf");
|
|
10191
|
-
if (
|
|
10192
|
-
|
|
10193
|
-
|
|
10194
|
-
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10582
|
+
if (def && def.execute === printfCommand.execute && command.words.length <= this.budget.maxExpansionFieldsSmi && this.arePureArgWords(command.words, rawState)) {
|
|
10583
|
+
let targetSpec = command.words[2]?.plain;
|
|
10584
|
+
if (targetSpec === undefined) {
|
|
10585
|
+
try {
|
|
10586
|
+
targetSpec = this.fastValueWord(command.words[2], rawState, io, true, false, false, true, undefined, diagnosticLine);
|
|
10587
|
+
}
|
|
10588
|
+
catch {
|
|
10589
|
+
targetSpec = undefined;
|
|
10590
|
+
}
|
|
10591
|
+
}
|
|
10592
|
+
if (typeof targetSpec === "string") {
|
|
10593
|
+
const openBr = targetSpec.indexOf("[");
|
|
10594
|
+
const isSubTarget = openBr > 0 && targetSpec.endsWith("]") && targetSpec.length > openBr + 2;
|
|
10595
|
+
const rawTargetVar = isSubTarget ? targetSpec.slice(0, openBr) : targetSpec;
|
|
10596
|
+
const targetVar = isShellIdentifier(rawTargetVar) ? resolveSyncNameref(rawState, rawTargetVar) : "";
|
|
10597
|
+
if (targetVar && isShellIdentifier(targetVar) && targetVar !== "OPTIND" && targetVar !== "PIPESTATUS" && targetVar !== "_" && !rawState.readonlyVariables?.has(targetVar) && !monitor.hasOverlay(targetVar) && (isSubTarget || !store?.get(targetVar))) {
|
|
10598
|
+
fastSubScratchArgs.length = 0;
|
|
10599
|
+
let allStrings = true;
|
|
10600
|
+
try {
|
|
10601
|
+
for (let i = 3; i < command.words.length; i++) {
|
|
10602
|
+
const v = this.fastValueWord(command.words[i], rawState, io, true, false, false, true, undefined, diagnosticLine);
|
|
10603
|
+
if (typeof v !== "string") {
|
|
10604
|
+
allStrings = false;
|
|
10605
|
+
break;
|
|
10606
|
+
}
|
|
10607
|
+
fastSubScratchArgs.push(v);
|
|
10608
|
+
}
|
|
10609
|
+
}
|
|
10610
|
+
catch {
|
|
10198
10611
|
allStrings = false;
|
|
10199
|
-
break;
|
|
10200
10612
|
}
|
|
10201
|
-
fastSubScratchArgs.
|
|
10613
|
+
const lastArg = fastSubScratchArgs.length > 0 ? fastSubScratchArgs[fastSubScratchArgs.length - 1] : targetSpec;
|
|
10614
|
+
const formatted = allStrings ? tryFastPrintf(fastSubScratchArgs) : undefined;
|
|
10615
|
+
fastSubScratchArgs.length = 0;
|
|
10616
|
+
if (formatted !== undefined && formatted.length <= this.budget.limits.maxExpansionBytes && (formatted.length * 3 <= this.budget.limits.maxExpansionBytes || shellValueByteLength(formatted) <= this.budget.limits.maxExpansionBytes)) {
|
|
10617
|
+
let wroteTarget = true;
|
|
10618
|
+
if (isSubTarget) {
|
|
10619
|
+
let subKey = targetSpec.slice(openBr + 1, -1);
|
|
10620
|
+
const existingArr = store?.get(targetVar);
|
|
10621
|
+
if (!existingArr?.associative && !/^(?:0|[1-9][0-9]{0,8})$/.test(subKey)) {
|
|
10622
|
+
const syncTouched = this._syncArithRawWriteOnly ? this._syncArithTouched : undefined;
|
|
10623
|
+
const directIdx = resolveSimpleArithOperand(subKey.trim(), rawState, monitor, store, syncTouched);
|
|
10624
|
+
if (directIdx !== undefined && directIdx >= 0)
|
|
10625
|
+
subKey = String(directIdx);
|
|
10626
|
+
else {
|
|
10627
|
+
const exprIdx = tryEvalSimpleExpandedArith(subKey.trim(), rawState, monitor, store, syncTouched);
|
|
10628
|
+
if (exprIdx !== undefined && Number(exprIdx) >= 0)
|
|
10629
|
+
subKey = exprIdx;
|
|
10630
|
+
else
|
|
10631
|
+
wroteTarget = false;
|
|
10632
|
+
}
|
|
10633
|
+
}
|
|
10634
|
+
if (wroteTarget && !this.tryFastArraySubscriptWriteSync(rawState, targetVar, subKey, formatted))
|
|
10635
|
+
wroteTarget = false;
|
|
10636
|
+
}
|
|
10637
|
+
else if (this._syncArithRawWriteOnly && this._syncArithTouched) {
|
|
10638
|
+
rawState.variables[targetVar] = formatted;
|
|
10639
|
+
this._syncArithTouched.add(targetVar);
|
|
10640
|
+
}
|
|
10641
|
+
else
|
|
10642
|
+
monitor.publishStringVariable(targetVar, formatted);
|
|
10643
|
+
if (wroteTarget) {
|
|
10644
|
+
if (rawState.extensions && !rawState.extensions.eventDepth)
|
|
10645
|
+
publishCommandSpelling(rawState, commandSpelling(command));
|
|
10646
|
+
const restEpoch = monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets).epoch;
|
|
10647
|
+
this.budget.tick();
|
|
10648
|
+
rawState.substitutionStatus = 0;
|
|
10649
|
+
if (rawState.variables._ !== undefined)
|
|
10650
|
+
delete rawState.variables._;
|
|
10651
|
+
rawState.lastArgument = lastArg;
|
|
10652
|
+
if (!isSubTarget && rawState.allexport)
|
|
10653
|
+
monitor.proxy.exported.add(targetVar);
|
|
10654
|
+
if (io.assignmentDiagnosticContext)
|
|
10655
|
+
io.assignmentDiagnosticContext.name = undefined;
|
|
10656
|
+
if (!existing) {
|
|
10657
|
+
monitor.lazyPipeStatus = singleStatusZero;
|
|
10658
|
+
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
10659
|
+
}
|
|
10660
|
+
else {
|
|
10661
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
10662
|
+
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
10663
|
+
}
|
|
10664
|
+
const finalStatus = pipeline.negate ? 1 : 0;
|
|
10665
|
+
rawState.status = finalStatus;
|
|
10666
|
+
monitor.epoch = restEpoch;
|
|
10667
|
+
if (store)
|
|
10668
|
+
store.epoch = restEpoch;
|
|
10669
|
+
return finalStatus;
|
|
10670
|
+
}
|
|
10671
|
+
}
|
|
10202
10672
|
}
|
|
10203
10673
|
}
|
|
10204
|
-
|
|
10205
|
-
|
|
10206
|
-
|
|
10207
|
-
|
|
10208
|
-
|
|
10209
|
-
|
|
10210
|
-
|
|
10211
|
-
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
if (
|
|
10220
|
-
|
|
10221
|
-
|
|
10674
|
+
}
|
|
10675
|
+
}
|
|
10676
|
+
if (command.words.length >= 2 && command.words.length <= 16 && (w0Plain === ":" || w0Plain === "true" || w0Plain === "false") && command.redirects.length === 0 && !hasShellFunction(rawState, w0Plain) && !rawState.extensions?.builtins.has(w0Plain)) {
|
|
10677
|
+
const rawStatus = w0Plain === "false" ? 1 : 0;
|
|
10678
|
+
const statusChar = rawStatus === 0 ? "0" : "1";
|
|
10679
|
+
if (!canMutatePipeStatus && elem0.text.shellValue !== statusChar)
|
|
10680
|
+
return undefined;
|
|
10681
|
+
const finalStatus = pipeline.negate ? Number(rawStatus === 0) : rawStatus;
|
|
10682
|
+
if (finalStatus !== 0 && !ignored && rawState.errexit)
|
|
10683
|
+
return undefined;
|
|
10684
|
+
let lastArg = w0Plain;
|
|
10685
|
+
let argsOk = true;
|
|
10686
|
+
try {
|
|
10687
|
+
for (let i = 1; i < command.words.length; i++) {
|
|
10688
|
+
const v = this.fastValueWord(command.words[i], rawState, io, true, false, false, true, undefined, diagnosticLine);
|
|
10689
|
+
if (typeof v !== "string") {
|
|
10690
|
+
argsOk = false;
|
|
10691
|
+
break;
|
|
10222
10692
|
}
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10693
|
+
lastArg = v;
|
|
10694
|
+
}
|
|
10695
|
+
}
|
|
10696
|
+
catch {
|
|
10697
|
+
argsOk = false;
|
|
10698
|
+
}
|
|
10699
|
+
if (argsOk) {
|
|
10700
|
+
if (rawState.extensions && !rawState.extensions.eventDepth)
|
|
10701
|
+
publishCommandSpelling(rawState, commandSpelling(command));
|
|
10702
|
+
const restEpoch = monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets).epoch;
|
|
10703
|
+
this.budget.tick();
|
|
10704
|
+
rawState.substitutionStatus = 0;
|
|
10705
|
+
if (rawState.variables._ !== undefined)
|
|
10706
|
+
delete rawState.variables._;
|
|
10707
|
+
rawState.lastArgument = lastArg;
|
|
10708
|
+
if (io.assignmentDiagnosticContext)
|
|
10709
|
+
io.assignmentDiagnosticContext.name = undefined;
|
|
10710
|
+
return this.finishSyncPipeStatus(rawState, monitor, monitor.store, monitor.store?.get("PIPESTATUS"), elem0, scope, finalStatus, restEpoch);
|
|
10711
|
+
}
|
|
10712
|
+
}
|
|
10713
|
+
if (command.words.length >= 3 && command.words.length <= 16 && w0Plain === "getopts" && command.redirects.length === 0 && !hasShellFunction(rawState, "getopts") && !rawState.extensions?.builtins.has("getopts")) {
|
|
10714
|
+
const optVar = command.words[2]?.plain;
|
|
10715
|
+
if (optVar && isShellIdentifier(optVar) && optVar !== "OPTIND" && optVar !== "PIPESTATUS" && optVar !== "_" && !rawState.readonlyVariables?.has(optVar) && !rawState.readonlyVariables?.has("OPTIND") && !rawState.readonlyVariables?.has("OPTARG") && !rawState.variableAttributes?.get(optVar) && !rawState.variableAttributes?.get("OPTIND") && !rawState.variableAttributes?.get("OPTARG") && !store?.get(optVar) && !store?.get("OPTIND") && !store?.get("OPTARG") && !monitor.hasOverlay(optVar)) {
|
|
10716
|
+
let optstring;
|
|
10717
|
+
let scanArgs;
|
|
10718
|
+
let lastArg = optVar;
|
|
10719
|
+
try {
|
|
10720
|
+
optstring = command.words[1].plain ?? this.fastValueWord(command.words[1], rawState, io, true, false, false, true, undefined, diagnosticLine);
|
|
10721
|
+
if (typeof optstring === "string") {
|
|
10722
|
+
if (command.words.length === 3) {
|
|
10723
|
+
scanArgs = this._fastSubPositional ?? rawState.positional;
|
|
10724
|
+
}
|
|
10725
|
+
else if (command.words.length === 4 && (() => { const ne = command.words[3].parts.filter(p => !(p.kind === "text" && p.value === "")); return ne.length === 1 && ne[0].kind === "variable" && ne[0].name === "@" && ne[0].quoted && !ne[0].length && !ne[0].substring && !ne[0].operator && !ne[0].transform && !ne[0].indirect && !ne[0].prefixNames && getArraySelector(ne[0]) === undefined; })()) {
|
|
10726
|
+
scanArgs = this._fastSubPositional ?? rawState.positional;
|
|
10727
|
+
if (scanArgs.length > 0)
|
|
10728
|
+
lastArg = scanArgs[scanArgs.length - 1];
|
|
10729
|
+
}
|
|
10730
|
+
else {
|
|
10731
|
+
const customArgs = [];
|
|
10732
|
+
let customOk = true;
|
|
10733
|
+
for (let i = 3; i < command.words.length; i++) {
|
|
10734
|
+
const v = this.fastValueWord(command.words[i], rawState, io, true, false, false, true, undefined, diagnosticLine);
|
|
10735
|
+
if (typeof v !== "string") {
|
|
10736
|
+
customOk = false;
|
|
10737
|
+
break;
|
|
10738
|
+
}
|
|
10739
|
+
customArgs.push(v);
|
|
10740
|
+
lastArg = v;
|
|
10741
|
+
}
|
|
10742
|
+
if (customOk)
|
|
10743
|
+
scanArgs = customArgs;
|
|
10744
|
+
}
|
|
10232
10745
|
}
|
|
10233
|
-
|
|
10234
|
-
|
|
10235
|
-
|
|
10746
|
+
}
|
|
10747
|
+
catch {
|
|
10748
|
+
scanArgs = undefined;
|
|
10749
|
+
}
|
|
10750
|
+
if (typeof optstring === "string" && optstring.startsWith(":") && scanArgs !== undefined) {
|
|
10751
|
+
rawState.getopts ??= cloneGetoptsBinding(rawState);
|
|
10752
|
+
const res = scanGetoptsSync(rawState.getopts.cursor, optstring, scanArgs);
|
|
10753
|
+
if (res !== undefined) {
|
|
10754
|
+
const rawStatus = res.status;
|
|
10755
|
+
const statusChar = rawStatus === 0 ? "0" : "1";
|
|
10756
|
+
if (canMutatePipeStatus || elem0.text.shellValue === statusChar) {
|
|
10757
|
+
const finalStatus = pipeline.negate ? Number(rawStatus === 0) : rawStatus;
|
|
10758
|
+
if (finalStatus === 0 || ignored || !rawState.errexit) {
|
|
10759
|
+
if (rawState.extensions && !rawState.extensions.eventDepth)
|
|
10760
|
+
publishCommandSpelling(rawState, commandSpelling(command));
|
|
10761
|
+
const restEpoch = monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets).epoch;
|
|
10762
|
+
this.budget.tick();
|
|
10763
|
+
rawState.substitutionStatus = 0;
|
|
10764
|
+
if (rawState.variables._ !== undefined)
|
|
10765
|
+
delete rawState.variables._;
|
|
10766
|
+
rawState.lastArgument = lastArg;
|
|
10767
|
+
rawState.getopts.cursor = res.state;
|
|
10768
|
+
const optindStr = String(res.optind);
|
|
10769
|
+
if (this._syncArithRawWriteOnly && this._syncArithTouched) {
|
|
10770
|
+
rawState.variables.OPTIND = optindStr;
|
|
10771
|
+
this._syncArithTouched.add("OPTIND");
|
|
10772
|
+
}
|
|
10773
|
+
else
|
|
10774
|
+
monitor.publishStringVariable("OPTIND", optindStr);
|
|
10775
|
+
if (rawState.allexport)
|
|
10776
|
+
monitor.proxy.exported.add("OPTIND");
|
|
10777
|
+
if (res.argument.kind === "set") {
|
|
10778
|
+
if (this._syncArithRawWriteOnly && this._syncArithTouched) {
|
|
10779
|
+
rawState.variables.OPTARG = res.argument.value;
|
|
10780
|
+
this._syncArithTouched.add("OPTARG");
|
|
10781
|
+
}
|
|
10782
|
+
else
|
|
10783
|
+
monitor.publishStringVariable("OPTARG", res.argument.value);
|
|
10784
|
+
if (rawState.allexport)
|
|
10785
|
+
monitor.proxy.exported.add("OPTARG");
|
|
10786
|
+
}
|
|
10787
|
+
else {
|
|
10788
|
+
delete rawState.variables.OPTARG;
|
|
10789
|
+
rawState.exported.delete("OPTARG");
|
|
10790
|
+
if (this._syncArithRawWriteOnly && this._syncArithTouched)
|
|
10791
|
+
this._syncArithTouched.add("OPTARG");
|
|
10792
|
+
else
|
|
10793
|
+
monitor.values.invalidate("OPTARG");
|
|
10794
|
+
}
|
|
10795
|
+
if (this._syncArithRawWriteOnly && this._syncArithTouched) {
|
|
10796
|
+
rawState.variables[optVar] = res.option;
|
|
10797
|
+
this._syncArithTouched.add(optVar);
|
|
10798
|
+
}
|
|
10799
|
+
else
|
|
10800
|
+
monitor.publishStringVariable(optVar, res.option);
|
|
10801
|
+
if (rawState.allexport)
|
|
10802
|
+
monitor.proxy.exported.add(optVar);
|
|
10803
|
+
if (io.assignmentDiagnosticContext)
|
|
10804
|
+
io.assignmentDiagnosticContext.name = undefined;
|
|
10805
|
+
return this.finishSyncPipeStatus(rawState, monitor, monitor.store, monitor.store?.get("PIPESTATUS"), elem0, scope, finalStatus, restEpoch);
|
|
10806
|
+
}
|
|
10807
|
+
}
|
|
10236
10808
|
}
|
|
10237
|
-
const finalStatus = pipeline.negate ? 1 : 0;
|
|
10238
|
-
rawState.status = finalStatus;
|
|
10239
|
-
monitor.epoch = restEpoch;
|
|
10240
|
-
if (store)
|
|
10241
|
-
store.epoch = restEpoch;
|
|
10242
|
-
return finalStatus;
|
|
10243
10809
|
}
|
|
10244
10810
|
}
|
|
10245
10811
|
}
|
|
@@ -10277,7 +10843,7 @@ export class Runtime {
|
|
|
10277
10843
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
10278
10844
|
}
|
|
10279
10845
|
else {
|
|
10280
|
-
|
|
10846
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
10281
10847
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
10282
10848
|
}
|
|
10283
10849
|
rawState.status = 0;
|
|
@@ -10383,7 +10949,7 @@ export class Runtime {
|
|
|
10383
10949
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
10384
10950
|
}
|
|
10385
10951
|
else {
|
|
10386
|
-
|
|
10952
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
10387
10953
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
10388
10954
|
}
|
|
10389
10955
|
const finalStatus = pipeline.negate ? 1 : 0;
|
|
@@ -10406,6 +10972,105 @@ export class Runtime {
|
|
|
10406
10972
|
!command.redirects[0].move &&
|
|
10407
10973
|
!command.redirects[0].document &&
|
|
10408
10974
|
(command.redirects[0].descriptor === undefined || command.redirects[0].descriptor === 0);
|
|
10975
|
+
if ((w0Plain === "mapfile" || w0Plain === "readarray") &&
|
|
10976
|
+
isHereStringRead &&
|
|
10977
|
+
(command.words.length === 2 || command.words.length === 3) &&
|
|
10978
|
+
command.words[1]?.plain === "-t" &&
|
|
10979
|
+
canMutatePipeStatus &&
|
|
10980
|
+
!pipeline.negate &&
|
|
10981
|
+
!rawState.allexport &&
|
|
10982
|
+
!hasShellFunction(rawState, w0Plain) &&
|
|
10983
|
+
!rawState.extensions?.builtins.has(w0Plain)) {
|
|
10984
|
+
const arrayTarget = command.words[2]?.plain ?? "MAPFILE";
|
|
10985
|
+
if (!hasUnpreparedLocal(rawState, arrayTarget) &&
|
|
10986
|
+
isShellIdentifier(arrayTarget) &&
|
|
10987
|
+
!rawState.readonlyVariables?.has(arrayTarget) &&
|
|
10988
|
+
!rawState.exported.has(arrayTarget) &&
|
|
10989
|
+
!rawState.variableAttributes?.get(arrayTarget) &&
|
|
10990
|
+
!controlNames.has(arrayTarget)) {
|
|
10991
|
+
let hv;
|
|
10992
|
+
try {
|
|
10993
|
+
hv = this.fastValueWord(command.redirects[0].target, rawState, io, false, false, false, false, undefined, diagnosticLine);
|
|
10994
|
+
}
|
|
10995
|
+
catch {
|
|
10996
|
+
hv = undefined;
|
|
10997
|
+
}
|
|
10998
|
+
if (typeof hv === "string" &&
|
|
10999
|
+
!hv.includes("\0") &&
|
|
11000
|
+
hv.length + 1 < this.budget.limits.maxExpansionBytes &&
|
|
11001
|
+
hv.length + 1 <= this.budget.limits.maxInputBytes) {
|
|
11002
|
+
const arrStore = monitor.store ?? requireArrays(rawState);
|
|
11003
|
+
let existingArrayBinding = arrStore.get(arrayTarget);
|
|
11004
|
+
if (!existingArrayBinding && rawState.variables[arrayTarget] === undefined && !arrStore.watches.has(arrayTarget) && !monitor.hasOverlay(arrayTarget)) {
|
|
11005
|
+
const recTickets = arrStore.owner.charge({ generation: true, version: true, epoch: true, work: 8 });
|
|
11006
|
+
const recBinding = arrStore.takeRecycled(arrayTarget, false, true, recTickets);
|
|
11007
|
+
if (recBinding) {
|
|
11008
|
+
monitor.epoch = recTickets.epoch;
|
|
11009
|
+
existingArrayBinding = recBinding;
|
|
11010
|
+
}
|
|
11011
|
+
else {
|
|
11012
|
+
try {
|
|
11013
|
+
const created = IndexedBinding.create(arrStore.owner, false);
|
|
11014
|
+
const prepared = arrStore.prepareExistingName(arrayTarget, shellValueByteLength(arrayTarget), arrStore.owner, this.signal);
|
|
11015
|
+
if (prepared) {
|
|
11016
|
+
const initTickets = arrStore.owner.charge({ generation: true, version: true, epoch: true, work: 8 });
|
|
11017
|
+
arrStore.publish(arrayTarget, created, initTickets, prepared, false, arrStore.owner);
|
|
11018
|
+
monitor.epoch = initTickets.epoch;
|
|
11019
|
+
existingArrayBinding = created;
|
|
11020
|
+
}
|
|
11021
|
+
else {
|
|
11022
|
+
void created.release();
|
|
11023
|
+
}
|
|
11024
|
+
}
|
|
11025
|
+
catch { }
|
|
11026
|
+
}
|
|
11027
|
+
}
|
|
11028
|
+
if (existingArrayBinding && !existingArrayBinding.associative && existingArrayBinding.references === 1 && !arrStore.watches.has(arrayTarget) && !monitor.hasOverlay(arrayTarget)) {
|
|
11029
|
+
const lines = hv.split("\n");
|
|
11030
|
+
const fieldLen = lines.length;
|
|
11031
|
+
if (fieldLen <= 256) {
|
|
11032
|
+
if (rawState.extensions && !rawState.extensions.eventDepth)
|
|
11033
|
+
publishCommandSpelling(rawState, commandSpelling(command));
|
|
11034
|
+
const tickets = arrStore.owner.charge({ generation: true, version: true, epoch: true, work: 8 + fieldLen * 4 });
|
|
11035
|
+
if (existingArrayBinding.values.size !== fieldLen || existingArrayBinding.maximum !== fieldLen - 1) {
|
|
11036
|
+
for (const k of [...existingArrayBinding.values.keys()]) {
|
|
11037
|
+
if (k >= fieldLen)
|
|
11038
|
+
existingArrayBinding.remove(k);
|
|
11039
|
+
}
|
|
11040
|
+
existingArrayBinding.maximum = fieldLen - 1;
|
|
11041
|
+
}
|
|
11042
|
+
for (let idx = 0; idx < fieldLen; idx++) {
|
|
11043
|
+
const val = lines[idx];
|
|
11044
|
+
const byteLen = shellValueByteLength(val);
|
|
11045
|
+
const slot = existingArrayBinding.values.get(idx);
|
|
11046
|
+
if (slot && slot.text.references === 1 && slot.text.bytes === byteLen) {
|
|
11047
|
+
existingArrayBinding.owner.chargeWork(byteLen);
|
|
11048
|
+
slot.text.shellValue = val;
|
|
11049
|
+
}
|
|
11050
|
+
else {
|
|
11051
|
+
existingArrayBinding.owner.chargeWork(byteLen);
|
|
11052
|
+
const token = new OwnedText(val, byteLen, existingArrayBinding.owner.reserve({ payload: byteLen, metadata: 32, work: 4 }));
|
|
11053
|
+
existingArrayBinding.insert(idx, token);
|
|
11054
|
+
}
|
|
11055
|
+
}
|
|
11056
|
+
delete rawState.variables[arrayTarget];
|
|
11057
|
+
monitor.values.invalidate(arrayTarget);
|
|
11058
|
+
monitor.epoch = tickets.epoch;
|
|
11059
|
+
arrStore.revise(arrayTarget, existingArrayBinding, tickets);
|
|
11060
|
+
const restEpoch = monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets).epoch;
|
|
11061
|
+
this.budget.tick();
|
|
11062
|
+
rawState.substitutionStatus = 0;
|
|
11063
|
+
if (rawState.variables._ !== undefined)
|
|
11064
|
+
delete rawState.variables._;
|
|
11065
|
+
rawState.lastArgument = command.words[command.words.length - 1].plain ?? arrayTarget;
|
|
11066
|
+
if (io.assignmentDiagnosticContext)
|
|
11067
|
+
io.assignmentDiagnosticContext.name = undefined;
|
|
11068
|
+
return this.finishSyncPipeStatus(rawState, monitor, monitor.store, monitor.store?.get("PIPESTATUS"), elem0, scope, 0, restEpoch);
|
|
11069
|
+
}
|
|
11070
|
+
}
|
|
11071
|
+
}
|
|
11072
|
+
}
|
|
11073
|
+
}
|
|
10409
11074
|
if ((w0Plain === "read" || (command.words[1]?.plain === "read" && w0.parts[0]?.kind === "text" && w0.parts[0].value.startsWith("IFS="))) &&
|
|
10410
11075
|
canMutatePipeStatus &&
|
|
10411
11076
|
!pipeline.negate &&
|
|
@@ -10470,7 +11135,7 @@ export class Runtime {
|
|
|
10470
11135
|
delimStr = nextW.plain;
|
|
10471
11136
|
else {
|
|
10472
11137
|
try {
|
|
10473
|
-
const fv = this.fastValueWord(nextW, rawState, io,
|
|
11138
|
+
const fv = this.fastValueWord(nextW, rawState, io, true, false, false, false, undefined, diagnosticLine);
|
|
10474
11139
|
if (typeof fv === "string")
|
|
10475
11140
|
delimStr = fv;
|
|
10476
11141
|
}
|
|
@@ -10516,7 +11181,7 @@ export class Runtime {
|
|
|
10516
11181
|
const varCount = command.words.length - readWordIdx;
|
|
10517
11182
|
let existingArrayBinding;
|
|
10518
11183
|
if (arrayTarget !== undefined) {
|
|
10519
|
-
if (
|
|
11184
|
+
if (hasUnpreparedLocal(rawState, arrayTarget))
|
|
10520
11185
|
return undefined;
|
|
10521
11186
|
if (varCount !== 0 || !isShellIdentifier(arrayTarget) || rawState.readonlyVariables?.has(arrayTarget) || rawState.exported.has(arrayTarget) || rawState.variableAttributes?.get(arrayTarget) || controlNames.has(arrayTarget)) {
|
|
10522
11187
|
simpleRead = false;
|
|
@@ -10524,26 +11189,7 @@ export class Runtime {
|
|
|
10524
11189
|
else {
|
|
10525
11190
|
const arrStore = monitor.store ?? requireArrays(rawState);
|
|
10526
11191
|
existingArrayBinding = arrStore.get(arrayTarget);
|
|
10527
|
-
if (
|
|
10528
|
-
try {
|
|
10529
|
-
const created = IndexedBinding.create(arrStore.owner, false);
|
|
10530
|
-
const nameByteLen = shellValueByteLength(arrayTarget);
|
|
10531
|
-
const prepared = arrStore.prepareExistingName(arrayTarget, nameByteLen, arrStore.owner, this.signal);
|
|
10532
|
-
if (prepared) {
|
|
10533
|
-
const initTickets = arrStore.owner.charge({ generation: true, version: true, epoch: true, work: 8 });
|
|
10534
|
-
arrStore.publish(arrayTarget, created, initTickets, prepared, false, arrStore.owner);
|
|
10535
|
-
monitor.epoch = initTickets.epoch;
|
|
10536
|
-
existingArrayBinding = created;
|
|
10537
|
-
}
|
|
10538
|
-
else {
|
|
10539
|
-
void created.release();
|
|
10540
|
-
}
|
|
10541
|
-
}
|
|
10542
|
-
catch { }
|
|
10543
|
-
}
|
|
10544
|
-
if (!existingArrayBinding ||
|
|
10545
|
-
existingArrayBinding.associative ||
|
|
10546
|
-
existingArrayBinding.references !== 1 ||
|
|
11192
|
+
if ((existingArrayBinding ? existingArrayBinding.associative || existingArrayBinding.references !== 1 : rawState.variables[arrayTarget] !== undefined) ||
|
|
10547
11193
|
arrStore.watches.has(arrayTarget) ||
|
|
10548
11194
|
monitor.hasOverlay(arrayTarget)) {
|
|
10549
11195
|
simpleRead = false;
|
|
@@ -10591,6 +11237,36 @@ export class Runtime {
|
|
|
10591
11237
|
else
|
|
10592
11238
|
lineStr = io.stdin.tryReadSimpleRawAsciiLineSync(readDelim, raw);
|
|
10593
11239
|
if (lineStr !== undefined) {
|
|
11240
|
+
// Expand/read the input before publishing the destination array.
|
|
11241
|
+
if (arrayTarget !== undefined && !existingArrayBinding) {
|
|
11242
|
+
const arrStore = monitor.store ?? requireArrays(rawState);
|
|
11243
|
+
if (!existingArrayBinding && rawState.variables[arrayTarget] === undefined && !arrStore.watches.has(arrayTarget) && !monitor.hasOverlay(arrayTarget)) {
|
|
11244
|
+
const recTickets = arrStore.owner.charge({ generation: true, version: true, epoch: true, work: 8 });
|
|
11245
|
+
const recBinding = arrStore.takeRecycled(arrayTarget, false, true, recTickets);
|
|
11246
|
+
if (recBinding) {
|
|
11247
|
+
monitor.epoch = recTickets.epoch;
|
|
11248
|
+
existingArrayBinding = recBinding;
|
|
11249
|
+
}
|
|
11250
|
+
else
|
|
11251
|
+
try {
|
|
11252
|
+
const created = IndexedBinding.create(arrStore.owner, false);
|
|
11253
|
+
const nameByteLen = shellValueByteLength(arrayTarget);
|
|
11254
|
+
const prepared = arrStore.prepareExistingName(arrayTarget, nameByteLen, arrStore.owner, this.signal);
|
|
11255
|
+
if (prepared) {
|
|
11256
|
+
const initTickets = arrStore.owner.charge({ generation: true, version: true, epoch: true, work: 8 });
|
|
11257
|
+
arrStore.publish(arrayTarget, created, initTickets, prepared, false, arrStore.owner);
|
|
11258
|
+
monitor.epoch = initTickets.epoch;
|
|
11259
|
+
existingArrayBinding = created;
|
|
11260
|
+
}
|
|
11261
|
+
else {
|
|
11262
|
+
void created.release();
|
|
11263
|
+
}
|
|
11264
|
+
}
|
|
11265
|
+
catch { }
|
|
11266
|
+
}
|
|
11267
|
+
if (!existingArrayBinding)
|
|
11268
|
+
return undefined;
|
|
11269
|
+
}
|
|
10594
11270
|
if (rawState.extensions && !rawState.extensions.eventDepth)
|
|
10595
11271
|
publishCommandSpelling(rawState, commandSpelling(command));
|
|
10596
11272
|
if (arrayTarget !== undefined && existingArrayBinding) {
|
|
@@ -10650,6 +11326,7 @@ export class Runtime {
|
|
|
10650
11326
|
readArrayScratchFields.length = 0;
|
|
10651
11327
|
delete rawState.variables[arrayTarget];
|
|
10652
11328
|
monitor.epoch = tickets.epoch;
|
|
11329
|
+
existingArrayBinding.assigned = true;
|
|
10653
11330
|
activeArrStore.revise(arrayTarget, existingArrayBinding, tickets);
|
|
10654
11331
|
}
|
|
10655
11332
|
catch (error) {
|
|
@@ -10729,7 +11406,7 @@ export class Runtime {
|
|
|
10729
11406
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
10730
11407
|
}
|
|
10731
11408
|
else {
|
|
10732
|
-
|
|
11409
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
10733
11410
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
10734
11411
|
}
|
|
10735
11412
|
rawState.status = 0;
|
|
@@ -10927,7 +11604,7 @@ export class Runtime {
|
|
|
10927
11604
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
10928
11605
|
}
|
|
10929
11606
|
else {
|
|
10930
|
-
|
|
11607
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
10931
11608
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
10932
11609
|
}
|
|
10933
11610
|
rawState.status = 0;
|
|
@@ -11001,7 +11678,7 @@ export class Runtime {
|
|
|
11001
11678
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
11002
11679
|
}
|
|
11003
11680
|
else {
|
|
11004
|
-
|
|
11681
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
11005
11682
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
11006
11683
|
}
|
|
11007
11684
|
rawState.status = 0;
|
|
@@ -11081,6 +11758,8 @@ export class Runtime {
|
|
|
11081
11758
|
if (isLocalScope) {
|
|
11082
11759
|
let existingLocal = currentFrame.get(an);
|
|
11083
11760
|
if (!existingLocal) {
|
|
11761
|
+
if (this._syncArithRawWriteOnly && this._syncArithTouched?.has(an))
|
|
11762
|
+
monitor.values.invalidate(an);
|
|
11084
11763
|
existingLocal = saveVariable(state, an);
|
|
11085
11764
|
syncLocalArrayVariables.add(existingLocal);
|
|
11086
11765
|
currentFrame.set(an, existingLocal);
|
|
@@ -11145,13 +11824,15 @@ export class Runtime {
|
|
|
11145
11824
|
}
|
|
11146
11825
|
return undefined;
|
|
11147
11826
|
}
|
|
11827
|
+
const isNamerefDecl = command.words[1]?.plain === "-n" && rawState.locals.length > 0 && command.words.length >= 3;
|
|
11828
|
+
const isGlobalDecl = command.words[1]?.plain === "-g" && (w0Plain === "declare" || w0Plain === "typeset") && command.words.length >= 3;
|
|
11148
11829
|
const parsedLocals = [];
|
|
11149
11830
|
let allValidLocal = true;
|
|
11150
|
-
for (let idx = 1; idx < command.words.length; idx++) {
|
|
11831
|
+
for (let idx = (isNamerefDecl || isGlobalDecl) ? 2 : 1; idx < command.words.length; idx++) {
|
|
11151
11832
|
const wArg = command.words[idx];
|
|
11152
11833
|
const assignment = !getArrayAssignment(wArg) ? this.assignment(wArg) : undefined;
|
|
11153
11834
|
if (assignment) {
|
|
11154
|
-
if (assignment.name === "OPTIND" || assignment.name === "PIPESTATUS" || assignment.name.includes("[") || rawState.readonlyVariables?.has(assignment.name) || store?.get(assignment.name)) {
|
|
11835
|
+
if ((!isNamerefDecl && rawState.variableAttributes?.get(assignment.name)) || (assignment.name === "OPTIND" && (assignment.append || rawState.variableAttributes?.get("OPTIND"))) || assignment.name === "PIPESTATUS" || assignment.name.includes("[") || rawState.readonlyVariables?.has(assignment.name) || store?.get(assignment.name)) {
|
|
11155
11836
|
allValidLocal = false;
|
|
11156
11837
|
break;
|
|
11157
11838
|
}
|
|
@@ -11166,9 +11847,17 @@ export class Runtime {
|
|
|
11166
11847
|
allValidLocal = false;
|
|
11167
11848
|
break;
|
|
11168
11849
|
}
|
|
11850
|
+
if (assignment.name === "OPTIND") {
|
|
11851
|
+
const trimmedOptind = fastAssigned.trim();
|
|
11852
|
+
if (!/^[0-9]{1,6}$/.test(trimmedOptind)) {
|
|
11853
|
+
allValidLocal = false;
|
|
11854
|
+
break;
|
|
11855
|
+
}
|
|
11856
|
+
fastAssigned = String(Number(trimmedOptind));
|
|
11857
|
+
}
|
|
11169
11858
|
parsedLocals.push({ name: assignment.name, val: fastAssigned, append: assignment.append, lastArg: `${assignment.name}=${fastAssigned}` });
|
|
11170
11859
|
}
|
|
11171
|
-
else if (wArg.plain && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(wArg.plain) && wArg.plain !== "OPTIND" && wArg.plain !== "PIPESTATUS" && !rawState.readonlyVariables?.has(wArg.plain) && !store?.get(wArg.plain)) {
|
|
11860
|
+
else if (wArg.plain && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(wArg.plain) && (wArg.plain !== "OPTIND" || !rawState.variableAttributes?.get("OPTIND")) && wArg.plain !== "PIPESTATUS" && !rawState.readonlyVariables?.has(wArg.plain) && !store?.get(wArg.plain)) {
|
|
11172
11861
|
parsedLocals.push({ name: wArg.plain, val: undefined, append: false, lastArg: wArg.plain });
|
|
11173
11862
|
}
|
|
11174
11863
|
else {
|
|
@@ -11176,8 +11865,28 @@ export class Runtime {
|
|
|
11176
11865
|
break;
|
|
11177
11866
|
}
|
|
11178
11867
|
}
|
|
11868
|
+
if (isNamerefDecl && allValidLocal) {
|
|
11869
|
+
for (let i = 0; i < parsedLocals.length; i++) {
|
|
11870
|
+
const it = parsedLocals[i];
|
|
11871
|
+
if (!it.val || it.append || !isShellIdentifier(it.val) || it.val === it.name || rawState.variableAttributes?.get(it.val)) {
|
|
11872
|
+
allValidLocal = false;
|
|
11873
|
+
break;
|
|
11874
|
+
}
|
|
11875
|
+
}
|
|
11876
|
+
}
|
|
11877
|
+
if (isGlobalDecl && allValidLocal && rawState.locals.length > 0) {
|
|
11878
|
+
for (let i = 0; i < parsedLocals.length; i++) {
|
|
11879
|
+
const it = parsedLocals[i];
|
|
11880
|
+
if (rawState.locals.some(f => f.has(it.name))) {
|
|
11881
|
+
allValidLocal = false;
|
|
11882
|
+
break;
|
|
11883
|
+
}
|
|
11884
|
+
}
|
|
11885
|
+
}
|
|
11179
11886
|
if (allValidLocal && parsedLocals.length > 0) {
|
|
11180
|
-
|
|
11887
|
+
if ((rawState.locals.length === 0 || isGlobalDecl) && parsedLocals.some(item => item.val === undefined && !rawState.variableAttributes?.has(item.name)))
|
|
11888
|
+
return undefined;
|
|
11889
|
+
const locals = (!isGlobalDecl && rawState.locals.length > 0) ? rawState.locals[rawState.locals.length - 1] : undefined;
|
|
11181
11890
|
const restEpoch = monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets).epoch;
|
|
11182
11891
|
this.budget.tick();
|
|
11183
11892
|
rawState.substitutionStatus = 0;
|
|
@@ -11191,7 +11900,7 @@ export class Runtime {
|
|
|
11191
11900
|
const curVal = this._syncArithTouched.has(item.name)
|
|
11192
11901
|
? rawState.variables[item.name]
|
|
11193
11902
|
: (rawState.variables[item.name] === undefined ? undefined : (monitor.values.get(item.name, rawState.variables[item.name]) ?? rawState.variables[item.name]));
|
|
11194
|
-
locals.set(item.name, { attributes: undefined, value: typeof curVal === "string" ? curVal : undefined, exported:
|
|
11903
|
+
locals.set(item.name, { attributes: undefined, value: typeof curVal === "string" ? curVal : undefined, exported: rawState.exported.has(item.name), readOnly: false, ...(item.name === "OPTIND" ? { getopts: cloneGetoptsBinding(rawState) } : {}) });
|
|
11195
11904
|
}
|
|
11196
11905
|
else
|
|
11197
11906
|
locals.set(item.name, saveVariable(state, item.name));
|
|
@@ -11214,18 +11923,31 @@ export class Runtime {
|
|
|
11214
11923
|
}
|
|
11215
11924
|
else
|
|
11216
11925
|
monitor.publishStringVariable(item.name, finalVal);
|
|
11926
|
+
if (item.name === "OPTIND") {
|
|
11927
|
+
rawState.variables.OPTIND = finalVal;
|
|
11928
|
+
this.syncGetopts(rawState);
|
|
11929
|
+
}
|
|
11217
11930
|
if (rawState.allexport)
|
|
11218
11931
|
monitor.proxy.exported.add(item.name);
|
|
11219
11932
|
rawState.lastArgument = `${item.name}=${finalVal}`;
|
|
11220
|
-
if (
|
|
11933
|
+
if (isNamerefDecl) {
|
|
11221
11934
|
rawState.variableAttributes ??= new Map();
|
|
11222
|
-
rawState.variableAttributes.set(item.name, "");
|
|
11935
|
+
rawState.variableAttributes.set(item.name, "n");
|
|
11223
11936
|
}
|
|
11937
|
+
else if (isNewLocal && rawState.variableAttributes?.has(item.name))
|
|
11938
|
+
rawState.variableAttributes.delete(item.name);
|
|
11224
11939
|
}
|
|
11225
11940
|
else {
|
|
11226
|
-
if (
|
|
11227
|
-
|
|
11228
|
-
|
|
11941
|
+
if (item.name === "OPTIND")
|
|
11942
|
+
this.syncGetopts(rawState);
|
|
11943
|
+
if (!locals) {
|
|
11944
|
+
if (!rawState.variableAttributes?.has(item.name)) {
|
|
11945
|
+
rawState.variableAttributes ??= new Map();
|
|
11946
|
+
rawState.variableAttributes.set(item.name, "");
|
|
11947
|
+
}
|
|
11948
|
+
}
|
|
11949
|
+
else if (isNewLocal && rawState.variableAttributes?.has(item.name)) {
|
|
11950
|
+
rawState.variableAttributes.delete(item.name);
|
|
11229
11951
|
}
|
|
11230
11952
|
rawState.lastArgument = item.lastArg;
|
|
11231
11953
|
}
|
|
@@ -11243,7 +11965,7 @@ export class Runtime {
|
|
|
11243
11965
|
}
|
|
11244
11966
|
}
|
|
11245
11967
|
else {
|
|
11246
|
-
|
|
11968
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
11247
11969
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
11248
11970
|
}
|
|
11249
11971
|
rawState.status = 0;
|
|
@@ -11269,8 +11991,6 @@ export class Runtime {
|
|
|
11269
11991
|
if (fastArg.length > 0 && fastArg.length <= 15 && /^-?[0-9]+$/.test(fastArg)) {
|
|
11270
11992
|
const retStatus = ((Number(fastArg) % 256) + 256) % 256;
|
|
11271
11993
|
const statusStr = retStatus === 0 ? "0" : retStatus === 1 ? "1" : String(retStatus);
|
|
11272
|
-
if (existing && elem0.text.bytes !== statusStr.length)
|
|
11273
|
-
return undefined;
|
|
11274
11994
|
const prevStatus = rawState.status;
|
|
11275
11995
|
const restEpoch = monitor.chargeInternal(syncRestorationCharge, syncRestorationTickets).epoch;
|
|
11276
11996
|
this.budget.tick();
|
|
@@ -11285,7 +12005,7 @@ export class Runtime {
|
|
|
11285
12005
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
11286
12006
|
}
|
|
11287
12007
|
else {
|
|
11288
|
-
|
|
12008
|
+
this.setSyncPipeStatusCell(existing, statusStr);
|
|
11289
12009
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
11290
12010
|
}
|
|
11291
12011
|
rawState.status = retStatus;
|
|
@@ -11339,10 +12059,14 @@ export class Runtime {
|
|
|
11339
12059
|
else {
|
|
11340
12060
|
const savedPos = rawState.positional;
|
|
11341
12061
|
rawState.positional = fnArgs;
|
|
12062
|
+
rawState.locals.push(new Map());
|
|
12063
|
+
rawState.functionDepth++;
|
|
11342
12064
|
try {
|
|
11343
12065
|
canSyncFn = this.canSyncScriptCompound(fnBody.body, rawState, 1);
|
|
11344
12066
|
}
|
|
11345
12067
|
finally {
|
|
12068
|
+
rawState.functionDepth--;
|
|
12069
|
+
rawState.locals.pop();
|
|
11346
12070
|
rawState.positional = savedPos;
|
|
11347
12071
|
}
|
|
11348
12072
|
}
|
|
@@ -11434,11 +12158,15 @@ export class Runtime {
|
|
|
11434
12158
|
rawState.locals.pop();
|
|
11435
12159
|
rawState.functionNames?.shift();
|
|
11436
12160
|
for (const [k, previous] of locals) {
|
|
11437
|
-
if (this._syncArithRawWriteOnly && this._syncArithTouched && !syncLocalArrayVariables.has(previous) && !previous.heldValue && !previous.attributes && !previous.exported && !previous.readOnly
|
|
12161
|
+
if (this._syncArithRawWriteOnly && this._syncArithTouched && !syncLocalArrayVariables.has(previous) && !previous.heldValue && !previous.attributes && !previous.exported && !previous.readOnly) {
|
|
11438
12162
|
if (previous.value === undefined)
|
|
11439
12163
|
delete rawState.variables[k];
|
|
11440
12164
|
else
|
|
11441
12165
|
rawState.variables[k] = shellValueText(previous.value);
|
|
12166
|
+
if (k === "OPTIND" && previous.getopts) {
|
|
12167
|
+
rawState.getopts = { integer: previous.getopts.integer, cursor: cloneGetoptsState(previous.getopts.cursor) };
|
|
12168
|
+
}
|
|
12169
|
+
rawState.variableAttributes?.delete(k);
|
|
11442
12170
|
this._syncArithTouched.add(k);
|
|
11443
12171
|
}
|
|
11444
12172
|
else
|
|
@@ -11459,8 +12187,8 @@ export class Runtime {
|
|
|
11459
12187
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
11460
12188
|
}
|
|
11461
12189
|
}
|
|
11462
|
-
else
|
|
11463
|
-
|
|
12190
|
+
else {
|
|
12191
|
+
this.setSyncPipeStatusCell(activeExisting, statusStr);
|
|
11464
12192
|
activeStore.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
11465
12193
|
}
|
|
11466
12194
|
rawState.status = exitStatus;
|
|
@@ -11531,7 +12259,7 @@ export class Runtime {
|
|
|
11531
12259
|
}
|
|
11532
12260
|
}
|
|
11533
12261
|
else {
|
|
11534
|
-
|
|
12262
|
+
this.setSyncPipeStatusCell(activeExisting, "0");
|
|
11535
12263
|
activeStore.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
11536
12264
|
}
|
|
11537
12265
|
rawState.status = 0;
|
|
@@ -11565,7 +12293,7 @@ export class Runtime {
|
|
|
11565
12293
|
rawState.depth++;
|
|
11566
12294
|
let evalStatus;
|
|
11567
12295
|
try {
|
|
11568
|
-
evalStatus = this.trySyncScript(cachedUnit.script, state, io, Boolean(ignored));
|
|
12296
|
+
evalStatus = this.trySyncScript(cachedUnit.script, state, { ...io, diagnosticOffset: (diagnosticLine ?? 1) - 1, functionCommandLines: undefined, assignmentDiagnosticContext: { name: "eval" } }, Boolean(ignored));
|
|
11569
12297
|
}
|
|
11570
12298
|
finally {
|
|
11571
12299
|
rawState.depth--;
|
|
@@ -11585,7 +12313,7 @@ export class Runtime {
|
|
|
11585
12313
|
}
|
|
11586
12314
|
}
|
|
11587
12315
|
else {
|
|
11588
|
-
|
|
12316
|
+
this.setSyncPipeStatusCell(activeExisting, "0");
|
|
11589
12317
|
activeStore.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
11590
12318
|
}
|
|
11591
12319
|
}
|
|
@@ -11669,7 +12397,7 @@ export class Runtime {
|
|
|
11669
12397
|
}
|
|
11670
12398
|
}
|
|
11671
12399
|
else {
|
|
11672
|
-
|
|
12400
|
+
this.setSyncPipeStatusCell(existing, statusChar);
|
|
11673
12401
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
11674
12402
|
}
|
|
11675
12403
|
const finalStatus = pipeline.negate ? Number(fastPred === 0) : fastPred;
|
|
@@ -11734,7 +12462,7 @@ export class Runtime {
|
|
|
11734
12462
|
else {
|
|
11735
12463
|
const idxNum = /^(?:0|[1-9][0-9]{0,8})$/.test(subExpr) ? Number(subExpr) : resolveSimpleArithOperand(subExpr, rawState, monitor, arrStore, this._syncArithRawWriteOnly ? this._syncArithTouched : undefined);
|
|
11736
12464
|
if (idxNum !== undefined && idxNum >= 0 && idxNum <= 2147483647) {
|
|
11737
|
-
if (!curB && rawState.variables[arrName] === undefined && !arrStore.watches.has(arrName) && !monitor.hasOverlay(arrName)) {
|
|
12465
|
+
if (!curB && !hasUnpreparedLocal(rawState, arrName) && rawState.variables[arrName] === undefined && !arrStore.watches.has(arrName) && !monitor.hasOverlay(arrName)) {
|
|
11738
12466
|
const created = IndexedBinding.create(arrStore.owner, false);
|
|
11739
12467
|
const prepared = arrStore.prepareExistingName(arrName, shellValueByteLength(arrName), arrStore.owner, this.signal);
|
|
11740
12468
|
if (prepared) {
|
|
@@ -11780,7 +12508,7 @@ export class Runtime {
|
|
|
11780
12508
|
}
|
|
11781
12509
|
}
|
|
11782
12510
|
else {
|
|
11783
|
-
|
|
12511
|
+
this.setSyncPipeStatusCell(activeExisting, "0");
|
|
11784
12512
|
activeStore.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
11785
12513
|
}
|
|
11786
12514
|
const finalStatus = pipeline.negate ? 1 : 0;
|
|
@@ -11866,7 +12594,7 @@ export class Runtime {
|
|
|
11866
12594
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
11867
12595
|
}
|
|
11868
12596
|
else {
|
|
11869
|
-
|
|
12597
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
11870
12598
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
11871
12599
|
}
|
|
11872
12600
|
const finalStatus = pipeline.negate ? 1 : 0;
|
|
@@ -11921,7 +12649,7 @@ export class Runtime {
|
|
|
11921
12649
|
return false;
|
|
11922
12650
|
continue;
|
|
11923
12651
|
}
|
|
11924
|
-
if (part.prefixNames || part.specialParameter || part.transform || part.name === "@" || part.name === "*" || part.name === "PIPESTATUS" || part.name === "LINENO" || part.name === "_" || part.name === "FUNCNAME" || !isShellIdentifier(part.name)) {
|
|
12652
|
+
if (part.prefixNames || part.specialParameter || part.transform || part.name === "@" || part.name === "*" || part.name === "PIPESTATUS" || part.name === "LINENO" || part.name === "_" || part.name === "FUNCNAME" || part.name === "DIRSTACK" || !isShellIdentifier(part.name)) {
|
|
11925
12653
|
return false;
|
|
11926
12654
|
}
|
|
11927
12655
|
if (part.indirect) {
|
|
@@ -11998,9 +12726,11 @@ export class Runtime {
|
|
|
11998
12726
|
if (part.alternate && part.alternate.parts.length > 0)
|
|
11999
12727
|
return false;
|
|
12000
12728
|
}
|
|
12001
|
-
else if (part.operator === "-" || part.operator === ":-" || part.operator === "+" || part.operator === ":+") {
|
|
12729
|
+
else if (part.operator === "-" || part.operator === ":-" || part.operator === "+" || part.operator === ":+" || part.operator === "=" || part.operator === ":=") {
|
|
12002
12730
|
if (!part.alternate || !part.alternate.parts.every(p => p.kind === "text" || p.kind === "arithmetic" || (p.kind === "variable" && !p.operator && !p.substring)))
|
|
12003
12731
|
return false;
|
|
12732
|
+
if ((part.operator === "=" || part.operator === ":=") && (!isShellIdentifier(part.name) || part.name === "OPTIND" || part.name === "PIPESTATUS" || part.name === "_" || rawState.readonlyVariables?.has(part.name) || rawState.variableAttributes?.get(part.name) || stateMonitor(rawState)?.store?.get(part.name)))
|
|
12733
|
+
return false;
|
|
12004
12734
|
}
|
|
12005
12735
|
else if (part.operator === "#" || part.operator === "##" || part.operator === "%" || part.operator === "%%") {
|
|
12006
12736
|
if (!part.alternate || part.alternate.parts.length === 0)
|
|
@@ -12036,8 +12766,18 @@ export class Runtime {
|
|
|
12036
12766
|
if (rawState.nounset)
|
|
12037
12767
|
return false;
|
|
12038
12768
|
const em = SIMPLE_EXPANDED_ARITH_RE.exec(part.source);
|
|
12039
|
-
if (!em || ((em[2] === "/" || em[2] === "%") && !(em[3] && /^[1-9][0-9]*$/.test(em[3]))))
|
|
12040
|
-
|
|
12769
|
+
if (!em || ((em[2] === "/" || em[2] === "%") && !(em[3] && /^[1-9][0-9]*$/.test(em[3])))) {
|
|
12770
|
+
if (part.source.includes("<<") || part.source.includes(">>") || part.source.includes("**") || /[/%](?!\s*[1-9][0-9]*\b)/.test(part.source))
|
|
12771
|
+
return false;
|
|
12772
|
+
try {
|
|
12773
|
+
const expW = parseArithmeticExpansion(part.source, this.budget.parsing, false, 0, undefined, rawState.extensions?.syntax);
|
|
12774
|
+
if (!this.isPureSyncValueWord(expW, rawState))
|
|
12775
|
+
return false;
|
|
12776
|
+
}
|
|
12777
|
+
catch {
|
|
12778
|
+
return false;
|
|
12779
|
+
}
|
|
12780
|
+
}
|
|
12041
12781
|
}
|
|
12042
12782
|
continue;
|
|
12043
12783
|
}
|
|
@@ -12406,7 +13146,7 @@ export class Runtime {
|
|
|
12406
13146
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
12407
13147
|
}
|
|
12408
13148
|
else {
|
|
12409
|
-
|
|
13149
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
12410
13150
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
12411
13151
|
}
|
|
12412
13152
|
}
|
|
@@ -12769,7 +13509,7 @@ export class Runtime {
|
|
|
12769
13509
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
12770
13510
|
}
|
|
12771
13511
|
else {
|
|
12772
|
-
|
|
13512
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
12773
13513
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
12774
13514
|
}
|
|
12775
13515
|
}
|
|
@@ -12994,7 +13734,7 @@ export class Runtime {
|
|
|
12994
13734
|
monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets);
|
|
12995
13735
|
}
|
|
12996
13736
|
else {
|
|
12997
|
-
|
|
13737
|
+
this.setSyncPipeStatusCell(existing, "0");
|
|
12998
13738
|
store.changed(monitor.chargeInternal(syncPipeStatusCharge, syncPipeStatusTickets), "PIPESTATUS");
|
|
12999
13739
|
}
|
|
13000
13740
|
}
|
|
@@ -15626,7 +16366,7 @@ export class Runtime {
|
|
|
15626
16366
|
previous.set(assignment.name, saved);
|
|
15627
16367
|
const existingArray = arrayStore(state)?.get(assignment.name);
|
|
15628
16368
|
const canSkipTypedScalarOverlay = !existingArray && words[0] === "read" && !state.functions.has("read") && !state.extensions?.builtins.has("read") && !words.some(w => w.startsWith("-a") || (w.startsWith("-") && !w.startsWith("--") && w.includes("a")));
|
|
15629
|
-
if (words.length && !canSkipTypedScalarOverlay && (guestArrays(state) ||
|
|
16369
|
+
if (words.length && !canSkipTypedScalarOverlay && (guestArrays(state) || existingArray)) {
|
|
15630
16370
|
const store = requireArrays(state);
|
|
15631
16371
|
await this.prepareVariable(state, assignment.name, saved, !existingArray);
|
|
15632
16372
|
if (existingArray) {
|
|
@@ -15651,7 +16391,7 @@ export class Runtime {
|
|
|
15651
16391
|
}
|
|
15652
16392
|
if (inlineInput || (state.profile === "sh" || !words.length) && assignments.some(assignment => state.readonlyVariables?.has(assignment.name)))
|
|
15653
16393
|
await assign();
|
|
15654
|
-
if (inlineInput &&
|
|
16394
|
+
if (inlineInput && previous?.size) {
|
|
15655
16395
|
if (stateMonitor(state)?.lazyPipeStatus !== undefined)
|
|
15656
16396
|
stateMonitor(state).activate(true);
|
|
15657
16397
|
const redirectState = tryCloneStateSync(state) ?? await cloneState(state, this.signal);
|
|
@@ -15659,10 +16399,26 @@ export class Runtime {
|
|
|
15659
16399
|
const redirectAssignments = new Map();
|
|
15660
16400
|
for (const [name, saved] of previous) {
|
|
15661
16401
|
redirectAssignments.set(name, stateMonitor(state).values.get(name, state.variables[name]));
|
|
16402
|
+
if (saved.exported)
|
|
16403
|
+
redirectState.exported.add(name);
|
|
16404
|
+
else
|
|
16405
|
+
redirectState.exported.delete(name);
|
|
15662
16406
|
if (saved.value === undefined)
|
|
15663
16407
|
delete variables[name];
|
|
15664
16408
|
else
|
|
15665
16409
|
publishVariable(redirectState, name, saved.heldValue?.value ?? saved.value);
|
|
16410
|
+
const binding = typedSavedVariables.get(saved)?.binding;
|
|
16411
|
+
if (binding) {
|
|
16412
|
+
const store = requireArrays(redirectState);
|
|
16413
|
+
const prepared = await store.prepareName(name, store.owner, this.signal);
|
|
16414
|
+
const tickets = store.tickets(name);
|
|
16415
|
+
try {
|
|
16416
|
+
await store.publish(name, binding.retain(), tickets, prepared);
|
|
16417
|
+
}
|
|
16418
|
+
finally {
|
|
16419
|
+
tickets.release();
|
|
16420
|
+
}
|
|
16421
|
+
}
|
|
15666
16422
|
}
|
|
15667
16423
|
redirectState.redirectAssignments = redirectAssignments;
|
|
15668
16424
|
const savedIndex = previous.get("OPTIND");
|
|
@@ -15680,7 +16436,7 @@ export class Runtime {
|
|
|
15680
16436
|
}
|
|
15681
16437
|
const epoch = stateMonitor(state)?.epoch;
|
|
15682
16438
|
try {
|
|
15683
|
-
io = await this.redirect(command.redirects, redirectState, io, inputs, outputs,
|
|
16439
|
+
io = await this.redirect(command.redirects, redirectState, io, inputs, outputs, isolatedInlineInput, !isolatedInlineInput, false, command.line ?? 1);
|
|
15684
16440
|
if (parentStore && stateMonitor(state).epoch !== epoch)
|
|
15685
16441
|
throw new ArrayFailure("stale state snapshot");
|
|
15686
16442
|
}
|
|
@@ -15703,6 +16459,12 @@ export class Runtime {
|
|
|
15703
16459
|
publishVariable(state, name, stateMonitor(redirectState).values.get(name, value));
|
|
15704
16460
|
}
|
|
15705
16461
|
for (const [name, saved] of previous) {
|
|
16462
|
+
const typed = typedSavedVariables.get(saved);
|
|
16463
|
+
const binding = arrayStore(redirectState)?.get(name);
|
|
16464
|
+
if (typed && binding !== typed.binding) {
|
|
16465
|
+
typedSavedVariables.set(saved, { ...typed, binding: binding?.retain() });
|
|
16466
|
+
await typed.binding?.release();
|
|
16467
|
+
}
|
|
15706
16468
|
saved.value = variables[name];
|
|
15707
16469
|
const value = stateMonitor(redirectState).values.get(name, saved.value ?? "");
|
|
15708
16470
|
const held = saved.value === undefined ? undefined : stateMonitor(state).values.scope.hold(value);
|
|
@@ -19897,6 +20659,9 @@ export class Runtime {
|
|
|
19897
20659
|
seen.add(name);
|
|
19898
20660
|
names.push(name);
|
|
19899
20661
|
};
|
|
20662
|
+
await consider("DIRSTACK", true);
|
|
20663
|
+
if (state.functionNames?.length)
|
|
20664
|
+
await consider("FUNCNAME", true);
|
|
19900
20665
|
for (const name in state.variables)
|
|
19901
20666
|
if (Object.hasOwn(state.variables, name))
|
|
19902
20667
|
await consider(name, state.variables[name] !== undefined);
|
|
@@ -19977,7 +20742,7 @@ export class Runtime {
|
|
|
19977
20742
|
setArraySelector(resolved, { kind: "element", index: { decimal: shellValueText(value), word: { offset: word.offset, parts: [{ kind: "text", value: shellValueText(value), quoted: true, ...(typeof value === "string" ? {} : { byteValue: value }) }] } } });
|
|
19978
20743
|
return resolved;
|
|
19979
20744
|
}
|
|
19980
|
-
const maximum = binding?.maximum ?? (state.variables[part.name] === undefined ? -1 : 0);
|
|
20745
|
+
const maximum = binding?.maximum ?? (part.name === "FUNCNAME" && state.variables.FUNCNAME === undefined ? (state.functionNames?.length ?? 0) - 1 : state.variables[part.name] === undefined ? -1 : 0);
|
|
19981
20746
|
const index = await this.arrayIndex(binding, selector.index, state, io, store.owner, false, maximum);
|
|
19982
20747
|
const resolved = { ...part };
|
|
19983
20748
|
copyArraySelector(part, resolved);
|
|
@@ -20049,8 +20814,7 @@ export class Runtime {
|
|
|
20049
20814
|
const selector = getArraySelector(part);
|
|
20050
20815
|
if (selector?.kind === "members" || part.name === "@" || part.name === "*") {
|
|
20051
20816
|
const members = selector ? await this.arrayMembers(part.name, state, io, part.keys) : this.positionalValues(state);
|
|
20052
|
-
const
|
|
20053
|
-
const separator = selector?.kind === "members" && !split && (selector.separator === "@" || !part.quoted) ? " " : ifs.length ? String.fromCodePoint(ifs.codePointAt(0)) : "";
|
|
20817
|
+
const separator = !split && (selector?.kind === "members" ? selector.separator === "@" : part.name === "@") ? " " : this.ifsSeparator(state, io);
|
|
20054
20818
|
const fragments = [];
|
|
20055
20819
|
let bytes = 0;
|
|
20056
20820
|
for (const member of members) {
|
|
@@ -20490,7 +21254,7 @@ export class Runtime {
|
|
|
20490
21254
|
if (part.length)
|
|
20491
21255
|
return String(binding?.values.size ?? (part.name === "FUNCNAME" && state.variables.FUNCNAME === undefined ? state.functionNames?.length ?? 0 : state.variables[part.name] === undefined ? 0 : 1));
|
|
20492
21256
|
const values = await this.arrayMembers(part.name, state, io, selector.kind === "keys" || part.keys === true, part.substring);
|
|
20493
|
-
const space = (selector.kind === "keys" || part.keys === true)
|
|
21257
|
+
const space = (selector.kind === "keys" || part.keys === true) ? Boolean(hereDocument || (selector.separator === "@" ? !part.quoted && !split || state.variables.IFS === "" : !part.quoted && split && state.variables.IFS === "")) : (!split && selector.separator === "@");
|
|
20494
21258
|
return this.arrayJoin(store.owner, values, space ? " " : this.ifsSeparator(state, io));
|
|
20495
21259
|
}
|
|
20496
21260
|
if (part.substring && (part.name === "@" || part.name === "*")) {
|
|
@@ -20504,7 +21268,7 @@ export class Runtime {
|
|
|
20504
21268
|
: part.name === "?" ? String(state.status)
|
|
20505
21269
|
: part.name === "-" ? `${state.allexport ? "a" : ""}${state.errexit ? "e" : ""}${state.noglob ? "f" : ""}${state.noexec ? "n" : ""}${state.nounset ? "u" : ""}${state.braceexpand !== false ? "B" : ""}${state.noclobber ? "C" : ""}`
|
|
20506
21270
|
: part.name === "#" ? String(state.positional.length)
|
|
20507
|
-
: part.name === "@" || part.name === "*" ? state.positional.join(hereString && (part.name === "@" || !part.quoted) ? " " : Array.from(state.variables.IFS ?? " ")[0] ?? "")
|
|
21271
|
+
: part.name === "@" || part.name === "*" ? state.positional.join(part.name === "@" && !split || hereString && (part.name === "@" || !part.quoted) ? " " : Array.from(state.variables.IFS ?? " ")[0] ?? "")
|
|
20508
21272
|
: /^0+$/u.test(part.name) ? state.arg0 ?? "virtual-bash"
|
|
20509
21273
|
: /^\d+$/u.test(part.name) ? state.positional[Number(part.name) - 1]
|
|
20510
21274
|
: part.name === "LINENO" ? (state.extensions ? String(io.diagnosticLine ?? part.line ?? 1) : state.variables.LINENO ?? String(io.diagnosticLine ?? part.line ?? 1)) : this.variable(state, part.name);
|
|
@@ -20521,7 +21285,7 @@ export class Runtime {
|
|
|
20521
21285
|
else if (/^[0-9]+$/u.test(part.name))
|
|
20522
21286
|
retained = stateMonitor(state)?.positionals.get(String(Number(part.name) - 1), value) ?? value;
|
|
20523
21287
|
else if (part.name === "@" || part.name === "*") {
|
|
20524
|
-
const separator = hereString && (part.name === "@" || !part.quoted) ? " " : this.ifsSeparator(state, io);
|
|
21288
|
+
const separator = part.name === "@" && !split || hereString && (part.name === "@" || !part.quoted) ? " " : this.ifsSeparator(state, io);
|
|
20525
21289
|
const values = this.positionalValues(state);
|
|
20526
21290
|
retained = concatShellValues(values.flatMap((entry, index) => index ? [separator, entry] : [entry]), io[valueScope]);
|
|
20527
21291
|
}
|
|
@@ -20906,7 +21670,7 @@ export class Runtime {
|
|
|
20906
21670
|
fastValueWord(word, state, io, split, pattern, hereDocument, braces, assignmentStart, overrideDiagnosticLine) {
|
|
20907
21671
|
const monitor = stateMonitor(state);
|
|
20908
21672
|
const rawState = monitor ? monitor.raw : state;
|
|
20909
|
-
if (pattern || word.parts.length === 0 || (rawState.depth + (io.parameterDepth ?? 0)) >= 32 ||
|
|
21673
|
+
if (pattern || word.parts.length === 0 || (rawState.depth + (io.parameterDepth ?? 0)) >= 32 || hasNonNamerefAttributes(rawState))
|
|
20910
21674
|
return undefined;
|
|
20911
21675
|
if (guestArrays(state) && word.parts.some(part => part.kind === "arithmetic" && !part.expression.error && !isSafeSmiProgram(part.expression)))
|
|
20912
21676
|
return undefined;
|
|
@@ -20915,7 +21679,7 @@ export class Runtime {
|
|
|
20915
21679
|
this.signal.throwIfAborted();
|
|
20916
21680
|
let out = "";
|
|
20917
21681
|
for (let i = 0; i < word.parts.length; i++) {
|
|
20918
|
-
|
|
21682
|
+
let part = word.parts[i];
|
|
20919
21683
|
if (part.kind === "text") {
|
|
20920
21684
|
if (part.byteValue || invokedValues.has(part))
|
|
20921
21685
|
return undefined;
|
|
@@ -20933,8 +21697,17 @@ export class Runtime {
|
|
|
20933
21697
|
out += part.value;
|
|
20934
21698
|
}
|
|
20935
21699
|
else if (part.kind === "variable") {
|
|
20936
|
-
if (rawState.variableAttributes?.get(part.name)?.includes("n"))
|
|
20937
|
-
|
|
21700
|
+
if (rawState.variableAttributes?.get(part.name)?.includes("n")) {
|
|
21701
|
+
if (part.indirect)
|
|
21702
|
+
return undefined;
|
|
21703
|
+
const resolvedName = resolveSyncNameref(rawState, part.name);
|
|
21704
|
+
if (resolvedName === part.name)
|
|
21705
|
+
return undefined;
|
|
21706
|
+
const origSel = getArraySelector(part);
|
|
21707
|
+
part = { ...part, name: resolvedName };
|
|
21708
|
+
if (origSel)
|
|
21709
|
+
setArraySelector(part, origSel);
|
|
21710
|
+
}
|
|
20938
21711
|
if (split && !part.quoted && (rawVars.IFS !== undefined && rawVars.IFS !== " \t\n"))
|
|
20939
21712
|
return undefined;
|
|
20940
21713
|
if (!part.indirect && !part.prefixNames && !part.length && !part.substring && !part.transform && part.operator === undefined && getArraySelector(part) === undefined && (part.name === "?" || part.name === "#" || (part.name.length === 1 && part.name >= "1" && part.name <= "9"))) {
|
|
@@ -20964,7 +21737,7 @@ export class Runtime {
|
|
|
20964
21737
|
const refName = refRaw === undefined ? undefined : (this._syncArithRawWriteOnly && this._syncArithTouched?.has(part.name) ? refRaw : (monitor?.values.get(part.name, refRaw) ?? refRaw));
|
|
20965
21738
|
if (typeof refName !== "string" || !isShellIdentifier(refName))
|
|
20966
21739
|
return undefined;
|
|
20967
|
-
if (activeArrayStore?.get(refName) || rawState.variableAttributes?.get(refName) || refName === "PIPESTATUS" || refName === "LINENO" || refName === "_" || refName === "FUNCNAME") {
|
|
21740
|
+
if (activeArrayStore?.get(refName) || rawState.variableAttributes?.get(refName) || refName === "PIPESTATUS" || refName === "LINENO" || refName === "_" || refName === "FUNCNAME" || refName === "DIRSTACK") {
|
|
20968
21741
|
return undefined;
|
|
20969
21742
|
}
|
|
20970
21743
|
const targetRaw = rawVars[refName];
|
|
@@ -20980,7 +21753,7 @@ export class Runtime {
|
|
|
20980
21753
|
}
|
|
20981
21754
|
if (part.indirect || part.prefixNames || part.specialParameter || part.transform)
|
|
20982
21755
|
return undefined;
|
|
20983
|
-
if (part.name === "@" || part.name === "*" || part.name === "PIPESTATUS" || part.name === "LINENO" || part.name === "_" || part.name === "FUNCNAME")
|
|
21756
|
+
if (part.name === "@" || part.name === "*" || part.name === "PIPESTATUS" || part.name === "LINENO" || part.name === "_" || part.name === "FUNCNAME" || part.name === "DIRSTACK")
|
|
20984
21757
|
return undefined;
|
|
20985
21758
|
if (!isShellIdentifier(part.name))
|
|
20986
21759
|
return undefined;
|
|
@@ -21061,11 +21834,12 @@ export class Runtime {
|
|
|
21061
21834
|
}
|
|
21062
21835
|
const ifsVal = monitor?.values.get("IFS", rawVars.IFS ?? " ") ?? rawVars.IFS ?? " ";
|
|
21063
21836
|
if (validElemOp && typeof ifsVal === "string" && (ifsVal.length === 0 || ifsVal.charCodeAt(0) < 128)) {
|
|
21064
|
-
const sep = selector.separator === "@" ? " " : ifsVal.length > 0 ? ifsVal[0] : "";
|
|
21837
|
+
const sep = selector.separator === "@" && (!isKeys || ifsVal.length === 0) ? " " : ifsVal.length > 0 ? ifsVal[0] : "";
|
|
21838
|
+
const parameterLine = part.line ?? overrideDiagnosticLine;
|
|
21065
21839
|
const evalSliceInt = (w) => {
|
|
21066
21840
|
if (w.parts.length === 0)
|
|
21067
21841
|
return 0;
|
|
21068
|
-
const expanded = this.fastValueWord(w, rawState, io, false, false, false, false, undefined,
|
|
21842
|
+
const expanded = this.fastValueWord(w, rawState, io, false, false, false, false, undefined, parameterLine);
|
|
21069
21843
|
if (typeof expanded !== "string")
|
|
21070
21844
|
return undefined;
|
|
21071
21845
|
const trimmed = expanded.trim();
|
|
@@ -21316,10 +22090,11 @@ export class Runtime {
|
|
|
21316
22090
|
if (part.length || part.operator !== undefined || this.budget.limits.maxExpansionBytes !== Infinity || rawState.depth + (io.parameterDepth ?? 0) >= 60 || !part.substring.offset.parts.every(p => p.kind === "text" || p.kind === "arithmetic" || (p.kind === "variable" && !p.operator && !p.substring)) || (part.substring.length && !part.substring.length.parts.every(p => p.kind === "text" || p.kind === "arithmetic" || (p.kind === "variable" && !p.operator && !p.substring))) || ValueScope.prototype.reserve !== defaultValueScopeReserve || String.prototype.codePointAt !== defaultStringCodePointAt || globalThis.Float64Array !== defaultFloat64Array || (!part.substring.offset.parts.length && !part.substring.length)) {
|
|
21317
22091
|
return undefined;
|
|
21318
22092
|
}
|
|
22093
|
+
const parameterLine = part.line ?? overrideDiagnosticLine;
|
|
21319
22094
|
const evalSubInt = (w) => {
|
|
21320
22095
|
if (w.parts.length === 0)
|
|
21321
22096
|
return 0;
|
|
21322
|
-
const expanded = this.fastValueWord(w, rawState, io, false, false, false, false, undefined,
|
|
22097
|
+
const expanded = this.fastValueWord(w, rawState, io, false, false, false, false, undefined, parameterLine);
|
|
21323
22098
|
if (typeof expanded !== "string")
|
|
21324
22099
|
return undefined;
|
|
21325
22100
|
const trimmed = expanded.trim();
|
|
@@ -21393,7 +22168,8 @@ export class Runtime {
|
|
|
21393
22168
|
if (part.operator !== undefined) {
|
|
21394
22169
|
if (this.budget.limits.maxExpansionBytes !== Infinity || rawState.depth + (io.parameterDepth ?? 0) >= 60 || ValueScope.prototype.reserve !== defaultValueScopeReserve || String.prototype.codePointAt !== defaultStringCodePointAt || globalThis.Float64Array !== defaultFloat64Array)
|
|
21395
22170
|
return undefined;
|
|
21396
|
-
|
|
22171
|
+
const patternQuoted = part.alternate?.parts[0]?.quoted;
|
|
22172
|
+
if (!rawState.nocasematch && (part.operator === "/" || part.operator === "//" || part.operator === "/#" || part.operator === "/%") && part.alternate && part.alternate.parts.length >= 1 && part.alternate.parts.every(p => p.quoted === patternQuoted && ((p.kind === "text" && !p.byteValue) || (p.kind === "variable" && !p.operator && !p.substring && !p.length && !p.indirect && !p.prefixNames && !p.specialParameter && !p.transform && getArraySelector(p) === undefined && isShellIdentifier(p.name)))) && (!part.replacement || part.replacement.parts.length === 0 || part.replacement.parts.every(p => (p.kind === "text" && !p.byteValue) || (p.kind === "variable" && !p.operator && !p.substring && !p.length && !p.indirect && !p.prefixNames && !p.specialParameter && !p.transform && getArraySelector(p) === undefined && isShellIdentifier(p.name))))) {
|
|
21397
22173
|
const patQuoted = part.alternate.parts[0].quoted;
|
|
21398
22174
|
const pat = (part.alternate.parts.length === 1 && part.alternate.parts[0].kind === "text")
|
|
21399
22175
|
? part.alternate.parts[0].value
|
|
@@ -21467,7 +22243,7 @@ export class Runtime {
|
|
|
21467
22243
|
out += replaced;
|
|
21468
22244
|
continue;
|
|
21469
22245
|
}
|
|
21470
|
-
if ((part.operator === "#" || part.operator === "##" || part.operator === "%" || part.operator === "%%") && part.alternate && part.alternate.parts.length >= 1 && part.alternate.parts.every(p => p.quoted ===
|
|
22246
|
+
if ((part.operator === "#" || part.operator === "##" || part.operator === "%" || part.operator === "%%") && part.alternate && part.alternate.parts.length >= 1 && part.alternate.parts.every(p => p.quoted === patternQuoted && ((p.kind === "text" && !p.byteValue) || (p.kind === "variable" && !p.operator && !p.substring && !p.length && !p.indirect && !p.prefixNames && !p.specialParameter && !p.transform && getArraySelector(p) === undefined && isShellIdentifier(p.name))))) {
|
|
21471
22247
|
const patQuoted = part.alternate.parts[0].quoted;
|
|
21472
22248
|
const pat = (part.alternate.parts.length === 1 && part.alternate.parts[0].kind === "text")
|
|
21473
22249
|
? part.alternate.parts[0].value
|
|
@@ -21574,7 +22350,10 @@ export class Runtime {
|
|
|
21574
22350
|
out += converted;
|
|
21575
22351
|
continue;
|
|
21576
22352
|
}
|
|
21577
|
-
if ((part.operator === "-" || part.operator === ":-" || part.operator === "+" || part.operator === ":+") && part.alternate && !rawState.nounset && part.alternate.parts.every(p => p.kind === "text" || p.kind === "arithmetic" || (p.kind === "variable" && !p.operator && !p.substring))) {
|
|
22353
|
+
if ((part.operator === "-" || part.operator === ":-" || part.operator === "+" || part.operator === ":+" || part.operator === "=" || part.operator === ":=") && part.alternate && !rawState.nounset && part.alternate.parts.every(p => p.kind === "text" || p.kind === "arithmetic" || (p.kind === "variable" && !p.operator && !p.substring))) {
|
|
22354
|
+
const isAssignOp = part.operator === "=" || part.operator === ":=";
|
|
22355
|
+
if (isAssignOp && (!isShellIdentifier(part.name) || part.name === "OPTIND" || part.name === "PIPESTATUS" || part.name === "_" || rawState.readonlyVariables?.has(part.name) || rawState.variableAttributes?.get(part.name) || activeArrayStore?.get(part.name) || monitor?.hasOverlay(part.name) || (i < word.parts.length - 1 && !this.isPureSyncValueWord({ offset: 0, parts: word.parts.slice(i + 1) }, rawState, false))))
|
|
22356
|
+
return undefined;
|
|
21578
22357
|
const raw = rawVars[part.name];
|
|
21579
22358
|
const cur = raw === undefined ? undefined : (this._syncArithRawWriteOnly && this._syncArithTouched?.has(part.name) ? raw : (monitor?.values.get(part.name, raw) ?? raw));
|
|
21580
22359
|
if (cur !== undefined && typeof cur !== "string")
|
|
@@ -21592,11 +22371,25 @@ export class Runtime {
|
|
|
21592
22371
|
resolvedScalar = "";
|
|
21593
22372
|
}
|
|
21594
22373
|
else {
|
|
21595
|
-
const isMissing = cur === undefined || (part.operator === ":-" && cur === "");
|
|
22374
|
+
const isMissing = cur === undefined || ((part.operator === ":-" || part.operator === ":=") && cur === "");
|
|
21596
22375
|
if (isMissing) {
|
|
21597
22376
|
const altVal = this.fastValueWord(part.alternate, rawState, io, false, false, false, false, undefined, part.line ?? overrideDiagnosticLine);
|
|
21598
22377
|
if (typeof altVal !== "string")
|
|
21599
22378
|
return undefined;
|
|
22379
|
+
if (isAssignOp) {
|
|
22380
|
+
if (this._syncArithRawWriteOnly && this._syncArithTouched) {
|
|
22381
|
+
rawState.variables[part.name] = altVal;
|
|
22382
|
+
this._syncArithTouched.add(part.name);
|
|
22383
|
+
}
|
|
22384
|
+
else if (monitor) {
|
|
22385
|
+
monitor.publishStringVariable(part.name, altVal);
|
|
22386
|
+
}
|
|
22387
|
+
else {
|
|
22388
|
+
rawState.variables[part.name] = altVal;
|
|
22389
|
+
}
|
|
22390
|
+
if (rawState.allexport)
|
|
22391
|
+
(monitor ? monitor.proxy.exported : rawState.exported).add(part.name);
|
|
22392
|
+
}
|
|
21600
22393
|
resolvedScalar = altVal;
|
|
21601
22394
|
}
|
|
21602
22395
|
else
|
|
@@ -21721,7 +22514,7 @@ export class Runtime {
|
|
|
21721
22514
|
return false;
|
|
21722
22515
|
continue;
|
|
21723
22516
|
}
|
|
21724
|
-
if (p.prefixNames || p.specialParameter || p.transform || p.name === "@" || p.name === "*" || p.name === "PIPESTATUS" || p.name === "LINENO" || p.name === "_" || p.name === "FUNCNAME" || !isShellIdentifier(p.name)) {
|
|
22517
|
+
if (p.prefixNames || p.specialParameter || p.transform || p.name === "@" || p.name === "*" || p.name === "PIPESTATUS" || p.name === "LINENO" || p.name === "_" || p.name === "FUNCNAME" || p.name === "DIRSTACK" || !isShellIdentifier(p.name)) {
|
|
21725
22518
|
return false;
|
|
21726
22519
|
}
|
|
21727
22520
|
if (p.operator !== undefined && (p.operator === "=" || p.operator === ":=" || p.operator === "?" || p.operator === ":?"))
|
|
@@ -22827,7 +23620,9 @@ export class Runtime {
|
|
|
22827
23620
|
: numericIndex(selector.index, 4294967295);
|
|
22828
23621
|
if (index === undefined && !binding?.associative)
|
|
22829
23622
|
throw new ArrayFailure("index outside 0..4294967295");
|
|
22830
|
-
value = binding ? index === undefined ? undefined : binding.getValue(index)
|
|
23623
|
+
value = binding ? index === undefined ? undefined : binding.getValue(index)
|
|
23624
|
+
: part.name === "FUNCNAME" && state.variables.FUNCNAME === undefined ? (index === undefined ? undefined : state.functionNames?.[index])
|
|
23625
|
+
: index === 0 ? value : undefined;
|
|
22831
23626
|
}
|
|
22832
23627
|
const missing = value === undefined || (part.operator.startsWith(":") && shellValueByteLength(value) === 0);
|
|
22833
23628
|
if (part.operator.endsWith("+") ? !missing : missing) {
|
|
@@ -23178,8 +23973,9 @@ export class Runtime {
|
|
|
23178
23973
|
return this.arithmeticValue(prepareArithmetic(source || "0", this.budget.parsing), state, io);
|
|
23179
23974
|
};
|
|
23180
23975
|
offset = await evaluate(substring.offset);
|
|
23976
|
+
const maximum = binding?.maximum ?? (name === "FUNCNAME" && state.variables.FUNCNAME === undefined ? (state.functionNames?.length ?? 0) - 1 : state.variables[name] === undefined ? -1 : 0);
|
|
23181
23977
|
if (offset < 0n)
|
|
23182
|
-
offset += BigInt(
|
|
23978
|
+
offset += BigInt(maximum + 1);
|
|
23183
23979
|
if (substring.length) {
|
|
23184
23980
|
count = await evaluate(substring.length);
|
|
23185
23981
|
if (count < 0n)
|
|
@@ -23192,7 +23988,7 @@ export class Runtime {
|
|
|
23192
23988
|
if (!binding) {
|
|
23193
23989
|
if (name === "FUNCNAME" && state.variables.FUNCNAME === undefined) {
|
|
23194
23990
|
const stack = state.functionNames ?? [];
|
|
23195
|
-
const start =
|
|
23991
|
+
const start = Number(offset);
|
|
23196
23992
|
const end = count === undefined ? stack.length : start + Number(count);
|
|
23197
23993
|
const sliced = stack.slice(start, end);
|
|
23198
23994
|
return keys ? sliced.map((_v, idx) => String(start + idx)) : sliced;
|