|
8 | 8 | // option. This file may not be copied, modified, or distributed
|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 |
| -#![feature(plugin_registrar, rustc_private)] |
| 11 | +#![crate_type = "rustc-macro"] |
| 12 | +#![feature(rustc_macro, rustc_macro_lib)] |
12 | 13 |
|
13 |
| -extern crate syntax; |
14 |
| -extern crate syntax_ext; |
15 |
| -extern crate rustc_plugin; |
| 14 | +extern crate syn; |
| 15 | +#[macro_use] |
| 16 | +extern crate quote; |
| 17 | +extern crate rustc_macro; |
16 | 18 |
|
17 |
| -use syntax::ast::{MetaItem, Expr, BinOpKind}; |
18 |
| -use syntax::ast; |
19 |
| -use syntax::codemap::Span; |
20 |
| -use syntax::ext::base::{ExtCtxt, Annotatable}; |
21 |
| -use syntax::ext::build::AstBuilder; |
22 |
| -use syntax_ext::deriving::generic::*; |
23 |
| -use syntax_ext::deriving::generic::ty::*; |
24 |
| -use syntax::parse::token::InternedString; |
25 |
| -use syntax::ptr::P; |
26 |
| -use syntax::ext::base::MultiDecorator; |
27 |
| -use syntax::parse::token; |
| 19 | +use rustc_macro::TokenStream; |
28 | 20 |
|
29 |
| -use rustc_plugin::Registry; |
| 21 | +use syn::Body::Enum; |
30 | 22 |
|
31 |
| -macro_rules! pathvec { |
32 |
| - ($($x:ident)::+) => ( |
33 |
| - vec![ $( stringify!($x) ),+ ] |
34 |
| - ) |
35 |
| -} |
| 23 | +#[rustc_macro_derive(FromPrimitive)] |
| 24 | +pub fn from_primitive(input: TokenStream) -> TokenStream { |
| 25 | + let source = input.to_string(); |
36 | 26 |
|
37 |
| -macro_rules! path { |
38 |
| - ($($x:tt)*) => ( |
39 |
| - ::syntax_ext::deriving::generic::ty::Path::new( pathvec!( $($x)* ) ) |
40 |
| - ) |
41 |
| -} |
42 |
| - |
43 |
| -macro_rules! path_local { |
44 |
| - ($x:ident) => ( |
45 |
| - ::syntax_ext::deriving::generic::ty::Path::new_local(stringify!($x)) |
46 |
| - ) |
47 |
| -} |
| 27 | + let ast = syn::parse_item(&source).unwrap(); |
| 28 | + // panic!("{:?}", ast); |
48 | 29 |
|
49 | 30 | macro_rules! pathvec_std {
|
50 | 31 | ($cx:expr, $first:ident :: $($rest:ident)::+) => ({
|
@@ -111,91 +92,32 @@ pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
|
111 | 92 | supports_unions: false,
|
112 | 93 | };
|
113 | 94 |
|
114 |
| - trait_def.expand(cx, mitem, &item, push) |
115 |
| -} |
116 |
| - |
117 |
| -fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> { |
118 |
| - if substr.nonself_args.len() != 1 { |
119 |
| - cx.span_bug(trait_span, "incorrect number of arguments in `derive(FromPrimitive)`") |
120 |
| - } |
121 |
| - |
122 |
| - let n = &substr.nonself_args[0]; |
123 |
| - |
124 |
| - match *substr.fields { |
125 |
| - StaticStruct(..) => { |
126 |
| - cx.span_err(trait_span, "`FromPrimitive` cannot be derived for structs"); |
127 |
| - return cx.expr_fail(trait_span, InternedString::new("")); |
128 |
| - } |
129 |
| - StaticEnum(enum_def, _) => { |
130 |
| - if enum_def.variants.is_empty() { |
131 |
| - cx.span_err(trait_span, |
132 |
| - "`FromPrimitive` cannot be derived for enums with no variants"); |
133 |
| - return cx.expr_fail(trait_span, InternedString::new("")); |
| 95 | + let mut idx = 0; |
| 96 | + let variants: Vec<_> = variants.iter() |
| 97 | + .map(|variant| { |
| 98 | + let ident = &variant.ident; |
| 99 | + let tt = quote!(#idx => Some(#name::#ident)); |
| 100 | + idx += 1; |
| 101 | + tt |
| 102 | + }) |
| 103 | + .collect(); |
| 104 | + |
| 105 | + let res = quote! { |
| 106 | + #ast |
| 107 | + |
| 108 | + impl ::num::traits::FromPrimitive for #name { |
| 109 | + fn from_i64(n: i64) -> Option<Self> { |
| 110 | + Self::from_u64(n as u64) |
134 | 111 | }
|
135 | 112 |
|
136 |
| - let mut arms = Vec::new(); |
137 |
| - |
138 |
| - for variant in &enum_def.variants { |
139 |
| - match variant.node.data { |
140 |
| - ast::VariantData::Unit(..) => { |
141 |
| - let span = variant.span; |
142 |
| - |
143 |
| - // expr for `$n == $variant as $name` |
144 |
| - let path = cx.path(span, vec![substr.type_ident, variant.node.name]); |
145 |
| - let variant = cx.expr_path(path); |
146 |
| - let ty = cx.ty_ident(span, cx.ident_of(name)); |
147 |
| - let cast = cx.expr_cast(span, variant.clone(), ty); |
148 |
| - let guard = cx.expr_binary(span, BinOpKind::Eq, n.clone(), cast); |
149 |
| - |
150 |
| - // expr for `Some($variant)` |
151 |
| - let body = cx.expr_some(span, variant); |
152 |
| - |
153 |
| - // arm for `_ if $guard => $body` |
154 |
| - let arm = ast::Arm { |
155 |
| - attrs: vec!(), |
156 |
| - pats: vec!(cx.pat_wild(span)), |
157 |
| - guard: Some(guard), |
158 |
| - body: body, |
159 |
| - }; |
160 |
| - |
161 |
| - arms.push(arm); |
162 |
| - } |
163 |
| - ast::VariantData::Tuple(..) => { |
164 |
| - cx.span_err(trait_span, |
165 |
| - "`FromPrimitive` cannot be derived for \ |
166 |
| - enum variants with arguments"); |
167 |
| - return cx.expr_fail(trait_span, |
168 |
| - InternedString::new("")); |
169 |
| - } |
170 |
| - ast::VariantData::Struct(..) => { |
171 |
| - cx.span_err(trait_span, |
172 |
| - "`FromPrimitive` cannot be derived for enums \ |
173 |
| - with struct variants"); |
174 |
| - return cx.expr_fail(trait_span, |
175 |
| - InternedString::new("")); |
176 |
| - } |
| 113 | + fn from_u64(n: u64) -> Option<Self> { |
| 114 | + match n { |
| 115 | + #(variants,)* |
| 116 | + _ => None, |
177 | 117 | }
|
178 | 118 | }
|
179 |
| - |
180 |
| - // arm for `_ => None` |
181 |
| - let arm = ast::Arm { |
182 |
| - attrs: vec!(), |
183 |
| - pats: vec!(cx.pat_wild(trait_span)), |
184 |
| - guard: None, |
185 |
| - body: cx.expr_none(trait_span), |
186 |
| - }; |
187 |
| - arms.push(arm); |
188 |
| - |
189 |
| - cx.expr_match(trait_span, n.clone(), arms) |
190 | 119 | }
|
191 |
| - _ => cx.span_bug(trait_span, "expected StaticEnum in derive(FromPrimitive)") |
192 |
| - } |
193 |
| -} |
| 120 | + }; |
194 | 121 |
|
195 |
| -#[plugin_registrar] |
196 |
| -#[doc(hidden)] |
197 |
| -pub fn plugin_registrar(reg: &mut Registry) { |
198 |
| - reg.register_syntax_extension( |
199 |
| - token::intern("derive_NumFromPrimitive"), |
200 |
| - MultiDecorator(Box::new(expand_deriving_from_primitive))); |
| 122 | + res.to_string().parse().unwrap() |
201 | 123 | }
|
0 commit comments