(index<- )        ./libsyntax/ext/deriving/clone.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri Apr 25 22:40:04 2014
   1  // Copyright 2012-2013 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::{MetaItem, Item, Expr};
  12  use codemap::Span;
  13  use ext::base::ExtCtxt;
  14  use ext::build::AstBuilder;
  15  use ext::deriving::generic::*;
  16  use parse::token::InternedString;
  17  
  18  pub fn expand_deriving_clone(cx: &mut ExtCtxt,
  19                               spanSpan,
  20                               mitem: @MetaItem,
  21                               item: @Item,
  22                               push: |@Item|) {
  23      let inline = cx.meta_word(span, InternedString::new("inline"));
  24      let attrs = vec!(cx.attribute(span, inline));
  25      let trait_def = TraitDef {
  26          span: span,
  27          attributes: Vec::new(),
  28          path: Path::new(vec!("std", "clone", "Clone")),
  29          additional_bounds: Vec::new(),
  30          generics: LifetimeBounds::empty(),
  31          methods: vec!(
  32              MethodDef {
  33                  name: "clone",
  34                  generics: LifetimeBounds::empty(),
  35                  explicit_self: borrowed_explicit_self(),
  36                  args: Vec::new(),
  37                  ret_ty: Self,
  38                  attributes: attrs,
  39                  const_nonmatching: false,
  40                  combine_substructure: combine_substructure(|c, s, sub| {
  41                      cs_clone("Clone", c, s, sub)
  42                  }),
  43              }
  44          )
  45      };
  46  
  47      trait_def.expand(cx, mitem, item, push)
  48  }
  49  
  50  fn cs_clone(
  51      name: &str,
  52      cx: &mut ExtCtxt, trait_spanSpan,
  53      substr: &Substructure) -> @Expr {
  54      let clone_ident = substr.method_ident;
  55      let ctor_ident;
  56      let all_fields;
  57      let subcall = |field&FieldInfo|
  58          cx.expr_method_call(field.span, field.self_, clone_ident, Vec::new());
  59  
  60      match *substr.fields {
  61          Struct(ref af) => {
  62              ctor_ident = substr.type_ident;
  63              all_fields = af;
  64          }
  65          EnumMatching(_, variant, ref af) => {
  66              ctor_ident = variant.node.name;
  67              all_fields = af;
  68          },
  69          EnumNonMatching(..) => cx.span_bug(trait_span,
  70                                             format!("non-matching enum variants in `deriving({})`",
  71                                                    name)),
  72          StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span,
  73                                                           format!("static method in `deriving({})`",
  74                                                                   name))
  75      }
  76  
  77      if all_fields.len() >= 1 && all_fields.get(0).name.is_none() {
  78          // enum-like
  79          let subcalls = all_fields.iter().map(subcall).collect();
  80          cx.expr_call_ident(trait_span, ctor_ident, subcalls)
  81      } else {
  82          // struct-like
  83          let fields = all_fields.iter().map(|field| {
  84              let ident = match field.name {
  85                  Some(i) => i,
  86                  None => cx.span_bug(trait_span,
  87                                      format!("unnamed field in normal struct in `deriving({})`",
  88                                              name))
  89              };
  90              cx.field_imm(field.span, ident, subcall(field))
  91          }).collect::<Vec<_>>();
  92  
  93          if fields.is_empty() {
  94              // no fields, so construct like `None`
  95              cx.expr_ident(trait_span, ctor_ident)
  96          } else {
  97              cx.expr_struct_ident(trait_span, ctor_ident, fields)
  98          }
  99      }
 100  }