11
11
use ast;
12
12
use ast:: { MetaItem , Item , Expr , } ;
13
13
use codemap:: Span ;
14
- use ext:: format;
15
14
use ext:: base:: ExtCtxt ;
16
15
use ext:: build:: AstBuilder ;
17
16
use ext:: deriving:: generic:: * ;
18
17
use ext:: deriving:: generic:: ty:: * ;
19
18
use parse:: token;
20
19
use ptr:: P ;
21
20
22
- use std:: collections:: HashMap ;
23
-
24
21
pub fn expand_deriving_show < F > ( cx : & mut ExtCtxt ,
25
22
span : Span ,
26
23
mitem : & MetaItem ,
@@ -56,14 +53,12 @@ pub fn expand_deriving_show<F>(cx: &mut ExtCtxt,
56
53
trait_def. expand ( cx, mitem, item, push)
57
54
}
58
55
59
- /// We construct a format string and then defer to std::fmt, since that
60
- /// knows what's up with formatting and so on.
56
+ /// We use the debug builders to do the heavy lifting here
61
57
fn show_substructure ( cx : & mut ExtCtxt , span : Span ,
62
58
substr : & Substructure ) -> P < Expr > {
63
- // build `<name>`, `<name>({}, {}, ...)` or `<name> { <field>: {},
64
- // <field>: {}, ... }` based on the "shape".
65
- //
66
- // Easy start: they all start with the name.
59
+ // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
60
+ // or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
61
+ // based on the "shape".
67
62
let name = match * substr. fields {
68
63
Struct ( _) => substr. type_ident ,
69
64
EnumMatching ( _, v, _) => v. node . name ,
@@ -72,70 +67,53 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span,
72
67
}
73
68
} ;
74
69
75
- let mut format_string = String :: from_str ( & token:: get_ident ( name) ) ;
76
- // the internal fields we're actually formatting
77
- let mut exprs = Vec :: new ( ) ;
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 } ;
72
+ let name = cx. expr_lit ( span, ast:: Lit_ :: LitStr ( token:: get_ident ( name) ,
73
+ ast:: StrStyle :: CookedStr ) ) ;
74
+ let mut expr = substr. nonself_args [ 0 ] . clone ( ) ;
78
75
79
- // Getting harder... making the format string:
80
76
match * substr. fields {
81
- // unit struct/nullary variant: no work necessary!
82
- Struct ( ref fields) if fields. len ( ) == 0 => { }
83
- EnumMatching ( _, _, ref fields) if fields. len ( ) == 0 => { }
84
-
85
77
Struct ( ref fields) | EnumMatching ( _, _, ref fields) => {
86
- if fields[ 0 ] . name . is_none ( ) {
78
+ if fields. is_empty ( ) || fields [ 0 ] . name . is_none ( ) {
87
79
// tuple struct/"normal" variant
88
-
89
- format_string. push_str ( "(" ) ;
90
-
91
- for ( i, field) in fields. iter ( ) . enumerate ( ) {
92
- if i != 0 { format_string. push_str ( ", " ) ; }
93
-
94
- format_string. push_str ( "{:?}" ) ;
95
-
96
- exprs. push ( field. self_ . clone ( ) ) ;
80
+ expr = cx. expr_method_call ( span,
81
+ expr,
82
+ token:: str_to_ident ( "debug_tuple" ) ,
83
+ vec ! [ name] ) ;
84
+
85
+ for field in fields {
86
+ expr = cx. expr_method_call ( span,
87
+ expr,
88
+ token:: str_to_ident ( "field" ) ,
89
+ vec ! [ cx. expr_addr_of( field. span,
90
+ field. self_. clone( ) ) ] ) ;
97
91
}
98
-
99
- format_string. push_str ( ")" ) ;
100
92
} else {
101
93
// normal struct/struct variant
102
-
103
- format_string. push_str ( " {{" ) ;
104
-
105
- for ( i, field) in fields. iter ( ) . enumerate ( ) {
106
- if i != 0 { format_string. push_str ( "," ) ; }
107
-
108
- let name = token:: get_ident ( field. name . unwrap ( ) ) ;
109
- format_string. push_str ( " " ) ;
110
- format_string. push_str ( & name) ;
111
- format_string. push_str ( ": {:?}" ) ;
112
-
113
- exprs. push ( field. self_ . clone ( ) ) ;
94
+ expr = cx. expr_method_call ( span,
95
+ expr,
96
+ token:: str_to_ident ( "debug_struct" ) ,
97
+ vec ! [ name] ) ;
98
+
99
+ for field in fields {
100
+ let name = cx. expr_lit ( field. span , ast:: Lit_ :: LitStr (
101
+ token:: get_ident ( field. name . clone ( ) . unwrap ( ) ) ,
102
+ ast:: StrStyle :: CookedStr ) ) ;
103
+ expr = cx. expr_method_call ( span,
104
+ expr,
105
+ token:: str_to_ident ( "field" ) ,
106
+ vec ! [ name,
107
+ cx. expr_addr_of( field. span,
108
+ field. self_. clone( ) ) ] ) ;
114
109
}
115
-
116
- format_string. push_str ( " }}" ) ;
117
110
}
118
111
}
119
112
_ => unreachable ! ( )
120
113
}
121
114
122
- // AST construction!
123
- // we're basically calling
124
- //
125
- // format_arg_method!(fmt, write_fmt, "<format_string>", exprs...)
126
- //
127
- // but doing it directly via ext::format.
128
- let formatter = substr. nonself_args [ 0 ] . clone ( ) ;
129
-
130
- let meth = cx. ident_of ( "write_fmt" ) ;
131
- let s = token:: intern_and_get_ident ( & format_string[ ..] ) ;
132
- let format_string = cx. expr_str ( span, s) ;
133
-
134
- // phew, not our responsibility any more!
135
-
136
- let args = vec ! [
137
- format:: expand_preparsed_format_args( cx, span, format_string,
138
- exprs, vec![ ] , HashMap :: new( ) )
139
- ] ;
140
- cx. expr_method_call ( span, formatter, meth, args)
115
+ cx. expr_method_call ( span,
116
+ expr,
117
+ token:: str_to_ident ( "finish" ) ,
118
+ vec ! [ ] )
141
119
}
0 commit comments