diff options
-rw-r--r-- | crates/ra_mbe/src/lib.rs | 91 | ||||
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 32 | ||||
-rw-r--r-- | crates/ra_mbe/src/subtree_parser.rs | 12 | ||||
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 5 | ||||
-rw-r--r-- | crates/ra_mbe/src/tt_cursor.rs | 40 | ||||
-rw-r--r-- | crates/ra_parser/src/grammar.rs | 33 | ||||
-rw-r--r-- | crates/ra_parser/src/lib.rs | 16 |
7 files changed, 227 insertions, 2 deletions
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs index 9d4744838..814586fd6 100644 --- a/crates/ra_mbe/src/lib.rs +++ b/crates/ra_mbe/src/lib.rs | |||
@@ -731,4 +731,95 @@ MACRO_ITEMS@[0; 40) | |||
731 | } | 731 | } |
732 | "#, r#"extern crate a ; mod b ; mod c {} use d ; const E : i32 = 0 ; static F : i32 = 0 ; impl G {} struct H ; enum I {Foo} trait J {} fn h () {} extern {} type T = u8 ;"#); | 732 | "#, r#"extern crate a ; mod b ; mod c {} use d ; const E : i32 = 0 ; static F : i32 = 0 ; impl G {} struct H ; enum I {Foo} trait J {} fn h () {} extern {} type T = u8 ;"#); |
733 | } | 733 | } |
734 | |||
735 | #[test] | ||
736 | fn test_block() { | ||
737 | let rules = create_rules( | ||
738 | r#" | ||
739 | macro_rules! foo { | ||
740 | ($ i:block) => { fn foo() $ i } | ||
741 | } | ||
742 | "#, | ||
743 | ); | ||
744 | assert_expansion(&rules, "foo! { { 1; } }", "fn foo () {1 ;}"); | ||
745 | } | ||
746 | |||
747 | #[test] | ||
748 | fn test_meta() { | ||
749 | let rules = create_rules( | ||
750 | r#" | ||
751 | macro_rules! foo { | ||
752 | ($ i:meta) => ( | ||
753 | #[$ i] | ||
754 | fn bar() {} | ||
755 | ) | ||
756 | } | ||
757 | "#, | ||
758 | ); | ||
759 | assert_expansion( | ||
760 | &rules, | ||
761 | r#"foo! { cfg(target_os = "windows") }"#, | ||
762 | r#"# [cfg (target_os = "windows")] fn bar () {}"#, | ||
763 | ); | ||
764 | } | ||
765 | |||
766 | #[test] | ||
767 | fn test_tt_block() { | ||
768 | let rules = create_rules( | ||
769 | r#" | ||
770 | macro_rules! foo { | ||
771 | ($ i:tt) => { fn foo() $ i } | ||
772 | } | ||
773 | "#, | ||
774 | ); | ||
775 | assert_expansion(&rules, r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#); | ||
776 | } | ||
777 | |||
778 | #[test] | ||
779 | fn test_tt_group() { | ||
780 | let rules = create_rules( | ||
781 | r#" | ||
782 | macro_rules! foo { | ||
783 | ($($ i:tt)*) => { $($ i)* } | ||
784 | } | ||
785 | "#, | ||
786 | ); | ||
787 | assert_expansion(&rules, r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#); | ||
788 | } | ||
789 | |||
790 | #[test] | ||
791 | fn test_lifetime() { | ||
792 | let rules = create_rules( | ||
793 | r#" | ||
794 | macro_rules! foo { | ||
795 | ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } } | ||
796 | } | ||
797 | "#, | ||
798 | ); | ||
799 | assert_expansion(&rules, r#"foo!{'a}"#, r#"struct Ref < 'a > {s : & 'a str}"#); | ||
800 | } | ||
801 | |||
802 | #[test] | ||
803 | fn test_literal() { | ||
804 | let rules = create_rules( | ||
805 | r#" | ||
806 | macro_rules! foo { | ||
807 | ($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;}; | ||
808 | } | ||
809 | "#, | ||
810 | ); | ||
811 | assert_expansion(&rules, r#"foo!(u8 0)"#, r#"const VALUE : u8 = 0 ;"#); | ||
812 | } | ||
813 | |||
814 | #[test] | ||
815 | fn test_vis() { | ||
816 | let rules = create_rules( | ||
817 | r#" | ||
818 | macro_rules! foo { | ||
819 | ($ vis:vis $ name:ident) => { $ vis fn $ name() {}}; | ||
820 | } | ||
821 | "#, | ||
822 | ); | ||
823 | assert_expansion(&rules, r#"foo!(pub foo);"#, r#"pub fn foo () {}"#); | ||
824 | } | ||
734 | } | 825 | } |
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index acba42809..01e29b556 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -161,11 +161,43 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
161 | let pat = input.eat_stmt().ok_or(ExpandError::UnexpectedToken)?.clone(); | 161 | let pat = input.eat_stmt().ok_or(ExpandError::UnexpectedToken)?.clone(); |
162 | res.inner.insert(text.clone(), Binding::Simple(pat.into())); | 162 | res.inner.insert(text.clone(), Binding::Simple(pat.into())); |
163 | } | 163 | } |
164 | "block" => { | ||
165 | let block = | ||
166 | input.eat_block().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
167 | res.inner.insert(text.clone(), Binding::Simple(block.into())); | ||
168 | } | ||
169 | "meta" => { | ||
170 | let meta = | ||
171 | input.eat_meta().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
172 | res.inner.insert(text.clone(), Binding::Simple(meta.into())); | ||
173 | } | ||
174 | "tt" => { | ||
175 | let token = input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
176 | res.inner.insert(text.clone(), Binding::Simple(token.into())); | ||
177 | } | ||
164 | "item" => { | 178 | "item" => { |
165 | let item = | 179 | let item = |
166 | input.eat_item().ok_or(ExpandError::UnexpectedToken)?.clone(); | 180 | input.eat_item().ok_or(ExpandError::UnexpectedToken)?.clone(); |
167 | res.inner.insert(text.clone(), Binding::Simple(item.into())); | 181 | res.inner.insert(text.clone(), Binding::Simple(item.into())); |
168 | } | 182 | } |
183 | "lifetime" => { | ||
184 | let lifetime = | ||
185 | input.eat_lifetime().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
186 | res.inner.insert(text.clone(), Binding::Simple(lifetime.into())); | ||
187 | } | ||
188 | "literal" => { | ||
189 | let literal = | ||
190 | input.eat_literal().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
191 | res.inner.insert( | ||
192 | text.clone(), | ||
193 | Binding::Simple(tt::Leaf::from(literal).into()), | ||
194 | ); | ||
195 | } | ||
196 | "vis" => { | ||
197 | let vis = input.eat_vis().ok_or(ExpandError::UnexpectedToken)?.clone(); | ||
198 | res.inner.insert(text.clone(), Binding::Simple(vis.into())); | ||
199 | } | ||
200 | |||
169 | _ => return Err(ExpandError::UnexpectedToken), | 201 | _ => return Err(ExpandError::UnexpectedToken), |
170 | } | 202 | } |
171 | } | 203 | } |
diff --git a/crates/ra_mbe/src/subtree_parser.rs b/crates/ra_mbe/src/subtree_parser.rs index 195e4c3ac..528aa0f8a 100644 --- a/crates/ra_mbe/src/subtree_parser.rs +++ b/crates/ra_mbe/src/subtree_parser.rs | |||
@@ -46,10 +46,22 @@ impl<'a> Parser<'a> { | |||
46 | self.parse(|src, sink| ra_parser::parse_stmt(src, sink, false)) | 46 | self.parse(|src, sink| ra_parser::parse_stmt(src, sink, false)) |
47 | } | 47 | } |
48 | 48 | ||
49 | pub fn parse_block(self) -> Option<tt::TokenTree> { | ||
50 | self.parse(ra_parser::parse_block) | ||
51 | } | ||
52 | |||
53 | pub fn parse_meta(self) -> Option<tt::TokenTree> { | ||
54 | self.parse(ra_parser::parse_meta) | ||
55 | } | ||
56 | |||
49 | pub fn parse_item(self) -> Option<tt::TokenTree> { | 57 | pub fn parse_item(self) -> Option<tt::TokenTree> { |
50 | self.parse(ra_parser::parse_item) | 58 | self.parse(ra_parser::parse_item) |
51 | } | 59 | } |
52 | 60 | ||
61 | pub fn parse_vis(self) -> Option<tt::TokenTree> { | ||
62 | self.parse(ra_parser::parse_vis) | ||
63 | } | ||
64 | |||
53 | fn parse<F>(self, f: F) -> Option<tt::TokenTree> | 65 | fn parse<F>(self, f: F) -> Option<tt::TokenTree> |
54 | where | 66 | where |
55 | F: FnOnce(&dyn TokenSource, &mut dyn TreeSink), | 67 | F: FnOnce(&dyn TokenSource, &mut dyn TreeSink), |
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index 5844d3f12..38a481029 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -157,7 +157,10 @@ fn convert_tt( | |||
157 | ); | 157 | ); |
158 | } | 158 | } |
159 | } else { | 159 | } else { |
160 | let child = if token.kind().is_keyword() || token.kind() == IDENT { | 160 | let child: tt::TokenTree = if token.kind().is_keyword() |
161 | || token.kind() == IDENT | ||
162 | || token.kind() == LIFETIME | ||
163 | { | ||
161 | let relative_range = token.range() - global_offset; | 164 | let relative_range = token.range() - global_offset; |
162 | let id = token_map.alloc(relative_range); | 165 | let id = token_map.alloc(relative_range); |
163 | let text = token.text().clone(); | 166 | let text = token.text().clone(); |
diff --git a/crates/ra_mbe/src/tt_cursor.rs b/crates/ra_mbe/src/tt_cursor.rs index 484437b0e..741b5ea1c 100644 --- a/crates/ra_mbe/src/tt_cursor.rs +++ b/crates/ra_mbe/src/tt_cursor.rs | |||
@@ -41,6 +41,13 @@ impl<'a> TtCursor<'a> { | |||
41 | } | 41 | } |
42 | } | 42 | } |
43 | 43 | ||
44 | pub(crate) fn at_literal(&mut self) -> Option<&'a tt::Literal> { | ||
45 | match self.current() { | ||
46 | Some(tt::TokenTree::Leaf(tt::Leaf::Literal(i))) => Some(i), | ||
47 | _ => None, | ||
48 | } | ||
49 | } | ||
50 | |||
44 | pub(crate) fn bump(&mut self) { | 51 | pub(crate) fn bump(&mut self) { |
45 | self.pos += 1; | 52 | self.pos += 1; |
46 | } | 53 | } |
@@ -79,6 +86,13 @@ impl<'a> TtCursor<'a> { | |||
79 | }) | 86 | }) |
80 | } | 87 | } |
81 | 88 | ||
89 | pub(crate) fn eat_literal(&mut self) -> Option<&'a tt::Literal> { | ||
90 | self.at_literal().map(|i| { | ||
91 | self.bump(); | ||
92 | i | ||
93 | }) | ||
94 | } | ||
95 | |||
82 | pub(crate) fn eat_path(&mut self) -> Option<tt::TokenTree> { | 96 | pub(crate) fn eat_path(&mut self) -> Option<tt::TokenTree> { |
83 | let parser = Parser::new(&mut self.pos, self.subtree); | 97 | let parser = Parser::new(&mut self.pos, self.subtree); |
84 | parser.parse_path() | 98 | parser.parse_path() |
@@ -104,11 +118,37 @@ impl<'a> TtCursor<'a> { | |||
104 | parser.parse_stmt() | 118 | parser.parse_stmt() |
105 | } | 119 | } |
106 | 120 | ||
121 | pub(crate) fn eat_block(&mut self) -> Option<tt::TokenTree> { | ||
122 | let parser = Parser::new(&mut self.pos, self.subtree); | ||
123 | parser.parse_block() | ||
124 | } | ||
125 | |||
126 | pub(crate) fn eat_meta(&mut self) -> Option<tt::TokenTree> { | ||
127 | let parser = Parser::new(&mut self.pos, self.subtree); | ||
128 | parser.parse_meta() | ||
129 | } | ||
130 | |||
107 | pub(crate) fn eat_item(&mut self) -> Option<tt::TokenTree> { | 131 | pub(crate) fn eat_item(&mut self) -> Option<tt::TokenTree> { |
108 | let parser = Parser::new(&mut self.pos, self.subtree); | 132 | let parser = Parser::new(&mut self.pos, self.subtree); |
109 | parser.parse_item() | 133 | parser.parse_item() |
110 | } | 134 | } |
111 | 135 | ||
136 | pub(crate) fn eat_lifetime(&mut self) -> Option<tt::TokenTree> { | ||
137 | // check if it start from "`" | ||
138 | if let Some(ident) = self.at_ident() { | ||
139 | if ident.text.chars().next()? != '\'' { | ||
140 | return None; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | self.eat_ident().cloned().map(|ident| tt::Leaf::from(ident).into()) | ||
145 | } | ||
146 | |||
147 | pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> { | ||
148 | let parser = Parser::new(&mut self.pos, self.subtree); | ||
149 | parser.parse_vis() | ||
150 | } | ||
151 | |||
112 | pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ParseError> { | 152 | pub(crate) fn expect_char(&mut self, char: char) -> Result<(), ParseError> { |
113 | if self.at_char(char) { | 153 | if self.at_char(char) { |
114 | self.bump(); | 154 | self.bump(); |
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs index e1762633e..67eae749d 100644 --- a/crates/ra_parser/src/grammar.rs +++ b/crates/ra_parser/src/grammar.rs | |||
@@ -95,6 +95,37 @@ pub(crate) fn stmt(p: &mut Parser, with_semi: bool) { | |||
95 | expressions::stmt(p, with_semi) | 95 | expressions::stmt(p, with_semi) |
96 | } | 96 | } |
97 | 97 | ||
98 | pub(crate) fn block(p: &mut Parser) { | ||
99 | expressions::block(p); | ||
100 | } | ||
101 | |||
102 | // Parse a meta item , which excluded [], e.g : #[ MetaItem ] | ||
103 | pub(crate) fn meta_item(p: &mut Parser) { | ||
104 | fn is_delimiter(p: &mut Parser) -> bool { | ||
105 | match p.current() { | ||
106 | L_CURLY | L_PAREN | L_BRACK => true, | ||
107 | _ => false, | ||
108 | } | ||
109 | } | ||
110 | |||
111 | if is_delimiter(p) { | ||
112 | items::token_tree(p); | ||
113 | return; | ||
114 | } | ||
115 | |||
116 | let m = p.start(); | ||
117 | while !p.at(EOF) { | ||
118 | if is_delimiter(p) { | ||
119 | items::token_tree(p); | ||
120 | break; | ||
121 | } else { | ||
122 | p.bump(); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | m.complete(p, TOKEN_TREE); | ||
127 | } | ||
128 | |||
98 | pub(crate) fn item(p: &mut Parser) { | 129 | pub(crate) fn item(p: &mut Parser) { |
99 | items::item_or_macro(p, true, items::ItemFlavor::Mod) | 130 | items::item_or_macro(p, true, items::ItemFlavor::Mod) |
100 | } | 131 | } |
@@ -136,7 +167,7 @@ impl BlockLike { | |||
136 | } | 167 | } |
137 | } | 168 | } |
138 | 169 | ||
139 | fn opt_visibility(p: &mut Parser) -> bool { | 170 | pub(crate) fn opt_visibility(p: &mut Parser) -> bool { |
140 | match p.current() { | 171 | match p.current() { |
141 | PUB_KW => { | 172 | PUB_KW => { |
142 | let m = p.start(); | 173 | let m = p.start(); |
diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs index 0ea942b6e..970d699c0 100644 --- a/crates/ra_parser/src/lib.rs +++ b/crates/ra_parser/src/lib.rs | |||
@@ -93,11 +93,27 @@ pub fn parse_stmt(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink, | |||
93 | parse_from_tokens(token_source, tree_sink, |p| grammar::stmt(p, with_semi)); | 93 | parse_from_tokens(token_source, tree_sink, |p| grammar::stmt(p, with_semi)); |
94 | } | 94 | } |
95 | 95 | ||
96 | /// Parse given tokens into the given sink as a block | ||
97 | pub fn parse_block(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) { | ||
98 | parse_from_tokens(token_source, tree_sink, grammar::block); | ||
99 | } | ||
100 | |||
101 | pub fn parse_meta(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) { | ||
102 | parse_from_tokens(token_source, tree_sink, grammar::meta_item); | ||
103 | } | ||
104 | |||
96 | /// Parse given tokens into the given sink as an item | 105 | /// Parse given tokens into the given sink as an item |
97 | pub fn parse_item(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) { | 106 | pub fn parse_item(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) { |
98 | parse_from_tokens(token_source, tree_sink, grammar::item); | 107 | parse_from_tokens(token_source, tree_sink, grammar::item); |
99 | } | 108 | } |
100 | 109 | ||
110 | /// Parse given tokens into the given sink as an visibility qualifier | ||
111 | pub fn parse_vis(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) { | ||
112 | parse_from_tokens(token_source, tree_sink, |p| { | ||
113 | grammar::opt_visibility(p); | ||
114 | }); | ||
115 | } | ||
116 | |||
101 | pub fn parse_macro_items(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) { | 117 | pub fn parse_macro_items(token_source: &dyn TokenSource, tree_sink: &mut dyn TreeSink) { |
102 | parse_from_tokens(token_source, tree_sink, grammar::macro_items); | 118 | parse_from_tokens(token_source, tree_sink, grammar::macro_items); |
103 | } | 119 | } |