about summary refs log tree commit diff
path: root/src/libsyntax/ext
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-06-22 17:13:51 -0700
committerbors <bors@rust-lang.org>2013-06-22 17:13:51 -0700
commitfc83d82fec5bc338ffa4aaf00ca2aef6bfd473a4 (patch)
treeefbdac2a1b9c2f2f29551d33f8cc5dc61f4e565b /src/libsyntax/ext
parent0739c6b5a00372e6c7ed2f9bdafea8a8c0e383a6 (diff)
parent30d755957a0f2cc3be3b355671da79cdf34fd50a (diff)
downloadrust-fc83d82fec5bc338ffa4aaf00ca2aef6bfd473a4.tar.gz
rust-fc83d82fec5bc338ffa4aaf00ca2aef6bfd473a4.zip
auto merge of #7204 : alexcrichton/rust/deriving-to-string, r=pcwalton
Closes #7180 and #7179.

Before, the `deriving(ToStr)` attribute was essentially `fmt!("%?")`. This changes it to recursively invoke `to_str()` on fields instead of relying on `fmt!`-style things. This seems more natural to me and what should actually be expected.
Diffstat (limited to 'src/libsyntax/ext')
-rw-r--r--src/libsyntax/ext/deriving/to_str.rs75
1 files changed, 64 insertions, 11 deletions
diff --git a/src/libsyntax/ext/deriving/to_str.rs b/src/libsyntax/ext/deriving/to_str.rs
index 41be3a775c1..4cd168b12c0 100644
--- a/src/libsyntax/ext/deriving/to_str.rs
+++ b/src/libsyntax/ext/deriving/to_str.rs
@@ -10,6 +10,7 @@
 
 use core::prelude::*;
 
+use ast;
 use ast::{meta_item, item, expr};
 use codemap::span;
 use ext::base::ExtCtxt;
@@ -40,16 +41,68 @@ pub fn expand_deriving_to_str(cx: @ExtCtxt,
     trait_def.expand(cx, span, mitem, in_items)
 }
 
-fn to_str_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr {
-    match substr.self_args {
-        [self_obj] => {
-            let self_addr = cx.expr_addr_of(span, self_obj);
-            cx.expr_call_global(span,
-                                ~[cx.ident_of("std"),
-                                  cx.ident_of("sys"),
-                                  cx.ident_of("log_str")],
-                                ~[self_addr])
+// It used to be the case that this deriving implementation invoked
+// std::sys::log_str, but this isn't sufficient because it doesn't invoke the
+// to_str() method on each field. Hence we mirror the logic of the log_str()
+// method, but with tweaks to call to_str() on sub-fields.
+fn to_str_substructure(cx: @ExtCtxt, span: span,
+                       substr: &Substructure) -> @expr {
+    let to_str = cx.ident_of("to_str");
+
+    let doit = |start: &str, end: @str, name: ast::ident,
+                fields: &[(Option<ast::ident>, @expr, ~[@expr])]| {
+        if fields.len() == 0 {
+            cx.expr_str_uniq(span, cx.str_of(name))
+        } else {
+            let buf = cx.ident_of("buf");
+            let start = cx.str_of(name) + start;
+            let init = cx.expr_str_uniq(span, start.to_managed());
+            let mut stmts = ~[cx.stmt_let(span, true, buf, init)];
+            let push_str = cx.ident_of("push_str");
+
+            let push = |s: @expr| {
+                let ebuf = cx.expr_ident(span, buf);
+                let call = cx.expr_method_call(span, ebuf, push_str, ~[s]);
+                stmts.push(cx.stmt_expr(call));
+            };
+
+            for fields.iter().enumerate().advance |(i, &(name, e, _))| {
+                if i > 0 {
+                    push(cx.expr_str(span, @", "));
+                }
+                match name {
+                    None => {}
+                    Some(id) => {
+                        let name = cx.str_of(id) + ": ";
+                        push(cx.expr_str(span, name.to_managed()));
+                    }
+                }
+                push(cx.expr_method_call(span, e, to_str, ~[]));
+            }
+            push(cx.expr_str(span, end));
+
+            cx.expr_blk(cx.blk(span, stmts, Some(cx.expr_ident(span, buf))))
+        }
+    };
+
+    return match *substr.fields {
+        Struct(ref fields) => {
+            if fields.len() == 0 || fields[0].n0_ref().is_none() {
+                doit("(", @")", substr.type_ident, *fields)
+            } else {
+                doit("{", @"}", substr.type_ident, *fields)
+            }
         }
-        _ => cx.span_bug(span, "Invalid number of arguments in `deriving(ToStr)`")
-    }
+
+        EnumMatching(_, variant, ref fields) => {
+            match variant.node.kind {
+                ast::tuple_variant_kind(*) =>
+                    doit("(", @")", variant.node.name, *fields),
+                ast::struct_variant_kind(*) =>
+                    doit("{", @"}", variant.node.name, *fields),
+            }
+        }
+
+        _ => cx.bug("expected Struct or EnumMatching in deriving(ToStr)")
+    };
 }