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 span: Span,
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_span: Span, 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 }
libsyntax/ext/deriving/primitive.rs:71:1-71:1 -fn- definition:
fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr {
let n = match substr.nonself_args {
[n] => n,
references:- 246: combine_substructure: combine_substructure(|c, s, sub| {
47: cs_from("i64", c, s, sub)
48: }),
--
63: combine_substructure: combine_substructure(|c, s, sub| {
64: cs_from("u64", c, s, sub)
65: }),