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

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 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 ast;
  13  use codemap::Span;
  14  use ext::base::ExtCtxt;
  15  use ext::build::AstBuilder;
  16  use ext::deriving::generic::*;
  17  use parse::token::InternedString;
  18  
  19  pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
  20                                        spanSpan,
  21                                        mitem: @MetaItem,
  22                                        item: @Item,
  23                                        push: |@Item|) {
  24      let inline = cx.meta_word(span, InternedString::new("inline"));
  25      let attrs = vec!(cx.attribute(span, inline));
  26      let trait_def = TraitDef {
  27          span: span,
  28          attributes: Vec::new(),
  29          path: Path::new(vec!("std", "num", "FromPrimitive")),
  30          additional_bounds: Vec::new(),
  31          generics: LifetimeBounds::empty(),
  32          methods: vec!(
  33              MethodDef {
  34                  name: "from_i64",
  35                  generics: LifetimeBounds::empty(),
  36                  explicit_self: None,
  37                  args: vec!(
  38                      Literal(Path::new(vec!("i64")))),
  39                  ret_ty: Literal(Path::new_(vec!("std", "option", "Option"),
  40                                             None,
  41                                             vec!(box Self),
  42                                             true)),
  43                  // #[inline] liable to cause code-bloat
  44                  attributes: attrs.clone(),
  45                  const_nonmatching: false,
  46                  combine_substructure: combine_substructure(|c, s, sub| {
  47                      cs_from("i64", c, s, sub)
  48                  }),
  49              },
  50              MethodDef {
  51                  name: "from_u64",
  52                  generics: LifetimeBounds::empty(),
  53                  explicit_self: None,
  54                  args: vec!(
  55                      Literal(Path::new(vec!("u64")))),
  56                  ret_ty: Literal(Path::new_(vec!("std", "option", "Option"),
  57                                             None,
  58                                             vec!(box Self),
  59                                             true)),
  60                  // #[inline] liable to cause code-bloat
  61                  attributes: attrs,
  62                  const_nonmatching: false,
  63                  combine_substructure: combine_substructure(|c, s, sub| {
  64                      cs_from("u64", c, s, sub)
  65                  }),
  66              })
  67      };
  68  
  69      trait_def.expand(cx, mitem, item, push)
  70  }
  71  
  72  fn cs_from(name: &str, cx: &mut ExtCtxt, trait_spanSpan, substr: &Substructure) -> @Expr {
  73      let n = match substr.nonself_args {
  74          [n] => n,
  75          _ => cx.span_bug(trait_span, "incorrect number of arguments in `deriving(FromPrimitive)`")
  76      };
  77  
  78      match *substr.fields {
  79          StaticStruct(..) => {
  80              cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs");
  81              return cx.expr_fail(trait_span, InternedString::new(""));
  82          }
  83          StaticEnum(enum_def, _) => {
  84              if enum_def.variants.is_empty() {
  85                  cx.span_err(trait_span,
  86                              "`FromPrimitive` cannot be derived for enums with no variants");
  87                  return cx.expr_fail(trait_span, InternedString::new(""));
  88              }
  89  
  90              let mut arms = Vec::new();
  91  
  92              for variant in enum_def.variants.iter() {
  93                  match variant.node.kind {
  94                      ast::TupleVariantKind(ref args) => {
  95                          if !args.is_empty() {
  96                              cx.span_err(trait_span,
  97                                          "`FromPrimitive` cannot be derived for \
  98                                          enum variants with arguments");
  99                              return cx.expr_fail(trait_span,
 100                                                  InternedString::new(""));
 101                          }
 102                          let span = variant.span;
 103  
 104                          // expr for `$n == $variant as $name`
 105                          let variant = cx.expr_ident(span, variant.node.name);
 106                          let ty = cx.ty_ident(span, cx.ident_of(name));
 107                          let cast = cx.expr_cast(span, variant, ty);
 108                          let guard = cx.expr_binary(span, ast::BiEq, n, cast);
 109  
 110                          // expr for `Some($variant)`
 111                          let body = cx.expr_some(span, variant);
 112  
 113                          // arm for `_ if $guard => $body`
 114                          let arm = ast::Arm {
 115                              attrs: vec!(),
 116                              pats: vec!(cx.pat_wild(span)),
 117                              guard: Some(guard),
 118                              body: body,
 119                          };
 120  
 121                          arms.push(arm);
 122                      }
 123                      ast::StructVariantKind(_) => {
 124                          cx.span_err(trait_span,
 125                                      "`FromPrimitive` cannot be derived for enums \
 126                                      with struct variants");
 127                          return cx.expr_fail(trait_span,
 128                                              InternedString::new(""));
 129                      }
 130                  }
 131              }
 132  
 133              // arm for `_ => None`
 134              let arm = ast::Arm {
 135                  attrs: vec!(),
 136                  pats: vec!(cx.pat_wild(trait_span)),
 137                  guard: None,
 138                  body: cx.expr_none(trait_span),
 139              };
 140              arms.push(arm);
 141  
 142              cx.expr_match(trait_span, n, arms)
 143          }
 144          _ => cx.span_bug(trait_span, "expected StaticEnum in deriving(FromPrimitive)")
 145      }
 146  }