| use proc_macro2::TokenStream; |
| use quote::quote; |
| use syn::{ |
| parenthesized, |
| parse::{Parse, ParseStream}, |
| Token, |
| }; |
| |
| use crate::{ |
| diagnostic::{DiagnosticConcreteArgs, DiagnosticDef}, |
| forward::WhichFn, |
| utils::gen_all_variants_with, |
| }; |
| |
| #[derive(Debug)] |
| pub struct Code(pub String); |
| |
| impl Parse for Code { |
| fn parse(input: ParseStream) -> syn::Result<Self> { |
| let ident = input.parse::<syn::Ident>()?; |
| if ident == "code" { |
| let la = input.lookahead1(); |
| if la.peek(syn::token::Paren) { |
| let content; |
| parenthesized!(content in input); |
| let la = content.lookahead1(); |
| if la.peek(syn::LitStr) { |
| let str = content.parse::<syn::LitStr>()?; |
| Ok(Code(str.value())) |
| } else { |
| let path = content.parse::<syn::Path>()?; |
| Ok(Code( |
| path.segments |
| .iter() |
| .map(|s| s.ident.to_string()) |
| .collect::<Vec<_>>() |
| .join("::"), |
| )) |
| } |
| } else { |
| input.parse::<Token![=]>()?; |
| Ok(Code(input.parse::<syn::LitStr>()?.value())) |
| } |
| } else { |
| Err(syn::Error::new(ident.span(), "diagnostic code is required. Use #[diagnostic(code = ...)] or #[diagnostic(code(...))] to define one.")) |
| } |
| } |
| } |
| |
| impl Code { |
| pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> { |
| gen_all_variants_with( |
| variants, |
| WhichFn::Code, |
| |ident, fields, DiagnosticConcreteArgs { code, .. }| { |
| let code = &code.as_ref()?.0; |
| Some(match fields { |
| syn::Fields::Named(_) => { |
| quote! { Self::#ident { .. } => std::option::Option::Some(std::boxed::Box::new(#code)), } |
| } |
| syn::Fields::Unnamed(_) => { |
| quote! { Self::#ident(..) => std::option::Option::Some(std::boxed::Box::new(#code)), } |
| } |
| syn::Fields::Unit => { |
| quote! { Self::#ident => std::option::Option::Some(std::boxed::Box::new(#code)), } |
| } |
| }) |
| }, |
| ) |
| } |
| |
| pub(crate) fn gen_struct(&self) -> Option<TokenStream> { |
| let code = &self.0; |
| Some(quote! { |
| fn code(&self) -> std::option::Option<std::boxed::Box<dyn std::fmt::Display + '_>> { |
| std::option::Option::Some(std::boxed::Box::new(#code)) |
| } |
| }) |
| } |
| } |