]>
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 | ||
d9579d0f AL |
21 | pub fn expand_deriving_show(cx: &mut ExtCtxt, |
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(), | |
85aaf69f | 37 | methods: vec![ |
1a4d82fc JJ |
38 | MethodDef { |
39 | name: "fmt", | |
40 | generics: LifetimeBounds::empty(), | |
41 | explicit_self: borrowed_explicit_self(), | |
42 | args: vec!(fmtr), | |
85aaf69f | 43 | ret_ty: Literal(path_std!(cx, core::fmt::Result)), |
1a4d82fc | 44 | attributes: Vec::new(), |
62682a34 | 45 | is_unsafe: false, |
c34b1796 | 46 | combine_substructure: combine_substructure(Box::new(|a, b, c| { |
1a4d82fc | 47 | show_substructure(a, b, c) |
c34b1796 | 48 | })) |
1a4d82fc | 49 | } |
85aaf69f SL |
50 | ], |
51 | associated_types: Vec::new(), | |
1a4d82fc | 52 | }; |
62682a34 | 53 | trait_def.expand(cx, mitem, item, push) |
1a4d82fc JJ |
54 | } |
55 | ||
c34b1796 | 56 | /// We use the debug builders to do the heavy lifting here |
1a4d82fc JJ |
57 | fn show_substructure(cx: &mut ExtCtxt, span: Span, |
58 | substr: &Substructure) -> P<Expr> { | |
c34b1796 AL |
59 | // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build() |
60 | // or fmt.debug_tuple(<name>).field(&<fieldval>)....build() | |
61 | // based on the "shape". | |
c1a9b12d | 62 | let ident = match *substr.fields { |
1a4d82fc JJ |
63 | Struct(_) => substr.type_ident, |
64 | EnumMatching(_, v, _) => v.node.name, | |
65 | EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => { | |
85aaf69f | 66 | cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`") |
1a4d82fc JJ |
67 | } |
68 | }; | |
69 | ||
c34b1796 AL |
70 | // We want to make sure we have the expn_id set so that we can use unstable methods |
71 | let span = Span { expn_id: cx.backtrace(), .. span }; | |
c1a9b12d | 72 | let name = cx.expr_lit(span, ast::Lit_::LitStr(ident.name.as_str(), |
c34b1796 AL |
73 | ast::StrStyle::CookedStr)); |
74 | let mut expr = substr.nonself_args[0].clone(); | |
1a4d82fc | 75 | |
1a4d82fc | 76 | match *substr.fields { |
1a4d82fc | 77 | Struct(ref fields) | EnumMatching(_, _, ref fields) => { |
62682a34 | 78 | |
c34b1796 | 79 | if fields.is_empty() || fields[0].name.is_none() { |
1a4d82fc | 80 | // tuple struct/"normal" variant |
c34b1796 AL |
81 | expr = cx.expr_method_call(span, |
82 | expr, | |
83 | token::str_to_ident("debug_tuple"), | |
84 | vec![name]); | |
85 | ||
86 | for field in fields { | |
62682a34 SL |
87 | // Use double indirection to make sure this works for unsized types |
88 | let field = cx.expr_addr_of(field.span, field.self_.clone()); | |
89 | let field = cx.expr_addr_of(field.span, field); | |
90 | ||
c34b1796 AL |
91 | expr = cx.expr_method_call(span, |
92 | expr, | |
93 | token::str_to_ident("field"), | |
62682a34 | 94 | vec![field]); |
1a4d82fc | 95 | } |
1a4d82fc JJ |
96 | } else { |
97 | // normal struct/struct variant | |
c34b1796 AL |
98 | expr = cx.expr_method_call(span, |
99 | expr, | |
100 | token::str_to_ident("debug_struct"), | |
101 | vec![name]); | |
102 | ||
103 | for field in fields { | |
104 | let name = cx.expr_lit(field.span, ast::Lit_::LitStr( | |
c1a9b12d | 105 | field.name.unwrap().name.as_str(), |
c34b1796 | 106 | ast::StrStyle::CookedStr)); |
62682a34 SL |
107 | |
108 | // Use double indirection to make sure this works for unsized types | |
109 | let field = cx.expr_addr_of(field.span, field.self_.clone()); | |
110 | let field = cx.expr_addr_of(field.span, field); | |
c34b1796 AL |
111 | expr = cx.expr_method_call(span, |
112 | expr, | |
113 | token::str_to_ident("field"), | |
62682a34 | 114 | vec![name, field]); |
1a4d82fc | 115 | } |
1a4d82fc JJ |
116 | } |
117 | } | |
118 | _ => unreachable!() | |
119 | } | |
120 | ||
c34b1796 AL |
121 | cx.expr_method_call(span, |
122 | expr, | |
123 | token::str_to_ident("finish"), | |
124 | vec![]) | |
1a4d82fc | 125 | } |