Skip to content

Commit 45c0d75

Browse files
authored
refactor(interpreter): extract LoopAccumulator for errexit suppression tracking (#896)
Extract duplicated loop result accumulation (stdout/stderr/exit_code/errexit_suppressed tracking + break/continue/return propagation) into a LoopAccumulator helper in state.rs. Used by execute_for, execute_arithmetic_for, and execute_condition_loop. Also adds cargo-vet exemption for rustc-hash 2.1.2. Closes #881
1 parent 76daad5 commit 45c0d75

File tree

3 files changed

+210
-175
lines changed

3 files changed

+210
-175
lines changed

crates/bashkit/src/interpreter/mod.rs

Lines changed: 22 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,10 +1458,7 @@ impl Interpreter {
14581458
));
14591459
}
14601460

1461-
let mut stdout = String::new();
1462-
let mut stderr = String::new();
1463-
let mut exit_code = 0;
1464-
let mut last_errexit_suppressed = false;
1461+
let mut acc = state::LoopAccumulator::new();
14651462

14661463
// Get iteration values: expand fields, then apply brace/glob expansion
14671464
let values: Vec<String> = if let Some(words) = &for_cmd.words {
@@ -1514,65 +1511,15 @@ impl Interpreter {
15141511
let emit_before = self.output_emit_count;
15151512
let result = self.execute_command_sequence(&for_cmd.body).await?;
15161513
self.maybe_emit_output(&result.stdout, &result.stderr, emit_before);
1517-
stdout.push_str(&result.stdout);
1518-
stderr.push_str(&result.stderr);
1519-
exit_code = result.exit_code;
1520-
last_errexit_suppressed = result.errexit_suppressed;
1521-
1522-
// Check for break/continue
1523-
match result.control_flow {
1524-
ControlFlow::Break(n) => {
1525-
if n <= 1 {
1526-
break;
1527-
} else {
1528-
// Propagate break with decremented count
1529-
return Ok(ExecResult {
1530-
stdout,
1531-
stderr,
1532-
exit_code,
1533-
control_flow: ControlFlow::Break(n - 1),
1534-
..Default::default()
1535-
});
1536-
}
1537-
}
1538-
ControlFlow::Continue(n) => {
1539-
if n <= 1 {
1540-
continue;
1541-
} else {
1542-
// Propagate continue with decremented count
1543-
return Ok(ExecResult {
1544-
stdout,
1545-
stderr,
1546-
exit_code,
1547-
control_flow: ControlFlow::Continue(n - 1),
1548-
..Default::default()
1549-
});
1550-
}
1551-
}
1552-
ControlFlow::Return(code) => {
1553-
// Propagate return
1554-
return Ok(ExecResult {
1555-
stdout,
1556-
stderr,
1557-
exit_code: code,
1558-
control_flow: ControlFlow::Return(code),
1559-
..Default::default()
1560-
});
1561-
}
1562-
ControlFlow::None => {
1563-
// errexit is already handled by execute_command_sequence_impl
1564-
}
1514+
match acc.accumulate(result) {
1515+
state::LoopAction::None => {}
1516+
state::LoopAction::Break => break,
1517+
state::LoopAction::Continue => continue,
1518+
state::LoopAction::Exit(r) => return Ok(r),
15651519
}
15661520
}
15671521

1568-
Ok(ExecResult {
1569-
stdout,
1570-
stderr,
1571-
exit_code,
1572-
control_flow: ControlFlow::None,
1573-
errexit_suppressed: last_errexit_suppressed,
1574-
..Default::default()
1575-
})
1522+
Ok(acc.finish())
15761523
}
15771524

15781525
/// Execute a select loop: select var in list; do body; done
@@ -1752,10 +1699,7 @@ impl Interpreter {
17521699
&mut self,
17531700
arith_for: &ArithmeticForCommand,
17541701
) -> Result<ExecResult> {
1755-
let mut stdout = String::new();
1756-
let mut stderr = String::new();
1757-
let mut exit_code = 0;
1758-
let mut last_errexit_suppressed = false;
1702+
let mut acc = state::LoopAccumulator::new();
17591703

17601704
// Execute initialization
17611705
if !arith_for.init.is_empty() {
@@ -1781,50 +1725,10 @@ impl Interpreter {
17811725
let emit_before = self.output_emit_count;
17821726
let result = self.execute_command_sequence(&arith_for.body).await?;
17831727
self.maybe_emit_output(&result.stdout, &result.stderr, emit_before);
1784-
stdout.push_str(&result.stdout);
1785-
stderr.push_str(&result.stderr);
1786-
exit_code = result.exit_code;
1787-
last_errexit_suppressed = result.errexit_suppressed;
1788-
1789-
// Check for break/continue
1790-
match result.control_flow {
1791-
ControlFlow::Break(n) => {
1792-
if n <= 1 {
1793-
break;
1794-
} else {
1795-
return Ok(ExecResult {
1796-
stdout,
1797-
stderr,
1798-
exit_code,
1799-
control_flow: ControlFlow::Break(n - 1),
1800-
..Default::default()
1801-
});
1802-
}
1803-
}
1804-
ControlFlow::Continue(n) => {
1805-
if n > 1 {
1806-
return Ok(ExecResult {
1807-
stdout,
1808-
stderr,
1809-
exit_code,
1810-
control_flow: ControlFlow::Continue(n - 1),
1811-
..Default::default()
1812-
});
1813-
}
1814-
// n <= 1: continue to next iteration (after step)
1815-
}
1816-
ControlFlow::Return(code) => {
1817-
return Ok(ExecResult {
1818-
stdout,
1819-
stderr,
1820-
exit_code: code,
1821-
control_flow: ControlFlow::Return(code),
1822-
..Default::default()
1823-
});
1824-
}
1825-
ControlFlow::None => {
1826-
// errexit is already handled by execute_command_sequence_impl
1827-
}
1728+
match acc.accumulate(result) {
1729+
state::LoopAction::None | state::LoopAction::Continue => {}
1730+
state::LoopAction::Break => break,
1731+
state::LoopAction::Exit(r) => return Ok(r),
18281732
}
18291733

18301734
// Execute step
@@ -1833,14 +1737,7 @@ impl Interpreter {
18331737
}
18341738
}
18351739

1836-
Ok(ExecResult {
1837-
stdout,
1838-
stderr,
1839-
exit_code,
1840-
control_flow: ControlFlow::None,
1841-
errexit_suppressed: last_errexit_suppressed,
1842-
..Default::default()
1843-
})
1740+
Ok(acc.finish())
18441741
}
18451742

18461743
/// Execute an arithmetic command ((expression))
@@ -2187,10 +2084,7 @@ impl Interpreter {
21872084
body: &[Command],
21882085
break_on_zero: bool,
21892086
) -> Result<ExecResult> {
2190-
let mut stdout = String::new();
2191-
let mut stderr = String::new();
2192-
let mut exit_code = 0;
2193-
let mut last_errexit_suppressed = false;
2087+
let mut acc = state::LoopAccumulator::new();
21942088

21952089
// Reset loop counter for this loop
21962090
self.counters.reset_loop();
@@ -2208,8 +2102,8 @@ impl Interpreter {
22082102
&condition_result.stderr,
22092103
emit_before_cond,
22102104
);
2211-
stdout.push_str(&condition_result.stdout);
2212-
stderr.push_str(&condition_result.stderr);
2105+
acc.stdout.push_str(&condition_result.stdout);
2106+
acc.stderr.push_str(&condition_result.stderr);
22132107
let should_break = if break_on_zero {
22142108
condition_result.exit_code == 0
22152109
} else {
@@ -2223,62 +2117,15 @@ impl Interpreter {
22232117
let emit_before = self.output_emit_count;
22242118
let result = self.execute_command_sequence(body).await?;
22252119
self.maybe_emit_output(&result.stdout, &result.stderr, emit_before);
2226-
stdout.push_str(&result.stdout);
2227-
stderr.push_str(&result.stderr);
2228-
exit_code = result.exit_code;
2229-
last_errexit_suppressed = result.errexit_suppressed;
2230-
2231-
// Check for break/continue
2232-
match result.control_flow {
2233-
ControlFlow::Break(n) => {
2234-
if n <= 1 {
2235-
break;
2236-
} else {
2237-
return Ok(ExecResult {
2238-
stdout,
2239-
stderr,
2240-
exit_code,
2241-
control_flow: ControlFlow::Break(n - 1),
2242-
..Default::default()
2243-
});
2244-
}
2245-
}
2246-
ControlFlow::Continue(n) => {
2247-
if n <= 1 {
2248-
continue;
2249-
} else {
2250-
return Ok(ExecResult {
2251-
stdout,
2252-
stderr,
2253-
exit_code,
2254-
control_flow: ControlFlow::Continue(n - 1),
2255-
..Default::default()
2256-
});
2257-
}
2258-
}
2259-
ControlFlow::Return(code) => {
2260-
return Ok(ExecResult {
2261-
stdout,
2262-
stderr,
2263-
exit_code: code,
2264-
control_flow: ControlFlow::Return(code),
2265-
..Default::default()
2266-
});
2267-
}
2268-
ControlFlow::None => {
2269-
// errexit is already handled by execute_command_sequence_impl
2270-
}
2120+
match acc.accumulate(result) {
2121+
state::LoopAction::None => {}
2122+
state::LoopAction::Break => break,
2123+
state::LoopAction::Continue => continue,
2124+
state::LoopAction::Exit(r) => return Ok(r),
22712125
}
22722126
}
22732127

2274-
Ok(ExecResult {
2275-
stdout,
2276-
stderr,
2277-
exit_code,
2278-
control_flow: ControlFlow::None,
2279-
errexit_suppressed: last_errexit_suppressed,
2280-
..Default::default()
2281-
})
2128+
Ok(acc.finish())
22822129
}
22832130

22842131
/// Execute a case statement

0 commit comments

Comments
 (0)