diff options
| author | Jonas Maier <> | 2026-03-05 08:15:37 +0100 |
|---|---|---|
| committer | Jonas Maier <> | 2026-03-05 08:15:37 +0100 |
| commit | a8f9ac71cfa31302b8577065c56fab2bc4b035d2 (patch) | |
| tree | 307758a0aef7b628d7c27d43402e336b3310bf96 /src/parse.rs | |
| parent | 4b83b63ddb81817ea7cc418f1b61f687ba813085 (diff) | |
| download | pish-a8f9ac71cfa31302b8577065c56fab2bc4b035d2.tar.gz | |
pipe parsing
Diffstat (limited to 'src/parse.rs')
| -rw-r--r-- | src/parse.rs | 64 |
1 files changed, 58 insertions, 6 deletions
diff --git a/src/parse.rs b/src/parse.rs index cc495b1..fae00a3 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -18,14 +18,20 @@ pub struct Command { } enum ParseError { + /// "clean" EOF, i.e. not in the middle of something + Eof, + + /// "unclean" EOF, i.e. EOF after beginning a quoted string Incomplete, + UnexpectedPipe, + UnknownChar(char), } type Result<T> = std::result::Result<T, ParseError>; -pub fn parse(x: &str) -> Result<Ast> { +pub fn do_parse(x: &str) -> Result<Ast> { let chars: Vec<char> = x.chars().collect(); Ast::parse(&mut &chars[..]) } @@ -34,12 +40,22 @@ trait Parse: Sized { fn parse(b: &mut &[char]) -> Result<Self>; } +#[inline(always)] +fn parse<T: Parse>(b: &mut &[char]) -> Result<T> { + T::parse(b) +} + fn spaces(b: &mut &[char]) { while let Some(' ' | '\t') = b.get(0) { *b = &b[1..]; } } +#[inline(always)] +fn adv(b: &mut &[char]) { + *b = &b[1..] +} + fn parse_quoted_string(b: &mut &[char], delim: char) -> Result<String> { // TODO: escape sequence stuff @@ -47,12 +63,12 @@ fn parse_quoted_string(b: &mut &[char], delim: char) -> Result<String> { let mut s = String::new(); while b.len() > 0 { if b[0] == delim { - *b = &b[1..]; + adv(b); return Ok(s); } s.push(b[0]); - *b = &b[1..]; + adv(b); } Err(ParseError::Incomplete) } @@ -61,13 +77,13 @@ impl Parse for String { fn parse(b: &mut &[char]) -> Result<Self> { spaces(b); if b.is_empty() { - return Err(ParseError::Incomplete); + return Err(ParseError::Eof); } let c = b[0]; if c == '|' { Err(ParseError::UnexpectedPipe) } else if c == '\'' || c == '"' { - *b = &b[1..]; + adv(b); parse_quoted_string(b, c) } else if c.is_ascii_graphic() { parse_quoted_string(b, ' ') @@ -79,6 +95,42 @@ impl Parse for String { impl Parse for Ast { fn parse(b: &mut &[char]) -> Result<Self> { - todo!() + Ok(Self::Pipes(parse(b)?)) + } +} + +impl Parse for Command { + fn parse(b: &mut &[char]) -> Result<Self> { + let path: String = parse(b)?; + let mut args = Vec::new(); + loop { + let arg: Result<String> = parse(b); + match arg { + Ok(arg) => args.push(arg), + Err(ParseError::Eof | ParseError::UnexpectedPipe) => break, + Err(e) => Err(e)?, + } + } + Ok(Self { path, args }) + } +} + +impl Parse for Pipes { + fn parse(b: &mut &[char]) -> Result<Self> { + let cmds: Vec<Command> = vec![parse(b)?]; + + loop { + spaces(b); + if b.is_empty() { + return Ok(Pipes { cmds }); + } + + let c = b[0]; + if c == '|' { + adv(b); + } else { + Err(ParseError::UnknownChar(c))?; + } + } } } |
