@poe-platform/safe-bash 0.1.528 → 0.1.530
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/core.browser.js +185 -40
- package/dist/safe-bash/core.browser.js.map +3 -3
- package/dist/safe-bash/shell/arrays/bindings.d.ts +11 -1
- package/dist/safe-bash/shell/arrays/bindings.d.ts.map +1 -1
- package/dist/safe-bash/shell/arrays/bindings.js +74 -4
- package/dist/safe-bash/shell/arrays/bindings.js.map +1 -1
- package/dist/safe-bash/shell/arrays/syntax.d.ts +5 -2
- package/dist/safe-bash/shell/arrays/syntax.d.ts.map +1 -1
- package/dist/safe-bash/shell/arrays/syntax.js +19 -6
- package/dist/safe-bash/shell/arrays/syntax.js.map +1 -1
- package/dist/safe-bash/shell/parser.d.ts +2 -0
- package/dist/safe-bash/shell/parser.d.ts.map +1 -1
- package/dist/safe-bash/shell/parser.js +14 -5
- package/dist/safe-bash/shell/parser.js.map +1 -1
- package/dist/safe-bash/shell/runtime.d.ts +2 -1
- package/dist/safe-bash/shell/runtime.d.ts.map +1 -1
- package/dist/safe-bash/shell/runtime.js +89 -27
- package/dist/safe-bash/shell/runtime.js.map +1 -1
- package/package.json +2 -2
|
@@ -37498,12 +37498,23 @@ function literalIndex(source2, offset, budget = new ParseBudget()) {
|
|
|
37498
37498
|
return { decimal: decimal4 };
|
|
37499
37499
|
}
|
|
37500
37500
|
function numericIndex(index) {
|
|
37501
|
+
if (index.source !== void 0) {
|
|
37502
|
+
try {
|
|
37503
|
+
return numericIndex(literalIndex(index.source, 0));
|
|
37504
|
+
} catch {
|
|
37505
|
+
return void 0;
|
|
37506
|
+
}
|
|
37507
|
+
}
|
|
37501
37508
|
if (index.decimal.length > 10 || index.decimal.length === 10 && index.decimal > "2147483647") return void 0;
|
|
37502
37509
|
return Number(index.decimal);
|
|
37503
37510
|
}
|
|
37504
|
-
function
|
|
37511
|
+
function stringIndex(source2, budget, word) {
|
|
37512
|
+
budget.admit(2);
|
|
37513
|
+
return { decimal: source2, source: source2, ...word ? { word } : {} };
|
|
37514
|
+
}
|
|
37515
|
+
function arraySelector(source2, offset, budget = new ParseBudget(), word) {
|
|
37505
37516
|
budget.admit();
|
|
37506
|
-
return source2 === "@" || source2 === "*" ? { kind: "members", separator: source2 } : { kind: "element", index: literalIndex(source2, offset, budget) };
|
|
37517
|
+
return source2 === "@" || source2 === "*" ? { kind: "members", separator: source2 } : { kind: "element", index: word ? stringIndex(source2, budget, word) : literalIndex(source2, offset, budget) };
|
|
37507
37518
|
}
|
|
37508
37519
|
function setArraySelector(part, selector) {
|
|
37509
37520
|
selectors.set(part, selector);
|
|
@@ -37543,21 +37554,22 @@ function removePrefix(word, length, budget) {
|
|
|
37543
37554
|
if (length !== 0) throw new ShellSyntaxError("Invalid indexed-array assignment", word.offset);
|
|
37544
37555
|
return { offset: word.offset, parts };
|
|
37545
37556
|
}
|
|
37546
|
-
function elementAssignment(word, budget = new ParseBudget()) {
|
|
37557
|
+
function elementAssignment(word, budget = new ParseBudget(), parseWord, subscriptEnd) {
|
|
37547
37558
|
const source2 = word.spelling;
|
|
37548
37559
|
const first = word.parts[0];
|
|
37549
37560
|
if (source2 === void 0 || first?.kind !== "text" || first.quoted) return void 0;
|
|
37550
37561
|
const name2 = /^([a-zA-Z_][a-zA-Z_0-9]*)\[/u.exec(source2)?.[1];
|
|
37551
37562
|
if (!name2) return void 0;
|
|
37552
|
-
const end = source2.indexOf("]", name2.length + 1);
|
|
37563
|
+
const end = subscriptEnd ? subscriptEnd(source2, name2.length + 1) : source2.indexOf("]", name2.length + 1);
|
|
37553
37564
|
if (end < 0 || !/^(?:\+?=)/u.test(source2.slice(end + 1))) {
|
|
37554
37565
|
if (source2.includes("=")) throw new ShellSyntaxError("Invalid indexed-array assignment", word.offset);
|
|
37555
37566
|
return void 0;
|
|
37556
37567
|
}
|
|
37557
37568
|
budget.admit();
|
|
37558
|
-
const
|
|
37569
|
+
const keySource = source2.slice(name2.length + 1, end);
|
|
37570
|
+
const index = parseWord ? stringIndex(keySource, budget, parseWord(keySource)) : literalIndex(keySource, word.offset + name2.length + 1, budget);
|
|
37559
37571
|
const append = source2[end + 1] === "+";
|
|
37560
|
-
const value2 = removePrefix(word, name2.length + index.decimal.length + (append ? 4 : 3), budget);
|
|
37572
|
+
const value2 = parseWord ? parseWord(source2.slice(end + (append ? 3 : 2))) : removePrefix(word, name2.length + index.decimal.length + (append ? 4 : 3), budget);
|
|
37561
37573
|
return { kind: "element", name: name2, index, append, value: value2 };
|
|
37562
37574
|
}
|
|
37563
37575
|
function compoundHead(word, budget = new ParseBudget()) {
|
|
@@ -38316,7 +38328,7 @@ shell: command substitution: line ${line}: \`${sourceLine}'
|
|
|
38316
38328
|
if (!name2) this.error("Unsupported parameter expansion");
|
|
38317
38329
|
this.position += name2.length;
|
|
38318
38330
|
let prefixNames;
|
|
38319
|
-
if (listing) {
|
|
38331
|
+
if (listing && this.source[this.position] !== "[") {
|
|
38320
38332
|
const separator = this.source[this.position];
|
|
38321
38333
|
if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2) || separator !== "*" && separator !== "@" || this.source[this.position + 1] !== "}") this.error("Unsupported indirect parameter expansion");
|
|
38322
38334
|
prefixNames = separator;
|
|
@@ -38326,12 +38338,14 @@ shell: command substitution: line ${line}: \`${sourceLine}'
|
|
|
38326
38338
|
if (this.source[this.position] === "[") {
|
|
38327
38339
|
if (!/^[a-zA-Z_][a-zA-Z_0-9]*$/u.test(name2)) this.error("Unsupported indexed-array parameter");
|
|
38328
38340
|
const start = ++this.position;
|
|
38329
|
-
const
|
|
38330
|
-
|
|
38331
|
-
|
|
38341
|
+
const keyWord = this.word("]");
|
|
38342
|
+
const end = this.position;
|
|
38343
|
+
if (this.source[end] !== "]") this.error("Unterminated indexed-array subscript");
|
|
38344
|
+
selector = arraySelector(this.source.slice(start, end), start, this.budget, keyWord);
|
|
38332
38345
|
this.position = end + 1;
|
|
38333
38346
|
if (this.source[this.position] !== "}" && this.source[this.position] !== "@") this.error("Unsupported indexed-array operator");
|
|
38334
38347
|
}
|
|
38348
|
+
if (listing && selector?.kind === "element") this.error("Unsupported indirect parameter expansion");
|
|
38335
38349
|
let transform2;
|
|
38336
38350
|
if (this.source[this.position] === "@") {
|
|
38337
38351
|
const operation2 = this.source[this.position + 1];
|
|
@@ -38382,6 +38396,7 @@ shell: command substitution: line ${line}: \`${sourceLine}'
|
|
|
38382
38396
|
} else {
|
|
38383
38397
|
this.position++;
|
|
38384
38398
|
const part = { kind: "variable", name: name2, quoted: quoted2, line, ...prefixNames ? { prefixNames } : {}, ...transform2 ? { transform: transform2 } : {}, ...length ? { length } : {}, ...operator ? { operator, alternate } : {}, ...replacement ? { replacement } : {}, ...substring ? { substring } : {} };
|
|
38399
|
+
if (listing && selector) part.keys = true;
|
|
38385
38400
|
if (selector) setArraySelector(part, selector);
|
|
38386
38401
|
parts.push(part);
|
|
38387
38402
|
}
|
|
@@ -38756,7 +38771,12 @@ var Parser4 = class {
|
|
|
38756
38771
|
word = { offset: word.offset, parts: word.parts, spelling: this.lexer.source.slice(word.offset, end) };
|
|
38757
38772
|
setArrayAssignment(word, { kind: "compound", ...head, entries: entries2 });
|
|
38758
38773
|
} else {
|
|
38759
|
-
const assignment = words.every((previous) => getArrayAssignment(previous) || scalarAssignmentName(previous)) ? elementAssignment(word, this.budget)
|
|
38774
|
+
const assignment = words.every((previous) => getArrayAssignment(previous) || scalarAssignmentName(previous)) ? elementAssignment(word, this.budget, (source2) => parseArraySubscript(source2, this.budget, this.lexer.byteLocale, this.lexer.depth), (source2, start) => {
|
|
38775
|
+
const lexer = new Lexer2(this.budget, source2, this.lexer.depth, [], 0, this.lexer.byteLocale);
|
|
38776
|
+
lexer.position = start;
|
|
38777
|
+
lexer.word("]");
|
|
38778
|
+
return lexer.source[lexer.position] === "]" ? lexer.position : -1;
|
|
38779
|
+
}) : void 0;
|
|
38760
38780
|
if (assignment) setArrayAssignment(word, assignment);
|
|
38761
38781
|
}
|
|
38762
38782
|
words.push(word);
|
|
@@ -38798,6 +38818,10 @@ function parseShell(source2, depth = 0, options3 = {}) {
|
|
|
38798
38818
|
budget.admit();
|
|
38799
38819
|
return { ...script, ...warnings.length ? { warnings } : {} };
|
|
38800
38820
|
}
|
|
38821
|
+
function parseArraySubscript(source2, budget, byteLocale2 = false, depth = 0) {
|
|
38822
|
+
const lexer = new Lexer2(budget, source2, depth, [], 0, byteLocale2);
|
|
38823
|
+
return lexer.word("\0");
|
|
38824
|
+
}
|
|
38801
38825
|
function parseBraceWord(source2, opaque, budget) {
|
|
38802
38826
|
budget.admit(source2.length + 1);
|
|
38803
38827
|
const lexer = new Lexer2(budget, source2, 0);
|
|
@@ -40947,26 +40971,77 @@ async function valueToken(owner, value2, signal) {
|
|
|
40947
40971
|
}
|
|
40948
40972
|
}
|
|
40949
40973
|
var IndexedBinding = class _IndexedBinding {
|
|
40950
|
-
constructor(owner) {
|
|
40974
|
+
constructor(owner, associative = false) {
|
|
40951
40975
|
this.owner = owner;
|
|
40976
|
+
this.associative = associative;
|
|
40952
40977
|
}
|
|
40953
40978
|
owner;
|
|
40979
|
+
associative;
|
|
40954
40980
|
values = /* @__PURE__ */ new Map();
|
|
40981
|
+
keys = /* @__PURE__ */ new Map();
|
|
40982
|
+
keyByIndex = /* @__PURE__ */ new Map();
|
|
40955
40983
|
maximum = -1;
|
|
40956
40984
|
generation = 0;
|
|
40957
40985
|
version = 0;
|
|
40958
40986
|
references = 1;
|
|
40959
40987
|
assigned = false;
|
|
40960
|
-
static create(parent) {
|
|
40988
|
+
static create(parent, associative = false) {
|
|
40961
40989
|
const owner = ArrayOwner.create(parent.ledger, parent);
|
|
40962
40990
|
try {
|
|
40963
40991
|
owner.reserve({ wrappers: 1, metadata: 128, work: 7 });
|
|
40964
|
-
return new _IndexedBinding(owner);
|
|
40992
|
+
return new _IndexedBinding(owner, associative);
|
|
40965
40993
|
} catch (error) {
|
|
40966
40994
|
void owner.close();
|
|
40967
40995
|
throw error;
|
|
40968
40996
|
}
|
|
40969
40997
|
}
|
|
40998
|
+
async keyIdentity(value2, owner, signal) {
|
|
40999
|
+
const length = shellValueByteLength(value2);
|
|
41000
|
+
if (!length) throw new ArrayFailure("bad array subscript");
|
|
41001
|
+
const admission = owner.reserve({ payload: length * 5, metadata: 64 + length * 16, work: length + 2 });
|
|
41002
|
+
try {
|
|
41003
|
+
const bytes3 = shellValueBytes(value2);
|
|
41004
|
+
const parts = [];
|
|
41005
|
+
for (const byte of bytes3) {
|
|
41006
|
+
parts.push(byte.toString(16).padStart(2, "0"));
|
|
41007
|
+
await owner.ledger.checkpoint(signal);
|
|
41008
|
+
}
|
|
41009
|
+
return parts.join("");
|
|
41010
|
+
} finally {
|
|
41011
|
+
admission.release();
|
|
41012
|
+
}
|
|
41013
|
+
}
|
|
41014
|
+
async keyIndex(value2, owner, signal, create = false) {
|
|
41015
|
+
const identity2 = await this.keyIdentity(value2, owner, signal);
|
|
41016
|
+
const existing2 = this.keys.get(identity2);
|
|
41017
|
+
if (existing2 || !create) return existing2?.index;
|
|
41018
|
+
const index = this.maximum + 1;
|
|
41019
|
+
const admission = this.owner.reserve({ metadata: 128 + identity2.length * 2, work: 8 });
|
|
41020
|
+
let text3;
|
|
41021
|
+
try {
|
|
41022
|
+
text3 = await valueToken(this.owner, value2, signal);
|
|
41023
|
+
} catch (error) {
|
|
41024
|
+
admission.release();
|
|
41025
|
+
throw error;
|
|
41026
|
+
}
|
|
41027
|
+
const entry = { index, text: text3, admission };
|
|
41028
|
+
admission.cleanup = () => {
|
|
41029
|
+
if (this.keys.get(identity2) === entry) {
|
|
41030
|
+
this.keys.delete(identity2);
|
|
41031
|
+
this.keyByIndex.delete(index);
|
|
41032
|
+
}
|
|
41033
|
+
text3.release();
|
|
41034
|
+
};
|
|
41035
|
+
this.keys.set(identity2, entry);
|
|
41036
|
+
this.keyByIndex.set(index, identity2);
|
|
41037
|
+
this.maximum = index;
|
|
41038
|
+
return index;
|
|
41039
|
+
}
|
|
41040
|
+
remove(index) {
|
|
41041
|
+
this.values.get(index)?.slot.release();
|
|
41042
|
+
const identity2 = this.keyByIndex.get(index);
|
|
41043
|
+
if (identity2 !== void 0) this.keys.get(identity2)?.admission.release();
|
|
41044
|
+
}
|
|
40970
41045
|
get(index) {
|
|
40971
41046
|
return this.values.get(index)?.text.value;
|
|
40972
41047
|
}
|
|
@@ -40993,13 +41068,30 @@ var IndexedBinding = class _IndexedBinding {
|
|
|
40993
41068
|
previous?.slot.release();
|
|
40994
41069
|
}
|
|
40995
41070
|
async copy(signal) {
|
|
40996
|
-
const copy2 = _IndexedBinding.create(this.owner.parent);
|
|
41071
|
+
const copy2 = _IndexedBinding.create(this.owner.parent, this.associative);
|
|
40997
41072
|
copy2.assigned = this.assigned;
|
|
40998
41073
|
this.retain();
|
|
40999
41074
|
try {
|
|
41075
|
+
for (const [identity2, entry] of this.keys) {
|
|
41076
|
+
const admission = copy2.owner.reserve({ metadata: 128 + identity2.length * 2, work: identity2.length + 8 });
|
|
41077
|
+
copy2.owner.parent.adopt(entry.text.admission);
|
|
41078
|
+
const text3 = entry.text.retain();
|
|
41079
|
+
const cloned = { index: entry.index, text: text3, admission };
|
|
41080
|
+
admission.cleanup = () => {
|
|
41081
|
+
if (copy2.keys.get(identity2) === cloned) {
|
|
41082
|
+
copy2.keys.delete(identity2);
|
|
41083
|
+
copy2.keyByIndex.delete(entry.index);
|
|
41084
|
+
}
|
|
41085
|
+
text3.release();
|
|
41086
|
+
};
|
|
41087
|
+
copy2.keys.set(identity2, cloned);
|
|
41088
|
+
copy2.keyByIndex.set(entry.index, identity2);
|
|
41089
|
+
await copy2.owner.ledger.checkpoint(signal, identity2.length + 8);
|
|
41090
|
+
}
|
|
41000
41091
|
for (const [index, element] of this.values) {
|
|
41001
41092
|
copy2.owner.reserve({ work: 2 }).release();
|
|
41002
41093
|
const slot = copy2.owner.reserve({ slots: 1, metadata: 32, work: 5 });
|
|
41094
|
+
copy2.owner.parent.adopt(element.text.admission);
|
|
41003
41095
|
const text3 = element.text.retain();
|
|
41004
41096
|
const cloned = { text: text3, slot };
|
|
41005
41097
|
slot.cleanup = () => {
|
|
@@ -42053,6 +42145,7 @@ var shellBuiltinNames = /* @__PURE__ */ new Set([
|
|
|
42053
42145
|
"local",
|
|
42054
42146
|
"unset",
|
|
42055
42147
|
"read",
|
|
42148
|
+
"declare",
|
|
42056
42149
|
"mapfile",
|
|
42057
42150
|
"readarray",
|
|
42058
42151
|
"exit",
|
|
@@ -43394,7 +43487,7 @@ var Runtime = class _Runtime {
|
|
|
43394
43487
|
}
|
|
43395
43488
|
variable(state, name2) {
|
|
43396
43489
|
const binding = arrayStore(state)?.get(name2);
|
|
43397
|
-
return binding ? binding.get(0) : state.variables[name2];
|
|
43490
|
+
return binding ? binding.get(binding.associative ? binding.keys.get("30")?.index ?? -1 : 0) : state.variables[name2];
|
|
43398
43491
|
}
|
|
43399
43492
|
requireParameter(value2, name2, state, io, line) {
|
|
43400
43493
|
if (state.nounset && value2 === void 0) throw new NounsetFailure(`${name2}: unbound variable`, io.diagnosticLine ?? line);
|
|
@@ -43530,7 +43623,7 @@ var Runtime = class _Runtime {
|
|
|
43530
43623
|
if (key !== index && key > maximum) maximum = key;
|
|
43531
43624
|
await operation2.ledger.checkpoint(this.signal, 2);
|
|
43532
43625
|
}
|
|
43533
|
-
if (typeof index === "number") staged.
|
|
43626
|
+
if (typeof index === "number") staged.remove(index);
|
|
43534
43627
|
staged.maximum = maximum;
|
|
43535
43628
|
}
|
|
43536
43629
|
this.signal.throwIfAborted();
|
|
@@ -43578,11 +43671,12 @@ var Runtime = class _Runtime {
|
|
|
43578
43671
|
const current = store.get(name2);
|
|
43579
43672
|
if (!current) throw new ArrayFailure("stale binding");
|
|
43580
43673
|
staged = await current.copy(this.signal);
|
|
43581
|
-
const
|
|
43674
|
+
const index = staged.associative ? await staged.keyIndex("0", operation2, this.signal, true) : 0;
|
|
43675
|
+
const previous = current.values.get(index)?.text.rawValue ?? current.get(index) ?? "";
|
|
43582
43676
|
const value2 = !append ? expanded : typeof previous === "string" && typeof expanded === "string" ? await this.arrayJoin(operation2, [previous, expanded], "") : concatShellValues([previous, expanded], valueAllocation);
|
|
43583
43677
|
const token = await valueToken(staged.owner, value2, this.signal);
|
|
43584
43678
|
try {
|
|
43585
|
-
staged.insert(
|
|
43679
|
+
staged.insert(index, token);
|
|
43586
43680
|
} catch (error) {
|
|
43587
43681
|
token.release();
|
|
43588
43682
|
throw error;
|
|
@@ -43627,10 +43721,33 @@ var Runtime = class _Runtime {
|
|
|
43627
43721
|
await owner.ledger.checkpoint(this.signal);
|
|
43628
43722
|
return result2;
|
|
43629
43723
|
}
|
|
43724
|
+
async arrayIndex(binding, index, state, io, owner, create = false) {
|
|
43725
|
+
if (!binding?.associative) {
|
|
43726
|
+
const selected = index.source === void 0 ? index : literalIndex(index.source, 0, this.budget.parsing);
|
|
43727
|
+
const number5 = numericIndex(selected);
|
|
43728
|
+
if (number5 === void 0) throw new ArrayFailure("index outside 0..2147483647");
|
|
43729
|
+
return number5;
|
|
43730
|
+
}
|
|
43731
|
+
const word = index.word ?? parseArraySubscript(index.source ?? index.decimal, this.budget.parsing, byteLocale(state.variables), state.depth);
|
|
43732
|
+
const fields3 = await this.valueWord(word, state, io, false);
|
|
43733
|
+
const value2 = fields3.length === 1 ? fields3[0] : concatShellValues(fields3, io[valueScope]);
|
|
43734
|
+
if (shellValueByteLength(value2) === 0) {
|
|
43735
|
+
await this.diagnostic(io, "associative array: bad array subscript");
|
|
43736
|
+
if (create) throw completedExit(1);
|
|
43737
|
+
return void 0;
|
|
43738
|
+
}
|
|
43739
|
+
return binding.keyIndex(value2, owner, this.signal, create);
|
|
43740
|
+
}
|
|
43630
43741
|
async arrayAssignment(assignment, state, io) {
|
|
43631
43742
|
const name2 = assignment.name;
|
|
43632
43743
|
this.signal.throwIfAborted();
|
|
43633
|
-
if (state.readonlyVariables?.has(name2))
|
|
43744
|
+
if (state.readonlyVariables?.has(name2)) {
|
|
43745
|
+
if (arrayStore(state)?.get(name2)?.associative) {
|
|
43746
|
+
await this.diagnostic(io, `${name2}: readonly variable`);
|
|
43747
|
+
throw completedExit(1);
|
|
43748
|
+
}
|
|
43749
|
+
throw new ArrayFailure("readonly binding");
|
|
43750
|
+
}
|
|
43634
43751
|
if (controlNames.has(name2)) throw new ArrayFailure("control binding cannot be indexed");
|
|
43635
43752
|
if (state.exported.has(name2)) throw new ArrayFailure("exported binding cannot be indexed");
|
|
43636
43753
|
const store = requireArrays(state);
|
|
@@ -43640,11 +43757,12 @@ var Runtime = class _Runtime {
|
|
|
43640
43757
|
try {
|
|
43641
43758
|
const watch = await store.watch(name2, operation2, this.signal);
|
|
43642
43759
|
const current = store.get(name2);
|
|
43760
|
+
if (current?.associative && assignment.kind === "compound" && assignment.entries.length) throw new ArrayFailure("nonempty associative compound assignment is unsupported");
|
|
43643
43761
|
const initialMaximum = current?.maximum ?? (state.variables[name2] === void 0 ? -1 : 0);
|
|
43644
43762
|
let planned = assignment.append && assignment.kind === "compound" ? initialMaximum + 1 : 0;
|
|
43645
43763
|
if (assignment.kind === "element") {
|
|
43646
43764
|
operation2.reserve({ work: assignment.index.decimal.length + 1 }).release();
|
|
43647
|
-
if (numericIndex(assignment.index) === void 0) throw new ArrayFailure("index outside 0..2147483647");
|
|
43765
|
+
if (!current?.associative && numericIndex(literalIndex(assignment.index.source ?? assignment.index.decimal, 0, this.budget.parsing)) === void 0) throw new ArrayFailure("index outside 0..2147483647");
|
|
43648
43766
|
} else for (const entry of assignment.entries) {
|
|
43649
43767
|
operation2.reserve({ work: entry.value.parts.length + (entry.index?.decimal.length ?? 0) + 2 }).release();
|
|
43650
43768
|
if (entry.index) {
|
|
@@ -43670,7 +43788,7 @@ var Runtime = class _Runtime {
|
|
|
43670
43788
|
const tickets = operation2.reserve({ generation: true, version: true, epoch: true, work: 8 });
|
|
43671
43789
|
const prepared = await store.prepareName(name2, operation2, this.signal);
|
|
43672
43790
|
const preserve = assignment.kind === "element" || assignment.append;
|
|
43673
|
-
staged = preserve && current ? await current.copy(this.signal) : IndexedBinding.create(store.owner);
|
|
43791
|
+
staged = preserve && current ? await current.copy(this.signal) : IndexedBinding.create(store.owner, current?.associative);
|
|
43674
43792
|
if (preserve && !current && state.variables[name2] !== void 0) {
|
|
43675
43793
|
const token = await valueToken(staged.owner, stateMonitor(state)?.values.get(name2, state.variables[name2]) ?? state.variables[name2], this.signal);
|
|
43676
43794
|
try {
|
|
@@ -43695,7 +43813,7 @@ var Runtime = class _Runtime {
|
|
|
43695
43813
|
};
|
|
43696
43814
|
const join = async (values) => values.every((value2) => typeof value2 === "string") ? this.arrayJoin(operation2, values, "") : concatShellValues(values, io[valueScope]);
|
|
43697
43815
|
if (assignment.kind === "element") {
|
|
43698
|
-
const index =
|
|
43816
|
+
const index = await this.arrayIndex(staged, assignment.index, state, io, operation2, true);
|
|
43699
43817
|
const fields3 = await this.valueWord(assignment.value, state, io, false);
|
|
43700
43818
|
let value2 = await join(fields3);
|
|
43701
43819
|
if (assignment.append) value2 = await join([staged.values.get(index)?.text.rawValue ?? staged.get(index) ?? "", value2]);
|
|
@@ -46423,6 +46541,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46423
46541
|
let releaseHolding;
|
|
46424
46542
|
try {
|
|
46425
46543
|
const options3 = await mapfileOptions(context2, work, allocation);
|
|
46544
|
+
if (arrayStore(state)?.get(options3.name)?.associative) throw new MapfileUsageError(`${options3.name}: not an indexed array`, 1);
|
|
46426
46545
|
if (state.readonlyVariables?.has(options3.name)) throw new MapfileUsageError(`${options3.name}: readonly variable`, 1);
|
|
46427
46546
|
if (controlNames.has(options3.name) || state.exported.has(options3.name)) throw new ArrayFailure("control or exported binding cannot be indexed");
|
|
46428
46547
|
const store = requireArrays(state);
|
|
@@ -46593,9 +46712,16 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46593
46712
|
this.replacePositionals(state, this.positionalValues(state).slice(count2));
|
|
46594
46713
|
return 0;
|
|
46595
46714
|
}
|
|
46596
|
-
if (command7 === "export" || command7 === "local" || command7 === "readonly") {
|
|
46715
|
+
if (command7 === "export" || command7 === "local" || command7 === "readonly" || command7 === "declare") {
|
|
46716
|
+
const associativeDeclaration = command7 === "declare";
|
|
46597
46717
|
const declarationArgs = [...args];
|
|
46598
|
-
let indexedLocal =
|
|
46718
|
+
let indexedLocal = associativeDeclaration;
|
|
46719
|
+
if (associativeDeclaration) {
|
|
46720
|
+
if (declarationArgs.shift() !== "-A" || !declarationArgs.length) {
|
|
46721
|
+
await this.diagnostic(context2, "declare: only -A NAME is supported");
|
|
46722
|
+
return 2;
|
|
46723
|
+
}
|
|
46724
|
+
}
|
|
46599
46725
|
if (command7 === "local") {
|
|
46600
46726
|
const options3 = localDeclarationOptions(declarationArgs, this.signal);
|
|
46601
46727
|
if (options3.error !== void 0) {
|
|
@@ -46658,11 +46784,11 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46658
46784
|
status2 = 1;
|
|
46659
46785
|
continue;
|
|
46660
46786
|
}
|
|
46661
|
-
if (command7 === "local" && indexedLocal) {
|
|
46787
|
+
if ((command7 === "local" || associativeDeclaration) && indexedLocal) {
|
|
46662
46788
|
if (controlNames.has(name2)) throw new ArrayFailure("control binding cannot be indexed");
|
|
46663
46789
|
if (state.exported.has(name2)) throw new ArrayFailure("exported binding cannot be indexed");
|
|
46664
|
-
const existingLocal = locals
|
|
46665
|
-
const saved = existingLocal ? void 0 : assignments2.get(name2) ?? saveVariable(state, name2);
|
|
46790
|
+
const existingLocal = locals?.get(name2);
|
|
46791
|
+
const saved = !locals || existingLocal ? void 0 : assignments2.get(name2) ?? saveVariable(state, name2);
|
|
46666
46792
|
let operation2;
|
|
46667
46793
|
let holding;
|
|
46668
46794
|
let shadow;
|
|
@@ -46687,12 +46813,14 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46687
46813
|
const tickets = operation2.reserve({ generation: true, version: true, epoch: true, work: 8 });
|
|
46688
46814
|
const prepared = await store.prepareName(name2, operation2, this.signal);
|
|
46689
46815
|
const current = store.get(name2);
|
|
46690
|
-
|
|
46816
|
+
if (!saved && current && current.associative !== associativeDeclaration) throw new ArrayFailure("cannot convert array kind");
|
|
46817
|
+
shadow = !saved && current ? await current.copy(this.signal) : IndexedBinding.create(store.owner, associativeDeclaration);
|
|
46691
46818
|
const value2 = match[2] ?? (!saved && !current && Object.hasOwn(state.variables, name2) ? state.variables[name2] : void 0);
|
|
46692
46819
|
if (value2 !== void 0) {
|
|
46693
|
-
const
|
|
46820
|
+
const retained = associativeDeclaration && match[2] === void 0 ? stateMonitor(state).values.get(name2, value2) : value2;
|
|
46821
|
+
const token = await valueToken(shadow.owner, retained, this.signal);
|
|
46694
46822
|
try {
|
|
46695
|
-
shadow.insert(0, token);
|
|
46823
|
+
shadow.insert(associativeDeclaration ? await shadow.keyIndex("0", operation2, this.signal, true) : 0, token);
|
|
46696
46824
|
} catch (error) {
|
|
46697
46825
|
token.release();
|
|
46698
46826
|
throw error;
|
|
@@ -46840,7 +46968,8 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46840
46968
|
}
|
|
46841
46969
|
if (command7 === "unset") {
|
|
46842
46970
|
let status2 = 0;
|
|
46843
|
-
for (
|
|
46971
|
+
for (let argument2 = 0; argument2 < args.length; argument2++) {
|
|
46972
|
+
const name2 = args[argument2];
|
|
46844
46973
|
const selected = /^([a-zA-Z_][a-zA-Z_0-9]*)\[(.*)\]$/su.exec(name2);
|
|
46845
46974
|
if (selected) {
|
|
46846
46975
|
const base = selected[1];
|
|
@@ -46850,7 +46979,12 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
46850
46979
|
status2 = 1;
|
|
46851
46980
|
continue;
|
|
46852
46981
|
}
|
|
46853
|
-
|
|
46982
|
+
const binding = arrayStore(state)?.get(base);
|
|
46983
|
+
if (binding?.associative) {
|
|
46984
|
+
const original = getCommandArguments(context2).values[argument2];
|
|
46985
|
+
const index = typeof original === "string" ? await this.arrayIndex(binding, { decimal: selector, source: selector }, state, context2, binding.owner) : await binding.keyIndex(shellValueFromBytes(shellValueBytes(original, context2[valueScope]).subarray(base.length + 1, shellValueByteLength(original) - 1), context2[valueScope]), binding.owner, this.signal);
|
|
46986
|
+
if (index !== void 0) await this.unsetIndexed(state, base, index);
|
|
46987
|
+
} else if (selector === "@" || selector === "*") await this.unsetIndexed(state, base, "members");
|
|
46854
46988
|
else {
|
|
46855
46989
|
let index;
|
|
46856
46990
|
try {
|
|
@@ -47084,7 +47218,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
47084
47218
|
if (part.kind === "variable" && part.transform) {
|
|
47085
47219
|
const selector2 = getArraySelector(part);
|
|
47086
47220
|
if (selector2?.kind === "members" || part.name === "@" || part.name === "*") {
|
|
47087
|
-
const members = selector2 ? await this.arrayMembers(part.name, state, io) : this.positionalValues(state);
|
|
47221
|
+
const members = selector2 ? await this.arrayMembers(part.name, state, io, part.keys) : this.positionalValues(state);
|
|
47088
47222
|
const ifs = state.variables.IFS ?? " ";
|
|
47089
47223
|
const separator = ifs.length ? String.fromCodePoint(ifs.codePointAt(0)) : "";
|
|
47090
47224
|
const fragments = [];
|
|
@@ -47124,7 +47258,18 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
47124
47258
|
const binding = part.kind === "variable" ? arrayStore(state)?.get(part.name) : void 0;
|
|
47125
47259
|
const holding = binding ? requireArrays(state).owner.hold() : void 0;
|
|
47126
47260
|
const selector = getArraySelector(part);
|
|
47127
|
-
|
|
47261
|
+
if (selector?.kind === "element" && binding?.associative) {
|
|
47262
|
+
try {
|
|
47263
|
+
const index2 = await this.arrayIndex(binding, selector.index, state, io, binding.owner);
|
|
47264
|
+
const token2 = index2 === void 0 ? void 0 : binding.values.get(index2)?.text;
|
|
47265
|
+
this.requireParameter(token2?.value, part.kind === "variable" ? part.name : "", state, io);
|
|
47266
|
+
if (part.kind === "variable" && part.length) return this.parameterLength(token2?.value ?? "");
|
|
47267
|
+
return token2?.rawValue ? shellValueFromBytes(shellValueBytes(token2.rawValue, io[valueScope]), io[valueScope]) : token2?.value ?? "";
|
|
47268
|
+
} finally {
|
|
47269
|
+
holding?.release();
|
|
47270
|
+
}
|
|
47271
|
+
}
|
|
47272
|
+
const index = selector?.kind === "element" ? numericIndex(selector.index) : binding?.associative ? binding.keys.get("30")?.index : 0;
|
|
47128
47273
|
const token = index === void 0 || selector?.kind === "members" ? void 0 : binding?.values.get(index)?.text;
|
|
47129
47274
|
token?.retain();
|
|
47130
47275
|
try {
|
|
@@ -47246,7 +47391,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
47246
47391
|
return part.length ? this.parameterLength(value3 ?? "") : value3 ?? "";
|
|
47247
47392
|
}
|
|
47248
47393
|
if (part.length) return String(binding?.values.size ?? (state.variables[part.name] === void 0 ? 0 : 1));
|
|
47249
|
-
const values = await this.arrayMembers(part.name, state, io);
|
|
47394
|
+
const values = await this.arrayMembers(part.name, state, io, part.keys);
|
|
47250
47395
|
const separator = Array.from(state.variables.IFS ?? " ")[0] ?? "";
|
|
47251
47396
|
if (values.every((value3) => typeof value3 === "string")) return this.arrayJoin(store.owner, values, separator);
|
|
47252
47397
|
io[valueScope]?.reserve(values.length * 32 + 64, 0);
|
|
@@ -47659,7 +47804,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
47659
47804
|
emptyNameGroups.add(quoteGroup);
|
|
47660
47805
|
}
|
|
47661
47806
|
} else if (part.kind === "variable" && split4 && (selector?.kind === "members" && !part.length && (!part.quoted || selector.separator === "@") || part.transform && part.name === "@")) {
|
|
47662
|
-
const members = selector?.kind === "members" ? await this.arrayMembers(part.name, state, io) : this.positionalValues(state);
|
|
47807
|
+
const members = selector?.kind === "members" ? await this.arrayMembers(part.name, state, io, part.keys) : this.positionalValues(state);
|
|
47663
47808
|
for (let position = 0; position < members.length; position++) {
|
|
47664
47809
|
if (position > 0) addField();
|
|
47665
47810
|
const original = members[position];
|
|
@@ -47801,7 +47946,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
47801
47946
|
for (const value2 of values) if (typeof value2 !== "string") allocation.hold(value2);
|
|
47802
47947
|
return createCommandArguments(values, allocation);
|
|
47803
47948
|
}
|
|
47804
|
-
async arrayMembers(name2, state, io) {
|
|
47949
|
+
async arrayMembers(name2, state, io, keys = false) {
|
|
47805
47950
|
const store = requireArrays(state);
|
|
47806
47951
|
const holding = store.owner.hold();
|
|
47807
47952
|
try {
|
|
@@ -47812,7 +47957,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
47812
47957
|
if (value2 === void 0) return [];
|
|
47813
47958
|
store.owner.reserve({ metadata: 32, allocatedSlots: 1, work: 3 });
|
|
47814
47959
|
await textToken(store.owner, value2, this.signal);
|
|
47815
|
-
return [value2];
|
|
47960
|
+
return [keys ? "0" : value2];
|
|
47816
47961
|
}
|
|
47817
47962
|
binding.retain();
|
|
47818
47963
|
try {
|
|
@@ -47820,7 +47965,7 @@ ${prefix3} line ${offset + line}: \`${source2.split("\n")[line - 1] ?? ""}'
|
|
|
47820
47965
|
const values = [];
|
|
47821
47966
|
for (const index of indices) {
|
|
47822
47967
|
store.owner.reserve({ metadata: 32, allocatedSlots: 1, work: 4 });
|
|
47823
|
-
const token = binding.values.get(index).text;
|
|
47968
|
+
const token = keys ? binding.associative ? binding.keys.get(binding.keyByIndex.get(index)).text : await textToken(store.owner, String(index), this.signal) : binding.values.get(index).text;
|
|
47824
47969
|
const value2 = token.rawValue === void 0 ? token.value : shellValueFromBytes(shellValueBytes(token.rawValue, io[valueScope]), io[valueScope]);
|
|
47825
47970
|
if (typeof value2 === "string") await textToken(store.owner, value2, this.signal);
|
|
47826
47971
|
values.push(value2);
|