Skip to content

Commit 7962756

Browse files
authored
feat(interpreter): nameref resolution for associative array operations (#821)
Resolve namerefs in ${!ref[@]}, ${#ref[@]}, and ref+=() array operations.\n\nCloses #801
1 parent e7c39cd commit 7962756

File tree

2 files changed

+107
-5
lines changed

2 files changed

+107
-5
lines changed

crates/bashkit/src/interpreter/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3168,7 +3168,9 @@ impl Interpreter {
31683168
expanded_values.push((value, has_command_subst));
31693169
}
31703170

3171-
let arr = self.arrays.entry(assignment.name.clone()).or_default();
3171+
// Resolve nameref for array assignments
3172+
let arr_name = self.resolve_nameref(&assignment.name).to_string();
3173+
let arr = self.arrays.entry(arr_name).or_default();
31723174
let mut idx = if assignment.append {
31733175
arr.keys().max().map(|k| k + 1).unwrap_or(0)
31743176
} else {
@@ -5921,9 +5923,10 @@ impl Interpreter {
59215923
result.push_str(&names.join(" "));
59225924
}
59235925
WordPart::ArrayLength(name) => {
5924-
if let Some(arr) = self.assoc_arrays.get(name) {
5926+
let resolved = self.resolve_nameref(name);
5927+
if let Some(arr) = self.assoc_arrays.get(resolved) {
59255928
result.push_str(&arr.len().to_string());
5926-
} else if let Some(arr) = self.arrays.get(name) {
5929+
} else if let Some(arr) = self.arrays.get(resolved) {
59275930
result.push_str(&arr.len().to_string());
59285931
} else {
59295932
result.push('0');
@@ -6028,12 +6031,13 @@ impl Interpreter {
60286031
}
60296032
// "${!arr[@]}" - array keys/indices as separate fields
60306033
if let WordPart::ArrayIndices(name) = &word.parts[0] {
6031-
if let Some(arr) = self.assoc_arrays.get(name) {
6034+
let resolved = self.resolve_nameref(name);
6035+
if let Some(arr) = self.assoc_arrays.get(resolved) {
60326036
let mut keys: Vec<_> = arr.keys().cloned().collect();
60336037
keys.sort();
60346038
return Ok(keys);
60356039
}
6036-
if let Some(arr) = self.arrays.get(name) {
6040+
if let Some(arr) = self.arrays.get(resolved) {
60376041
let mut indices: Vec<_> = arr.keys().collect();
60386042
indices.sort();
60396043
return Ok(indices.iter().map(|i| i.to_string()).collect());
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
### nameref_assign_key_to_assoc
2+
# Nameref assign key to caller's associative array
3+
add_entry() {
4+
local -n ref="$1"
5+
ref["hello"]="world"
6+
ref["foo"]="bar"
7+
}
8+
declare -A mymap
9+
add_entry mymap
10+
echo "${mymap[hello]}"
11+
echo "${mymap[foo]}"
12+
### expect
13+
world
14+
bar
15+
### end
16+
17+
### nameref_iterate_assoc_keys
18+
# Nameref iterate keys of associative array
19+
show_keys() {
20+
local -n ref="$1"
21+
for key in "${!ref[@]}"; do
22+
echo "${key}=${ref[$key]}"
23+
done | sort
24+
}
25+
declare -A colors=([red]=ff0000 [green]=00ff00 [blue]=0000ff)
26+
show_keys colors
27+
### expect
28+
blue=0000ff
29+
green=00ff00
30+
red=ff0000
31+
### end
32+
33+
### nameref_append_indexed_array
34+
# Nameref append to caller's indexed array
35+
collect() {
36+
local -n arr_ref="$1"
37+
arr_ref+=("alpha")
38+
arr_ref+=("beta")
39+
arr_ref+=("gamma")
40+
}
41+
items=()
42+
collect items
43+
echo "${#items[@]}"
44+
echo "${items[0]} ${items[1]} ${items[2]}"
45+
### expect
46+
3
47+
alpha beta gamma
48+
### end
49+
50+
### nameref_two_refs_same_function
51+
# Two namerefs in same function (harness pattern)
52+
collect_from() {
53+
local dir="$1"
54+
local -n map_ref="$2"
55+
local -n order_ref="$3"
56+
map_ref["key-a"]="${dir}/file-a"
57+
map_ref["key-b"]="${dir}/file-b"
58+
order_ref+=("key-a")
59+
order_ref+=("key-b")
60+
}
61+
declare -A my_map
62+
my_order=()
63+
collect_from "/src" my_map my_order
64+
echo "${my_map[key-a]}"
65+
echo "${my_map[key-b]}"
66+
echo "${my_order[0]} ${my_order[1]}"
67+
### expect
68+
/src/file-a
69+
/src/file-b
70+
key-a key-b
71+
### end
72+
73+
### nameref_assoc_length
74+
# Nameref with associative array length
75+
count_entries() {
76+
local -n ref="$1"
77+
echo "${#ref[@]}"
78+
}
79+
declare -A data=([x]=1 [y]=2 [z]=3)
80+
count_entries data
81+
### expect
82+
3
83+
### end
84+
85+
### nameref_overwrite_assoc_key
86+
# Nameref overwrite existing key in associative array
87+
update() {
88+
local -n ref="$1"
89+
ref["name"]="updated"
90+
}
91+
declare -A record=([name]=original [age]=30)
92+
update record
93+
echo "${record[name]}"
94+
echo "${record[age]}"
95+
### expect
96+
updated
97+
30
98+
### end

0 commit comments

Comments
 (0)