Duplicate name checking now takes case insensitivity into account
This commit is contained in:
1 parent
ed83ffc5f3
commit
1fab354030
3 files changed
+71
-28
No files matched your search
@@ -1,11 +1,12 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{DataEnum, Fields};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
use crate::{CASE_INSENSITIVE, CRATE_ATTR, IGNORE, NAME, OTHER};
|
||||
use crate::TokenStream2;
|
||||
use crate::attribute::{Dict, Value};
|
||||
use crate::error::{MacroError, MacroResult};
|
||||
|
||||
@@ -47,10 +48,10 @@ impl<'a> Variant<'a> {
|
||||
enum_ident: &Ident,
|
||||
named_fn: &F,
|
||||
other_fn: &G
|
||||
) -> MacroResult<Option<(TokenStream, TokenStream)>>
|
||||
) -> MacroResult<Option<(TokenStream2, TokenStream2)>>
|
||||
where
|
||||
F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream>,
|
||||
G: Fn(&Variant, &Ident, TokenStream) -> MacroResult<TokenStream>
|
||||
F: Fn(&Variant, &Ident, &str) -> MacroResult<TokenStream2>,
|
||||
G: Fn(&Variant, &Ident, TokenStream2) -> MacroResult<TokenStream2>
|
||||
{
|
||||
let variant_ident = &self.data.ident;
|
||||
|
||||
@@ -84,6 +85,8 @@ impl<'a> Variant<'a> {
|
||||
pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
|
||||
let mut variants = Vec::with_capacity(data.variants.len());
|
||||
let mut taken_names = HashSet::new();
|
||||
let mut taken_insensitive_names = HashSet::new();
|
||||
let mut taken_sensitive_names = HashSet::new();
|
||||
let mut other_variant = false;
|
||||
|
||||
for variant in data.variants.iter() {
|
||||
@@ -167,6 +170,23 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
|
||||
));
|
||||
}
|
||||
|
||||
taken_names.insert(name.clone());
|
||||
|
||||
// Extra duplicate checking for case-insensitive names
|
||||
let lowercase_name = name.to_lowercase();
|
||||
if taken_insensitive_names.contains(&lowercase_name) || (case_insensitive && taken_sensitive_names.contains(&lowercase_name)) {
|
||||
return Err(MacroError::new(
|
||||
format!("duplicate name \"{}\"", name),
|
||||
name_span,
|
||||
));
|
||||
}
|
||||
|
||||
if case_insensitive {
|
||||
taken_insensitive_names.insert(lowercase_name);
|
||||
} else {
|
||||
taken_sensitive_names.insert(lowercase_name);
|
||||
}
|
||||
|
||||
// Return an error if the variant has any fields
|
||||
if variant.fields.len() != 0 {
|
||||
let variant_ident = variant.ident.to_string();
|
||||
@@ -189,8 +209,6 @@ pub(crate) fn parse_enum(data: &DataEnum) -> MacroResult<Enum> {
|
||||
Fields::Unit => VariantConstructor::None,
|
||||
};
|
||||
|
||||
taken_names.insert(name.clone());
|
||||
|
||||
Variant {
|
||||
data: variant,
|
||||
v_type: VariantType::Named { name, constructor, case_insensitive },
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
use proc_macro::TokenStream;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::result;
|
||||
|
||||
use proc_macro2::Span;
|
||||
use quote::quote_spanned;
|
||||
use syn::Error;
|
||||
|
||||
use crate::TokenStream2;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct MacroError {
|
||||
pub(crate) message: Cow<'static, str>,
|
||||
@@ -16,18 +19,18 @@ pub(crate) struct MacroError {
|
||||
pub(crate) type MacroResult<T> = result::Result<T, MacroError>;
|
||||
|
||||
impl MacroError {
|
||||
pub(crate) fn new<T>(message: T, span: Span) -> Self where T : Into<Cow<'static, str>> {
|
||||
pub(crate) fn new<T>(message: T, span: Span) -> Self where T: Into<Cow<'static, str>> {
|
||||
MacroError {
|
||||
message: message.into(),
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_token_stream(&self) -> proc_macro::TokenStream {
|
||||
pub(crate) fn to_token_stream(&self) -> TokenStream {
|
||||
self.to_token_stream2().into()
|
||||
}
|
||||
|
||||
pub(crate) fn to_token_stream2(&self) -> proc_macro2::TokenStream {
|
||||
pub(crate) fn to_token_stream2(&self) -> TokenStream2 {
|
||||
let message = &self.message;
|
||||
quote_spanned! {
|
||||
self.span => ::std::compile_error!(#message);
|
||||
@@ -41,13 +44,13 @@ impl From<syn::Error> for MacroError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MacroError> for proc_macro::TokenStream {
|
||||
impl From<MacroError> for TokenStream {
|
||||
fn from(err: MacroError) -> Self {
|
||||
err.to_token_stream()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MacroError> for proc_macro2::TokenStream {
|
||||
impl From<MacroError> for TokenStream2 {
|
||||
fn from(err: MacroError) -> Self {
|
||||
err.to_token_stream2()
|
||||
}
|
||||
@@ -63,7 +66,7 @@ impl error::Error for MacroError {}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct ValueTypeError {
|
||||
pub(crate) message: Cow<'static, str>
|
||||
pub(crate) message: Cow<'static, str>,
|
||||
}
|
||||
|
||||
pub(crate) type ValueTypeResult<T> = result::Result<T, ValueTypeError>;
|
||||
|
||||
@@ -9,7 +9,7 @@ use syn::{Data, DataEnum, DeriveInput};
|
||||
|
||||
use error::{MacroError, MacroResult};
|
||||
|
||||
use crate::enums::Variant;
|
||||
use crate::enums::{Variant, VariantType};
|
||||
use proc_macro2::Ident;
|
||||
|
||||
mod enums;
|
||||
@@ -55,15 +55,11 @@ fn derive_scribe<F, G, E>(
|
||||
|
||||
let enum_ident = &input.ident;
|
||||
|
||||
let mut match_patterns = Vec::with_capacity(parsed_enum.variants.len());
|
||||
let mut match_results = Vec::with_capacity(parsed_enum.variants.len());
|
||||
let mut match_arms = Vec::with_capacity(parsed_enum.variants.len());
|
||||
|
||||
for variant in parsed_enum.variants.iter() {
|
||||
match variant.match_variant(enum_ident, &named_fn, &other_fn) {
|
||||
Ok(Some((pattern, result))) => {
|
||||
match_patterns.push(pattern);
|
||||
match_results.push(result);
|
||||
}
|
||||
Ok(Some((pattern, result))) => match_arms.push(quote! { #pattern => #result }),
|
||||
Ok(None) => return ignore_err_fn(variant, enum_ident).into(),
|
||||
Err(err) => return err.into()
|
||||
}
|
||||
@@ -73,7 +69,7 @@ fn derive_scribe<F, G, E>(
|
||||
impl #trait_ident for #enum_ident {
|
||||
fn scribe(&self) -> #trait_return_type {
|
||||
match self {
|
||||
#(#match_patterns => #match_results,)*
|
||||
#(#match_arms,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,15 +97,11 @@ fn derive_try_scribe<F, G>(
|
||||
let enum_ident = &input.ident;
|
||||
|
||||
let mut ignore_variant = false;
|
||||
let mut match_patterns = Vec::with_capacity(parsed_enum.variants.len());
|
||||
let mut match_results = Vec::with_capacity(parsed_enum.variants.len());
|
||||
let mut match_arms = Vec::with_capacity(parsed_enum.variants.len());
|
||||
|
||||
for variant in parsed_enum.variants.iter() {
|
||||
match variant.match_variant(enum_ident, &named_fn, &other_fn) {
|
||||
Ok(Some((pattern, result))) => {
|
||||
match_patterns.push(pattern);
|
||||
match_results.push(result);
|
||||
}
|
||||
Ok(Some((pattern, result))) => match_arms.push(quote! { #pattern => #result }),
|
||||
Ok(None) => ignore_variant = true,
|
||||
Err(err) => return err.into()
|
||||
}
|
||||
@@ -125,7 +117,7 @@ fn derive_try_scribe<F, G>(
|
||||
impl #trait_ident for #enum_ident {
|
||||
fn try_scribe(&self) -> #trait_return_type {
|
||||
match self {
|
||||
#(#match_patterns => #match_results,)*
|
||||
#(#match_arms,)*
|
||||
#ignore_arm
|
||||
}
|
||||
}
|
||||
@@ -290,6 +282,36 @@ pub fn derive_try_scribe_cow_str(input: TokenStream) -> TokenStream {
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Unscribe, attributes(enumscribe))]
|
||||
pub fn derive_unscribe(input: TokenStream) -> TokenStream {
|
||||
// let input: DeriveInput = syn::parse(input)
|
||||
// .expect("failed to parse input");
|
||||
//
|
||||
// let enum_data = proc_try!(get_enum_data(&input));
|
||||
// let parsed_enum = proc_try!(enums::parse_enum(enum_data));
|
||||
//
|
||||
// let enum_ident = &input.ident;
|
||||
//
|
||||
// let mut other_arm = None;
|
||||
// let mut case_sensitive_arms = Vec::new();
|
||||
// let mut case_insensitive_arms = Vec::new();
|
||||
//
|
||||
// for variant in parsed_enum.variants.iter() {
|
||||
// match variant.v_type {
|
||||
// VariantType::Ignore => {}
|
||||
// VariantType::Named { .. } => {}
|
||||
// VariantType::Other { .. } => {}
|
||||
// }
|
||||
// }
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(TryUnscribe, attributes(enumscribe))]
|
||||
pub fn derive_try_unscribe(input: TokenStream) -> TokenStream {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_enum_data(input: &DeriveInput) -> MacroResult<&DataEnum> {
|
||||
let enum_data = match &input.data {
|
||||
Data::Enum(enum_data) => enum_data,
|
||||
|
||||
Reference in new issue
Block a user