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.
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.
11 use ast::{MetaItem, Item, Expr};
14 use ext::base::ExtCtxt;
15 use ext::build::AstBuilder;
16 use ext::deriving::generic::*;
17 use ext::deriving::generic::ty::*;
18 use parse::token::InternedString;
21 pub fn expand_deriving_from_primitive<F>(cx: &mut ExtCtxt,
28 let inline = cx.meta_word(span, InternedString::new("inline"));
29 let attrs = vec!(cx.attribute(span, inline));
30 let trait_def = TraitDef {
32 attributes: Vec::new(),
33 path: Path::new(vec!("std", "num", "FromPrimitive")),
34 additional_bounds: Vec::new(),
35 generics: LifetimeBounds::empty(),
39 generics: LifetimeBounds::empty(),
42 Literal(Path::new(vec!("i64")))),
43 ret_ty: Literal(Path::new_(vec!("std", "option", "Option"),
47 // #[inline] liable to cause code-bloat
48 attributes: attrs.clone(),
49 combine_substructure: combine_substructure(box |c, s, sub| {
50 cs_from("i64", c, s, sub)
55 generics: LifetimeBounds::empty(),
58 Literal(Path::new(vec!("u64")))),
59 ret_ty: Literal(Path::new_(vec!("std", "option", "Option"),
63 // #[inline] liable to cause code-bloat
65 combine_substructure: combine_substructure(box |c, s, sub| {
66 cs_from("u64", c, s, sub)
71 trait_def.expand(cx, mitem, item, push)
74 fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
75 let n = match substr.nonself_args {
77 _ => cx.span_bug(trait_span, "incorrect number of arguments in `deriving(FromPrimitive)`")
80 match *substr.fields {
82 cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs");
83 return cx.expr_fail(trait_span, InternedString::new(""));
85 StaticEnum(enum_def, _) => {
86 if enum_def.variants.is_empty() {
87 cx.span_err(trait_span,
88 "`FromPrimitive` cannot be derived for enums with no variants");
89 return cx.expr_fail(trait_span, InternedString::new(""));
92 let mut arms = Vec::new();
94 for variant in enum_def.variants.iter() {
95 match variant.node.kind {
96 ast::TupleVariantKind(ref args) => {
98 cx.span_err(trait_span,
99 "`FromPrimitive` cannot be derived for \
100 enum variants with arguments");
101 return cx.expr_fail(trait_span,
102 InternedString::new(""));
104 let span = variant.span;
106 // expr for `$n == $variant as $name`
107 let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
108 let variant = cx.expr_path(path);
109 let ty = cx.ty_ident(span, cx.ident_of(name));
110 let cast = cx.expr_cast(span, variant.clone(), ty);
111 let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);
113 // expr for `Some($variant)`
114 let body = cx.expr_some(span, variant);
116 // arm for `_ if $guard => $body`
119 pats: vec!(cx.pat_wild(span)),
126 ast::StructVariantKind(_) => {
127 cx.span_err(trait_span,
128 "`FromPrimitive` cannot be derived for enums \
129 with struct variants");
130 return cx.expr_fail(trait_span,
131 InternedString::new(""));
136 // arm for `_ => None`
139 pats: vec!(cx.pat_wild(trait_span)),
141 body: cx.expr_none(trait_span),
145 cx.expr_match(trait_span, n.clone(), arms)
147 _ => cx.span_bug(trait_span, "expected StaticEnum in deriving(FromPrimitive)")