From fb63779507c21b5f0a73fef2dbaa10480b02b126 Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Tue, 17 Mar 2026 16:37:44 +0100 Subject: better parsing --- src/parse/mod.rs | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) (limited to 'src/parse/mod.rs') diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 006fce2..9d3164e 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -912,6 +912,20 @@ struct Cursor<'a> { backtrace: bool, } +#[derive(Default)] +struct SpaceStats { + space: u32, + tab: u32, + lf: u32, + cr: u32, +} + +impl SpaceStats { + fn is_empty(&self) -> bool { + self.space == 0 && self.tab == 0 && self.lf == 0 && self.cr == 0 + } +} + impl<'a> Cursor<'a> { fn new(buf: &'a [u8], mode: ParseMode) -> Self { Self { @@ -978,6 +992,31 @@ impl<'a> Cursor<'a> { } } + fn spaces_stats(&mut self) -> SpaceStats { + let mut stats = SpaceStats::default(); + while self.has() && b" \t\n\r".contains(&self.buf[0]) { + match self.buf[0] { + b' ' => stats.space += 1, + b'\t' => stats.tab += 1, + b'\n' => stats.lf += 1, + b'\r' => stats.cr += 1, + _ => unreachable!(), + } + self.adv(); + } + stats + } + + /// returns true if the next thing in the buffer is whitespace (including at least one newline) + /// + /// does not modify the buffer + fn whitespace_newline(&mut self) -> bool { + let x = self.buf; + let s = self.spaces_stats(); + self.buf = x; + s.lf > 0 + } + fn is_completion(&self) -> bool { matches!(self.mode, ParseMode::Completion) } @@ -1015,7 +1054,7 @@ impl Parse for Command { fn parse(b: &mut Cursor<'_>) -> Result { let path: ExpString = b.parse()?; let mut args = Vec::new(); - loop { + while !b.whitespace_newline() { match ExpString::parse(b) { Ok(arg) => args.push(arg), Err(ParseError::NotAString) => break, @@ -1031,7 +1070,8 @@ impl Parse for Pipes { let mut cmds: Vec> = vec![b.parse()?]; loop { - b.spaces(); + let space_stats = b.spaces_stats(); + if b.is_empty() { return Ok(Pipes { cmds }); } @@ -1040,7 +1080,7 @@ impl Parse for Pipes { if c == b'|' { b.adv(); cmds.push(b.parse()?); - } else if is_symbol(c) { + } else if space_stats.lf > 0 || is_symbol(c) { return Ok(Pipes { cmds }); } else { Err(ParseError::Unknown(c))?; -- cgit v1.2.3