mirror of https://github.com/zkat/miette.git
fix(derive): #[diagnosic(severity)] works for named and unnamed variants/structs now
Fixes: https://github.com/zkat/miette/issues/26
This commit is contained in:
parent
729ccd32da
commit
adf0bc933f
|
|
@ -10,6 +10,7 @@ mod fmt;
|
|||
mod help;
|
||||
mod severity;
|
||||
mod snippets;
|
||||
mod utils;
|
||||
|
||||
#[proc_macro_derive(Diagnostic, attributes(diagnostic, snippet, highlight))]
|
||||
pub fn derive_diagnostic(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
parenthesized,
|
||||
|
|
@ -8,7 +8,7 @@ use syn::{
|
|||
|
||||
use crate::diagnostic::DiagnosticVariant;
|
||||
|
||||
pub struct Severity(pub syn::Path);
|
||||
pub struct Severity(pub syn::Ident);
|
||||
|
||||
impl Parse for Severity {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
|
|
@ -21,20 +21,40 @@ impl Parse for Severity {
|
|||
let la = content.lookahead1();
|
||||
if la.peek(syn::LitStr) {
|
||||
let str = content.parse::<syn::LitStr>()?;
|
||||
Ok(Severity(str.parse()?))
|
||||
let sev = get_severity(&str.value(), str.span())?;
|
||||
Ok(Severity(syn::Ident::new(&sev, str.span())))
|
||||
} else {
|
||||
let path = content.parse::<syn::Path>()?;
|
||||
Ok(Severity(path))
|
||||
let ident = content.parse::<syn::Ident>()?;
|
||||
let sev = get_severity(&ident.to_string(), ident.span())?;
|
||||
Ok(Severity(syn::Ident::new(&sev, ident.span())))
|
||||
}
|
||||
} else {
|
||||
input.parse::<Token![=]>()?;
|
||||
Ok(Severity(input.parse::<syn::LitStr>()?.parse()?))
|
||||
let str = input.parse::<syn::LitStr>()?;
|
||||
let sev = get_severity(&str.value(), str.span())?;
|
||||
Ok(Severity(syn::Ident::new(&sev, str.span())))
|
||||
}
|
||||
} else {
|
||||
Err(syn::Error::new(ident.span(), "not a severity level."))
|
||||
Err(syn::Error::new(
|
||||
ident.span(),
|
||||
"MIETTE BUG: not a severity option",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_severity(input: &str, span: Span) -> syn::Result<String> {
|
||||
match input.to_lowercase().as_ref() {
|
||||
"error" | "err" => Ok("Error".into()),
|
||||
"warning" | "warn" => Ok("Warning".into()),
|
||||
"advice" | "adv" | "info" => Ok("Advice".into()),
|
||||
_ => Err(syn::Error::new(
|
||||
span,
|
||||
"Invalid severity level. Only Error, Warning, and Advice are supported.",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
impl Severity {
|
||||
pub(crate) fn gen_enum(variants: &[DiagnosticVariant]) -> Option<TokenStream> {
|
||||
let sev_pairs = variants
|
||||
|
|
@ -42,10 +62,15 @@ impl Severity {
|
|||
.filter(|v| v.severity.is_some())
|
||||
.map(
|
||||
|DiagnosticVariant {
|
||||
ident, severity, ..
|
||||
ident, severity, fields, ..
|
||||
}| {
|
||||
let severity = &severity.as_ref().unwrap().0;
|
||||
quote! { Self::#ident => std::option::Option::Some(miette::Severity::#severity), }
|
||||
let fields = match fields {
|
||||
syn::Fields::Named(_) => quote! { { .. } },
|
||||
syn::Fields::Unnamed(_) => quote! { (..) },
|
||||
syn::Fields::Unit => quote!{},
|
||||
};
|
||||
quote! { Self::#ident #fields => std::option::Option::Some(miette::Severity::#severity), }
|
||||
},
|
||||
)
|
||||
.collect::<Vec<_>>();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
punctuated::Punctuated,
|
||||
|
|
@ -10,6 +10,7 @@ use syn::{
|
|||
};
|
||||
|
||||
use crate::diagnostic::DiagnosticVariant;
|
||||
use crate::utils::MemberOrString;
|
||||
|
||||
pub struct Snippets(Vec<Snippet>);
|
||||
|
||||
|
|
@ -33,37 +34,6 @@ struct HighlightAttr {
|
|||
snippet: syn::Member,
|
||||
}
|
||||
|
||||
enum MemberOrString {
|
||||
Member(syn::Member),
|
||||
String(syn::LitStr),
|
||||
}
|
||||
|
||||
impl ToTokens for MemberOrString {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
use MemberOrString::*;
|
||||
match self {
|
||||
Member(member) => member.to_tokens(tokens),
|
||||
String(string) => string.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for MemberOrString {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(syn::Ident) || lookahead.peek(syn::LitInt) {
|
||||
Ok(MemberOrString::Member(input.parse()?))
|
||||
} else if lookahead.peek(syn::LitStr) {
|
||||
Ok(MemberOrString::String(input.parse()?))
|
||||
} else {
|
||||
Err(syn::Error::new(
|
||||
input.span(),
|
||||
"Expected a string or a field reference.",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for SnippetAttr {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let punc = Punctuated::<MemberOrString, Token![,]>::parse_terminated(input)?;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
|
||||
pub(crate) enum MemberOrString {
|
||||
Member(syn::Member),
|
||||
String(syn::LitStr),
|
||||
}
|
||||
|
||||
impl ToTokens for MemberOrString {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
use MemberOrString::*;
|
||||
match self {
|
||||
Member(member) => member.to_tokens(tokens),
|
||||
String(string) => string.to_tokens(tokens),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for MemberOrString {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(syn::Ident) || lookahead.peek(syn::LitInt) {
|
||||
Ok(MemberOrString::Member(input.parse()?))
|
||||
} else if lookahead.peek(syn::LitStr) {
|
||||
Ok(MemberOrString::String(input.parse()?))
|
||||
} else {
|
||||
Err(syn::Error::new(
|
||||
input.span(),
|
||||
"Expected a string or a field reference.",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -92,7 +92,7 @@ fn path_code() {
|
|||
fn path_severity() {
|
||||
#[derive(Debug, Diagnostic, Error)]
|
||||
#[error("welp")]
|
||||
#[diagnostic(code(foo::bar::baz), severity(Warning))]
|
||||
#[diagnostic(code(foo::bar::baz), severity("warning"))]
|
||||
struct FooStruct;
|
||||
|
||||
assert_eq!(Some(Severity::Warning), FooStruct.severity());
|
||||
|
|
|
|||
Loading…
Reference in New Issue