summaryrefslogtreecommitdiff
path: root/src/code.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/code.rs')
-rw-r--r--src/code.rs80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/code.rs b/src/code.rs
new file mode 100644
index 0000000..22dc795
--- /dev/null
+++ b/src/code.rs
@@ -0,0 +1,80 @@
+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))
+ }
+ })
+ }
+}