From c871022f9810547f3eeaa5af3a3dc4bc0c85a386 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 5 Aug 2018 14:08:46 +0300 Subject: item-macros --- src/grammar.ron | 2 + src/grammar/items/mod.rs | 78 +++++++++++++++++++--- src/grammar/items/traits.rs | 2 +- src/syntax_kinds/generated.rs | 4 ++ tests/data/parser/err/0008_item_block_recovery.txt | 14 ++-- tests/data/parser/inline/0078_mod_contents.rs | 5 ++ tests/data/parser/inline/0078_mod_contents.txt | 62 +++++++++++++++++ 7 files changed, 151 insertions(+), 16 deletions(-) create mode 100644 tests/data/parser/inline/0078_mod_contents.rs create mode 100644 tests/data/parser/inline/0078_mod_contents.txt diff --git a/src/grammar.ron b/src/grammar.ron index 9f80b3ebf..0a79eeb95 100644 --- a/src/grammar.ron +++ b/src/grammar.ron @@ -109,6 +109,8 @@ Grammar( "TRAIT_ITEM", "IMPL_ITEM", "TYPE_ITEM", + "MACRO_CALL", + "TOKEN_TREE", "PAREN_TYPE", "TUPLE_TYPE", diff --git a/src/grammar/items/mod.rs b/src/grammar/items/mod.rs index 1ed0aea07..8f766901e 100644 --- a/src/grammar/items/mod.rs +++ b/src/grammar/items/mod.rs @@ -5,27 +5,43 @@ mod structs; mod traits; mod use_item; +// test mod_contents +// fn foo() {} +// macro_rules! foo {} +// foo::bar!(); +// super::baz! {} +// struct S; pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { attributes::inner_attributes(p); while !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) { - item(p, stop_on_r_curly) + item_or_macro(p, stop_on_r_curly) } } -pub(super) fn item(p: &mut Parser, stop_on_r_curly: bool) { +pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) { let m = p.start(); match maybe_item(p) { MaybeItem::Item(kind) => { m.complete(p, kind); } MaybeItem::None => { - m.abandon(p); - if p.at(L_CURLY) { - error_block(p, "expected an item"); - } else if !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) { - p.err_and_bump("expected an item"); + if paths::is_path_start(p) { + match macro_call(p) { + MacroFlavor::Curly => (), + MacroFlavor::NonCurly => { + p.expect(SEMI); + } + } + m.complete(p, MACRO_CALL); } else { - p.error("expected an item"); + m.abandon(p); + if p.at(L_CURLY) { + error_block(p, "expected an item"); + } else if !p.at(EOF) && !(stop_on_r_curly && p.at(R_CURLY)) { + p.err_and_bump("expected an item"); + } else { + p.error("expected an item"); + } } } MaybeItem::Modifiers => { @@ -260,3 +276,49 @@ fn mod_item(p: &mut Parser) { } } } + +enum MacroFlavor { + Curly, + NonCurly, +} + +fn macro_call(p: &mut Parser) -> MacroFlavor { + assert!(paths::is_path_start(p)); + paths::use_path(p); + p.expect(EXCL); + p.eat(IDENT); + let flavor = match p.current() { + L_CURLY => { + token_tree(p); + MacroFlavor::Curly + } + L_PAREN | L_BRACK => { + token_tree(p); + MacroFlavor::NonCurly + } + _ => { + p.error("expected `{`, `[`, `(`"); + MacroFlavor::NonCurly + }, + }; + + flavor +} + +fn token_tree(p: &mut Parser) { + let closing_paren_kind = match p.current() { + L_CURLY => R_CURLY, + L_PAREN => R_PAREN, + L_BRACK => R_BRACK, + _ => unreachable!(), + }; + p.bump(); + while !p.at(EOF) && !p.at(closing_paren_kind) { + match p.current() { + L_CURLY | L_PAREN | L_BRACK => token_tree(p), + R_CURLY | R_PAREN | R_BRACK => p.err_and_bump("unmatched brace"), + _ => p.bump() + } + }; + p.expect(closing_paren_kind); +} diff --git a/src/grammar/items/traits.rs b/src/grammar/items/traits.rs index 0614e8ab6..7c0935371 100644 --- a/src/grammar/items/traits.rs +++ b/src/grammar/items/traits.rs @@ -45,7 +45,7 @@ pub(super) fn impl_item(p: &mut Parser) { // fn bar(&self) {} // } while !p.at(EOF) && !p.at(R_CURLY) { - item(p, true); + item_or_macro(p, true); } p.expect(R_CURLY); } diff --git a/src/syntax_kinds/generated.rs b/src/syntax_kinds/generated.rs index 1d3d3b9c1..8ac13fd63 100644 --- a/src/syntax_kinds/generated.rs +++ b/src/syntax_kinds/generated.rs @@ -103,6 +103,8 @@ pub enum SyntaxKind { TRAIT_ITEM, IMPL_ITEM, TYPE_ITEM, + MACRO_CALL, + TOKEN_TREE, PAREN_TYPE, TUPLE_TYPE, NEVER_TYPE, @@ -322,6 +324,8 @@ impl SyntaxKind { TRAIT_ITEM => &SyntaxInfo { name: "TRAIT_ITEM" }, IMPL_ITEM => &SyntaxInfo { name: "IMPL_ITEM" }, TYPE_ITEM => &SyntaxInfo { name: "TYPE_ITEM" }, + MACRO_CALL => &SyntaxInfo { name: "MACRO_CALL" }, + TOKEN_TREE => &SyntaxInfo { name: "TOKEN_TREE" }, PAREN_TYPE => &SyntaxInfo { name: "PAREN_TYPE" }, TUPLE_TYPE => &SyntaxInfo { name: "TUPLE_TYPE" }, NEVER_TYPE => &SyntaxInfo { name: "NEVER_TYPE" }, diff --git a/tests/data/parser/err/0008_item_block_recovery.txt b/tests/data/parser/err/0008_item_block_recovery.txt index 80253d8af..62ca31080 100644 --- a/tests/data/parser/err/0008_item_block_recovery.txt +++ b/tests/data/parser/err/0008_item_block_recovery.txt @@ -13,15 +13,15 @@ FILE@[0; 95) WHITESPACE@[10; 11) R_CURLY@[11; 12) WHITESPACE@[12; 14) - err: `expected an item` - ERROR@[14; 17) - IDENT@[14; 17) "bar" - err: `expected an item` - ERROR@[17; 18) + MACRO_CALL@[14; 20) + PATH@[14; 17) + PATH_SEGMENT@[14; 17) + NAME_REF@[14; 17) + IDENT@[14; 17) "bar" + err: `expected EXCL` L_PAREN@[17; 18) - err: `expected an item` - ERROR@[18; 20) R_PAREN@[18; 19) + err: `expected SEMI` WHITESPACE@[19; 20) err: `expected an item` ERROR@[20; 82) diff --git a/tests/data/parser/inline/0078_mod_contents.rs b/tests/data/parser/inline/0078_mod_contents.rs new file mode 100644 index 000000000..24a15c5c5 --- /dev/null +++ b/tests/data/parser/inline/0078_mod_contents.rs @@ -0,0 +1,5 @@ +fn foo() {} +macro_rules! foo {} +foo::bar!(); +super::baz! {} +struct S; diff --git a/tests/data/parser/inline/0078_mod_contents.txt b/tests/data/parser/inline/0078_mod_contents.txt new file mode 100644 index 000000000..4f97c3ee3 --- /dev/null +++ b/tests/data/parser/inline/0078_mod_contents.txt @@ -0,0 +1,62 @@ +FILE@[0; 70) + FN_ITEM@[0; 12) + FN_KW@[0; 2) + NAME@[2; 6) + WHITESPACE@[2; 3) + IDENT@[3; 6) "foo" + PARAM_LIST@[6; 9) + L_PAREN@[6; 7) + R_PAREN@[7; 8) + WHITESPACE@[8; 9) + BLOCK_EXPR@[9; 12) + L_CURLY@[9; 10) + R_CURLY@[10; 11) + WHITESPACE@[11; 12) + MACRO_CALL@[12; 32) + PATH@[12; 23) + PATH_SEGMENT@[12; 23) + NAME_REF@[12; 23) + IDENT@[12; 23) "macro_rules" + EXCL@[23; 24) + WHITESPACE@[24; 25) + IDENT@[25; 28) "foo" + WHITESPACE@[28; 29) + L_CURLY@[29; 30) + R_CURLY@[30; 31) + WHITESPACE@[31; 32) + MACRO_CALL@[32; 45) + PATH@[32; 40) + PATH@[32; 35) + PATH_SEGMENT@[32; 35) + NAME_REF@[32; 35) + IDENT@[32; 35) "foo" + COLONCOLON@[35; 37) + PATH_SEGMENT@[37; 40) + NAME_REF@[37; 40) + IDENT@[37; 40) "bar" + EXCL@[40; 41) + L_PAREN@[41; 42) + R_PAREN@[42; 43) + SEMI@[43; 44) + WHITESPACE@[44; 45) + MACRO_CALL@[45; 60) + PATH@[45; 55) + PATH@[45; 50) + PATH_SEGMENT@[45; 50) + SUPER_KW@[45; 50) + COLONCOLON@[50; 52) + PATH_SEGMENT@[52; 55) + NAME_REF@[52; 55) + IDENT@[52; 55) "baz" + EXCL@[55; 56) + WHITESPACE@[56; 57) + L_CURLY@[57; 58) + R_CURLY@[58; 59) + WHITESPACE@[59; 60) + STRUCT_ITEM@[60; 70) + STRUCT_KW@[60; 66) + NAME@[66; 68) + WHITESPACE@[66; 67) + IDENT@[67; 68) "S" + SEMI@[68; 69) + WHITESPACE@[69; 70) -- cgit v1.2.3