From d97f262a67f39ccdb0e29aabe10646068bc2d749 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 18 Jan 2022 00:41:09 -0500 Subject: simplify --- src/parse/ast.rs | 70 +++++++++++++++++++------------------------------------- src/shell.pest | 11 ++++----- 2 files changed, 28 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/parse/ast.rs b/src/parse/ast.rs index 294afe5..dd5065a 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -181,27 +181,21 @@ impl Exe { }; } let mut iter = pair.into_inner(); - let exe = match WordOrRedirect::build_ast(iter.next().unwrap()) { - WordOrRedirect::Word(word) => word, - WordOrRedirect::Redirect(_) => todo!(), + let exe = iter.next().unwrap(); + let exe = match exe.as_rule() { + Rule::word => Word::build_ast(exe), + Rule::redirect => todo!(), + _ => unreachable!(), }; - let (args, redirects): (_, Vec<_>) = iter - .map(WordOrRedirect::build_ast) - .partition(|word| matches!(word, WordOrRedirect::Word(_))); - let args = args - .into_iter() - .map(|word| match word { - WordOrRedirect::Word(word) => word, - WordOrRedirect::Redirect(_) => unreachable!(), - }) - .collect(); - let redirects = redirects - .into_iter() - .map(|word| match word { - WordOrRedirect::Word(_) => unreachable!(), - WordOrRedirect::Redirect(redirect) => redirect, - }) - .collect(); + let mut args = vec![]; + let mut redirects = vec![]; + for arg in iter { + match arg.as_rule() { + Rule::word => args.push(Word::build_ast(arg)), + Rule::redirect => redirects.push(Redirect::build_ast(arg)), + _ => unreachable!(), + } + } Self { exe, args, @@ -408,7 +402,12 @@ struct Redirect { } impl Redirect { - fn parse(prefix: &str, to: Word) -> Self { + #[allow(clippy::needless_pass_by_value)] + fn build_ast(pair: pest::iterators::Pair) -> Self { + assert!(matches!(pair.as_rule(), Rule::redirect)); + let mut iter = pair.into_inner(); + + let prefix = iter.next().unwrap().as_str(); let (from, dir) = if let Some(from) = prefix.strip_suffix(">>") { (from, super::Direction::Append) } else if let Some(from) = prefix.strip_suffix('>') { @@ -426,6 +425,9 @@ impl Redirect { } else { parse_fd(from) }; + + let to = Word::build_ast(iter.next().unwrap()); + Self { from, to, dir } } @@ -460,32 +462,6 @@ impl Redirect { } } -enum WordOrRedirect { - Word(Word), - Redirect(Redirect), -} - -impl WordOrRedirect { - fn build_ast(pair: pest::iterators::Pair) -> Self { - assert!(matches!(pair.as_rule(), Rule::word_or_redirect)); - let mut inner = pair.into_inner().peekable(); - let prefix = if matches!( - inner.peek().map(pest::iterators::Pair::as_rule), - Some(Rule::redir_prefix) - ) { - Some(inner.next().unwrap().as_str().trim().to_string()) - } else { - None - }; - let word = Word::build_ast(inner.next().unwrap()); - if let Some(prefix) = prefix { - Self::Redirect(Redirect::parse(&prefix, word)) - } else { - Self::Word(word) - } - } -} - fn strip_escape(s: &str) -> String { let mut new = String::new(); let mut escape = false; diff --git a/src/shell.pest b/src/shell.pest index 94f78d2..d2c96b8 100644 --- a/src/shell.pest +++ b/src/shell.pest @@ -9,10 +9,6 @@ bareword_char = @{ single_string_char = @{ basic_escape_char | (!"'" ~ ANY) } double_string_char = @{ escape_char | (!("\"" | "$") ~ ANY) } -redir_prefix = @{ - ("in" | "out" | "err" | ASCII_DIGIT*) ~ (">>" | ">" | "<") ~ WHITESPACE* -} - var = @{ ("$" ~ XID_START ~ XID_CONTINUE*) | ("$" ~ ("?" | "$" | "*" | ASCII_DIGIT)) | @@ -45,9 +41,12 @@ word_part = ${ } word = ${ word_part+ } -word_or_redirect = ${ redir_prefix? ~ word } +redir_prefix = @{ + ("in" | "out" | "err" | ASCII_DIGIT*) ~ (">>" | ">" | "<") +} +redirect = ${ redir_prefix ~ w? ~ word } -exe = ${ word_or_redirect ~ (w ~ word_or_redirect)* } +exe = ${ (redirect | word) ~ (w ~ (redirect | word))* } subshell = ${ "(" ~ w? ~ commands ~ w? ~ ")" } list = ${ word ~ (w ~ word)* } pipeline = ${ (subshell | exe) ~ (w? ~ "|" ~ w? ~ (subshell | exe))* } -- cgit v1.2.3-54-g00ecf