miette_derive/
severity.rs

1use proc_macro2::{Span, TokenStream};
2use quote::quote;
3use syn::{
4    parenthesized,
5    parse::{Parse, ParseStream},
6    Token,
7};
8
9use crate::{
10    diagnostic::{DiagnosticConcreteArgs, DiagnosticDef},
11    forward::WhichFn,
12    utils::gen_all_variants_with,
13};
14
15pub struct Severity(pub syn::Ident);
16
17impl Parse for Severity {
18    fn parse(input: ParseStream) -> syn::Result<Self> {
19        let ident = input.parse::<syn::Ident>()?;
20        if ident == "severity" {
21            let la = input.lookahead1();
22            if la.peek(syn::token::Paren) {
23                let content;
24                parenthesized!(content in input);
25                let la = content.lookahead1();
26                if la.peek(syn::LitStr) {
27                    let str = content.parse::<syn::LitStr>()?;
28                    let sev = get_severity(&str.value(), str.span())?;
29                    Ok(Severity(syn::Ident::new(&sev, str.span())))
30                } else {
31                    let ident = content.parse::<syn::Ident>()?;
32                    let sev = get_severity(&ident.to_string(), ident.span())?;
33                    Ok(Severity(syn::Ident::new(&sev, ident.span())))
34                }
35            } else {
36                input.parse::<Token![=]>()?;
37                let str = input.parse::<syn::LitStr>()?;
38                let sev = get_severity(&str.value(), str.span())?;
39                Ok(Severity(syn::Ident::new(&sev, str.span())))
40            }
41        } else {
42            Err(syn::Error::new(
43                ident.span(),
44                "MIETTE BUG: not a severity option",
45            ))
46        }
47    }
48}
49
50fn get_severity(input: &str, span: Span) -> syn::Result<String> {
51    match input.to_lowercase().as_ref() {
52        "error" | "err" => Ok("Error".into()),
53        "warning" | "warn" => Ok("Warning".into()),
54        "advice" | "adv" | "info" => Ok("Advice".into()),
55        _ => Err(syn::Error::new(
56            span,
57            "Invalid severity level. Only Error, Warning, and Advice are supported.",
58        )),
59    }
60}
61
62impl Severity {
63    pub(crate) fn gen_enum(variants: &[DiagnosticDef]) -> Option<TokenStream> {
64        gen_all_variants_with(
65            variants,
66            WhichFn::Severity,
67            |ident, fields, DiagnosticConcreteArgs { severity, .. }| {
68                let severity = &severity.as_ref()?.0;
69                let fields = match fields {
70                    syn::Fields::Named(_) => quote! { { .. } },
71                    syn::Fields::Unnamed(_) => quote! { (..) },
72                    syn::Fields::Unit => quote! {},
73                };
74                Some(
75                    quote! { Self::#ident #fields => std::option::Option::Some(miette::Severity::#severity), },
76                )
77            },
78        )
79    }
80
81    pub(crate) fn gen_struct(&self) -> Option<TokenStream> {
82        let sev = &self.0;
83        Some(quote! {
84            fn severity(&self) -> std::option::Option<miette::Severity> {
85                Some(miette::Severity::#sev)
86            }
87        })
88    }
89}