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)
70 associated_types: Vec::new(),
73 trait_def.expand(cx, mitem, item, push)
76 fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
77 let n = match substr.nonself_args {
79 _ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(FromPrimitive)`")
82 match *substr.fields {
84 cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs");
85 return cx.expr_fail(trait_span, InternedString::new(""));
87 StaticEnum(enum_def, _) => {
88 if enum_def.variants.is_empty() {
89 cx.span_err(trait_span,
90 "`FromPrimitive` cannot be derived for enums with no variants");
91 return cx.expr_fail(trait_span, InternedString::new(""));
94 let mut arms = Vec::new();
96 for variant in enum_def.variants.iter() {
97 match variant.node.kind {
98 ast::TupleVariantKind(ref args) => {
100 cx.span_err(trait_span,
101 "`FromPrimitive` cannot be derived for \
102 enum variants with arguments");
103 return cx.expr_fail(trait_span,
104 InternedString::new(""));
106 let span = variant.span;
108 // expr for `$n == $variant as $name`
109 let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
110 let variant = cx.expr_path(path);
111 let ty = cx.ty_ident(span, cx.ident_of(name));
112 let cast = cx.expr_cast(span, variant.clone(), ty);
113 let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);
115 // expr for `Some($variant)`
116 let body = cx.expr_some(span, variant);
118 // arm for `_ if $guard => $body`
121 pats: vec!(cx.pat_wild(span)),
128 ast::StructVariantKind(_) => {
129 cx.span_err(trait_span,
130 "`FromPrimitive` cannot be derived for enums \
131 with struct variants");
132 return cx.expr_fail(trait_span,
133 InternedString::new(""));
138 // arm for `_ => None`
141 pats: vec!(cx.pat_wild(trait_span)),
143 body: cx.expr_none(trait_span),
147 cx.expr_match(trait_span, n.clone(), arms)
149 _ => cx.span_bug(trait_span, "expected StaticEnum in derive(FromPrimitive)")