diff options
| author | Jonas Maier <jonas@x77.dev> | 2026-05-08 22:15:29 +0200 |
|---|---|---|
| committer | Jonas Maier <jonas@x77.dev> | 2026-05-08 22:15:29 +0200 |
| commit | ce5810be396461d4b4edb4eba191f4094e0f97a8 (patch) | |
| tree | 4c9e917471b2e64c1db34cf0744d769e63ed2650 /src/run | |
| parent | d8712f7ccc8cb26458f3244f6066b9161968f9e1 (diff) | |
| download | pish-ce5810be396461d4b4edb4eba191f4094e0f97a8.tar.gz | |
#16: add break and continue to loops
Diffstat (limited to 'src/run')
| -rw-r--r-- | src/run/builtin.rs | 38 | ||||
| -rw-r--r-- | src/run/mod.rs | 35 |
2 files changed, 70 insertions, 3 deletions
diff --git a/src/run/builtin.rs b/src/run/builtin.rs index a52c345..a40ef51 100644 --- a/src/run/builtin.rs +++ b/src/run/builtin.rs @@ -856,3 +856,41 @@ impl Builtin for source { Ok(()) } } + +#[derive(Copy, Clone)] +pub struct Break; + +impl Builtin for Break { + fn name(&self) -> &str { + "break" + } + + fn io( + &self, + _session: Arc<Mutex<Session>>, + _args: &[BString], + _stdin: &mut dyn Read, + _stdout: &mut dyn Write, + ) -> Result { + Err(Error::Break) + } +} + +#[derive(Copy, Clone)] +pub struct Continue; + +impl Builtin for Continue { + fn name(&self) -> &str { + "continue" + } + + fn io( + &self, + _session: Arc<Mutex<Session>>, + _args: &[BString], + _stdin: &mut dyn Read, + _stdout: &mut dyn Write, + ) -> Result { + Err(Error::Continue) + } +}
\ No newline at end of file diff --git a/src/run/mod.rs b/src/run/mod.rs index 8c45548..7770b86 100644 --- a/src/run/mod.rs +++ b/src/run/mod.rs @@ -20,6 +20,8 @@ pub enum ExecError { Panic, AliasDepthExceeded, Parse(crate::parse::ParseError), + Break, + Continue, } impl ExecError { @@ -63,6 +65,8 @@ impl ExecError { } ExecError::AliasDepthExceeded => "alias depth exceeded".to_string(), ExecError::Parse(pe) => format!("parse error: {pe:?}"), + ExecError::Break => "break: only useful in loops".to_string(), + ExecError::Continue => "continue: only useful in loops".to_string(), } } } @@ -72,6 +76,8 @@ impl From<BuiltinError> for ExecError { match value { BuiltinError::IO(error) => Self::IO(error), BuiltinError::Exit(code) => Self::ExecError(code), + BuiltinError::Break => Self::Break, + BuiltinError::Continue => Self::Continue, } } } @@ -105,6 +111,7 @@ enum SpawnedCmd { trait IsSuccessful { fn is_successful(&self) -> bool; + fn as_bool(&self) -> Result<bool, ExecError>; } impl IsSuccessful for Result<(), ExecError> { fn is_successful(&self) -> bool { @@ -113,6 +120,18 @@ impl IsSuccessful for Result<(), ExecError> { _ => false, } } + + /// returns the boolean value interpreted from this exit code. + /// + /// in case the exit code indicates divergence (break/continue) that "error" will be propagated + fn as_bool(&self) -> Result<bool, ExecError> { + match self { + Ok(_) | Err(ExecError::ExecError(0)) => Ok(true), + Err(ExecError::Break) => Err(ExecError::Break), + Err(ExecError::Continue) => Err(ExecError::Continue), + Err(_) => Ok(false), + } + } } impl SpawnedCmd { @@ -380,7 +399,7 @@ impl Executor { let res = this .execute_pipeline(cond.condition, stdin.try_clone()?, stdout.try_clone()?) .join(); - let block = if res.is_successful() { + let block = if res.as_bool()? { cond.true_block } else { cond.false_block @@ -403,9 +422,15 @@ impl Executor { let condition = condition.clone().expand(&mut this)?; this.execute_pipeline(condition, stdin.try_clone()?, stdout.try_clone()?) .join() - .is_successful() + .as_bool()? } { - this.execute_block_inner(&block, stdin.try_clone()?, stdout.try_clone()?)?; + let res = this.execute_block_inner(&block, stdin.try_clone()?, stdout.try_clone()?); + match res { + Ok(_) => (), + Err(ExecError::Break) => break, + Err(ExecError::Continue) => continue, + Err(e) => Err(e)?, + } } Ok(()) }); @@ -597,6 +622,8 @@ pub fn source(se: Arc<Mutex<Session>>, file: &bstr) -> Result<(), ExecError> { pub enum BuiltinError { IO(std::io::Error), Exit(i32), + Break, + Continue, } impl From<std::io::Error> for BuiltinError { @@ -658,6 +685,8 @@ const BUILTINS: &[&'static dyn BuiltinClone] = &[ &builtin::exit, &builtin::ct, &builtin::source, + &builtin::Break, + &builtin::Continue, ]; pub fn builtin_map() -> HashMap<BString, &'static dyn BuiltinClone> { |
