diff options
Diffstat (limited to 'crates/ra_mbe')
| -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 | } |
