]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use ast; | |
d9579d0f | 12 | use ast::{MetaItem, Expr,}; |
1a4d82fc | 13 | use codemap::Span; |
d9579d0f | 14 | use ext::base::{ExtCtxt, Annotatable}; |
1a4d82fc JJ |
15 | use ext::build::AstBuilder; |
16 | use ext::deriving::generic::*; | |
17 | use ext::deriving::generic::ty::*; | |
18 | use parse::token; | |
19 | use ptr::P; | |
20 | ||
b039eaaf | 21 | pub fn expand_deriving_debug(cx: &mut ExtCtxt, |
d9579d0f AL |
22 | span: Span, |
23 | mitem: &MetaItem, | |
62682a34 | 24 | item: &Annotatable, |
d9579d0f | 25 | push: &mut FnMut(Annotatable)) |
1a4d82fc JJ |
26 | { |
27 | // &mut ::std::fmt::Formatter | |
d9579d0f | 28 | let fmtr = Ptr(Box::new(Literal(path_std!(cx, core::fmt::Formatter))), |
1a4d82fc JJ |
29 | Borrowed(None, ast::MutMutable)); |
30 | ||
31 | let trait_def = TraitDef { | |
32 | span: span, | |
33 | attributes: Vec::new(), | |
85aaf69f | 34 | path: path_std!(cx, core::fmt::Debug), |
1a4d82fc JJ |
35 | additional_bounds: Vec::new(), |
36 | generics: LifetimeBounds::empty(), | |
e9174d1e | 37 | is_unsafe: false, |
85aaf69f | 38 | methods: vec![ |
1a4d82fc JJ |
39 | MethodDef { |
40 | name: "fmt", | |
41 | generics: LifetimeBounds::empty(), | |
42 | explicit_self: borrowed_explicit_self(), | |
43 | args: vec!(fmtr), | |
85aaf69f | 44 | ret_ty: Literal(path_std!(cx, core::fmt::Result)), |
1a4d82fc | 45 | attributes: Vec::new(), |
62682a34 | 46 | is_unsafe: false, |
c34b1796 | 47 | combine_substructure: combine_substructure(Box::new(|a, b, c| { |
1a4d82fc | 48 | show_substructure(a, b, c) |
c34b1796 | 49 | })) |
1a4d82fc | 50 | } |
85aaf69f SL |
51 | ], |
52 | associated_types: Vec::new(), | |
1a4d82fc | 53 | }; |
62682a34 | 54 | trait_def.expand(cx, mitem, item, push) |
1a4d82fc JJ |
55 | } |
56 | ||
c34b1796 | 57 | /// We use the debug builders to do the heavy lifting here |
1a4d82fc JJ |
58 | fn show_substructure(cx: &mut ExtCtxt, span: Span, |
59 | substr: &Substructure) -> P<Expr> { | |
c34b1796 AL |
60 | // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build() |
61 | // or fmt.debug_tuple(<name>).field(&<fieldval>)....build() | |
62 | // based on the "shape". | |
c1a9b12d | 63 | let ident = match *substr.fields { |
1a4d82fc JJ |
64 | Struct(_) => substr.type_ident, |
65 | EnumMatching(_, v, _) => v.node.name, | |
66 | EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { | |
85aaf69f | 67 | cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") |
1a4d82fc JJ |
68 | } |
69 | }; | |
70 | ||
c34b1796 AL |
71 | // We want to make sure we have the expn_id set so that we can use unstable methods |
72 | let span = Span { expn_id: cx.backtrace(), .. span }; | |
c1a9b12d | 73 | let name = cx.expr_lit(span, ast::Lit_::LitStr(ident.name.as_str(), |
c34b1796 AL |
74 | ast::StrStyle::CookedStr)); |
75 | let mut expr = substr.nonself_args[0].clone(); | |
1a4d82fc | 76 | |
1a4d82fc | 77 | match *substr.fields { |
1a4d82fc | 78 | Struct(ref fields) | EnumMatching(_, _, ref fields) => { |
62682a34 | 79 | |
c34b1796 | 80 | if fields.is_empty() || fields[0].name.is_none() { |
1a4d82fc | 81 | // tuple struct/"normal" variant |
c34b1796 AL |
82 | expr = cx.expr_method_call(span, |
83 | expr, | |
84 | token::str_to_ident("debug_tuple"), | |
85 | vec![name]); | |
86 | ||
87 | for field in fields { | |
62682a34 SL |
88 | // Use double indirection to make sure this works for unsized types |
89 | let field = cx.expr_addr_of(field.span, field.self_.clone()); | |
90 | let field = cx.expr_addr_of(field.span, field); | |
91 | ||
c34b1796 AL |
92 | expr = cx.expr_method_call(span, |
93 | expr, | |
94 | token::str_to_ident("field"), | |
62682a34 | 95 | vec![field]); |
1a4d82fc | 96 | } |
1a4d82fc JJ |
97 | } else { |
98 | // normal struct/struct variant | |
c34b1796 AL |
99 | expr = cx.expr_method_call(span, |
100 | expr, | |
101 | token::str_to_ident("debug_struct"), | |
102 | vec![name]); | |
103 | ||
104 | for field in fields { | |
105 | let name = cx.expr_lit(field.span, ast::Lit_::LitStr( | |
c1a9b12d | 106 | field.name.unwrap().name.as_str(), |
c34b1796 | 107 | ast::StrStyle::CookedStr)); |
62682a34 SL |
108 | |
109 | // Use double indirection to make sure this works for unsized types | |
110 | let field = cx.expr_addr_of(field.span, field.self_.clone()); | |
111 | let field = cx.expr_addr_of(field.span, field); | |
c34b1796 AL |
112 | expr = cx.expr_method_call(span, |
113 | expr, | |
114 | token::str_to_ident("field"), | |
62682a34 | 115 | vec![name, field]); |
1a4d82fc | 116 | } |
1a4d82fc JJ |
117 | } |
118 | } | |
119 | _ => unreachable!() | |
120 | } | |
121 | ||
c34b1796 AL |
122 | cx.expr_method_call(span, |
123 | expr, | |
124 | token::str_to_ident("finish"), | |
125 | vec![]) | |
1a4d82fc | 126 | } |