Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 51 additions & 6 deletions crates/bashkit/src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4421,11 +4421,9 @@ impl Interpreter {
if is_internal_variable(var_name) {
continue;
}
// Handle compound array assignment: local -a arr=(1 2 3)
if (flags.array || flags.assoc)
&& value.starts_with('(')
&& value.ends_with(')')
{
// Handle compound array assignment: local arr=(1 2 3) or local -a/-A arr=(...)
let is_compound = value.starts_with('(') && value.ends_with(')');
if is_compound {
let inner = &value[1..value.len() - 1];
if flags.assoc {
let arr = self.assoc_arrays.entry(var_name.to_string()).or_default();
Expand Down Expand Up @@ -4534,7 +4532,54 @@ impl Interpreter {
if is_internal_variable(var_name) {
continue;
}
if flags.nameref {
let is_compound = value.starts_with('(') && value.ends_with(')');
if is_compound {
let inner = &value[1..value.len() - 1];
if flags.assoc {
let arr = self.assoc_arrays.entry(var_name.to_string()).or_default();
arr.clear();
let mut rest = inner.trim();
while let Some(bracket_start) = rest.find('[') {
if let Some(bracket_end) = rest[bracket_start..].find(']') {
let key = &rest[bracket_start + 1..bracket_start + bracket_end];
let after = &rest[bracket_start + bracket_end + 1..];
if let Some(eq_rest) = after.strip_prefix('=') {
let eq_rest = eq_rest.trim_start();
let (val, remainder) =
if let Some(stripped) = eq_rest.strip_prefix('"') {
if let Some(end_q) = stripped.find('"') {
(
&stripped[..end_q],
stripped[end_q + 1..].trim_start(),
)
} else {
(stripped.trim_end_matches('"'), "")
}
} else {
match eq_rest.find(char::is_whitespace) {
Some(sp) => {
(&eq_rest[..sp], eq_rest[sp..].trim_start())
}
None => (eq_rest, ""),
}
};
arr.insert(key.to_string(), val.to_string());
rest = remainder;
} else {
break;
}
} else {
break;
}
}
} else {
let arr = self.arrays.entry(var_name.to_string()).or_default();
arr.clear();
for (idx, val) in inner.split_whitespace().enumerate() {
arr.insert(idx, val.trim_matches('"').to_string());
}
}
} else if flags.nameref {
self.variables
.insert(format!("_NAMEREF_{}", var_name), value.to_string());
} else {
Expand Down
23 changes: 23 additions & 0 deletions crates/bashkit/tests/spec_cases/bash/arrays.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,26 @@ echo "${arr[@]}"
### expect
10 20 30 40 99
### end

### local_array_compound_assignment
# local arr=(a b c) should initialize the array
myfunc() {
local arr=(one two three)
echo "count: ${#arr[@]}"
echo "values: ${arr[*]}"
}
myfunc
### expect
count: 3
values: one two three
### end

### local_array_compound_in_global
# local arr=(...) at global scope should also work
local arr=(x y z)
echo "${#arr[@]}"
echo "${arr[1]}"
### expect
3
y
### end
2 changes: 1 addition & 1 deletion crates/bashkit/tests/spec_cases/bash/nameref.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jam

### nameref_local_dynamic_scope
# pass local array by reference via dynamic scoping
### skip: TODO parser does not handle local arr=(...) syntax (indexed array after command name)
### bash_diff: nameref + local array by reference
show_value() {
local -n array_name=$1
local idx=$2
Expand Down
4 changes: 1 addition & 3 deletions crates/bashkit/tests/spec_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! - `### skip: reason` - Skip test entirely (not run in any test)
//! - `### bash_diff: reason` - Known difference from real bash (runs in spec tests, excluded from comparison)
//!
//! ## Skipped Tests (33 total)
//! ## Skipped Tests (32 total)
//!
//! Actual `### skip:` markers across spec test files:
//!
Expand All @@ -24,8 +24,6 @@
//! - [ ] od output format varies
//! - [ ] hexdump -C output format varies
//!
//! ### nameref.test.sh (1 skipped)
//! - [ ] parser does not handle local arr=(...) syntax
//!
//! ### parse-errors.test.sh (6 skipped)
//! - [ ] parser does not reject unexpected 'do' keyword
Expand Down
Loading