diff options
| author | Jonas Maier <jonas@x77.dev> | 2026-03-14 22:12:42 +0100 |
|---|---|---|
| committer | Jonas Maier <jonas@x77.dev> | 2026-03-14 22:12:42 +0100 |
| commit | 3f7d80b746df37ffcb76076d84c15b7027042a89 (patch) | |
| tree | b0f5cc10b937c8f06a9e65458e01fd05e7d18878 | |
| parent | ad9572cc6e89634a4d029cc8d311bb51626c17c3 (diff) | |
| download | pish-3f7d80b746df37ffcb76076d84c15b7027042a89.tar.gz | |
proper blocks
| -rw-r--r-- | src/parse/mod.rs | 37 | ||||
| -rw-r--r-- | src/run/mod.rs | 27 | ||||
| -rw-r--r-- | src/rw.rs | 63 |
3 files changed, 109 insertions, 18 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 93d2de8..eda89f1 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -282,7 +282,40 @@ pub struct FunDecl<S: Stage> { impl Parse for Block { fn parse(b: &mut Cursor<'_>) -> Result<Self> { - todo!() + let mut commands = Vec::new(); + b.spaces(); + + if b.has() && b.peek() == b'{' { + b.adv(); + } else { + return Err(ParseError::NotABlock); + } + + loop { + while { + b.spaces(); + b.has() && b.peek() == b';' + } { + b.adv(); + } + + if b.has() && b"})".contains(&b.peek()) { + break; + } + + let cmd = Ast::parse(b)?; + commands.push(cmd); + } + + if b.has() { + if b.peek() != b'}' { + return Err(ParseError::Expected('}')); + } + } else if !b.is_completion() { + return Err(ParseError::Expected('}')); + } + + Ok(Self { commands }) } } @@ -750,6 +783,8 @@ pub enum ParseError { NotAVarAssign, NotHexDigit, + + NotABlock, } type Result<T> = std::result::Result<T, ParseError>; diff --git a/src/run/mod.rs b/src/run/mod.rs index 751f557..5605639 100644 --- a/src/run/mod.rs +++ b/src/run/mod.rs @@ -213,14 +213,7 @@ impl Executor { CommandKind::Fun(body) => { let mut this = self.clone(); this.args = Some(args); - - let handle = wait::spawn(move || { - let body = body.expand(&mut this)?; - let cmd = this.execute(body, stdin, stdout); - this.exec_loop(cmd, &mut []) - }); - - SpawnedCmd::Fun(handle) + this.execute_block(body, stdin, stdout) } CommandKind::Path(path) => { let mut command = Command::new(&path); @@ -241,6 +234,24 @@ impl Executor { } } + fn execute_block( + &mut self, + block: parse::Block, + stdin: InputReader, + stdout: OutputWriter, + ) -> SpawnedCmd { + let mut this = self.clone(); + let handle = wait::spawn(move || -> Result<(), ExecError> { + for cmd in block.commands { + let cmd = cmd.expand(&mut this)?; + this.execute(cmd, stdin.try_clone()?, stdout.try_clone()?) + .join()?; + } + Ok(()) + }); + SpawnedCmd::Fun(handle) + } + fn execute_pipeline( &mut self, pipes: parse::Pipes<parse::PostExpansion>, @@ -4,6 +4,10 @@ use std::{ io::{self, PipeReader, PipeWriter, Read, Write}, os::fd::{AsFd, BorrowedFd}, process::Stdio, + sync::{ + Arc, + atomic::{AtomicBool, Ordering::SeqCst}, + }, }; use nix::poll::{PollFd, PollFlags}; @@ -40,6 +44,26 @@ impl From<Output> for Stdio { } } +impl Input { + pub fn try_clone(&self) -> io::Result<Self> { + Ok(match self { + Input::Stdin => Input::Stdin, + Input::Pipe(pr) => Input::Pipe(pr.try_clone()?), + Input::File(f) => Input::File(f.try_clone()?), + }) + } +} + +impl Output { + pub fn try_clone(&self) -> io::Result<Self> { + Ok(match self { + Output::Stdout => Output::Stdout, + Output::Pipe(pw) => Output::Pipe(pw.try_clone()?), + Output::File(f) => Output::File(f.try_clone()?), + }) + } +} + pub struct Canceler { tx: PipeWriter, } @@ -53,7 +77,7 @@ impl Canceler { pub struct InputReader { input: Input, cancel: PipeReader, - canceled: bool, + canceled: Arc<AtomicBool>, } impl InputReader { @@ -63,11 +87,22 @@ impl InputReader { Self { input, cancel, - canceled: false, + canceled: Arc::new(AtomicBool::new(false)), }, Canceler { tx }, ) } + + pub fn try_clone(&self) -> io::Result<Self> { + let input = self.input.try_clone()?; + let cancel = self.cancel.try_clone()?; + let canceled = self.canceled.clone(); + Ok(Self { + input, + cancel, + canceled, + }) + } } const TIMEOUT_MS: u16 = 1000; @@ -79,12 +114,12 @@ enum PollStatus { } fn check<'a>( - canceled: &mut bool, + canceled: &AtomicBool, cancel: &PipeReader, fd: BorrowedFd<'a>, flags: PollFlags, ) -> PollStatus { - if *canceled { + if canceled.load(SeqCst) { return PollStatus::Cancel; } @@ -94,13 +129,13 @@ fn check<'a>( ]; if nix::poll::poll(&mut poll_fds, TIMEOUT_MS).is_err() { - *canceled = true; + canceled.store(true, SeqCst); return PollStatus::Cancel; }; if let Some(event) = poll_fds[0].revents() { if event.contains(PollFlags::POLLIN) { - *canceled = true; + canceled.store(true, SeqCst); return PollStatus::Cancel; } } @@ -122,7 +157,7 @@ impl InputReader { Input::Pipe(pipe) => pipe.as_fd(), Input::File(file) => file.as_fd(), }; - check(&mut self.canceled, &self.cancel, read_fd, PollFlags::POLLIN) + check(&*self.canceled, &self.cancel, read_fd, PollFlags::POLLIN) } } @@ -157,7 +192,7 @@ impl Read for InputReader { pub struct OutputWriter { output: Output, cancel: PipeReader, - canceled: bool, + canceled: Arc<AtomicBool>, } impl OutputWriter { @@ -167,7 +202,7 @@ impl OutputWriter { Self { output, cancel, - canceled: false, + canceled: Arc::new(AtomicBool::new(false)), }, Canceler { tx }, ) @@ -186,6 +221,16 @@ impl OutputWriter { PollFlags::POLLOUT, ) } + pub fn try_clone(&self) -> io::Result<Self> { + let output = self.output.try_clone()?; + let cancel = self.cancel.try_clone()?; + let canceled = self.canceled.clone(); + Ok(Self { + output, + cancel, + canceled, + }) + } } impl Write for OutputWriter { |
