1extern crate proc_macro;
2extern crate syn;
3#[macro_use]
4extern crate quote;
5
6use proc_macro::TokenStream;
7
8#[proc_macro_derive(TypeScriptify)]
9pub fn hello_world(input: TokenStream) -> TokenStream {
10 let s = input.to_string();
12
13 let ast = syn::parse_derive_input(&s).unwrap();
15
16 let gen = impl_hello_world(&ast);
18
19 gen.parse().unwrap()
21}
22
23
24fn impl_hello_world(ast: &syn::DeriveInput) -> quote::Tokens {
25 let name = &ast.ident;
26 let structname = name.to_string();
27 let _body = &ast.body;
28 let mut complete_string: String = "".to_string();
29 let _n = match ast.body {
30 syn::Body::Struct(ref data) => {
31 let mut fieldlines: Vec<String> = vec![];
32 for field in data.fields() {
33 let fieldname: String = format!("{}", field.ident.clone().unwrap().to_string());
39 match field.ty {
40 syn::Ty::Array(ref _b, ref _c) => {
41 unimplemented!()
42 }
43 syn::Ty::Ptr(ref _p) => {
44 unimplemented!()
45 }
46 syn::Ty::Path(ref _qselfopt, ref path) => {
47 let intype = format!("{}", path.segments.last().unwrap().ident);
48 let generic_params_unformated = &path.segments.last().clone().unwrap().parameters;
49 let mut generics_parameters: Vec<String> = Vec::new();
50 match generic_params_unformated {
51 &syn::PathParameters::AngleBracketed(ref angle_bracketed_parameter_data) => {
52 for ty in &angle_bracketed_parameter_data.types {
53 match ty {
54 &syn::Ty::Path(ref _qotherself, ref qotherpath) => {
55 generics_parameters.push(format!("{}", qotherpath.segments.last().unwrap().ident));
56 }
57 _ => unimplemented!(),
58 }
59 }
60 }
61 _ => unimplemented!(),
62 };
63 let mtyp: String = if intype.eq("Option") {
65 (match generics_parameters.first().unwrap().as_ref() {
66 "i8" => "number",
67 "i16" => "number",
68 "i32" => "number",
69 "i64" => "number",
70 "u8" => "number",
71 "u16" => "number",
72 "u32" => "number",
73 "u64" => "number",
74 "usize" => "number",
75 "bool" => "boolean",
76 "String" => "string",
77 "f32" => "number",
78 "f64" => "number",
79 "HashMap" => "Map",
80 "Vec" => "Array",
81 "HashSet" => "Array",
82 "Value" => "any",
83 a @ _ => a,
84 }).to_string()
85 } else {
86 let mut generic_term_in_angle_brackets: String = if generics_parameters.is_empty() { "".to_string() } else { "<".to_string() };
87 for gen in &generics_parameters {
88 if generic_term_in_angle_brackets.len() > 1 {
89 generic_term_in_angle_brackets = generic_term_in_angle_brackets + ", ";
90 }
91 generic_term_in_angle_brackets = generic_term_in_angle_brackets + match gen.as_ref() {
92 "i8" => "number",
93 "i16" => "number",
94 "i32" => "number",
95 "i64" => "number",
96 "u8" => "number",
97 "u16" => "number",
98 "u32" => "number",
99 "u64" => "number",
100 "usize" => "number",
101 "bool" => "boolean",
102 "String" => "string",
103 "f32" => "number",
104 "f64" => "number",
105 "HashMap" => "Map",
106 "Vec" => "Array",
107 "HashSet" => "Array",
108 "Value" => "any",
109 a @ _ => a,
110 };
111 }
112 if !generics_parameters.is_empty() {
113 generic_term_in_angle_brackets = generic_term_in_angle_brackets + ">";
114 }
115 (match intype.as_ref() {
116 "i8" => "number".to_string(),
117 "i16" => "number".to_string(),
118 "i32" => "number".to_string(),
119 "i64" => "number".to_string(),
120 "u8" => "number".to_string(),
121 "u16" => "number".to_string(),
122 "u32" => "number".to_string(),
123 "u64" => "number".to_string(),
124 "usize" => "number".to_string(),
125 "bool" => "boolean".to_string(),
126 "String" => "string".to_string(),
127 "f32" => "number".to_string(),
128 "f64" => "number".to_string(),
129 "HashMap" => "Map".to_string(),
130 "Vec" => "Array".to_string(),
131 "HashSet" => "Array".to_string(),
132 "Value" => "any".to_string(),
133 a @ _ => a.to_string(),
134 } + &generic_term_in_angle_brackets)
135 };
136 fieldlines.push(format!("{}: {};", fieldname, mtyp));
137 }
138 _ => unimplemented!(),
139 }
140 }
141
142
143 let mut s = "".to_string();
144 for fieldline in fieldlines {
145 s = s + " " + &fieldline + "\n";
146 }
147 complete_string = format!("export interface {} {{\n{}}}", structname, s);
148 data.fields().len()
149 }
150 syn::Body::Enum(ref variant_vec) => {
151 let k = variant_vec.len();
152 let enum_name = format!("{}", name);
153 let mut variants: Vec<String> = Vec::new();
154 for variant in variant_vec {
155 let mut fieldlines: Vec<String> = vec![];
156 let variant_name = format!("{}", variant.ident);
157 variants.push(variant_name.to_string());
158 let data = &variant.data;
159
160 for field in data.fields() {
163 let fieldname: String = format!("{}", field.ident.clone().unwrap().to_string());
169 match field.ty {
170 syn::Ty::Array(ref _b, ref _c) => {
171 unimplemented!()
172 }
173 syn::Ty::Ptr(ref _p) => {
174 unimplemented!()
175 }
176 syn::Ty::Path(ref _qselfopt, ref path) => {
177 let intype = format!("{}", path.segments.last().unwrap().ident);
178 let generic_params_unformated = &path.segments.last().clone().unwrap().parameters;
179 let mut generics_parameters: Vec<String> = Vec::new();
180 match generic_params_unformated {
181 &syn::PathParameters::AngleBracketed(ref angle_bracketed_parameter_data) => {
182 for ty in &angle_bracketed_parameter_data.types {
183 match ty {
184 &syn::Ty::Path(ref _qotherself, ref qotherpath) => {
185 generics_parameters.push(format!("{}", qotherpath.segments.last().unwrap().ident));
186 }
187 _ => unimplemented!(),
188 }
189 }
190 }
191 _ => unimplemented!(),
192 };
193 let mtyp: String = if intype.eq("Option") {
195 (match generics_parameters.first().unwrap().as_ref() {
196 "i8" => "number",
197 "i16" => "number",
198 "i32" => "number",
199 "i64" => "number",
200 "u8" => "number",
201 "u16" => "number",
202 "u32" => "number",
203 "u64" => "number",
204 "usize" => "number",
205 "bool" => "boolean",
206 "String" => "string",
207 "f32" => "number",
208 "f64" => "number",
209 "HashMap" => "Map",
210 "Vec" => "Array",
211 "HashSet" => "Array",
212 "Value" => "any",
213 a @ _ => a,
214 }).to_string()
215 } else {
216 let mut generic_term_in_angle_brackets: String = if generics_parameters.is_empty() { "".to_string() } else { "<".to_string() };
217 for gen in &generics_parameters {
218 if generic_term_in_angle_brackets.len() > 1 {
219 generic_term_in_angle_brackets = generic_term_in_angle_brackets + ", ";
220 }
221 generic_term_in_angle_brackets = generic_term_in_angle_brackets + match gen.as_ref() {
222 "i8" => "number",
223 "i16" => "number",
224 "i32" => "number",
225 "i64" => "number",
226 "u8" => "number",
227 "u16" => "number",
228 "u32" => "number",
229 "u64" => "number",
230 "usize" => "number",
231 "bool" => "boolean",
232 "String" => "string",
233 "f32" => "number",
234 "f64" => "number",
235 "HashMap" => "Map",
236 "Vec" => "Array",
237 "HashSet" => "Array",
238 "Value" => "any",
239 a @ _ => a,
240 };
241 }
242 if !generics_parameters.is_empty() {
243 generic_term_in_angle_brackets = generic_term_in_angle_brackets + ">";
244 }
245 (match intype.as_ref() {
246 "i8" => "number".to_string(),
247 "i16" => "number".to_string(),
248 "i32" => "number".to_string(),
249 "i64" => "number".to_string(),
250 "u8" => "number".to_string(),
251 "u16" => "number".to_string(),
252 "u32" => "number".to_string(),
253 "u64" => "number".to_string(),
254 "usize" => "number".to_string(),
255 "bool" => "boolean".to_string(),
256 "String" => "string".to_string(),
257 "f32" => "number".to_string(),
258 "f64" => "number".to_string(),
259 "HashMap" => "Map".to_string(),
260 "Vec" => "Array".to_string(),
261 "HashSet" => "Array".to_string(),
262 "Value" => "any".to_string(),
263 a @ _ => a.to_string(),
264 } + &generic_term_in_angle_brackets)
265 };
266 fieldlines.push(format!("{}: {};", fieldname, mtyp));
267 }
268 _ => unimplemented!(),
269 }
270 }
271
272
273 let mut s = "".to_string();
274 for fieldline in &fieldlines {
275 s = s + " " + fieldline.as_ref() + "\n";
276 }
277
278 complete_string = complete_string + &format!("export interface {} {{\n{}}}\n\n", variant_name, s);
279 }
280
281 let mut s = "".to_string();
283 for v in variants {
284 s = s + " " + v.as_ref() + ": " + v.as_ref() + ";\n";
285 }
286 complete_string = complete_string + &format!("export interface {} {{\n{}}}\n\n", enum_name, s);
287
288 k
289 }
290 };
291 quote! {
292 impl TypeScriptifyTrait for #name {
293 fn type_script_ify() -> String {
294 format!("{}\n", #complete_string)
295 }
296 }
297 }
298}