aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe/src')
-rw-r--r--crates/ra_mbe/src/mbe_expander/matcher.rs56
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs7
-rw-r--r--crates/ra_mbe/src/tests.rs44
-rw-r--r--crates/ra_mbe/src/tt_iter.rs4
4 files changed, 107 insertions, 4 deletions
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs
index 2bdea11e1..ffba03898 100644
--- a/crates/ra_mbe/src/mbe_expander/matcher.rs
+++ b/crates/ra_mbe/src/mbe_expander/matcher.rs
@@ -155,6 +155,60 @@ impl<'a> TtIter<'a> {
155 ok 155 ok
156 } 156 }
157 157
158 pub(crate) fn expect_tt(&mut self) -> Result<tt::TokenTree, ()> {
159 let tt = self.next().ok_or_else(|| ())?.clone();
160 let punct = match tt {
161 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => {
162 punct
163 }
164 _ => return Ok(tt),
165 };
166
167 let (second, third) = match (self.peek_n(0), self.peek_n(1)) {
168 (
169 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))),
170 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p3))),
171 ) if p2.spacing == tt::Spacing::Joint => (p2.char, Some(p3.char)),
172 (Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p2))), _) => (p2.char, None),
173 _ => return Ok(tt),
174 };
175
176 match (punct.char, second, third) {
177 ('.', '.', Some('.'))
178 | ('.', '.', Some('='))
179 | ('<', '<', Some('='))
180 | ('>', '>', Some('=')) => {
181 let tt2 = self.next().unwrap().clone();
182 let tt3 = self.next().unwrap().clone();
183 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt, tt2, tt3] }.into())
184 }
185 ('-', '=', None)
186 | ('-', '>', None)
187 | (':', ':', None)
188 | ('!', '=', None)
189 | ('.', '.', None)
190 | ('*', '=', None)
191 | ('/', '=', None)
192 | ('&', '&', None)
193 | ('&', '=', None)
194 | ('%', '=', None)
195 | ('^', '=', None)
196 | ('+', '=', None)
197 | ('<', '<', None)
198 | ('<', '=', None)
199 | ('=', '=', None)
200 | ('=', '>', None)
201 | ('>', '=', None)
202 | ('>', '>', None)
203 | ('|', '=', None)
204 | ('|', '|', None) => {
205 let tt2 = self.next().unwrap().clone();
206 Ok(tt::Subtree { delimiter: None, token_trees: vec![tt.clone(), tt2] }.into())
207 }
208 _ => Ok(tt),
209 }
210 }
211
158 pub(crate) fn expect_lifetime(&mut self) -> Result<&tt::Ident, ()> { 212 pub(crate) fn expect_lifetime(&mut self) -> Result<&tt::Ident, ()> {
159 let ident = self.expect_ident()?; 213 let ident = self.expect_ident()?;
160 // check if it start from "`" 214 // check if it start from "`"
@@ -302,7 +356,7 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> Result<Option<Fragment>, Ex
302 let ident = input.expect_ident().map_err(|()| err!("expected ident"))?.clone(); 356 let ident = input.expect_ident().map_err(|()| err!("expected ident"))?.clone();
303 tt::Leaf::from(ident).into() 357 tt::Leaf::from(ident).into()
304 } 358 }
305 "tt" => input.next().ok_or_else(|| err!())?.clone(), 359 "tt" => input.expect_tt().map_err(|()| err!())?.clone(),
306 "lifetime" => { 360 "lifetime" => {
307 let ident = input.expect_lifetime().map_err(|()| err!())?; 361 let ident = input.expect_lifetime().map_err(|()| err!())?;
308 tt::Leaf::Ident(ident.clone()).into() 362 tt::Leaf::Ident(ident.clone()).into()
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 2aaf0215f..d8ee74faa 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -388,11 +388,12 @@ impl<'a> TreeSink for TtTreeSink<'a> {
388 return; 388 return;
389 } 389 }
390 390
391 let mut last = self.cursor;
391 for _ in 0..n_tokens { 392 for _ in 0..n_tokens {
392 if self.cursor.eof() { 393 if self.cursor.eof() {
393 break; 394 break;
394 } 395 }
395 396 last = self.cursor;
396 let text: SmolStr = match self.cursor.token_tree() { 397 let text: SmolStr = match self.cursor.token_tree() {
397 Some(tt::TokenTree::Leaf(leaf)) => { 398 Some(tt::TokenTree::Leaf(leaf)) => {
398 // Mark the range if needed 399 // Mark the range if needed
@@ -441,11 +442,11 @@ impl<'a> TreeSink for TtTreeSink<'a> {
441 self.inner.token(kind, text); 442 self.inner.token(kind, text);
442 443
443 // Add whitespace between adjoint puncts 444 // Add whitespace between adjoint puncts
444 let next = self.cursor.bump(); 445 let next = last.bump();
445 if let ( 446 if let (
446 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(curr))), 447 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(curr))),
447 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(_))), 448 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(_))),
448 ) = (self.cursor.token_tree(), next.token_tree()) 449 ) = (last.token_tree(), next.token_tree())
449 { 450 {
450 if curr.spacing == tt::Spacing::Alone { 451 if curr.spacing == tt::Spacing::Alone {
451 self.inner.token(WHITESPACE, " ".into()); 452 self.inner.token(WHITESPACE, " ".into());
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index 1dba82915..304867881 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -825,6 +825,50 @@ fn test_tt_group() {
825 ) 825 )
826 .assert_expand_items(r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#); 826 .assert_expand_items(r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#);
827} 827}
828
829#[test]
830fn test_tt_composite() {
831 parse_macro(
832 r#"
833 macro_rules! foo {
834 ($i:tt) => { 0 }
835 }
836 "#,
837 )
838 .assert_expand_items(r#"foo! { => }"#, r#"0"#);
839}
840
841#[test]
842fn test_tt_composite2() {
843 let node = parse_macro(
844 r#"
845 macro_rules! foo {
846 ($($tt:tt)*) => { abs!(=> $($tt)*) }
847 }
848 "#,
849 )
850 .expand_items(r#"foo!{#}"#);
851
852 let res = format!("{:#?}", &node);
853 assert_eq_text!(
854 res.trim(),
855 r###"MACRO_ITEMS@[0; 10)
856 MACRO_CALL@[0; 10)
857 PATH@[0; 3)
858 PATH_SEGMENT@[0; 3)
859 NAME_REF@[0; 3)
860 IDENT@[0; 3) "abs"
861 EXCL@[3; 4) "!"
862 TOKEN_TREE@[4; 10)
863 L_PAREN@[4; 5) "("
864 EQ@[5; 6) "="
865 R_ANGLE@[6; 7) ">"
866 WHITESPACE@[7; 8) " "
867 POUND@[8; 9) "#"
868 R_PAREN@[9; 10) ")""###
869 );
870}
871
828#[test] 872#[test]
829fn test_lifetime() { 873fn test_lifetime() {
830 parse_macro( 874 parse_macro(
diff --git a/crates/ra_mbe/src/tt_iter.rs b/crates/ra_mbe/src/tt_iter.rs
index 319f1ee65..100184e66 100644
--- a/crates/ra_mbe/src/tt_iter.rs
+++ b/crates/ra_mbe/src/tt_iter.rs
@@ -53,6 +53,10 @@ impl<'a> TtIter<'a> {
53 _ => Err(()), 53 _ => Err(()),
54 } 54 }
55 } 55 }
56
57 pub(crate) fn peek_n(&self, n: usize) -> Option<&tt::TokenTree> {
58 self.inner.as_slice().get(n)
59 }
56} 60}
57 61
58impl<'a> Iterator for TtIter<'a> { 62impl<'a> Iterator for TtIter<'a> {