Duplicate name checking now takes case insensitivity into account

rename
Pantonshire 5 years ago
parent ed83ffc5f3
commit 1fab354030

@ -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,

Loading…
Cancel
Save