use crate::grammar::parse_tree::{GrammarItem, MatchItem};
use crate::parser;
#[test]
fn match_block() {
let blocks = vec![
r#"grammar; match { _ }"#, r#"grammar; match { _ } else { _ }"#, r#"grammar; match { "abc" }"#, r#"grammar; match { "abc" => "QUOTED" }"#, r#"grammar; match { "abc" => UNQUOTED }"#, r#"grammar; match { r"(?i)begin" => BEGIN }"#, r#"grammar; match { "abc", "def" => "DEF", _ } else { "foo" => BAR, r"(?i)begin" => BEGIN, _ }"#, r#"grammar; match { "abc" } else { "def" } else { _ }"#, ];
for block in blocks {
let parsed = parser::parse_grammar(block)
.unwrap_or_else(|_| panic!("Invalid grammar; grammar={block}"));
let first_item = parsed.items.first().expect("has item");
match *first_item {
GrammarItem::MatchToken(_) => (), _ => panic!("expected MatchToken, but was {first_item:?}"),
}
}
}
#[test]
fn match_complex() {
let parsed = parser::parse_grammar(
r#"
grammar;
match {
r"(?i)begin" => "BEGIN",
r"(?i)end" => "END",
} else {
r"[a-zA-Z_][a-zA-Z0-9_]*" => IDENTIFIER,
} else {
"other",
_
}
"#,
)
.unwrap();
let first_item = parsed.items.first().expect("has item");
match *first_item {
GrammarItem::MatchToken(ref data) => {
let contents0 = data.contents.first().unwrap();
let item00 = contents0.items.first().unwrap();
match *item00 {
MatchItem::Mapped(ref sym, ref mapping, _) => {
assert_eq!(format!("{sym:?}"), "r#\"(?i)begin\"#");
assert_eq!(format!("{mapping}"), "\"BEGIN\"");
}
_ => panic!("expected MatchItem::Mapped, but was: {item00:?}"),
};
let item01 = contents0.items.get(1).unwrap();
match *item01 {
MatchItem::Mapped(ref sym, ref mapping, _) => {
assert_eq!(format!("{sym:?}"), "r#\"(?i)end\"#");
assert_eq!(format!("{mapping}"), "\"END\"");
}
_ => panic!("expected MatchItem::Mapped, but was: {item00:?}"),
};
let contents1 = data.contents.get(1).unwrap();
let item10 = contents1.items.first().unwrap();
match *item10 {
MatchItem::Mapped(ref sym, ref mapping, _) => {
assert_eq!(format!("{sym:?}"), "r#\"[a-zA-Z_][a-zA-Z0-9_]*\"#");
assert_eq!(format!("{mapping}"), "IDENTIFIER");
}
_ => panic!("expected MatchItem::Mapped, but was: {item10:?}"),
};
let contents2 = data.contents.get(2).unwrap();
let item20 = contents2.items.first().unwrap();
match *item20 {
MatchItem::Unmapped(ref sym, _) => {
assert_eq!(format!("{sym:?}"), "\"other\"");
}
_ => panic!("expected MatchItem::Unmapped, but was: {item20:?}"),
};
let item21 = contents2.items.get(1).unwrap();
match *item21 {
MatchItem::CatchAll(_) => (),
_ => panic!("expected MatchItem::CatchAll, but was: {item20:?}"),
};
}
_ => panic!("expected MatchToken, but was: {first_item:?}"),
}
}
#[test]
fn where_clauses() {
let clauses = vec![
"where T: Debug",
"where T: Debug + Display",
"where T: std::ops::Add<usize>",
"where T: IntoIterator<Item = usize>",
"where T: 'a",
"where 'a: 'b",
"where for<'a> &'a T: Debug",
"where T: for<'a> Flobbles<'a>",
"where T: FnMut(usize)",
"where T: FnMut(usize, bool)",
"where T: FnMut() -> bool",
"where T: for<'a> FnMut(&'a usize)",
"where T: Debug, U: Display",
];
for santa in clauses {
assert!(
parser::parse_where_clauses(santa).is_ok(),
"should parse where clauses: {santa}"
);
}
}
#[test]
fn grammars_with_where_clauses() {
let grammars = vec![
r###"
grammar<T> where T: StaticMethods;
"###,
r###"
grammar<T>(methods: &mut T) where T: MutMethods;
"###,
r###"
grammar<'input, T>(methods: &mut T) where T: 'input + Debug + MutMethods;
"###,
r###"
grammar<F>(methods: &mut F) where F: for<'a> FnMut(&'a usize) -> bool;
"###,
r###"
grammar<F>(logger: &mut F) where F: for<'a> FnMut(&'a str);
"###,
];
for g in grammars {
assert!(parser::parse_grammar(g).is_ok());
}
}
#[test]
fn optional_semicolon() {
let g = r#"
grammar;
pub Foo: () = { Bar }
Bar: () = "bar";
"#;
assert!(parser::parse_grammar(g).is_ok());
let g = r#"
grammar;
pub Foo: () = { Bar };
Bar: () = "bar"
"#;
assert!(parser::parse_grammar(g).is_err());
}