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 let mut tokens = Vec::new();
309 let a: Ident = input.parse()?;
310 let b: Group = input.parse()?;
311 if a != "name" {
312 panic!("expect name")
313 }
314 let name: TyNameSeq = syn::parse(b.stream().into())?;
315 let _: Punct = input.parse()?;
316 let _: syn::token::Enum = input.parse()?;
317 let n: Ident = input.parse()?;
318 let b: Group = input.parse()?;
319 let _: Punct = input.parse()?;
320 let mut variants = None;
321 if n == "variants" {
322 let gr: proc_macro2::Group = b;
323 let mut vars = Vec::new();
324 let mut curr: Option<ErrorVariant> = None;
325 let mut finish_curr = |curr| {
326 vars.push(curr);
327 };
328 let stream = gr.stream();
329 for token in stream {
330 match token {
331 TokenTree::Group(x) => {
332 tokens.push(format!("GROUP[{}]", x));
333 let fg: VariantFieldGroup = syn::parse(x.stream().into())?;
334 let curr = curr.as_mut().unwrap();
335 curr.field_group = fg;
336 }
337 TokenTree::Ident(x) => {
338 tokens.push(format!("IDENT[{}]", x));
339 if let Some(_curr) = curr.as_mut() {
340 panic!("variant already in progress");
341 } else {
342 let v = ErrorVariant {
343 name: x,
344 field_group: VariantFieldGroup::Plain,
345 };
346 curr = Some(v);
347 }
348 }
349 TokenTree::Punct(x) => {
350 tokens.push(format!("PUNCT[{}]", x));
351 if let Some(curr) = curr.take() {
352 finish_curr(curr);
353 }
354 }
355 TokenTree::Literal(x) => {
356 tokens.push(format!("LITERAL[{}]", x));
357 }
358 }
359 }
360 if let Some(curr) = curr.take() {
361 finish_curr(curr);
362 }
363 variants = Some(vars);
364 }
365 let ret = Self {
367 name,
368 variants: variants.expect("error variants"),
369 };
370 Ok(ret)
371 }
372}
373
374#[proc_macro]
375pub fn create_error_v1(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
376 let input = parse_macro_input!(input as MacroInput);
377 let errname = input.name.name.clone();
378 let errdesc = input.name.desc.clone();
379 let mut vars_ts = TokenStream::new();
380 let mut froms_ts = TokenStream::new();
381 let mut fmtbranches_ts = TokenStream::new();
382 for v in input.variants {
383 let vn = &v.name;
384 let vn_litstr = syn::LitStr::new(&vn.to_string(), Span::call_site());
385 match v.field_group {
386 VariantFieldGroup::Plain => {
387 let q = quote! {
388 #vn,
389 };
390 vars_ts.extend(q);
391 let q = quote! {
392 #errname::#vn => ::core::write!(fmt, "{}::{}", #errname::txt(), #vn_litstr),
393 };
394 fmtbranches_ts.extend(q);
395 }
396 VariantFieldGroup::Basic(x) => {
397 let tys = &x.tys;
398 let q = quote! {
399 #vn(#(#tys),*),
400 };
401 vars_ts.extend(q);
402 let dvs: Vec<_> = x
403 .tys
404 .iter()
405 .zip(['a', 'b', 'c', 'd', 'e', 'f', 'g'].iter())
406 .map(|x| syn::Ident::new(&x.1.to_string(), Span::call_site()))
407 .collect();
408 let plcs: Vec<String> = x.tys.iter().map(|_| "{}".to_string()).collect();
409 let fmtstr = format!("{{}}::{{}}({})", plcs.join(", "));
410 let q = quote! {
411 #errname::#vn(#(#dvs),*) => ::core::write!(fmt, #fmtstr, #errname::txt(), #vn_litstr, #(#dvs),*),
412 };
413 fmtbranches_ts.extend(q);
414 }
415 VariantFieldGroup::From(x) => {
416 let tys = &x.tys;
417 let q = quote! {
418 #vn(#(#tys),*),
419 };
420 vars_ts.extend(q);
421
422 let dvs: Vec<_> = x
423 .tys
424 .iter()
425 .zip(['a', 'b', 'c', 'd', 'e', 'f', 'g'].iter())
426 .map(|x| syn::Ident::new(&x.1.to_string(), Span::call_site()))
427 .collect();
428 let plcs: Vec<String> = x.tys.iter().map(|_| "{}".to_string()).collect();
429 let fmtstr = format!("{{}}::{{}}({})", plcs.join(", "));
430 let q = quote! {
431 #errname::#vn(#(#dvs),*) => ::core::write!(fmt, #fmtstr, #errname::txt(), #vn_litstr, #(#dvs),*),
432 };
433 fmtbranches_ts.extend(q);
434
435 let ty = &x.tys[0];
436 let q = quote! {
437 impl From<#ty> for #errname {
438 fn from(value: #ty) -> Self {
439 Self::#vn(value)
440 }
441 }
442 };
443 froms_ts.extend(q);
444 }
445 }
446 }
447 let show_ident = quote::format_ident!("show_{}", errname);
448 let ret = quote! {
449 #[derive(Debug)]
450 pub enum #errname {
451 #vars_ts
452 }
453
454 impl #errname {
455 fn txt() -> &'static str {
456 #errdesc
457 }
458 }
459
460 #froms_ts
461
462 impl ::core::fmt::Display for #errname {
463 fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
464 match self {
465 #fmtbranches_ts
466 }
467 }
468 }
469
470 impl ::core::error::Error for #errname {}
471
472 #[allow(non_snake_case)]
473 fn #show_ident() -> &'static str {
474 ""
475 }
476 };
477
478 ret.into()
479}
480
481#[proc_macro_derive(Error, attributes(backtrace, error, from, source, cstm))]
482pub fn derive_error(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
483 let input = parse_macro_input!(input as DeriveInput);
484 let helpers = expand::DummyHelpers::new();
485 expand::derive(&input, &helpers).into()
486}