From 31d143ba18b74bdbe032a305c7705123e055b39e Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Sat, 2 Feb 2019 12:11:12 -0500 Subject: Fix macro_rules separator parsing. macro_rules rules are separated by ';' including an optional ';' at the end --- crates/ra_mbe/src/lib.rs | 42 +++++++++++++++++++++++++++++++++++++++++ crates/ra_mbe/src/mbe_parser.rs | 8 +++++++- 2 files changed, 49 insertions(+), 1 deletion(-) (limited to 'crates/ra_mbe/src') diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 3e7f458cf..bafa301ea 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs @@ -160,4 +160,46 @@ impl_froms!(TokenTree: Leaf, Subtree); impl From < Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree :: Subtree (it)}}" ) } + + #[test] + fn test_fail_match_pattern_by_token() { + let macro_definition = r#" + macro_rules! foo { + ($ i:ident) => ( + mod $ i {} + ); + (= $ i:ident) => ( + fn $ i() {} + ); + (+ $ i:ident) => ( + struct $ i; + ) + } +"#; + + let macro_invocation = r#" +foo! { foo } +"#; + + let source_file = ast::SourceFile::parse(macro_definition); + let macro_definition = source_file + .syntax() + .descendants() + .find_map(ast::MacroCall::cast) + .unwrap(); + + let source_file = ast::SourceFile::parse(macro_invocation); + let macro_invocation = source_file + .syntax() + .descendants() + .find_map(ast::MacroCall::cast) + .unwrap(); + + let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap(); + let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap(); + let rules = crate::MacroRules::parse(&definition_tt).unwrap(); + let expansion = rules.expand(&invocation_tt).unwrap(); + assert_eq!(expansion.to_string(), "mod foo {}") + } + } diff --git a/crates/ra_mbe/src/mbe_parser.rs b/crates/ra_mbe/src/mbe_parser.rs index a3e6abffc..abad2e8c8 100644 --- a/crates/ra_mbe/src/mbe_parser.rs +++ b/crates/ra_mbe/src/mbe_parser.rs @@ -7,7 +7,13 @@ pub(crate) fn parse(tt: &tt::Subtree) -> Option { let mut parser = TtCursor::new(tt); let mut rules = Vec::new(); while !parser.is_eof() { - rules.push(parse_rule(&mut parser)?) + rules.push(parse_rule(&mut parser)?); + if parser.expect_char(';') == None { + if !parser.is_eof() { + return None; + } + break; + } } Some(crate::MacroRules { rules }) } -- cgit v1.2.3 From 0bb8456e7d7b6994c9e5efa9d5962f003ffa0a1e Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Sat, 2 Feb 2019 22:36:26 -0500 Subject: Fill out test a little more This factors out an assert_expansion function to make things more managable. --- crates/ra_mbe/src/lib.rs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'crates/ra_mbe/src') diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index bafa301ea..922256c03 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs @@ -161,6 +161,20 @@ impl_froms!(TokenTree: Leaf, Subtree); ) } + fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) { + let source_file = ast::SourceFile::parse(invocation); + let macro_invocation = source_file + .syntax() + .descendants() + .find_map(ast::MacroCall::cast) + .unwrap(); + + let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap(); + + let expaned = rules.expand(&invocation_tt).unwrap(); + assert_eq!(expaned.to_string(), expansion); + } + #[test] fn test_fail_match_pattern_by_token() { let macro_definition = r#" @@ -177,10 +191,6 @@ impl_froms!(TokenTree: Leaf, Subtree); } "#; - let macro_invocation = r#" -foo! { foo } -"#; - let source_file = ast::SourceFile::parse(macro_definition); let macro_definition = source_file .syntax() @@ -188,18 +198,12 @@ foo! { foo } .find_map(ast::MacroCall::cast) .unwrap(); - let source_file = ast::SourceFile::parse(macro_invocation); - let macro_invocation = source_file - .syntax() - .descendants() - .find_map(ast::MacroCall::cast) - .unwrap(); - let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap(); - let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap(); let rules = crate::MacroRules::parse(&definition_tt).unwrap(); - let expansion = rules.expand(&invocation_tt).unwrap(); - assert_eq!(expansion.to_string(), "mod foo {}") + + assert_expansion(&rules, "foo! { foo }", "mod foo {}"); + assert_expansion(&rules, "foo! { = bar }", "fn bar () {}"); + assert_expansion(&rules, "foo! { + Baz }", "struct Baz ;"); } } -- cgit v1.2.3