]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/ext/deriving/primitive.rs
Imported Upstream version 1.1.0+dfsg1
[rustc.git] / src / libsyntax / ext / deriving / primitive.rs
CommitLineData
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 11use ast::{MetaItem, Expr};
1a4d82fc
JJ
12use ast;
13use codemap::Span;
d9579d0f 14use ext::base::{ExtCtxt, Annotatable};
1a4d82fc
JJ
15use ext::build::AstBuilder;
16use ext::deriving::generic::*;
17use ext::deriving::generic::ty::*;
18use parse::token::InternedString;
19use ptr::P;
20
d9579d0f
AL
21pub 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
73fn 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}