diff options
author | Jesse Luehrs <doy@tozt.net> | 2022-01-10 01:54:21 -0500 |
---|---|---|
committer | Jesse Luehrs <doy@tozt.net> | 2022-01-10 01:54:21 -0500 |
commit | feb02a8048a31a46ab57fa268d3f22b40af73c61 (patch) | |
tree | f252b92ca9c6ab80d4acc21d296b9f1fac80d009 | |
parent | fd823c090b2a1cd95c237206f9887215c0f9230a (diff) | |
download | nbsh-feb02a8048a31a46ab57fa268d3f22b40af73c61.tar.gz nbsh-feb02a8048a31a46ab57fa268d3f22b40af73c61.zip |
refactor the grammar a bit
-rw-r--r-- | src/parse/ast.rs | 17 | ||||
-rw-r--r-- | src/shell.pest | 21 |
2 files changed, 21 insertions, 17 deletions
diff --git a/src/parse/ast.rs b/src/parse/ast.rs index 9cf583a..053f07f 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -160,7 +160,7 @@ impl Word { fn build_ast(pair: pest::iterators::Pair<Rule>) -> Self { assert!(matches!(pair.as_rule(), Rule::word)); Self { - parts: pair.into_inner().map(WordPart::build_ast).collect(), + parts: pair.into_inner().flat_map(WordPart::build_ast).collect(), } } @@ -183,8 +183,11 @@ enum WordPart { impl WordPart { #[allow(clippy::needless_pass_by_value)] - fn build_ast(pair: pest::iterators::Pair<Rule>) -> Self { - match pair.as_rule() { + fn build_ast( + pair: pest::iterators::Pair<Rule>, + ) -> impl Iterator<Item = Self> + '_ { + assert!(matches!(pair.as_rule(), Rule::word_part)); + pair.into_inner().map(|pair| match pair.as_rule() { Rule::var => { let s = pair.as_str(); let inner = s.strip_prefix('$').unwrap(); @@ -205,7 +208,7 @@ impl WordPart { Self::SingleQuoted(strip_basic_escape(pair.as_str())) } _ => unreachable!(), - } + }) } fn eval(self, env: &Env) -> String { @@ -282,7 +285,7 @@ enum WordOrRedirect { impl WordOrRedirect { fn build_ast(pair: pest::iterators::Pair<Rule>) -> Self { - assert!(matches!(pair.as_rule(), Rule::word)); + 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), @@ -292,9 +295,7 @@ impl WordOrRedirect { } else { None }; - let word = Word { - parts: inner.map(WordPart::build_ast).collect(), - }; + let word = Word::build_ast(inner.next().unwrap()); if let Some(prefix) = prefix { Self::Redirect(Redirect::parse(&prefix, word)) } else { diff --git a/src/shell.pest b/src/shell.pest index dc3f247..393e60e 100644 --- a/src/shell.pest +++ b/src/shell.pest @@ -8,27 +8,30 @@ 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)) | ("${" ~ (!"}" ~ ANY)+ ~ "}") } - -redir_prefix = @{ - ("in" | "out" | "err" | ASCII_DIGIT*) ~ (">>" | ">" | "<") ~ WHITESPACE* -} bareword = @{ bareword_char+ } single_string = @{ single_string_char+ } double_string = @{ double_string_char+ } -word = ${ - redir_prefix? ~ - (var | bareword | +word_part = ${ + var | + bareword | "'" ~ single_string ~ "'" | - "\"" ~ (var | double_string)+ ~ "\"")+ + "\"" ~ (var | double_string)+ ~ "\"" } +word = ${ word_part+ } + +word_or_redirect = ${ redir_prefix? ~ word } -exe = ${ word ~ (w ~ word)* } +exe = ${ word_or_redirect ~ (w ~ word_or_redirect)* } list = ${ word ~ (w ~ word)* } pipeline = ${ exe ~ (w? ~ "|" ~ w? ~ exe)* } |