diff options
Diffstat (limited to 'src/parse')
-rw-r--r-- | src/parse/ast.rs | 19 | ||||
-rw-r--r-- | src/parse/test_ast.rs | 56 |
2 files changed, 72 insertions, 3 deletions
diff --git a/src/parse/ast.rs b/src/parse/ast.rs index 053f07f..2f4ae86 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -158,7 +158,10 @@ pub struct Word { impl Word { fn build_ast(pair: pest::iterators::Pair<Rule>) -> Self { - assert!(matches!(pair.as_rule(), Rule::word)); + assert!(matches!( + pair.as_rule(), + Rule::word | Rule::alternation_word + )); Self { parts: pair.into_inner().flat_map(WordPart::build_ast).collect(), } @@ -175,6 +178,7 @@ impl Word { #[derive(Debug, Clone, PartialEq, Eq)] enum WordPart { + Alternation(Vec<Word>), Var(String), Bareword(String), DoubleQuoted(String), @@ -186,7 +190,10 @@ impl WordPart { fn build_ast( pair: pest::iterators::Pair<Rule>, ) -> impl Iterator<Item = Self> + '_ { - assert!(matches!(pair.as_rule(), Rule::word_part)); + assert!(matches!( + pair.as_rule(), + Rule::word_part | Rule::alternation_word_part + )); pair.into_inner().map(|pair| match pair.as_rule() { Rule::var => { let s = pair.as_str(); @@ -200,19 +207,25 @@ impl WordPart { .to_string(), ) } - Rule::bareword => Self::Bareword(strip_escape(pair.as_str())), + Rule::bareword | Rule::alternation_bareword => { + Self::Bareword(strip_escape(pair.as_str())) + } Rule::double_string => { Self::DoubleQuoted(strip_escape(pair.as_str())) } Rule::single_string => { Self::SingleQuoted(strip_basic_escape(pair.as_str())) } + Rule::alternation => Self::Alternation( + pair.into_inner().map(Word::build_ast).collect(), + ), _ => unreachable!(), }) } fn eval(self, env: &Env) -> String { match self { + Self::Alternation(_) => todo!(), Self::Var(name) => env.var(&name), Self::Bareword(s) | Self::DoubleQuoted(s) diff --git a/src/parse/test_ast.rs b/src/parse/test_ast.rs index b16eba4..19bf7af 100644 --- a/src/parse/test_ast.rs +++ b/src/parse/test_ast.rs @@ -79,6 +79,12 @@ macro_rules! w { } } +macro_rules! wpa { + ($($word:expr),*) => { + WordPart::Alternation(vec![$($word),*]) + } +} + macro_rules! wpv { ($var:literal) => { WordPart::Var($var.to_string()) @@ -231,3 +237,53 @@ fn test_parts() { cs!(p!(e!(w!("perl"), w!(wpb!("-E"), wps!("say \"foo\""))))) ); } + +#[test] +fn test_alternation() { + parse_eq!( + "echo {foo,bar}", + cs!(p!(e!(w!("echo"), w!(wpa!(w!("foo"), w!("bar")))))) + ); + parse_eq!( + "echo {foo,bar}.rs", + cs!(p!(e!( + w!("echo"), + w!(wpa!(w!("foo"), w!("bar")), wpb!(".rs")) + ))) + ); + parse_eq!( + "echo {foo,bar,baz}.rs", + cs!(p!(e!( + w!("echo"), + w!(wpa!(w!("foo"), w!("bar"), w!("baz")), wpb!(".rs")) + ))) + ); + parse_eq!( + "echo {foo,}.rs", + cs!(p!(e!(w!("echo"), w!(wpa!(w!("foo"), w!()), wpb!(".rs"))))) + ); + parse_eq!("echo {foo}", cs!(p!(e!(w!("echo"), w!(wpa!(w!("foo"))))))); + parse_eq!("echo {}", cs!(p!(e!(w!("echo"), w!(wpa!(w!())))))); + parse_eq!( + "echo {foo,bar}.{rs,c}", + cs!(p!(e!( + w!("echo"), + w!( + wpa!(w!("foo"), w!("bar")), + wpb!("."), + wpa!(w!("rs"), w!("c")) + ) + ))) + ); + parse_eq!( + "echo {$foo,\"${HOME}/bin\"}.{'r'\"s\",c}", + cs!(p!(e!( + w!("echo"), + w!( + wpa!(w!(wpv!("foo")), w!(wpv!("HOME"), wpd!("/bin"))), + wpb!("."), + wpa!(w!(wps!("r"), wpd!("s")), w!("c")) + ) + ))) + ); +} |