aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/parse.rs64
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))?;
+ }
+ }
}
}