diff options
Diffstat (limited to 'crates/ra_mbe/src')
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 103 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 56 |
2 files changed, 147 insertions, 12 deletions
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index fcb73fbc7..0678c37ee 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -267,6 +267,108 @@ struct RawConvertor<'a> { | |||
267 | inner: std::slice::Iter<'a, Token>, | 267 | inner: std::slice::Iter<'a, Token>, |
268 | } | 268 | } |
269 | 269 | ||
270 | trait SrcToken { | ||
271 | fn kind() -> SyntaxKind; | ||
272 | } | ||
273 | |||
274 | trait TokenConvertor { | ||
275 | type Token : SrcToken; | ||
276 | |||
277 | fn go(&mut self) -> Option<tt::Subtree> { | ||
278 | let mut subtree = tt::Subtree::default(); | ||
279 | subtree.delimiter = None; | ||
280 | while self.peek().is_some() { | ||
281 | self.collect_leaf(&mut subtree.token_trees); | ||
282 | } | ||
283 | if subtree.token_trees.is_empty() { | ||
284 | return None; | ||
285 | } | ||
286 | if subtree.token_trees.len() == 1 { | ||
287 | if let tt::TokenTree::Subtree(first) = &subtree.token_trees[0] { | ||
288 | return Some(first.clone()); | ||
289 | } | ||
290 | } | ||
291 | Some(subtree) | ||
292 | } | ||
293 | |||
294 | fn bump(&mut self) -> Option<(Self::Token, TextRange)>; | ||
295 | |||
296 | fn peek(&self) -> Option<Self::Token>; | ||
297 | |||
298 | fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) { | ||
299 | let (token, range) = match self.bump() { | ||
300 | None => return, | ||
301 | Some(it) => it, | ||
302 | }; | ||
303 | |||
304 | let k: SyntaxKind = token.kind(); | ||
305 | if k == COMMENT { | ||
306 | let node = doc_comment(&self.text[range]); | ||
307 | if let Some(tokens) = convert_doc_comment(&node) { | ||
308 | result.extend(tokens); | ||
309 | } | ||
310 | return; | ||
311 | } | ||
312 | |||
313 | result.push(if k.is_punct() { | ||
314 | let delim = match k { | ||
315 | T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])), | ||
316 | T!['{'] => Some((tt::DelimiterKind::Brace, T!['}'])), | ||
317 | T!['['] => Some((tt::DelimiterKind::Bracket, T![']'])), | ||
318 | _ => None, | ||
319 | }; | ||
320 | |||
321 | if let Some((kind, closed)) = delim { | ||
322 | let mut subtree = tt::Subtree::default(); | ||
323 | let id = self.id_alloc.open_delim(range); | ||
324 | subtree.delimiter = Some(tt::Delimiter { kind, id }); | ||
325 | |||
326 | while self.peek().map(|it| it.kind != closed).unwrap_or(false) { | ||
327 | self.collect_leaf(&mut subtree.token_trees); | ||
328 | } | ||
329 | let last_range = match self.bump() { | ||
330 | None => return, | ||
331 | Some(it) => it.1, | ||
332 | }; | ||
333 | self.id_alloc.close_delim(id, last_range); | ||
334 | subtree.into() | ||
335 | } else { | ||
336 | let spacing = match self.peek() { | ||
337 | Some(next) | ||
338 | if next.kind.is_trivia() | ||
339 | || next.kind == T!['['] | ||
340 | || next.kind == T!['{'] | ||
341 | || next.kind == T!['('] => | ||
342 | { | ||
343 | tt::Spacing::Alone | ||
344 | } | ||
345 | Some(next) if next.kind.is_punct() => tt::Spacing::Joint, | ||
346 | _ => tt::Spacing::Alone, | ||
347 | }; | ||
348 | let char = | ||
349 | self.text[range].chars().next().expect("Token from lexer must be single char"); | ||
350 | |||
351 | tt::Leaf::from(tt::Punct { char, spacing, id: self.id_alloc.alloc(range) }).into() | ||
352 | } | ||
353 | } else { | ||
354 | macro_rules! make_leaf { | ||
355 | ($i:ident) => { | ||
356 | tt::$i { id: self.id_alloc.alloc(range), text: self.text[range].into() }.into() | ||
357 | }; | ||
358 | } | ||
359 | let leaf: tt::Leaf = match k { | ||
360 | T![true] | T![false] => make_leaf!(Literal), | ||
361 | IDENT | LIFETIME => make_leaf!(Ident), | ||
362 | k if k.is_keyword() => make_leaf!(Ident), | ||
363 | k if k.is_literal() => make_leaf!(Literal), | ||
364 | _ => return, | ||
365 | }; | ||
366 | |||
367 | leaf.into() | ||
368 | }); | ||
369 | } | ||
370 | } | ||
371 | |||
270 | impl RawConvertor<'_> { | 372 | impl RawConvertor<'_> { |
271 | fn go(&mut self) -> Option<tt::Subtree> { | 373 | fn go(&mut self) -> Option<tt::Subtree> { |
272 | let mut subtree = tt::Subtree::default(); | 374 | let mut subtree = tt::Subtree::default(); |
@@ -295,6 +397,7 @@ impl RawConvertor<'_> { | |||
295 | fn peek(&self) -> Option<Token> { | 397 | fn peek(&self) -> Option<Token> { |
296 | self.inner.as_slice().get(0).cloned() | 398 | self.inner.as_slice().get(0).cloned() |
297 | } | 399 | } |
400 | |||
298 | 401 | ||
299 | fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) { | 402 | fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) { |
300 | let (token, range) = match self.bump() { | 403 | let (token, range) = match self.bump() { |
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index 44f381938..966af1d12 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -427,22 +427,28 @@ MACRO_ITEMS@[0; 40) | |||
427 | ); | 427 | ); |
428 | } | 428 | } |
429 | 429 | ||
430 | #[test] | 430 | fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree { |
431 | fn test_expand_literals_to_token_tree() { | 431 | if let tt::TokenTree::Subtree(subtree) = tt { |
432 | fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree { | 432 | return &subtree; |
433 | if let tt::TokenTree::Subtree(subtree) = tt { | ||
434 | return &subtree; | ||
435 | } | ||
436 | unreachable!("It is not a subtree"); | ||
437 | } | 433 | } |
434 | unreachable!("It is not a subtree"); | ||
435 | } | ||
436 | fn to_literal(tt: &tt::TokenTree) -> &tt::Literal { | ||
437 | if let tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) = tt { | ||
438 | return lit; | ||
439 | } | ||
440 | unreachable!("It is not a literal"); | ||
441 | } | ||
438 | 442 | ||
439 | fn to_literal(tt: &tt::TokenTree) -> &tt::Literal { | 443 | fn to_punct(tt: &tt::TokenTree) -> &tt::Punct { |
440 | if let tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) = tt { | 444 | if let tt::TokenTree::Leaf(tt::Leaf::Punct(lit)) = tt { |
441 | return lit; | 445 | return lit; |
442 | } | ||
443 | unreachable!("It is not a literal"); | ||
444 | } | 446 | } |
447 | unreachable!("It is not a Punct"); | ||
448 | } | ||
445 | 449 | ||
450 | #[test] | ||
451 | fn test_expand_literals_to_token_tree() { | ||
446 | let expansion = parse_macro( | 452 | let expansion = parse_macro( |
447 | r#" | 453 | r#" |
448 | macro_rules! literals { | 454 | macro_rules! literals { |
@@ -471,6 +477,22 @@ fn test_expand_literals_to_token_tree() { | |||
471 | } | 477 | } |
472 | 478 | ||
473 | #[test] | 479 | #[test] |
480 | fn test_attr_to_token_tree() { | ||
481 | let expansion = parse_to_token_tree_by_syntax( | ||
482 | r#" | ||
483 | #[derive(Copy)] | ||
484 | struct Foo; | ||
485 | "#, | ||
486 | ); | ||
487 | |||
488 | assert_eq!(to_punct(&expansion.token_trees[0]).char, '#'); | ||
489 | assert_eq!( | ||
490 | to_subtree(&expansion.token_trees[1]).delimiter_kind(), | ||
491 | Some(tt::DelimiterKind::Bracket) | ||
492 | ); | ||
493 | } | ||
494 | |||
495 | #[test] | ||
474 | fn test_two_idents() { | 496 | fn test_two_idents() { |
475 | parse_macro( | 497 | parse_macro( |
476 | r#" | 498 | r#" |
@@ -1517,6 +1539,16 @@ pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture { | |||
1517 | MacroFixture { rules } | 1539 | MacroFixture { rules } |
1518 | } | 1540 | } |
1519 | 1541 | ||
1542 | pub(crate) fn parse_to_token_tree_by_syntax(ra_fixture: &str) -> tt::Subtree { | ||
1543 | let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap(); | ||
1544 | let tt = syntax_node_to_token_tree(source_file.syntax()).unwrap().0; | ||
1545 | |||
1546 | let parsed = parse_to_token_tree(ra_fixture).unwrap().0; | ||
1547 | assert_eq!(tt, parsed); | ||
1548 | |||
1549 | parsed | ||
1550 | } | ||
1551 | |||
1520 | fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String { | 1552 | fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String { |
1521 | let mut level = 0; | 1553 | let mut level = 0; |
1522 | let mut buf = String::new(); | 1554 | let mut buf = String::new(); |