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.rs40
-rw-r--r--crates/ra_mbe/src/subtree_source.rs47
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs39
-rw-r--r--crates/ra_mbe/src/tests.rs57
-rw-r--r--crates/ra_mbe/src/tt_iter.rs8
5 files changed, 163 insertions, 28 deletions
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs
index 2579382da..78f9efa1b 100644
--- a/crates/ra_mbe/src/mbe_expander/matcher.rs
+++ b/crates/ra_mbe/src/mbe_expander/matcher.rs
@@ -187,7 +187,11 @@ impl<'a> TtIter<'a> {
187 _ => false, 187 _ => false,
188 }, 188 },
189 Separator::Literal(lhs) => match fork.expect_literal() { 189 Separator::Literal(lhs) => match fork.expect_literal() {
190 Ok(rhs) => rhs.text == lhs.text, 190 Ok(rhs) => match rhs {
191 tt::Leaf::Literal(rhs) => rhs.text == lhs.text,
192 tt::Leaf::Ident(rhs) => rhs.text == lhs.text,
193 tt::Leaf::Punct(_) => false,
194 },
191 _ => false, 195 _ => false,
192 }, 196 },
193 Separator::Puncts(lhss) => lhss.iter().all(|lhs| match fork.expect_punct() { 197 Separator::Puncts(lhss) => lhss.iter().all(|lhs| match fork.expect_punct() {
@@ -202,6 +206,13 @@ impl<'a> TtIter<'a> {
202 } 206 }
203 207
204 pub(crate) fn expect_tt(&mut self) -> Result<tt::TokenTree, ()> { 208 pub(crate) fn expect_tt(&mut self) -> Result<tt::TokenTree, ()> {
209 match self.peek_n(0) {
210 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) if punct.char == '\'' => {
211 return self.expect_lifetime();
212 }
213 _ => (),
214 }
215
205 let tt = self.next().ok_or_else(|| ())?.clone(); 216 let tt = self.next().ok_or_else(|| ())?.clone();
206 let punct = match tt { 217 let punct = match tt {
207 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => { 218 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.spacing == tt::Spacing::Joint => {
@@ -255,13 +266,21 @@ impl<'a> TtIter<'a> {
255 } 266 }
256 } 267 }
257 268
258 pub(crate) fn expect_lifetime(&mut self) -> Result<&tt::Ident, ()> { 269 pub(crate) fn expect_lifetime(&mut self) -> Result<tt::TokenTree, ()> {
259 let ident = self.expect_ident()?; 270 let punct = self.expect_punct()?;
260 // check if it start from "`" 271 if punct.char != '\'' {
261 if !ident.text.starts_with('\'') {
262 return Err(()); 272 return Err(());
263 } 273 }
264 Ok(ident) 274 let ident = self.expect_ident()?;
275
276 Ok(tt::Subtree {
277 delimiter: None,
278 token_trees: vec![
279 tt::Leaf::Punct(punct.clone()).into(),
280 tt::Leaf::Ident(ident.clone()).into(),
281 ],
282 }
283 .into())
265 } 284 }
266 285
267 pub(crate) fn expect_fragment( 286 pub(crate) fn expect_fragment(
@@ -274,7 +293,10 @@ impl<'a> TtIter<'a> {
274 } 293 }
275 294
276 impl<'a> TreeSink for OffsetTokenSink<'a> { 295 impl<'a> TreeSink for OffsetTokenSink<'a> {
277 fn token(&mut self, _kind: SyntaxKind, n_tokens: u8) { 296 fn token(&mut self, kind: SyntaxKind, mut n_tokens: u8) {
297 if kind == SyntaxKind::LIFETIME {
298 n_tokens = 2;
299 }
278 for _ in 0..n_tokens { 300 for _ in 0..n_tokens {
279 self.cursor = self.cursor.bump_subtree(); 301 self.cursor = self.cursor.bump_subtree();
280 } 302 }
@@ -286,7 +308,7 @@ impl<'a> TtIter<'a> {
286 } 308 }
287 } 309 }
288 310
289 let buffer = TokenBuffer::new(self.inner.as_slice()); 311 let buffer = TokenBuffer::new(&self.inner.as_slice());
290 let mut src = SubtreeTokenSource::new(&buffer); 312 let mut src = SubtreeTokenSource::new(&buffer);
291 let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false }; 313 let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false };
292 314
@@ -422,7 +444,7 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
422 "tt" => input.expect_tt().map(Some).map_err(|()| err!()), 444 "tt" => input.expect_tt().map(Some).map_err(|()| err!()),
423 "lifetime" => input 445 "lifetime" => input
424 .expect_lifetime() 446 .expect_lifetime()
425 .map(|ident| Some(tt::Leaf::Ident(ident.clone()).into())) 447 .map(|tt| Some(tt))
426 .map_err(|()| err!("expected lifetime")), 448 .map_err(|()| err!("expected lifetime")),
427 "literal" => input 449 "literal" => input
428 .expect_literal() 450 .expect_literal()
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs
index 91e324db9..d7866452d 100644
--- a/crates/ra_mbe/src/subtree_source.rs
+++ b/crates/ra_mbe/src/subtree_source.rs
@@ -50,6 +50,26 @@ impl<'a> SubtreeTokenSource<'a> {
50 } 50 }
51 51
52 fn get(&self, pos: usize) -> Ref<Option<TtToken>> { 52 fn get(&self, pos: usize) -> Ref<Option<TtToken>> {
53 fn is_lifetime(c: Cursor) -> Option<(Cursor, SmolStr)> {
54 let tkn = c.token_tree();
55
56 if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = tkn {
57 if punct.char == '\'' {
58 let next = c.bump();
59 if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = next.token_tree() {
60 let res_cursor = next.bump();
61 let text = SmolStr::new("'".to_string() + &ident.to_string());
62
63 return Some((res_cursor, text));
64 } else {
65 panic!("Next token must be ident : {:#?}", next.token_tree());
66 }
67 }
68 }
69
70 None
71 }
72
53 if pos < self.cached.borrow().len() { 73 if pos < self.cached.borrow().len() {
54 return Ref::map(self.cached.borrow(), |c| &c[pos]); 74 return Ref::map(self.cached.borrow(), |c| &c[pos]);
55 } 75 }
@@ -63,6 +83,12 @@ impl<'a> SubtreeTokenSource<'a> {
63 continue; 83 continue;
64 } 84 }
65 85
86 if let Some((curr, text)) = is_lifetime(cursor) {
87 cached.push(Some(TtToken { kind: LIFETIME, is_joint_to_next: false, text }));
88 self.cached_cursor.set(curr);
89 continue;
90 }
91
66 match cursor.token_tree() { 92 match cursor.token_tree() {
67 Some(tt::TokenTree::Leaf(leaf)) => { 93 Some(tt::TokenTree::Leaf(leaf)) => {
68 cached.push(Some(convert_leaf(&leaf))); 94 cached.push(Some(convert_leaf(&leaf)));
@@ -132,27 +158,28 @@ fn convert_literal(l: &tt::Literal) -> TtToken {
132 let kind = lex_single_syntax_kind(&l.text) 158 let kind = lex_single_syntax_kind(&l.text)
133 .map(|(kind, _error)| kind) 159 .map(|(kind, _error)| kind)
134 .filter(|kind| kind.is_literal()) 160 .filter(|kind| kind.is_literal())
135 .unwrap_or_else(|| match l.text.as_ref() { 161 .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &l));
136 "true" => T![true],
137 "false" => T![false],
138 _ => panic!("Fail to convert given literal {:#?}", &l),
139 });
140 162
141 TtToken { kind, is_joint_to_next: false, text: l.text.clone() } 163 TtToken { kind, is_joint_to_next: false, text: l.text.clone() }
142} 164}
143 165
144fn convert_ident(ident: &tt::Ident) -> TtToken { 166fn convert_ident(ident: &tt::Ident) -> TtToken {
145 let kind = if ident.text.starts_with('\'') { 167 let kind = match ident.text.as_ref() {
146 LIFETIME 168 "true" => T![true],
147 } else { 169 "false" => T![false],
148 SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT) 170 i if i.starts_with('\'') => LIFETIME,
171 _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT),
149 }; 172 };
150 173
151 TtToken { kind, is_joint_to_next: false, text: ident.text.clone() } 174 TtToken { kind, is_joint_to_next: false, text: ident.text.clone() }
152} 175}
153 176
154fn convert_punct(p: tt::Punct) -> TtToken { 177fn convert_punct(p: tt::Punct) -> TtToken {
155 let kind = SyntaxKind::from_char(p.char).unwrap(); 178 let kind = match SyntaxKind::from_char(p.char) {
179 None => panic!("{:#?} is not a valid punct", p),
180 Some(kind) => kind,
181 };
182
156 let text = { 183 let text = {
157 let mut buf = [0u8; 4]; 184 let mut buf = [0u8; 4];
158 let s: &str = p.char.encode_utf8(&mut buf); 185 let s: &str = p.char.encode_utf8(&mut buf);
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 31e9b22e7..2b4390eb2 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -271,7 +271,7 @@ struct RawConvertor<'a> {
271 inner: std::slice::Iter<'a, RawToken>, 271 inner: std::slice::Iter<'a, RawToken>,
272} 272}
273 273
274trait SrcToken { 274trait SrcToken: std::fmt::Debug {
275 fn kind(&self) -> SyntaxKind; 275 fn kind(&self) -> SyntaxKind;
276 276
277 fn to_char(&self) -> Option<char>; 277 fn to_char(&self) -> Option<char>;
@@ -361,8 +361,12 @@ trait TokenConvertor {
361 Some(next) if next.kind().is_punct() => tt::Spacing::Joint, 361 Some(next) if next.kind().is_punct() => tt::Spacing::Joint,
362 _ => tt::Spacing::Alone, 362 _ => tt::Spacing::Alone,
363 }; 363 };
364 let char = token.to_char().expect("Token from lexer must be single char"); 364 let char = match token.to_char() {
365 365 Some(c) => c,
366 None => {
367 panic!("Token from lexer must be single char: token = {:#?}", token);
368 }
369 };
366 tt::Leaf::from(tt::Punct { char, spacing, id: self.id_alloc().alloc(range) }).into() 370 tt::Leaf::from(tt::Punct { char, spacing, id: self.id_alloc().alloc(range) }).into()
367 } 371 }
368 } else { 372 } else {
@@ -372,10 +376,29 @@ trait TokenConvertor {
372 }; 376 };
373 } 377 }
374 let leaf: tt::Leaf = match k { 378 let leaf: tt::Leaf = match k {
375 T![true] | T![false] => make_leaf!(Literal), 379 T![true] | T![false] => make_leaf!(Ident),
376 IDENT | LIFETIME => make_leaf!(Ident), 380 IDENT => make_leaf!(Ident),
377 k if k.is_keyword() => make_leaf!(Ident), 381 k if k.is_keyword() => make_leaf!(Ident),
378 k if k.is_literal() => make_leaf!(Literal), 382 k if k.is_literal() => make_leaf!(Literal),
383 LIFETIME => {
384 let char_unit = TextUnit::from_usize(1);
385 let r = TextRange::offset_len(range.start(), char_unit);
386 let apostrophe = tt::Leaf::from(tt::Punct {
387 char: '\'',
388 spacing: tt::Spacing::Joint,
389 id: self.id_alloc().alloc(r),
390 });
391 result.push(apostrophe.into());
392
393 let r =
394 TextRange::offset_len(range.start() + char_unit, range.len() - char_unit);
395 let ident = tt::Leaf::from(tt::Ident {
396 text: SmolStr::new(&token.to_text()[1..]),
397 id: self.id_alloc().alloc(r),
398 });
399 result.push(ident.into());
400 return;
401 }
379 _ => return, 402 _ => return,
380 }; 403 };
381 404
@@ -455,6 +478,7 @@ impl Convertor {
455 } 478 }
456} 479}
457 480
481#[derive(Debug)]
458enum SynToken { 482enum SynToken {
459 Ordiniary(SyntaxToken), 483 Ordiniary(SyntaxToken),
460 Punch(SyntaxToken, TextUnit), 484 Punch(SyntaxToken, TextUnit),
@@ -592,11 +616,14 @@ fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> SmolStr {
592} 616}
593 617
594impl<'a> TreeSink for TtTreeSink<'a> { 618impl<'a> TreeSink for TtTreeSink<'a> {
595 fn token(&mut self, kind: SyntaxKind, n_tokens: u8) { 619 fn token(&mut self, kind: SyntaxKind, mut n_tokens: u8) {
596 if kind == L_DOLLAR || kind == R_DOLLAR { 620 if kind == L_DOLLAR || kind == R_DOLLAR {
597 self.cursor = self.cursor.bump_subtree(); 621 self.cursor = self.cursor.bump_subtree();
598 return; 622 return;
599 } 623 }
624 if kind == LIFETIME {
625 n_tokens = 2;
626 }
600 627
601 let mut last = self.cursor; 628 let mut last = self.cursor;
602 for _ in 0..n_tokens { 629 for _ in 0..n_tokens {
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index 5d1274d21..100ed41f2 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -215,6 +215,33 @@ SUBTREE $
215} 215}
216 216
217#[test] 217#[test]
218fn test_lifetime_split() {
219 parse_macro(
220 r#"
221macro_rules! foo {
222 ($($t:tt)*) => { $($t)*}
223}
224"#,
225 )
226 .assert_expand(
227 r#"foo!(static bar: &'static str = "hello";);"#,
228 r#"
229SUBTREE $
230 IDENT static 17
231 IDENT bar 18
232 PUNCH : [alone] 19
233 PUNCH & [alone] 20
234 PUNCH ' [joint] 21
235 IDENT static 22
236 IDENT str 23
237 PUNCH = [alone] 24
238 LITERAL "hello" 25
239 PUNCH ; [joint] 26
240"#,
241 );
242}
243
244#[test]
218fn test_expr_order() { 245fn test_expr_order() {
219 let expanded = parse_macro( 246 let expanded = parse_macro(
220 r#" 247 r#"
@@ -989,6 +1016,36 @@ fn test_literal() {
989} 1016}
990 1017
991#[test] 1018#[test]
1019fn test_boolean_is_ident() {
1020 parse_macro(
1021 r#"
1022 macro_rules! foo {
1023 ($lit0:literal, $lit1:literal) => { const VALUE: (bool,bool) = ($lit0,$lit1); };
1024 }
1025"#,
1026 )
1027 .assert_expand(
1028 r#"foo!(true,false);"#,
1029 r#"
1030SUBTREE $
1031 IDENT const 14
1032 IDENT VALUE 15
1033 PUNCH : [alone] 16
1034 SUBTREE () 17
1035 IDENT bool 18
1036 PUNCH , [alone] 19
1037 IDENT bool 20
1038 PUNCH = [alone] 21
1039 SUBTREE () 22
1040 IDENT true 29
1041 PUNCH , [joint] 25
1042 IDENT false 31
1043 PUNCH ; [alone] 28
1044"#,
1045 );
1046}
1047
1048#[test]
992fn test_vis() { 1049fn test_vis() {
993 parse_macro( 1050 parse_macro(
994 r#" 1051 r#"
diff --git a/crates/ra_mbe/src/tt_iter.rs b/crates/ra_mbe/src/tt_iter.rs
index 100184e66..46c420718 100644
--- a/crates/ra_mbe/src/tt_iter.rs
+++ b/crates/ra_mbe/src/tt_iter.rs
@@ -40,9 +40,11 @@ impl<'a> TtIter<'a> {
40 } 40 }
41 } 41 }
42 42
43 pub(crate) fn expect_literal(&mut self) -> Result<&'a tt::Literal, ()> { 43 pub(crate) fn expect_literal(&mut self) -> Result<&'a tt::Leaf, ()> {
44 match self.expect_leaf()? { 44 let it = self.expect_leaf()?;
45 tt::Leaf::Literal(it) => Ok(it), 45 match it {
46 tt::Leaf::Literal(_) => Ok(it),
47 tt::Leaf::Ident(ident) if ident.text == "true" || ident.text == "false" => Ok(it),
46 _ => Err(()), 48 _ => Err(()),
47 } 49 }
48 } 50 }