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::*;
21 use std::hashmap::HashMap;
23 pub fn expand_deriving_show(cx: &mut ExtCtxt,
28 // &mut ::std::fmt::Formatter
29 let fmtr = Ptr(~Literal(Path::new(~["std", "fmt", "Formatter"])),
30 Borrowed(None, ast::MutMutable));
32 let trait_def = TraitDef {
35 path: Path::new(~["std", "fmt", "Show"]),
36 additional_bounds: ~[],
37 generics: LifetimeBounds::empty(),
41 generics: LifetimeBounds::empty(),
42 explicit_self: borrowed_explicit_self(),
44 ret_ty: Literal(Path::new(~["std", "fmt", "Result"])),
46 const_nonmatching: false,
47 combine_substructure: show_substructure
51 trait_def.expand(mitem, in_items)
54 // we construct a format string and then defer to std::fmt, since that
55 // knows what's up with formatting at so on.
56 fn show_substructure(cx: &mut ExtCtxt, span: Span,
57 substr: &Substructure) -> @Expr {
58 // build `<name>`, `<name>({}, {}, ...)` or `<name> { <field>: {},
59 // <field>: {}, ... }` based on the "shape".
61 // Easy start: they all start with the name.
62 let name = match *substr.fields {
63 Struct(_) => substr.type_ident,
64 EnumMatching(_, v, _) => v.node.name,
66 EnumNonMatching(..) | StaticStruct(..) | StaticEnum(..) => {
67 cx.span_bug(span, "nonsensical .fields in `#[deriving(Show)]`")
71 let mut format_string = token::get_ident(name.name).get().to_owned();
72 // the internal fields we're actually formatting
75 // Getting harder... making the format string:
76 match *substr.fields {
77 // unit struct/nullary variant: no work necessary!
78 Struct([]) | EnumMatching(_, _, []) => {}
80 Struct(ref fields) | EnumMatching(_, _, ref fields) => {
81 if fields[0].name.is_none() {
82 // tuple struct/"normal" variant
84 format_string.push_str("(");
86 for (i, field) in fields.iter().enumerate() {
87 if i != 0 { format_string.push_str(", "); }
89 format_string.push_str("{}");
91 exprs.push(field.self_);
94 format_string.push_str(")");
96 // normal struct/struct variant
98 format_string.push_str(" \\{");
100 for (i, field) in fields.iter().enumerate() {
101 if i != 0 { format_string.push_str(","); }
103 let name = token::get_ident(field.name.unwrap().name);
104 format_string.push_str(" ");
105 format_string.push_str(name.get());
106 format_string.push_str(": {}");
108 exprs.push(field.self_);
111 format_string.push_str(" \\}");
118 // we're basically calling
120 // format_arg!(|__args| ::std::fmt::write(fmt.buf, __args), "<format_string>", exprs...)
122 // but doing it directly via ext::format.
123 let formatter = substr.nonself_args[0];
124 let buf = cx.expr_field_access(span, formatter, cx.ident_of("buf"));
126 let std_write = ~[cx.ident_of("std"), cx.ident_of("fmt"), cx.ident_of("write")];
127 let args = cx.ident_of("__args");
128 let write_call = cx.expr_call_global(span, std_write, ~[buf, cx.expr_ident(span, args)]);
129 let format_closure = cx.lambda_expr(span, ~[args], write_call);
131 let s = token::intern_and_get_ident(format_string);
132 let format_string = cx.expr_str(span, s);
134 // phew, not our responsibility any more!
135 format::expand_preparsed_format_args(cx, span,
137 format_string, exprs, HashMap::new())