From bd6ed22fdf3df4e47d418487320a47d308c4477e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 7 Mar 2015 19:36:36 -0800 Subject: Switch derive(Debug) to use the debug builders --- src/libsyntax/ext/deriving/show.rs | 102 +++++++++++++++---------------------- src/libsyntax/ext/expand.rs | 2 +- 2 files changed, 41 insertions(+), 63 deletions(-) (limited to 'src/libsyntax/ext') diff --git a/src/libsyntax/ext/deriving/show.rs b/src/libsyntax/ext/deriving/show.rs index ce89c541fd4..ae9a4020060 100644 --- a/src/libsyntax/ext/deriving/show.rs +++ b/src/libsyntax/ext/deriving/show.rs @@ -11,7 +11,6 @@ use ast; use ast::{MetaItem, Item, Expr,}; use codemap::Span; -use ext::format; use ext::base::ExtCtxt; use ext::build::AstBuilder; use ext::deriving::generic::*; @@ -19,8 +18,6 @@ use ext::deriving::generic::ty::*; use parse::token; use ptr::P; -use std::collections::HashMap; - pub fn expand_deriving_show(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, @@ -56,14 +53,12 @@ pub fn expand_deriving_show(cx: &mut ExtCtxt, trait_def.expand(cx, mitem, item, push) } -/// We construct a format string and then defer to std::fmt, since that -/// knows what's up with formatting and so on. +/// We use the debug builders to do the heavy lifting here fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - // build ``, `({}, {}, ...)` or ` { : {}, - // : {}, ... }` based on the "shape". - // - // Easy start: they all start with the name. + // build fmt.debug_struct().field(, &)....build() + // or fmt.debug_tuple().field(&)....build() + // based on the "shape". let name = match *substr.fields { Struct(_) => substr.type_ident, EnumMatching(_, v, _) => v.node.name, @@ -72,70 +67,53 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, } }; - let mut format_string = String::from_str(&token::get_ident(name)); - // the internal fields we're actually formatting - let mut exprs = Vec::new(); + // We want to make sure we have the expn_id set so that we can use unstable methods + let span = Span { expn_id: cx.backtrace(), .. span }; + let name = cx.expr_lit(span, ast::Lit_::LitStr(token::get_ident(name), + ast::StrStyle::CookedStr)); + let mut expr = substr.nonself_args[0].clone(); - // Getting harder... making the format string: match *substr.fields { - // unit struct/nullary variant: no work necessary! - Struct(ref fields) if fields.len() == 0 => {} - EnumMatching(_, _, ref fields) if fields.len() == 0 => {} - Struct(ref fields) | EnumMatching(_, _, ref fields) => { - if fields[0].name.is_none() { + if fields.is_empty() || fields[0].name.is_none() { // tuple struct/"normal" variant - - format_string.push_str("("); - - for (i, field) in fields.iter().enumerate() { - if i != 0 { format_string.push_str(", "); } - - format_string.push_str("{:?}"); - - exprs.push(field.self_.clone()); + expr = cx.expr_method_call(span, + expr, + token::str_to_ident("debug_tuple"), + vec![name]); + + for field in fields { + expr = cx.expr_method_call(span, + expr, + token::str_to_ident("field"), + vec![cx.expr_addr_of(field.span, + field.self_.clone())]); } - - format_string.push_str(")"); } else { // normal struct/struct variant - - format_string.push_str(" {{"); - - for (i, field) in fields.iter().enumerate() { - if i != 0 { format_string.push_str(","); } - - let name = token::get_ident(field.name.unwrap()); - format_string.push_str(" "); - format_string.push_str(&name); - format_string.push_str(": {:?}"); - - exprs.push(field.self_.clone()); + expr = cx.expr_method_call(span, + expr, + token::str_to_ident("debug_struct"), + vec![name]); + + for field in fields { + let name = cx.expr_lit(field.span, ast::Lit_::LitStr( + token::get_ident(field.name.clone().unwrap()), + ast::StrStyle::CookedStr)); + expr = cx.expr_method_call(span, + expr, + token::str_to_ident("field"), + vec![name, + cx.expr_addr_of(field.span, + field.self_.clone())]); } - - format_string.push_str(" }}"); } } _ => unreachable!() } - // AST construction! - // we're basically calling - // - // format_arg_method!(fmt, write_fmt, "", exprs...) - // - // but doing it directly via ext::format. - let formatter = substr.nonself_args[0].clone(); - - let meth = cx.ident_of("write_fmt"); - let s = token::intern_and_get_ident(&format_string[..]); - let format_string = cx.expr_str(span, s); - - // phew, not our responsibility any more! - - let args = vec![ - format::expand_preparsed_format_args(cx, span, format_string, - exprs, vec![], HashMap::new()) - ]; - cx.expr_method_call(span, formatter, meth, args) + cx.expr_method_call(span, + expr, + token::str_to_ident("finish"), + vec![]) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 98c7aefcd8a..6883395933e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1121,7 +1121,7 @@ fn expand_annotatable(a: Annotatable, callee: NameAndSpan { name: mname.to_string(), format: MacroAttribute, - span: None, + span: Some(attr.span), // attributes can do whatever they like, // for now. allow_internal_unstable: true, -- cgit 1.4.1-3-g733a5