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