aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe')
-rw-r--r--crates/ra_mbe/src/lib.rs91
-rw-r--r--crates/ra_mbe/src/mbe_expander.rs32
-rw-r--r--crates/ra_mbe/src/subtree_parser.rs12
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs5
-rw-r--r--crates/ra_mbe/src/tt_cursor.rs40
5 files changed, 179 insertions, 1 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();