1use std::fmt;
5use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
6use syn::{parse::{Parse, ParseStream, ParseBuffer}, parse2};
7use quote::{quote,ToTokens};
8
9trait TryParse {
10 fn try_parse<T: Parse>(&self) -> syn::Result<T>;
11}
12
13impl TryParse for ParseBuffer<'_> {
14 fn try_parse<T: Parse>(&self) -> syn::Result<T> {
15 match self.fork().parse::<T>() {
16 Ok(_) => Ok(self.parse::<T>()?),
17 Err(e) => Err(e)
18 }
19 }
20}
21
22trait ProcessQuickError<T> {
23 fn process_quick_error(self) -> T;
24}
25
26mod errors_child_element {
27 use std::fmt;
28 use syn::{LitStr, parenthesized, parse::{Parse, ParseStream, ParseBuffer}, token, punctuated};
29 use proc_macro2::{Delimiter, Group, Ident, TokenStream, TokenTree};
30 use quote::{ToTokens, quote};
31 use crate::quick::{ProcessQuickError,TryParse};
32
33 #[derive(Debug)]
34 pub struct NormalError {
35 ident: Ident,
36 args: Option<Group>,
37 body: Group
38 }
39
40 impl Parse for NormalError {
41 fn parse(input: ParseStream) -> syn::Result<Self> {
42 let ident = input.try_parse::<Ident>()?;
43 let first_group = input.try_parse::<Group>()?;
44 if first_group.delimiter() == Delimiter::Parenthesis {
45 let second_group = input.try_parse::<Group>()?;
46 if second_group.delimiter() == Delimiter::Brace {
47 Ok(NormalError {
48 ident,
49 args: Some(first_group),
50 body: second_group
51 })
52 } else {
53 Err(syn::Error::new(second_group.span_open(),"Unexpected Delimiter Here"))
54 }
55 } else if first_group.delimiter() == Delimiter::Brace {
56 Ok(NormalError {
57 ident,
58 args: None,
59 body: first_group
60 })
61 } else {
62 Err(syn::Error::new(first_group.span_open(), "Unexpected delimiter here"))
63 }
64 }
65 }
66
67 impl ToTokens for NormalError {
68 fn to_tokens(&self, tokens: &mut TokenStream) {
69 tokens.extend_one(TokenTree::from(self.ident.clone()));
70 match self.args.clone() {
71 Some(val) => tokens.extend_one(TokenTree::from(val)),
72 _ => ()
73 };
74 tokens.extend_one(TokenTree::from(self.body.clone()));
75 }
76 }
77
78 pub struct QuickError {
79 err_ident: Ident,
80 desc: LitStr,
81 inner_args: punctuated::Punctuated<Ident,token::Comma>
82 }
83
84 impl fmt::Debug for QuickError {
85 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(),fmt::Error> {
86
87 struct LitStrDebug<'a> {
88 inner: &'a LitStr
89 }
90
91 impl fmt::Debug for LitStrDebug<'_> {
92 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(),fmt::Error> {
93 fmt.write_str("LitStr( ")?;
94 self.inner.value().fmt(fmt)?;
95 fmt.write_str(" )")?;
96 Ok(())
97 }
98 }
99
100 struct PunctuatedDebug<'a,T,U> {
101 inner: &'a punctuated::Punctuated<T,U>
102 }
103
104 impl<T: fmt::Debug,U> fmt::Debug for PunctuatedDebug<'_,T,U> {
105 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(),fmt::Error> {
106 fmt.write_str("Punctuated( ")?;
107 self.inner.iter().collect::<Vec<&T>>().fmt(fmt)?;
108 fmt.write_str(" )")?;
109 Ok(())
110 }
111 }
112
113 #[derive(Debug)]
114 struct QuickErrorDebug<'a> {
115 err_ident: &'a Ident,
116 desc: LitStrDebug<'a>,
117 inner_args: PunctuatedDebug<'a,Ident,token::Comma>
118 }
119
120 (QuickErrorDebug {
121 err_ident: &self.err_ident,
122 desc: LitStrDebug { inner: &self.desc },
123 inner_args: PunctuatedDebug {
124 inner: &self.inner_args
125 }
126 }).fmt(fmt)
127 }
128
129 }
130
131 fn parse_parens(input: ParseStream) -> syn::Result<ParseBuffer> {
132 let contents;
133 parenthesized!(contents in input);
134 Ok(contents)
135 }
136
137 fn try_parse_parens(input: ParseStream) -> syn::Result<ParseBuffer> {
138 match parse_parens(&mut input.fork()) {
139 Ok(_) => Ok(parse_parens(input).unwrap()),
140 Err(e) => Err(e.clone())
141 }
142 }
143
144 impl Parse for QuickError {
145 fn parse(input: ParseStream) -> syn::Result<Self> {
146 let ident = input.try_parse::<Ident>()?;
147 (ident.to_string() == "quick")
148 .then_some(())
149 .ok_or(syn::Error::new(ident.span(),"Ident was not 'quick'"))?;
150 input.try_parse::<token::Bang>()?;
151 let late_fail: Result<QuickError,syn::Error> = try {
152 let args = &mut try_parse_parens(input)?;
153 let err_ident = args.try_parse::<Ident>()?;
154 args.try_parse::<token::Comma>()?;
155 let desc = args.try_parse::<LitStr>()?;
156 let mut invalid_inner_args = false;
157 let optional_paren: syn::Result<punctuated::Punctuated<Ident,token::Comma>> = try{
158 args.try_parse::<token::Comma>()?;
159 let inner_args_unparsed = &mut try_parse_parens(args)?;
160 match punctuated::Punctuated::parse_terminated(&inner_args_unparsed) {
161 Ok(val) => Ok(val),
162 Err(e) => {
163 invalid_inner_args = true;
164 Err(e)
165 }
166 }?
167 };
168 let inner_args = match optional_paren {
169 Ok(val) => Ok(val),
170 Err(_) => {
171 if invalid_inner_args {
172 Err(syn::Error::new(args.span(),"INV_QUICK"))
173 } else {
174 Ok(punctuated::Punctuated::new())
175 }
176 }
177 };
178
179 match args.try_parse::<token::Comma>() { _ => ()};
180 args.is_empty().then_some(()).ok_or(syn::Error::new(args.span(),"INV_QUICK"))?;
181
182 QuickError {
183 err_ident,
184 desc,
185 inner_args: inner_args?
186 }
187 };
188 late_fail.or_else(|i:syn::Error| {Err(syn::Error::new(i.span(),"INV_QUICK"))})
189
190 }
191 }
192
193 impl ProcessQuickError<NormalError> for QuickError {
194 fn process_quick_error(self) -> NormalError {
195 let ident = self.err_ident;
196 let mut args_token_stream = TokenStream::new();
197 let mut first_arg = true;
198 for arg in self.inner_args.clone() {
199 if first_arg {
200 first_arg = false;
201 } else {
202 args_token_stream.extend(quote!(, ));
203 }
204 args_token_stream.extend_one(TokenTree::from(arg));
205 args_token_stream.extend(quote!( : String));
206 }
207 let args;
208 let are_args_empty = args_token_stream.is_empty();
209 if are_args_empty {
210 args = None;
211 } else {
212 args = Some(Group::new(Delimiter::Parenthesis,args_token_stream));
213 }
214
215 let mut body_token_stream = TokenStream::new();
216 body_token_stream.extend(quote!(description));
217 body_token_stream.extend_one(TokenTree::from(Group::new(Delimiter::Parenthesis,self.desc.to_token_stream())));
218 body_token_stream.extend(quote!(display));
219
220 let mut display_args_token_stream = TokenStream::new();
221 if are_args_empty {
222 display_args_token_stream.extend(self.desc.to_token_stream());
223 } else {
224 let mut format_str: String = self.desc.value();
225 format_str += ":";
226 for _ in self.inner_args.clone() {
227 format_str += " {},"
228 }
229 format_str.pop();
230 display_args_token_stream.extend_one(LitStr::new(format_str.as_str(),self.desc.span()).into_token_stream());
231 }
232
233 for arg in self.inner_args {
234 display_args_token_stream.extend(quote!(,));
235 display_args_token_stream.extend_one(TokenTree::from(arg));
236 }
237
238 body_token_stream.extend_one(TokenTree::from(Group::new(Delimiter::Parenthesis,display_args_token_stream)));
239 let body = Group::new(Delimiter::Brace,body_token_stream);
240 NormalError { ident, args, body }
241 }
242 }
243}
244
245#[derive(Debug)]
246enum ErrorsChildElementEnum {
247 QuickError(errors_child_element::QuickError),
248 NormalError(errors_child_element::NormalError)
249}
250
251impl Parse for ErrorsChildElementEnum {
252 fn parse(input: ParseStream) -> syn::Result<Self> {
253 match input.try_parse() as syn::Result<errors_child_element::QuickError> {
254 Ok(val) => return Ok(Self::QuickError(val)),
255 Err(e) => {
256 if e.to_string() == "INV_QUICK" {
257 return Err(e)
258 } else {
259 ()
260 }
261 }
262 };
263 match input.try_parse() as syn::Result<errors_child_element::NormalError> {
264 Ok(val) => return Ok(Self::NormalError(val)),
265 Err(_) => ()
266 };
267 Err(input.error("Could not parse as ErrorsChildElementEnum"))
268 }
269}
270
271impl ProcessQuickError<ErrorsChildElementEnum> for ErrorsChildElementEnum {
272 fn process_quick_error(self) -> ErrorsChildElementEnum {
273 match self {
274 Self::QuickError(val) => Self::NormalError(val.process_quick_error()),
275 _ => self
276 }
277 }
278}
279
280impl ToTokens for ErrorsChildElementEnum {
281 fn to_tokens(&self, tokens: &mut TokenStream) {
282 match self {
283 Self::NormalError(ref val) => val.to_tokens(tokens),
284 Self::QuickError(ref _val) => panic!("Not all QuickError structs were converted to NormalError ones")
285 }
286 }
287}
288
289mod root_element {
290 use quote::ToTokens;
291 use syn::{braced, parse::{Parse, ParseStream}};
292 use proc_macro2::{Delimiter, Group, Ident, TokenStream, TokenTree};
293 use crate::quick::{ErrorsChildElementEnum, ProcessQuickError, TryParse};
294
295 #[derive(Debug)]
296 pub struct ErrorsIdGroup {
297 ident: Ident,
298 items: Vec<ErrorsChildElementEnum>
299 }
300
301 impl Parse for ErrorsIdGroup {
302 fn parse(input: ParseStream) -> syn::Result<Self> {
303 let ident = input.try_parse::<Ident>()?;
304 if ident.to_string() == "errors" {
305 let errors;
306 braced!(errors in input);
307 let mut items = vec![];
308 if errors.is_empty() {
309 Err(errors.error("Unexpected end of input"))
310 } else {
311 while !errors.is_empty() {
312 items.push(errors.try_parse::<ErrorsChildElementEnum>()?);
313 }
314 Ok(ErrorsIdGroup {
315 ident,
316 items
317 })
318 }
319 } else {
320 Err(syn::Error::new(ident.span(),"Expected 'errors'"))
321 }
322 }
323 }
324
325 impl ProcessQuickError<ErrorsIdGroup> for ErrorsIdGroup {
326 fn process_quick_error(self) -> ErrorsIdGroup {
327 let mut new_items = vec![];
328 for item in self.items {
329 new_items.push(item.process_quick_error());
330 }
331 ErrorsIdGroup {
332 ident: self.ident,
333 items: new_items
334 }
335 }
336 }
337
338 impl ToTokens for ErrorsIdGroup {
339 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
340 tokens.extend_one(TokenTree::from(self.ident.clone()));
341 let mut group_token_stream = TokenStream::new();
342 for item in &self.items {
343 item.to_tokens(&mut group_token_stream);
344 }
345 tokens.extend_one(TokenTree::from(Group::new(Delimiter::Brace,group_token_stream)));
346 }
347 }
348
349 #[derive(Debug)]
350 pub struct OtherIdGroup {
351 ident: Ident,
352 body: Option<Group>
353 }
354
355 impl Parse for OtherIdGroup {
356 fn parse(input: ParseStream) -> syn::Result<Self> {
357 let ident = input.try_parse::<Ident>()?;
358 let body = input.try_parse() as syn::Result<Group>;
359 match body {
360 Ok(val) => Ok(OtherIdGroup {
361 ident,
362 body: Some(val)
363 }),
364 Err(_) => Ok(OtherIdGroup {
365 ident,
366 body: None
367 })
368 }
369 }
370 }
371
372 impl ToTokens for OtherIdGroup {
373 fn to_tokens(&self, tokens: &mut TokenStream) {
374 tokens.extend_one(TokenTree::from(self.ident.clone()));
375 match self.body.clone() {
376 Some(val) => tokens.extend_one(TokenTree::from(val)),
377 None => ()
378 };
379 }
380 }
381}
382
383#[derive(Debug)]
384enum RootElementEnum {
385 ErrorsIdGroup(root_element::ErrorsIdGroup),
386 OtherIdGroup(root_element::OtherIdGroup)
387}
388
389impl Parse for RootElementEnum {
390 fn parse(input: ParseStream) -> syn::Result<Self> {
391 match input.try_parse() as syn::Result<root_element::ErrorsIdGroup> {
392 Ok(val) => Ok(RootElementEnum::ErrorsIdGroup(val)),
393 Err(e) => {
394 if e.to_string() == "INV_QUICK" {
395 return Err(e);
396 }
397 match input.try_parse() as syn::Result<root_element::OtherIdGroup> {
398 Ok(val) => Ok(RootElementEnum::OtherIdGroup(val)),
399 Err(e) => Err(e)
400 }
401 }
402 }
403 }
404}
405
406impl ProcessQuickError<RootElementEnum> for RootElementEnum {
407 fn process_quick_error(self) -> RootElementEnum {
408 match self {
409 Self::ErrorsIdGroup(val) => Self::ErrorsIdGroup(val.process_quick_error()),
410 _ => self
411 }
412 }
413}
414
415impl ToTokens for RootElementEnum {
416 fn to_tokens(&self, tokens: &mut TokenStream) {
417 match self {
418 Self::ErrorsIdGroup(ref val) => val.to_tokens(tokens),
419 Self::OtherIdGroup(ref val) => val.to_tokens(tokens)
420 }
421 }
422}
423
424struct RootElementVec {
425 items: Vec<RootElementEnum>
426}
427
428impl fmt::Debug for RootElementVec {
429 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
430 self.items.fmt(f)
431 }
432}
433
434impl Parse for RootElementVec {
435 fn parse(input: ParseStream) -> syn::Result<Self> {
436 let mut items = vec![];
437 if input.is_empty() {
438 Err(input.error("Unexpected end of input"))
439 } else {
440 while !input.is_empty() {
441 items.push(RootElementEnum::parse(input)?);
442 }
443 Ok(RootElementVec {
444 items
445 })
446 }
447 }
448}
449
450impl ProcessQuickError<RootElementVec> for RootElementVec {
451 fn process_quick_error(self) -> RootElementVec {
452 let mut new_items = vec![];
453 for item in self.items {
454 new_items.push(item.process_quick_error());
455 }
456 RootElementVec {
457 items: new_items
458 }
459 }
460}
461
462impl ToTokens for RootElementVec {
463 fn to_tokens(&self, tokens: &mut TokenStream) {
464 let mut group_token_stream = TokenStream::new();
465 for item in &self.items {
466 item.to_tokens(&mut group_token_stream);
467 }
468 tokens.extend_one(TokenTree::from(Group::new(Delimiter::Brace,group_token_stream)));
469 }
470}
471
472
473
474pub fn main(input: TokenStream) -> syn::Result<TokenStream> {
476 let parsed_input: RootElementVec = match parse2(input) {
477 Ok(val) => val,
478 Err(e) => {
479 if e.to_string() == "INV_QUICK" {
480 let mut new_e = syn::Error::new(e.span(),"Invalid 'quick!()' macro");
481 new_e.combine(e);
482 return Err(new_e);
483 } else {
484 return Err(e);
485 }
486 }
487 };
488 let transformed_input: RootElementVec = parsed_input.process_quick_error();
489 let mut output_stream: TokenStream = TokenStream::new();
490 output_stream.extend(quote!(::error_chain::error_chain!));
491 transformed_input.to_tokens(&mut output_stream);
492 Ok(output_stream)
493}
494
495
496#[cfg(test)]
497mod tests{
498 use std::assert_eq;
499 use quote::quote;
500 use crate::quick;
501 #[test]
502 pub fn test() {
503 let input = quote!{
504
505 types {
506 BuildError, BEKind, BETrait, BEResult;
507 }
508
509 errors {
510 NormalError1 {
511 description("Error 1 Description: Without Arguments"),
512 display("Error 1 Display")
513 }
514 NormalError2 (arg1: String, arg2: String) {
515 description("Error 2 Description: With Arguments"),
516 display("Error 2 Display: {}, {}", arg1, arg2),
517 }
518 quick!(QuickError1, "Error 1 Description: Zero arguments")
519 quick!(QuickError2, "Error 2 Description: One Argument",(arg1,))
520 quick!(QuickError3, "Error 3 Description: Three Arguments",(arg1,arg2,arg3,))
521 quick!(QuickError4, "Error 4 Description: Zero arguments, trailing comma",)
522 }
523 };
524 let output = quick::main(input).unwrap();
525 let expected_output = quote!{
526 ::error_chain::error_chain!{
527 types {
528 BuildError, BEKind, BETrait, BEResult;
529 }
530
531 errors {
532 NormalError1 {
533 description("Error 1 Description: Without Arguments"),
534 display("Error 1 Display")
535 }
536 NormalError2 (arg1: String , arg2: String){
537 description("Error 2 Description: With Arguments"),
538 display("Error 2 Display: {}, {}", arg1, arg2),
539 }
540 QuickError1 {
541 description("Error 1 Description: Zero arguments")
542 display ("Error 1 Description: Zero arguments")
543 }
544 QuickError2 (arg1: String){
545 description("Error 2 Description: One Argument")
546 display("Error 2 Description: One Argument: {}", arg1)
547 }
548 QuickError3 (arg1: String, arg2: String, arg3: String){
549 description("Error 3 Description: Three Arguments")
550 display("Error 3 Description: Three Arguments: {}, {}, {}", arg1, arg2, arg3)
551 }
552 QuickError4 {
553 description("Error 4 Description: Zero arguments, trailing comma")
554 display ("Error 4 Description: Zero arguments, trailing comma")
555 }
556 }
557 }
558 };
559 assert_eq!(output.to_string(),expected_output.to_string(),"Actual output and Expected output did not match.\n Expected Output: \n{:#?}\n Actual Output: \n{:#?}\n",expected_output,output);
560 }
561}