diff --git a/crates/bashkit/src/interpreter/mod.rs b/crates/bashkit/src/interpreter/mod.rs index ddfc2add..2bfa96fe 100644 --- a/crates/bashkit/src/interpreter/mod.rs +++ b/crates/bashkit/src/interpreter/mod.rs @@ -2431,6 +2431,16 @@ impl Interpreter { positional: args.clone(), }); + // Set FUNCNAME array from call stack (index 0 = current, 1 = caller, ...) + let funcname_arr: HashMap = self + .call_stack + .iter() + .rev() + .enumerate() + .map(|(i, f)| (i, f.name.clone())) + .collect(); + let prev_funcname = self.arrays.insert("FUNCNAME".to_string(), funcname_arr); + // Execute function body let mut result = self.execute_command(&func_def.body).await?; @@ -2438,6 +2448,13 @@ impl Interpreter { self.call_stack.pop(); self.counters.pop_function(); + // Restore previous FUNCNAME (or set from remaining stack) + if self.call_stack.is_empty() { + self.arrays.remove("FUNCNAME"); + } else if let Some(prev) = prev_funcname { + self.arrays.insert("FUNCNAME".to_string(), prev); + } + // Handle return - convert Return control flow to exit code if let ControlFlow::Return(code) = result.control_flow { result.exit_code = code; diff --git a/crates/bashkit/tests/spec_cases/bash/functions.test.sh b/crates/bashkit/tests/spec_cases/bash/functions.test.sh index bc15bbfc..1c65bb1d 100644 --- a/crates/bashkit/tests/spec_cases/bash/functions.test.sh +++ b/crates/bashkit/tests/spec_cases/bash/functions.test.sh @@ -159,3 +159,47 @@ echo "after outer: $x" in outer: local_val after outer: global ### end + +### func_funcname_basic +# FUNCNAME[0] is current function name +myfunc() { echo "${FUNCNAME[0]}"; } +myfunc +### expect +myfunc +### end + +### func_funcname_call_stack +# FUNCNAME array reflects call stack +inner() { echo "${FUNCNAME[@]}"; } +outer() { inner; } +outer +### expect +inner outer +### end + +### func_funcname_depth +# FUNCNAME array length matches nesting depth +a() { echo "${#FUNCNAME[@]}"; } +b() { a; } +c() { b; } +c +### expect +3 +### end + +### func_funcname_empty_outside +# FUNCNAME is empty outside functions +echo "${#FUNCNAME[@]}" +### expect +0 +### end + +### func_funcname_restored +# FUNCNAME is cleared after function returns +f() { echo "in: ${FUNCNAME[0]}"; } +f +echo "out: ${#FUNCNAME[@]}" +### expect +in: f +out: 0 +### end diff --git a/specs/009-implementation-status.md b/specs/009-implementation-status.md index 8a76c1c7..9164a1ee 100644 --- a/specs/009-implementation-status.md +++ b/specs/009-implementation-status.md @@ -103,16 +103,16 @@ Bashkit implements IEEE 1003.1-2024 Shell Command Language. See ## Spec Test Coverage -**Total spec test cases:** 1199 (1194 pass, 5 skip) +**Total spec test cases:** 1204 (1199 pass, 5 skip) | Category | Cases | In CI | Pass | Skip | Notes | |----------|-------|-------|------|------|-------| -| Bash (core) | 838 | Yes | 833 | 5 | `bash_spec_tests` in CI | +| Bash (core) | 843 | Yes | 838 | 5 | `bash_spec_tests` in CI | | AWK | 96 | Yes | 96 | 0 | loops, arrays, -v, ternary, field assign, getline, %.6g | | Grep | 76 | Yes | 76 | 0 | -z, -r, -a, -b, -H, -h, -f, -P, --include, --exclude, binary detect | | Sed | 75 | Yes | 75 | 0 | hold space, change, regex ranges, -E | | JQ | 114 | Yes | 114 | 0 | reduce, walk, regex funcs, --arg/--argjson, combined flags, input/inputs, env | -| **Total** | **1199** | **Yes** | **1194** | **5** | | +| **Total** | **1204** | **Yes** | **1199** | **5** | | ### Bash Spec Tests Breakdown @@ -136,7 +136,7 @@ Bashkit implements IEEE 1003.1-2024 Shell Command Language. See | errexit.test.sh | 8 | set -e tests | | fileops.test.sh | 21 | | | find.test.sh | 10 | file search | -| functions.test.sh | 17 | local dynamic scoping, nested writes | +| functions.test.sh | 22 | local dynamic scoping, nested writes, FUNCNAME call stack | | getopts.test.sh | 9 | POSIX option parsing, combined flags, silent mode | | globs.test.sh | 12 | for-loop glob expansion, recursive `**` | | headtail.test.sh | 14 | | diff --git a/supply-chain/config.toml b/supply-chain/config.toml index 3e450dc5..010ed373 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -962,6 +962,10 @@ criteria = "safe-to-deploy" version = "0.8.9" criteria = "safe-to-deploy" +[[exemptions.regex-syntax]] +version = "0.8.10" +criteria = "safe-to-deploy" + [[exemptions.reqwest]] version = "0.13.2" criteria = "safe-to-deploy"