From 19d952c603344d853567aeac42dcfa6fe40ba04b Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Thu, 9 Apr 2020 23:48:08 +0800 Subject: [PATCH] Improve tt::Subtree debug print --- crates/ra_hir_expand/src/quote.rs | 2 +- crates/ra_mbe/src/tests.rs | 79 +++++++++++++++++++++++++++++++ crates/ra_tt/src/lib.rs | 57 +++++++++++++++++++++- 3 files changed, 136 insertions(+), 2 deletions(-) diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs index 3fd4233da8..219bc20978 100644 --- a/crates/ra_hir_expand/src/quote.rs +++ b/crates/ra_hir_expand/src/quote.rs @@ -232,7 +232,7 @@ mod tests { let quoted = quote!(#a); assert_eq!(quoted.to_string(), "hello"); let t = format!("{:?}", quoted); - assert_eq!(t, "Subtree { delimiter: None, token_trees: [Leaf(Ident(Ident { text: \"hello\", id: TokenId(4294967295) }))] }"); + assert_eq!(t, "SUBTREE $\n IDENT hello 4294967295"); } #[test] diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index 254318e239..1ef6f6eedd 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs @@ -141,6 +141,79 @@ macro_rules! impl_froms { ); } +#[test] +fn test_convert_tt2() { + parse_macro( + r#" +macro_rules! impl_froms { + ($e:ident: $($v:ident),*) => { + $( + impl From<$v> for $e { + fn from(it: $v) -> $e { + $e::$v(it) + } + } + )* + } +} +"#, + ) + .assert_expand( + "impl_froms!(TokenTree: Leaf, Subtree);", + r#" +SUBTREE $ + IDENT impl 20 + IDENT From 21 + PUNCH < [joint] 22 + IDENT Leaf 53 + PUNCH > [alone] 25 + IDENT for 26 + IDENT TokenTree 51 + SUBTREE {} 29 + IDENT fn 30 + IDENT from 31 + SUBTREE () 32 + IDENT it 33 + PUNCH : [alone] 34 + IDENT Leaf 53 + PUNCH - [joint] 37 + PUNCH > [alone] 38 + IDENT TokenTree 51 + SUBTREE {} 41 + IDENT TokenTree 51 + PUNCH : [joint] 44 + PUNCH : [joint] 45 + IDENT Leaf 53 + SUBTREE () 48 + IDENT it 49 + IDENT impl 20 + IDENT From 21 + PUNCH < [joint] 22 + IDENT Subtree 55 + PUNCH > [alone] 25 + IDENT for 26 + IDENT TokenTree 51 + SUBTREE {} 29 + IDENT fn 30 + IDENT from 31 + SUBTREE () 32 + IDENT it 33 + PUNCH : [alone] 34 + IDENT Subtree 55 + PUNCH - [joint] 37 + PUNCH > [alone] 38 + IDENT TokenTree 51 + SUBTREE {} 41 + IDENT TokenTree 51 + PUNCH : [joint] 44 + PUNCH : [joint] 45 + IDENT Subtree 55 + SUBTREE () 48 + IDENT it 49 +"#, + ); +} + #[test] fn test_expr_order() { let expanded = parse_macro( @@ -1479,6 +1552,12 @@ impl MacroFixture { assert_eq!(expansion.to_string(), expected); } + fn assert_expand(&self, invocation: &str, expected: &str) { + let expansion = self.expand_tt(invocation); + let actual = format!("{:?}", expansion); + test_utils::assert_eq_text!(&actual.trim(), &expected.trim()); + } + fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture { self.assert_expansion(FragmentKind::Items, invocation, expected); self diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs index bd484aa30a..5248e026c5 100644 --- a/crates/ra_tt/src/lib.rs +++ b/crates/ra_tt/src/lib.rs @@ -57,7 +57,7 @@ pub enum Leaf { } impl_froms!(Leaf: Literal, Punct, Ident); -#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +#[derive(Clone, PartialEq, Eq, Hash, Default)] pub struct Subtree { pub delimiter: Option, pub token_trees: Vec, @@ -101,6 +101,61 @@ pub struct Ident { pub id: TokenId, } +fn print_debug_subtree(f: &mut fmt::Formatter<'_>, subtree: &Subtree, level: usize) -> fmt::Result { + let align = std::iter::repeat(" ").take(level).collect::(); + + let aux = match subtree.delimiter.map(|it| (it.kind, it.id.0)) { + None => "$".to_string(), + Some((DelimiterKind::Parenthesis, id)) => format!("() {}", id), + Some((DelimiterKind::Brace, id)) => format!("{{}} {}", id), + Some((DelimiterKind::Bracket, id)) => format!("[] {}", id), + }; + + if subtree.token_trees.is_empty() { + write!(f, "{}SUBTREE {}", align, aux)?; + } else { + writeln!(f, "{}SUBTREE {}", align, aux)?; + for (idx, child) in subtree.token_trees.iter().enumerate() { + print_debug_token(f, child, level + 1)?; + if idx != subtree.token_trees.len() - 1 { + writeln!(f, "")?; + } + } + } + + Ok(()) +} + +fn print_debug_token(f: &mut fmt::Formatter<'_>, tkn: &TokenTree, level: usize) -> fmt::Result { + let align = std::iter::repeat(" ").take(level).collect::(); + + match tkn { + TokenTree::Leaf(leaf) => match leaf { + Leaf::Literal(lit) => write!(f, "{}LITERAL {} {}", align, lit.text, lit.id.0)?, + Leaf::Punct(punct) => write!( + f, + "{}PUNCH {} [{}] {}", + align, + punct.char, + if punct.spacing == Spacing::Alone { "alone" } else { "joint" }, + punct.id.0 + )?, + Leaf::Ident(ident) => write!(f, "{}IDENT {} {}", align, ident.text, ident.id.0)?, + }, + TokenTree::Subtree(subtree) => { + print_debug_subtree(f, subtree, level)?; + } + } + + Ok(()) +} + +impl Debug for Subtree { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + print_debug_subtree(f, self, 0) + } +} + impl fmt::Display for TokenTree { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self {