diff options
Diffstat (limited to 'crates/ra_mbe/src/syntax_bridge.rs')
-rw-r--r-- | crates/ra_mbe/src/syntax_bridge.rs | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs index d1c49c0b3..1de399fee 100644 --- a/crates/ra_mbe/src/syntax_bridge.rs +++ b/crates/ra_mbe/src/syntax_bridge.rs | |||
@@ -5,6 +5,7 @@ use ra_syntax::{ | |||
5 | ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode, | 5 | ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode, |
6 | SyntaxTreeBuilder, TextRange, TextUnit, T, | 6 | SyntaxTreeBuilder, TextRange, TextUnit, T, |
7 | }; | 7 | }; |
8 | use std::iter::successors; | ||
8 | use tt::buffer::{Cursor, TokenBuffer}; | 9 | use tt::buffer::{Cursor, TokenBuffer}; |
9 | 10 | ||
10 | use crate::subtree_source::SubtreeTokenSource; | 11 | use crate::subtree_source::SubtreeTokenSource; |
@@ -160,6 +161,31 @@ impl Convertor { | |||
160 | 161 | ||
161 | let first_child = tt.first_child_or_token()?; | 162 | let first_child = tt.first_child_or_token()?; |
162 | let last_child = tt.last_child_or_token()?; | 163 | let last_child = tt.last_child_or_token()?; |
164 | |||
165 | // ignore trivial first_child and last_child | ||
166 | let first_child = successors(Some(first_child), |it| { | ||
167 | if it.kind().is_trivia() { | ||
168 | it.next_sibling_or_token() | ||
169 | } else { | ||
170 | None | ||
171 | } | ||
172 | }) | ||
173 | .last() | ||
174 | .unwrap(); | ||
175 | if first_child.kind().is_trivia() { | ||
176 | return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None }); | ||
177 | } | ||
178 | |||
179 | let last_child = successors(Some(last_child), |it| { | ||
180 | if it.kind().is_trivia() { | ||
181 | it.prev_sibling_or_token() | ||
182 | } else { | ||
183 | None | ||
184 | } | ||
185 | }) | ||
186 | .last() | ||
187 | .unwrap(); | ||
188 | |||
163 | let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) { | 189 | let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) { |
164 | (T!['('], T![')']) => (tt::Delimiter::Parenthesis, true), | 190 | (T!['('], T![')']) => (tt::Delimiter::Parenthesis, true), |
165 | (T!['{'], T!['}']) => (tt::Delimiter::Brace, true), | 191 | (T!['{'], T!['}']) => (tt::Delimiter::Brace, true), |
@@ -363,6 +389,7 @@ mod tests { | |||
363 | use super::*; | 389 | use super::*; |
364 | use crate::tests::{create_rules, expand}; | 390 | use crate::tests::{create_rules, expand}; |
365 | use ra_parser::TokenSource; | 391 | use ra_parser::TokenSource; |
392 | use ra_syntax::algo::{insert_children, InsertPosition}; | ||
366 | 393 | ||
367 | #[test] | 394 | #[test] |
368 | fn convert_tt_token_source() { | 395 | fn convert_tt_token_source() { |
@@ -423,4 +450,45 @@ mod tests { | |||
423 | let expansion = expand(&rules, "stmts!();"); | 450 | let expansion = expand(&rules, "stmts!();"); |
424 | assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err()); | 451 | assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err()); |
425 | } | 452 | } |
453 | |||
454 | #[test] | ||
455 | fn test_token_tree_last_child_is_white_space() { | ||
456 | let source_file = ast::SourceFile::parse("f!({} );").ok().unwrap(); | ||
457 | let macro_call = source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
458 | let token_tree = macro_call.token_tree().unwrap(); | ||
459 | |||
460 | // Token Tree now is : | ||
461 | // TokenTree | ||
462 | // - T!['('] | ||
463 | // - TokenTree | ||
464 | // - T!['{'] | ||
465 | // - T!['}'] | ||
466 | // - WHITE_SPACE | ||
467 | // - T![')'] | ||
468 | |||
469 | let rbrace = | ||
470 | token_tree.syntax().descendants_with_tokens().find(|it| it.kind() == T!['}']).unwrap(); | ||
471 | let space = token_tree | ||
472 | .syntax() | ||
473 | .descendants_with_tokens() | ||
474 | .find(|it| it.kind() == SyntaxKind::WHITESPACE) | ||
475 | .unwrap(); | ||
476 | |||
477 | // reorder th white space, such that the white is inside the inner token-tree. | ||
478 | let token_tree = insert_children( | ||
479 | &rbrace.parent().unwrap(), | ||
480 | InsertPosition::Last, | ||
481 | &mut std::iter::once(space), | ||
482 | ); | ||
483 | |||
484 | // Token Tree now is : | ||
485 | // TokenTree | ||
486 | // - T!['{'] | ||
487 | // - T!['}'] | ||
488 | // - WHITE_SPACE | ||
489 | let token_tree = ast::TokenTree::cast(token_tree).unwrap(); | ||
490 | let tt = ast_to_token_tree(&token_tree).unwrap().0; | ||
491 | |||
492 | assert_eq!(tt.delimiter, tt::Delimiter::Brace); | ||
493 | } | ||
426 | } | 494 | } |