1mod expand;
2
3use proc_macro2::Group;
4use proc_macro2::Ident;
5use proc_macro2::Punct;
6use proc_macro2::Span;
7use proc_macro2::TokenStream;
8use proc_macro2::TokenTree;
9use quote::quote;
10use syn::parse_macro_input;
11use syn::DeriveInput;
12
13struct VariantFieldGroupBasic {
14 tys: Vec<syn::Path>,
15}
16
17impl syn::parse::Parse for VariantFieldGroupBasic {
18 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
19 let mut tys = Vec::new();
20 let ty: syn::Path = input.parse()?;
21 tys.push(ty.clone());
22 loop {
23 if !input.peek(syn::token::Comma) {
24 break;
25 }
26 let _p: Punct = input.parse()?;
27 let ty: syn::Path = input.parse()?;
28 tys.push(ty);
29 }
30 let ret = Self { tys };
31 Ok(ret)
32 }
33}
34
35struct VariantFieldGroupFrom {
36 tys: Vec<syn::Path>,
37}
38
39impl syn::parse::Parse for VariantFieldGroupFrom {
40 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
41 let _p: Punct = input.parse()?;
42 let _gr: proc_macro2::Group = input.parse()?;
43 let mut tys = Vec::new();
45 let ty: syn::Path = input.parse()?;
46 tys.push(ty.clone());
47 loop {
48 if !input.peek(syn::token::Comma) {
49 break;
50 }
51 let _p: Punct = input.parse()?;
52 let ty: syn::Path = input.parse()?;
53 tys.push(ty);
54 }
55 let ret = Self { tys };
56 Ok(ret)
57 }
58}
59
60enum VariantFieldGroup {
61 Plain,
62 Basic(VariantFieldGroupBasic),
63 From(VariantFieldGroupFrom),
64}
65
66impl syn::parse::Parse for VariantFieldGroup {
67 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
68 if input.peek(syn::token::Pound) {
69 let v = input.parse()?;
70 let ret = Self::From(v);
71 Ok(ret)
72 } else {
73 let v = input.parse()?;
74 let ret = Self::Basic(v);
75 Ok(ret)
76 }
77 }
78}
79
80struct ErrorVariant {
81 name: Ident,
82 field_group: VariantFieldGroup,
83}
84
85struct MacroInput2 {
86 errname: Ident,
87 errdesc: syn::LitStr,
88 variants: Vec<ErrorVariant>,
89}
90
91impl syn::parse::Parse for MacroInput2 {
92 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
93 let mut tokens = Vec::new();
94 let a: Ident = input.parse()?;
95 let b: Punct = input.parse()?;
96 if a != "name" {
97 panic!("expect name")
98 }
99 if b.as_char() != ':' {
100 panic!("expect colon")
101 }
102 let errname: syn::Ident = input.parse()?;
104 let _: Punct = input.parse()?;
105 let a: Ident = input.parse()?;
106 let b: Punct = input.parse()?;
107 if a != "txt" {
108 panic!("expect txt")
109 }
110 if b.as_char() != ':' {
111 panic!("expect colon")
112 }
113 let errdesc: syn::LitStr = input.parse()?;
114 let _p: Punct = input.parse()?;
115 let n: Ident = input.parse()?;
116 let p: Punct = input.parse()?;
117 if p.as_char() != ':' {
118 panic!("expect colon")
119 }
120 let mut variants = None;
121 if n == "variants" {
122 let gr: proc_macro2::Group = input.parse()?;
123 let p: Punct = input.parse()?;
124 if p.as_char() != ';' {
125 panic!("expect semicolon")
126 }
127 let mut vars = Vec::new();
128 let mut curr: Option<ErrorVariant> = None;
129 let mut finish_curr = |curr| {
130 vars.push(curr);
131 };
132 let stream = gr.stream();
133 for token in stream {
134 match token {
135 TokenTree::Group(x) => {
136 tokens.push(format!("GROUP[{}]", x));
137 let fg: VariantFieldGroup = syn::parse(x.stream().into())?;
138 let curr = curr.as_mut().unwrap();
139 curr.field_group = fg;
140 }
141 TokenTree::Ident(x) => {
142 tokens.push(format!("IDENT[{}]", x));
143 if let Some(_curr) = curr.as_mut() {
144 panic!("variant already in progress");
145 } else {
146 let v = ErrorVariant {
147 name: x,
148 field_group: VariantFieldGroup::Plain,
149 };
150 curr = Some(v);
151 }
152 }
153 TokenTree::Punct(x) => {
154 tokens.push(format!("PUNCT[{}]", x));
155 if let Some(curr) = curr.take() {
156 finish_curr(curr);
157 }
158 }
159 TokenTree::Literal(x) => {
160 tokens.push(format!("LITERAL[{}]", x));
161 }
162 }
163 }
164 if let Some(curr) = curr.take() {
165 finish_curr(curr);
166 }
167 variants = Some(vars);
168 }
169 let ret = Self {
171 errname,
172 errdesc,
173 variants: variants.expect("error variants"),
174 };
175 Ok(ret)
176 }
177}
178
179#[proc_macro]
180pub fn create_error_v2(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
181 let input = parse_macro_input!(input as MacroInput2);
182 let errname = input.errname.clone();
183 let errdesc = input.errdesc.clone();
184 let errname_litstr = syn::LitStr::new(&input.errname.to_string(), Span::call_site());
185 let mut vars_ts = TokenStream::new();
186 let mut froms_ts = TokenStream::new();
187 let mut fmtbranches_ts = TokenStream::new();
188 for v in input.variants {
189 let vn = &v.name;
190 let vn_litstr = syn::LitStr::new(&vn.to_string(), Span::call_site());
191 match v.field_group {
192 VariantFieldGroup::Plain => {
193 let q = quote! {
194 #vn,
195 };
196 vars_ts.extend(q);
197 let q = quote! {
198 #errname::#vn => ::core::write!(fmt, "{}::{}", #errname_litstr, #vn_litstr),
199 };
200 fmtbranches_ts.extend(q);
201 }
202 VariantFieldGroup::Basic(x) => {
203 let tys = &x.tys;
204 let q = quote! {
205 #vn(#(#tys),*),
206 };
207 vars_ts.extend(q);
208 let dvs: Vec<_> = x
209 .tys
210 .iter()
211 .zip(['a', 'b', 'c', 'd', 'e', 'f', 'g'].iter())
212 .map(|x| syn::Ident::new(&x.1.to_string(), Span::call_site()))
213 .collect();
214 let plcs: Vec<String> = x.tys.iter().map(|_| "{}".to_string()).collect();
215 let fmtstr = format!("{{}}::{{}}({})", plcs.join(", "));
216 let q = quote! {
217 #errname::#vn(#(#dvs),*) => ::core::write!(fmt, #fmtstr, #errname_litstr, #vn_litstr, #(#dvs),*),
218 };
219 fmtbranches_ts.extend(q);
220 }
221 VariantFieldGroup::From(x) => {
222 let tys = &x.tys;
223 let q = quote! {
224 #vn(#(#tys),*),
225 };
226 vars_ts.extend(q);
227
228 let dvs: Vec<_> = x
229 .tys
230 .iter()
231 .zip(['a', 'b', 'c', 'd', 'e', 'f', 'g'].iter())
232 .map(|x| syn::Ident::new(&x.1.to_string(), Span::call_site()))
233 .collect();
234 let plcs: Vec<String> = x.tys.iter().map(|_| "{}".to_string()).collect();
235 let fmtstr = format!("{{}}::{{}}({})", plcs.join(", "));
236 let q = quote! {
237 #errname::#vn(#(#dvs),*) => ::core::write!(fmt, #fmtstr, #errname_litstr, #vn_litstr, #(#dvs),*),
238 };
239 fmtbranches_ts.extend(q);
240
241 let ty = &x.tys[0];
242 let q = quote! {
243 impl From<#ty> for #errname {
244 fn from(value: #ty) -> Self {
245 Self::#vn(value)
246 }
247 }
248 };
249 froms_ts.extend(q);
250 }
251 }
252 }
253 let ret = quote! {
254 #[derive(Debug)]
255 pub enum #errname {
256 #vars_ts
257 }
258
259 impl #errname {
260 fn desc() -> &'static str {
261 #errdesc
262 }
263 }
264
265 #froms_ts
266
267 impl ::core::fmt::Display for #errname {
268 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
269 match self {
270 #fmtbranches_ts
271 }
272 }
273 }
274
275 impl ::core::error::Error for #errname {}
276
277 #[allow(non_snake_case)]
278 fn show() -> &'static str {
279 ""
280 }
281 };
282
283 ret.into()
284}
285
286struct TyNameSeq {
287 name: Ident,
288 desc: syn::LitStr,
289}
290
291impl syn::parse::Parse for TyNameSeq {
292 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
293 let name: Ident = input.parse()?;
294 let _p: syn::token::Comma = input.parse()?;
295 let desc: syn::LitStr = input.parse()?;
296 let ret = Self { name, desc };
297 Ok(ret)
298 }
299}
300
301struct MacroInput {
302 name: TyNameSeq,
303 variants: Vec<ErrorVariant>,
304}
305
306impl syn::parse::Parse for MacroInput {
307 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
308 if input.peek(syn::token::Pub) {
312 let _: syn::token::Pub = input.parse()?;
313 let _: syn::token::Comma = input.parse()?;
314 }
315 let a: Ident = input.parse()?;
316 let b: Group = input.parse()?;
317 if a != "name" {
318 panic!("expect name")
319 }
320 let name: TyNameSeq = syn::parse(b.stream().into())?;
321 let _: Punct = input.parse()?;
322 let _: syn::token::Enum = input.parse()?;
323 let n: Ident = input.parse()?;
324 let b: Group = input.parse()?;
325 let _: Punct = input.parse()?;
326 let mut variants = None;
327 if n == "variants" {
328 let gr: proc_macro2::Group = b;
329 let mut vars = Vec::new();
330 let mut curr: Option<ErrorVariant> = None;
331 let mut finish_curr = |curr| {
332 vars.push(curr);
333 };
334 let stream = gr.stream();
335 for token in stream {
336 match token {
337 TokenTree::Group(x) => {
338 let fg: VariantFieldGroup = syn::parse(x.stream().into())?;
339 let curr = curr.as_mut().unwrap();
340 curr.field_group = fg;
341 }
342 TokenTree::Ident(x) => {
343 if let Some(_curr) = curr.as_mut() {
344 panic!("variant already in progress");
345 } else {
346 let v = ErrorVariant {
347 name: x,
348 field_group: VariantFieldGroup::Plain,
349 };
350 curr = Some(v);
351 }
352 }
353 TokenTree::Punct(_x) => {
354 if let Some(curr) = curr.take() {
355 finish_curr(curr);
356 }
357 }
358 TokenTree::Literal(_x) => {}
359 }
360 }
361 if let Some(curr) = curr.take() {
362 finish_curr(curr);
363 }
364 variants = Some(vars);
365 }
366 let ret = Self {
368 name,
369 variants: variants.expect("error variants"),
370 };
371 Ok(ret)
372 }
373}
374
375#[proc_macro]
376pub fn create_error_v1(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
377 let input = parse_macro_input!(input as MacroInput);
378 let errname = input.name.name.clone();
379 let errdesc = input.name.desc.clone();
380 let mut vars_ts = TokenStream::new();
381 let mut froms_ts = TokenStream::new();
382 let mut fmtbranches_ts = TokenStream::new();
383 for v in input.variants {
384 let vn = &v.name;
385 let vn_litstr = syn::LitStr::new(&vn.to_string(), Span::call_site());
386 match v.field_group {
387 VariantFieldGroup::Plain => {
388 let q = quote! {
389 #vn,
390 };
391 vars_ts.extend(q);
392 let q = quote! {
393 #errname::#vn => ::core::write!(fmt, "{}::{}", #errname::txt(), #vn_litstr),
394 };
395 fmtbranches_ts.extend(q);
396 }
397 VariantFieldGroup::Basic(x) => {
398 let tys = &x.tys;
399 let q = quote! {
400 #vn(#(#tys),*),
401 };
402 vars_ts.extend(q);
403 let dvs: Vec<_> = x
404 .tys
405 .iter()
406 .zip(['a', 'b', 'c', 'd', 'e', 'f', 'g'].iter())
407 .map(|x| syn::Ident::new(&x.1.to_string(), Span::call_site()))
408 .collect();
409 let plcs: Vec<String> = x.tys.iter().map(|_| "{}".to_string()).collect();
410 let fmtstr = format!("{{}}::{{}}({})", plcs.join(", "));
411 let q = quote! {
412 #errname::#vn(#(#dvs),*) => ::core::write!(fmt, #fmtstr, #errname::txt(), #vn_litstr, #(#dvs),*),
413 };
414 fmtbranches_ts.extend(q);
415 }
416 VariantFieldGroup::From(x) => {
417 let tys = &x.tys;
418 let q = quote! {
419 #vn(#(#tys),*),
420 };
421 vars_ts.extend(q);
422
423 let dvs: Vec<_> = x
424 .tys
425 .iter()
426 .zip(['a', 'b', 'c', 'd', 'e', 'f', 'g'].iter())
427 .map(|x| syn::Ident::new(&x.1.to_string(), Span::call_site()))
428 .collect();
429 let plcs: Vec<String> = x.tys.iter().map(|_| "{}".to_string()).collect();
430 let fmtstr = format!("{{}}::{{}}({})", plcs.join(", "));
431 let q = quote! {
432 #errname::#vn(#(#dvs),*) => ::core::write!(fmt, #fmtstr, #errname::txt(), #vn_litstr, #(#dvs),*),
433 };
434 fmtbranches_ts.extend(q);
435
436 let ty = &x.tys[0];
437 let q = quote! {
438 impl From<#ty> for #errname {
439 fn from(value: #ty) -> Self {
440 Self::#vn(value)
441 }
442 }
443 };
444 froms_ts.extend(q);
445 }
446 }
447 }
448 let show_ident = quote::format_ident!("show_{}", errname);
449 let ret = quote! {
450 #[derive(Debug)]
451 pub enum #errname {
452 #vars_ts
453 }
454
455 impl #errname {
456 fn txt() -> &'static str {
457 #errdesc
458 }
459 }
460
461 #froms_ts
462
463 impl ::core::fmt::Display for #errname {
464 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
465 match self {
466 #fmtbranches_ts
467 }
468 }
469 }
470
471 impl ::core::error::Error for #errname {}
472
473 #[allow(non_snake_case)]
474 fn #show_ident() -> &'static str {
475 ""
476 }
477 };
478
479 ret.into()
480}
481
482#[proc_macro_derive(Error, attributes(backtrace, error, from, source, cstm))]
483pub fn derive_error(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
484 let input = parse_macro_input!(input as DeriveInput);
485 let helpers = expand::DummyHelpers::new();
486 expand::derive(&input, &helpers).into()
487}