Expand description
Shell executor state for zshrs.
Not a port of Src/exec.c. zshrs replaces zsh’s tree-walking
interpreter (execlist / execpline / execcmd) with a fusevm
bytecode VM; the actual VM bridge lives in src/fusevm_bridge.rs.
This file holds:
ShellExecutor— the runtime state struct that the VM and every ported builtin/utility threads through- VM-adjacent helpers that read/write that state
- drift extension scaffolding still being moved out
Path-wise this file lives at the crate root (src/exec.rs) rather
than in src/ported/ because nothing here corresponds 1:1 to a
Src/*.c source file. crate::ported::exec is kept as a
re-export alias so existing call-sites continue to compile.
Modules§
- zsh_
version ZSH_VERSION/ZSH_PATCHLEVEL/ZSH_VERSION_DATEconsts generated bybuild.rsfromsrc/zsh/Config/version.mk. Usezsh_version::ZSH_VERSIONetc. at call sites so version bumps pick up automatically.
Structs§
- Autoload
Flags - Flags for autoloaded functions (autoload builtin – Src/builtin.c bin_autoload).
- Comp
Group - Completion group bundling multiple match candidates.
- Comp
Init BgResult - Result from background compinit thread.
Outcome of background
compinitautoload. zshrs-original — Src/Modules/complete.c blocks oncompinitinline. The Rust port runs it on the worker pool. - Comp
Match - One completion-match candidate surfaced by the
completebuiltin. - Comp
Spec completebuiltin per-command spec (bash-style).- Comp
State - Per-completion state tracked across
completebuiltin invocations. - Fork
Flags - Flags for zfork()
- Intercept
- An intercept registration. One AOP intercept registered against a function pattern. zshrs-original — no C counterpart.
- Shell
Executor - Top-level shell executor state.
Port of the file-static globals +
Estatechain Src/exec.c uses —execlist()(line 1349) drives every list, withexecpline()(line 1668),execpline2()(line 1991),execsimple()(line 1290), and the per-WC_*execfuncs[]table (line 268) feeding off it. The Rust port collapses everything into oneShellExecutorso we don’t need thread-local globals. - Subshell
Flags - Flags for entersubsh()
- Subshell
Snapshot - Snapshot of subshell-isolated state. Captured at
(entry, restored at)exit. zsh subshell semantics: assignments inside(…)don’t leak to the outer scope — and that includesexport. zsh forks a child for the subshell so the child’s env::set_var dies with the child; without a fork (zshrs runs subshells in-process for perf), we snapshot+restore the OS env table around the subshell. Otherwise(export y=v)would leakyto the parent shell, breaking every script that uses a subshell to scope an env override. Snapshot of mutable executor state across a subshell boundary. Port of theentersubsh()save/restore Src/exec.c does at line 1084 — captures everything that must be replaced when a(...)group fires. - Zshrs
Host ShellHostimplementation that delegates to the currentShellExecutorvia thewith_executorthread-local.- zstyle_
entry - One
zstyleentry — Rust extension that flattens what C splits acrossstruct style(zutil.c:91, holds the style name) andstruct stypat(zutil.c:97, holds pat + vals). The canonical split structs are at lines 1596 / 1608 above; this flat shape is kept while the C-style HashTable port lands.
Enums§
- Advice
Kind - AOP advice type — before, after, or around.
Aspect-oriented advice classification.
zshrs-original — no C zsh counterpart. C zsh’s closest
analog is the function-wrapper hook in Src/module.c
(
addwrapper(), used byzsh/zprof), but per-function before/after/around AOP intercepts are unique to zshrs. - Builtin
Type - Builtin command type
Builtin classification.
Mirrors the
BINF_*flag set Src/builtin.c uses to classify special vs regular builtins. - Fork
Result - Result of fork operation
fork()outcome (parent / child / error). Mirrors the integer return ofzfork()from Src/exec.c:349. - Loop
Signal - Cross-VM loop-control signal. When
break/continueis hit inside a body that runs on a sub-VM (e.g. select’s body), the inline patches mechanism can’t reach the outer loop — set this flag and the outer-loop builtin drains it after each iteration. Loop control signal from a command body. Mirrors theLF_*set Src/loop.c uses to threadbreak/continue/returnflags up through the executor. - Redir
Mode - Redirection mode
File-redirection mode (
>/>>/</ etc.). Mirrors theREDIR_*enum from Src/zsh.h.
Constants§
- BUILTIN_
APPEND_ ARRAY arr+=(d e f)— append N elements to an existing indexed array. Compile emits N element pushes + name push, thenCallBuiltin(295, N+1). Handler drains args (last popped = name), extendsexecutor.arrays[name](creates the entry if missing). Mirrors zsh’s+=semantics for indexed arrays.- BUILTIN_
APPEND_ ASSOC m[k]+=value— append onto an existing assoc-array value (string concat). If the key doesn’t exist, behaves like SET_ASSOC. Stack: [name, key, value].- BUILTIN_
APPEND_ SCALAR_ OR_ PUSH name+=val(no parens) — runtime-dispatched append. If name is an indexed array → push val as element. If name is an assoc array → error (zsh requires(k v)form). Else → scalar concat (existing SET_VAR behavior).- BUILTIN_
ARITH_ EVAL $((expr))arithmetic substitution. Pops [expr_string], evaluates via the executor’s MathEval (integer-aware), returns result as Value::Str. Bypasses ArithCompiler’s float-only Op::Div path so$((10/3))returns “3” not “3.333…”.- BUILTIN_
ARRAY_ ALL ${arr[@]}— splice all elements as a Value::Array. Pops one arg: name. The Array gets flattened by Op::Exec/ExecBg/CallFunction into argv.- BUILTIN_
ARRAY_ FLATTEN - Flatten one level of Value::Array nesting. Pops N values; for each, if it’s
a Value::Array, its elements are appended directly; otherwise the value is
appended as-is. Pushes a single Value::Array of the flattened result. Used
by the for-loop word-list compile path: when a word like
${arr[@]}produces a nested Array, this letsfor i in ${arr[@]}iterate over the inner elements rather than the outer single-element array. - BUILTIN_
ARRAY_ INDEX ${arr[idx]}— single-element array index. Pops two args: stack: [name, idx_str] Returns the indexed element as Value::str. Indexing semantics: zsh is 1-based by default; bash is 0-based. We follow zsh. Special idx values:@and*return the whole array as Value::Array (which fuses correctly via the Op::Exec splice for argv splice).- BUILTIN_
ARRAY_ JOIN - Builtin ID for
Array → Stringjoining. Pops one value: if it’s an Array, joins its string-coerced elements with a single space; otherwise passes through. Used afterOp::Globto convert the pattern’s matched paths into the single argv-token form the bytecode word model expects (no per-word splitting yet — that’s a future phase). - BUILTIN_
ARRAY_ JOIN_ STAR - BUILTIN_
ARRAY_ LENGTH ${#arr[@]}and${#arr}(when arr is an array name) — array length. Pops one arg: name. Returns Value::str of len.- BUILTIN_
BEGIN_ INLINE_ ENV - BUILTIN_
BRACE_ EXPAND - Brace expansion:
{a,b,c}→ 3 values,{1..5}→ 5 values,{01..05}→ zero-padded numerics,{a..e}→ letter range. Pops one string, returns Value::Array of expansions (empty array → original string preserved). - BUILTIN_
BRIDGE_ BRACE_ ARRAY - Bridge into subst_port::substitute_brace_array for nested forms
that need to PRESERVE array shape across the expand_string
boundary. Stack:
[content_string]. Returns Value::Array of the per-element words. Used by the compile path for${(@)<nested>...##pat}shapes — the standard substitute_brace returns String which collapses array→scalar; this builtin preserves the multi-word output via paramsubst’s third return (nodesvec, the C source’savalthread). - BUILTIN_
CMD_ POP - Pop the top of the command-context stack. Direct port of zsh’s
cmdpop(void)(Src/prompt.c:1631). - BUILTIN_
CMD_ PUSH - Push a
CmdStatetoken onto the command-context stack. Direct port of zsh’scmdpush(int cmdtok)(Src/prompt.c:1623). The stack is consulted by%_in PS4/prompt expansion to produce the cumulative control-flow-context labels (if,then,cmdand,cmdor,cmdsubst, …) thatzsh -xxtrace shows in the trace prefix. Compile_zsh emits push/pop pairs around each compound command (if/while/[[…]]/((…))/$(…) etc.). Token is aCmdState as u8. - BUILTIN_
CMD_ SUBST_ TEXT $(cmd)command substitution. Pops [cmd_string], runs throughrun_command_substitutionwhich compiles via parse_init+parse + ZshCompiler and captures stdout via an in-process pipe. Returns trimmed output as Value::Str. Avoids the sub-chunk word-emit quoting bug in the raw Op::CmdSubst path.- BUILTIN_
CONCAT_ DISTRIBUTE - Word-segment concat that does cartesian-product distribution over
arrays. Stack: [lhs, rhs]. Used for RC_EXPAND_PARAM
${arr}and explicit-distribute forms (${^arr},${(@)…}). - BUILTIN_
CONCAT_ DISTRIBUTE_ FORCED - Forced-distribute concat — like
BUILTIN_CONCAT_DISTRIBUTEbut always distributes cartesian regardless of thercexpandparamoption. Emitted by the segments fast-path when anis_distribute_expansionsegment is present (${^arr},${(@)arr},${(s.…)arr}etc.) per zsh: the source-level distribution flag overrides the option default. Direct port of Src/subst.c:1875case Hat: nojoin = 1and thercexpandparamtest bypass for the explicit-distribute flags. - BUILTIN_
CONCAT_ SPLICE - Word-segment concat with FIRST/LAST sticking. Stack: [lhs, rhs].
Used for default unquoted splice forms (
${arr[@]},$@,$*) where prefix sticks to first element only and suffix to last only. - BUILTIN_
END_ INLINE_ ENV - BUILTIN_
ERREXIT_ CHECK - BUILTIN_
EXPAND_ TEXT - Text-based word expansion. Pops [preserved_text]: the word with
quotes preserved (Dnull→
", Snull→', Bnull→\), runsexpand_string(variable + cmd-sub + arith) thenxpandbracesthenexpand_glob. Returns Value::str (single match) or Value::Array (multi-match brace/glob). - BUILTIN_
FILE_ MODIFIED_ SINCE_ ACCESS [[ -N path ]]— file modified since last accessed (atime <= mtime).- BUILTIN_
FILE_ NEWER [[ a -nt b ]]— fileanewer than fileb(mtime strict). Stack: [path_a, path_b]. Pushes Bool. zsh-compatible “missing” rules: if both exist, compare mtime; if onlyaexists → true; otherwise false.- BUILTIN_
FILE_ OLDER [[ a -ot b ]]— mirror of-nt. If both exist, compare mtime; if onlybexists → true; otherwise false.- BUILTIN_
GET_ VAR - Builtin ID for
${name}reads — routes throughShellExecutor::get_variablewhich knows about special params ($?,$@,$#,$1..$9), shell vars (self.variables), arrays, and env. Replaces emission ofOp::GetVarfor shell variable names so nested VMs (function calls) see the same storage. - BUILTIN_
GLOB_ EXPAND - Pop a scalar from the VM stack, run expand_glob on it, push the
result as Value::Array. Used by the segment-concat compile path
when var refs concatenate with glob meta literals (
$D/*,${prefix}*, etc.) — those skip the bridge’s pathname-expansion pass and would otherwise leak the glob meta to argv as a literal. - BUILTIN_
GLOB_ QUALIFIED - Glob qualifier filter:
*(qualifier)filters glob results by predicate. Pops [pattern, qualifier_string]. Returns Value::Array of matching paths. - BUILTIN_
HAS_ SETGID [[ -g path ]]— setgid bit (S_ISGID).- BUILTIN_
HAS_ SETUID [[ -u path ]]— setuid bit (S_ISUID).- BUILTIN_
HAS_ STICKY [[ -k path ]]— sticky bit (S_ISVTX) set on path.- BUILTIN_
IS_ BLOCKDEV [[ -b path ]]— block device.- BUILTIN_
IS_ CHARDEV [[ -c path ]]— character device.- BUILTIN_
IS_ FIFO [[ -p path ]]— FIFO / named pipe.- BUILTIN_
IS_ SOCKET [[ -S path ]]— socket.- BUILTIN_
IS_ TTY [[ -t fd ]]— fd-is-a-tty check. Stack: [fd_string]. Routes through libc::isatty. Pushes Bool.- BUILTIN_
OPEN_ NAMED_ FD {name}>file/{name}<file/{name}>>file— named-fd allocation. Stack: [path, varid, op_byte]. Openspathperop_byte, gets the new fd (≥10 in zsh; we use libc::open with O_CLOEXEC bit cleared so the inherited fd survives Command::new spawns), stores the fd number as a string in$varid. Pushes Status (0 success, 1 error).- BUILTIN_
OPTION_ SET [[ -o option ]]— shell-option-set test. Stack: [option_name]. Normalizes the name (strip underscores, lowercase) and readsexec.options. Pushes Bool.- BUILTIN_
OWNED_ BY_ GROUP [[ -G path ]]— owned by effective GID.- BUILTIN_
OWNED_ BY_ USER [[ -O path ]]— owned by effective UID.- BUILTIN_
PARAM_ DEFAULT_ FAMILY - Phase 1 native param-modifier builtins. Each takes a fixed argv shape and returns the modified value as Value::Str. Replaces the runtime ShellWord round-trip via BUILTIN_EXPAND_WORD_RUNTIME for the common shapes.
- BUILTIN_
PARAM_ FILTER ${var:#pattern}— array filter: remove elements matchingpattern. Stack: [name, pattern]. For scalarvar, returns empty if it matches the pattern, else the value. For arrayvar, returns Array of non-matching elements.- BUILTIN_
PARAM_ FLAG ${(flags)name}— zsh parameter expansion flags. Stack: [name, flags]. Flags applied left-to-right. Supported subset (high-value, used by zpwr):- BUILTIN_
PARAM_ LENGTH ${#name}— character length of a scalar value, or element count of an indexed/assoc array. Pops [name], returns count as Value::Str.- BUILTIN_
PARAM_ REPLACE ${var/pat/repl}/${var//pat/repl}/${var/#pat/repl}/${var/%pat/repl}— pop [name, pattern, replacement, op_byte]. op_byte: 0=first, 1=all, 2=anchor-prefix, 3=anchor-suffix.- BUILTIN_
PARAM_ STRIP ${var#pat}/${var##pat}/${var%pat}/${var%%pat}— pop [name, pattern, op_byte]. op_byte: 0=#, 1=##, 2=%, 3=%%.- BUILTIN_
PARAM_ SUBSTRING ${var:offset[:length]}— pop [name, offset, length] (length=-1 means “rest of value”; negative offset counts from end).- BUILTIN_
PARAM_ SUBSTRING_ EXPR - BUILTIN_
REGEX_ MATCH - Re-export the regex_match host method as a builtin so
[[ s =~ pat ]]works even when fusevm’s Op::RegexMatch isn’t routed (compat fallback). - BUILTIN_
REGISTER_ COMPILED_ FN - Register a pre-compiled fusevm chunk as a function. Stack: [name, base64-bincode-of-Chunk]. Used by compile_zsh’s compile_funcdef to register functions parsed via parse_init+parse without going through the ShellCommand JSON serialization path.
- BUILTIN_
RESTORE_ TRY_ BLOCK_ STATUS - BUILTIN_
RUN_ BG - Builtin ID for
cmd &background execution. IDs 287/288/289 are reserved for the planned array work in Phase G1 (SET_ARRAY/SET_ASSOC/ARRAY_INDEX), so this lands at 290. Pops one sub-chunk index; forks; child detaches (setsid), runs the sub-chunk on a fresh VM, exits with last_status; parent returns Status(0) immediately. Job-table registration (sojobs/fg/waitcan see the pid) is deferred to Phase G6 — fire-and-forget for now. - BUILTIN_
RUN_ COPROC coproc [name] { body }— bidirectional pipe to async child. Pops a name (optional, “” for default) and a sub-chunk index. Creates two pipes, forks, child redirects its fd 0/1 to the inner ends and runs the body, parent stores [write_fd, read_fd] into the named array (defaultCOPROC). Caller closes the fds andwaits when done. Job-table integration deferred to Phase G6 alongside the bg&work.- BUILTIN_
RUN_ PIPELINE - Builtin ID for pipeline execution. Pops N sub-chunk indices from the stack;
each index points into
vm.chunk.sub_chunks(compiled stage bodies). Forks N children, wires stdin/stdout between them via pipes, runs each stage’s bytecode on a fresh VM in its child, parent waits for all and pushes the last stage’s exit status. This is bytecode-native pipeline execution — no tree-walker delegation. - BUILTIN_
RUN_ SELECT select var in words; do body; done— interactive numbered-menu loop. Compile emits N word pushes + var-name push + sub-chunk index push, thenCallBuiltin(296, N+2). Handler prints1) word1\n2) word2\n...to stderr, prints$PROMPT3(default?#) to stderr, reads a line from stdin. On EOF returns 0. On a valid 1-based number, setsvarto the chosen word, runs the sub-chunk, then redisplays the menu and loops. On invalid input redraws the menu without running the body.breakfrom inside the body exits the loop (handled by the body’s own bytecode).- BUILTIN_
SAME_ FILE [[ a -ef b ]]— same-inode test. Stack: [a, b]. Pushes Bool true iff both paths resolve to the same(dev, inode)pair (zsh + bash semantics).- BUILTIN_
SET_ ARRAY - Indexed-array assignment:
arr=(a b c). Compile_simple emits N element pushes followed by name push, thenCallBuiltin(BUILTIN_SET_ARRAY, N+1). The handler pops args (last popped = name in our pushing order) and storesVec<String>intoexecutor.arrays. Tree-walker callers see the same storage. Any prior scalar binding inexecutor.variablesfornameis removed so${name}(scalar context) consistently reflects the array’s first element viaget_variable. - BUILTIN_
SET_ ASSOC - Single-key set on an associative array:
foo[key]=val. Stack (top-down): [name, key, value]. Storesvalueintoexecutor.assoc_arrays[name][key], creating the outer entry if missing. compile_simple detectsvar[...]=...in assignments and emits this builtin. - BUILTIN_
SET_ BREAK breakfrom inside a body that runs on a sub-VM (select, future loop-via- builtin constructs). Setsexecutor.loop_signal = Some(LoopSignal::Break). Outer-loop builtins drain the flag after each body run and exit early.- BUILTIN_
SET_ CONTINUE continuefrom inside a sub-VM body. Sets the signal to Continue. Outer loop builtins drain + skip-to-next-iteration.- BUILTIN_
SET_ LINENO - Update
$LINENOto track the source line of the next statement. Stack: [n] (the line number fromZshPipe.lineno). Direct port of zsh’slinenoglobal tracking (Src/input.c:330) — the compiler emits one of these per top-level pipe so$LINENOreflects the source position at runtime. ID 342 picked because the previous326collided withBUILTIN_HAS_STICKY(the file has several other duplicate IDs — 325 has two as well — but fixing those is out of scope for this port). - BUILTIN_
SET_ RAW_ OPT - BUILTIN_
SET_ SUBSCRIPT_ RANGE a[i]=(elements)/a[i,j]=(elements)/a[i]=()— subscripted-array assign with array-literal RHS. Stack: […elements, name, key]. Empty elements + single-int keya[i]=()removes that element. Comma-keya[i,j]=(...)splices.- BUILTIN_
SET_ TRY_ BLOCK_ ERROR - Capture current
last_statusinto theTRY_BLOCK_ERRORvariable. Emitted between the try block and the always block of{ … } always { … }so the finally arm can read $TRY_BLOCK_ERROR. - BUILTIN_
SET_ VAR - Builtin ID for
name=valueassignments — pops [name, value] and stores intoexecutor.variables. ReplacesOp::SetVaremission for the same reason: the storage must be visible to both bytecode and tree-walker code, across nested VM boundaries. - BUILTIN_
TIME_ SUBLIST time { compound; ... }— wall-clock-time the sub-chunk and print elapsed seconds. Stack: [sub_chunk_idx as Int]. Runs the sub-chunk on the current VM (so positional/local state is shared) and prints the timing summary to stderr in zsh’s format. Pushes Status.- BUILTIN_
UNKNOWN_ COND [[ -X file ]]for unknown unary test op-X. Stack: [op_name]. Emits zsh’sunknown condition: -Xdiagnostic to stderr and pushes Bool(false). Without this, unknown conditions silently returned false matching neither zsh’s error format nor the expected status code (zsh returns 2 for parse error).- BUILTIN_
VAR_ EXISTS - BUILTIN_
WORD_ SPLIT - Word-split a string on IFS (default: whitespace). Pops one string,
returns Value::Array of fields. Used in array-literal context where
arr=($(cmd))should expand cmd’s stdout into multiple elements. - BUILTIN_
XTRACE_ ARGS - Emit an xtrace line built from the top
argcvalues on the VM stack, peeked WITHOUT consuming. Used to trace simple commands AFTER expansion, soecho for $ishows asecho for a/echo for b. Direct port of Src/exec.c:2055-2066. - BUILTIN_
XTRACE_ ASSIGN - Trace one assignment: emits
name=<quoted-value>(no newline) to xtrerr if XTRACE is on. Coalesces with subsequent XTRACE_ASSIGN / XTRACE_ARGS calls onto the SAME line via theXTRACE_DONE_PS4flag soa=1 b=2 echo $a $bproduces:<PS4>a=1 b=2 echo 1 2\nmatching C zsh’sexeccmd_execbody (Src/exec.c:2517-2582): xtr = isset(XTRACE); if (xtr) { printprompt4(); doneps4 = 1; } while (assign) { if (xtr) fprintf(xtrerr, “%s=”, name); … eval value … if (xtr) { quotedzputs(val, xtrerr); fputc(’ ’, xtrerr); } } - BUILTIN_
XTRACE_ LINE - BUILTIN_
XTRACE_ NEWLINE - Emit a trailing
\n+ flush iff XTRACE is on AND PS4 was emitted by an earlier XTRACE_ASSIGN this line. Used at the end of compile_simple’s assignment-only path so the trace line gets terminated. Mirrors C’s exec.c:3397-3399 (the assign-only return path through execcmd_exec which doesfputc('\n', xtrerr); fflush(xtrerr)).
Statics§
- TRAP_
RETURN - Port of
int trap_return;fromSrc/exec.c:155. Carries the pending exit status from inside a trap; sentinel-2means “running an EXIT/DEBUG-style trap at the current level” (signals.c:1166). Promoted to the user’sreturn Nvalue bybin_returnwhen POSIX-trap semantics apply (builtin.c:5852). - TRAP_
STATE - Port of
int trap_state;fromSrc/exec.c:134. Tracks whether a trap handler is currently being processed and, paired withTRAP_RETURNbelow, whether areturninside the trap should promote toTRAP_STATE_FORCE_RETURNto unwind the trap caller.
Functions§
- convbase_
underscore - Convert integer to string with underscores for readability
Port of
convbase_underscore(char *s, zlong v, int base, int underscore)fromSrc/params.c:5646. WARNING: param names don’t match C — Rust=(val, base, underscore) vs C=(s, v, base, underscore) - format_
int_ in_ base - Format an integer in the given base (2-36) using zsh’s
BASE#DIGITSform. Port ofconvbase(char *s, zlong v, int base)from Src/utils.c (also called from Src/math.c:1089). Bases 2-9 are unsigned-style; uppercase A-Z are used for digits >= 10. A negative value is output as-BASE#DIGITS. WARNING: param names don’t match C — Rust=(n, base) vs C=(buf, l, 10) - getfpfunc
- Port of
getfpfunc(char *s, int *ksh, char **fdir, char **alt_path, int test_only)from Src/exec.c:5260. Walks$fpath(or the suppliedspec_pathslice) for a file namednameand writes the resolved directory through*dir_path_out(matching the Cchar **dir_path). ReturnsSome(file_contents_path)on success,Nonewhen not found. - getoutput
- Free-function wrapper for
getoutput()fromSrc/exec.c:4712. Runs a command-substitution body in the active executor and returns its captured stdout. The C signature isLinkList getoutput(char *cmd, int qt)but every caller in subst.rs joins the list back into a string, so the Rust port collapses the intermediate. - glob_
match_ static - Static glob match — same logic as glob_match but callable without &self, needed for Rayon parallel iterators that can’t capture &self.
- loadautofn
- Direct port of
Shfunc loadautofn(Shfunc shf, int ks, int test_only, int ignore_loaddir)fromSrc/exec.c:5050. Walks$fpathfor a file namedshf->node.nam, reads it, installs the text body on the correspondingshfunctabentry, and clearsPM_UNDEFINED. - scan_
magic_ assoc_ keys