pub enum Ast { AssignVar(AssignVar), Pipes(Pipes), } pub struct AssignVar { pub to: String, // TODO: body } pub struct Pipes { pub cmds: Vec, } pub struct Command { pub path: String, pub args: Vec, } enum ParseError { Incomplete, UnexpectedPipe, UnknownChar(char), } type Result = std::result::Result; pub fn parse(x: &str) -> Result { let chars: Vec = x.chars().collect(); Ast::parse(&mut &chars[..]) } trait Parse: Sized { fn parse(b: &mut &[char]) -> Result; } fn spaces(b: &mut &[char]) { while let Some(' ' | '\t') = b.get(0) { *b = &b[1..]; } } fn parse_quoted_string(b: &mut &[char], delim: char) -> Result { // TODO: escape sequence stuff *b = &b[1..]; let mut s = String::new(); while b.len() > 0 { if b[0] == delim { *b = &b[1..]; return Ok(s); } s.push(b[0]); *b = &b[1..]; } Err(ParseError::Incomplete) } impl Parse for String { fn parse(b: &mut &[char]) -> Result { spaces(b); if b.is_empty() { return Err(ParseError::Incomplete); } let c = b[0]; if c == '|' { Err(ParseError::UnexpectedPipe) } else if c == '\'' || c == '"' { *b = &b[1..]; parse_quoted_string(b, c) } else if c.is_ascii_graphic() { parse_quoted_string(b, ' ') } else { Err(ParseError::UnknownChar(c)) } } } impl Parse for Ast { fn parse(b: &mut &[char]) -> Result { todo!() } }