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.
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.
12 use ast::{MetaItem, Item, Expr,};
15 use ext::base::ExtCtxt;
16 use ext::build::AstBuilder;
17 use ext::deriving::generic::*;
18 use ext::deriving::generic::ty::*;
22 use std::collections::HashMap;
24 pub fn expand_deriving_show<F>(cx: &mut ExtCtxt,
31 // &mut ::std::fmt::Formatter
32 let fmtr = Ptr(box Literal(Path::new(vec!("std", "fmt", "Formatter"))),
33 Borrowed(None, ast::MutMutable));
35 let trait_def = TraitDef {
37 attributes: Vec::new(),
38 path: Path::new(vec!("std", "fmt", "Show")),
39 additional_bounds: Vec::new(),
40 generics: LifetimeBounds::empty(),
44 generics: LifetimeBounds::empty(),
45 explicit_self: borrowed_explicit_self(),
47 ret_ty: Literal(Path::new(vec!("std", "fmt", "Result"))),
48 attributes: Vec::new(),
49 combine_substructure: combine_substructure(|a, b, c| {
50 show_substructure(a, b, c)
55 trait_def.expand(cx, mitem, item, push)
58 /// We construct a format string and then defer to std::fmt, since that
59 /// knows what's up with formatting and so on.
60 fn show_substructure(cx: &mut ExtCtxt, span: Span,
61 substr: &Substructure) -> P<Expr> {
62 // build `<name>`, `<name>({}, {}, ...)` or `<name> { <field>: {},
63 // <field>: {}, ... }` based on the "shape".
65 // Easy start: they all start with the name.
66 let name = match *substr.fields {
67 Struct(_) => substr.type_ident,
68 EnumMatching(_, v, _) => v.node.name,
69 EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
70 cx.span_bug(span, "nonsensical .fields in `#[deriving(Show)]`")
74 let mut format_string = String::from_str(token::get_ident(name).get());
75 // the internal fields we're actually formatting
76 let mut exprs = Vec::new();
78 // Getting harder... making the format string:
79 match *substr.fields {
80 // unit struct/nullary variant: no work necessary!
81 Struct(ref fields) if fields.len() == 0 => {}
82 EnumMatching(_, _, ref fields) if fields.len() == 0 => {}
84 Struct(ref fields) | EnumMatching(_, _, ref fields) => {
85 if fields[0].name.is_none() {
86 // tuple struct/"normal" variant
88 format_string.push_str("(");
90 for (i, field) in fields.iter().enumerate() {
91 if i != 0 { format_string.push_str(", "); }
93 format_string.push_str("{}");
95 exprs.push(field.self_.clone());
98 format_string.push_str(")");
100 // normal struct/struct variant
102 format_string.push_str(" {{");
104 for (i, field) in fields.iter().enumerate() {
105 if i != 0 { format_string.push_str(","); }
107 let name = token::get_ident(field.name.unwrap());
108 format_string.push_str(" ");
109 format_string.push_str(name.get());
110 format_string.push_str(": {}");
112 exprs.push(field.self_.clone());
115 format_string.push_str(" }}");
122 // we're basically calling
124 // format_arg_method!(fmt, write_fmt, "<format_string>", exprs...)
126 // but doing it directly via ext::format.
127 let formatter = substr.nonself_args[0].clone();
129 let meth = cx.ident_of("write_fmt");
130 let s = token::intern_and_get_ident(format_string[]);
131 let format_string = cx.expr_str(span, s);
133 // phew, not our responsibility any more!
136 format::expand_preparsed_format_args(cx, span, format_string,
137 exprs, vec![], HashMap::new())
139 cx.expr_method_call(span, formatter, meth, args)