aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJonas Maier <jonas@x77.dev>2026-03-14 22:12:42 +0100
committerJonas Maier <jonas@x77.dev>2026-03-14 22:12:42 +0100
commit3f7d80b746df37ffcb76076d84c15b7027042a89 (patch)
treeb0f5cc10b937c8f06a9e65458e01fd05e7d18878 /src
parentad9572cc6e89634a4d029cc8d311bb51626c17c3 (diff)
downloadpish-3f7d80b746df37ffcb76076d84c15b7027042a89.tar.gz
proper blocks
Diffstat (limited to 'src')
-rw-r--r--src/parse/mod.rs37
-rw-r--r--src/run/mod.rs27
-rw-r--r--src/rw.rs63
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>,
diff --git a/src/rw.rs b/src/rw.rs
index 1f8fa92..96031cc 100644
--- a/src/rw.rs
+++ b/src/rw.rs
@@ -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 {