locspan-derive 0.6.0

Derive macros for the `locspan` code mapping library
Documentation
use crate::{Method, ParamConfig};
use std::collections::HashMap;
use syn::parse;
use syn::punctuated::Punctuated;
use syn::token;

pub(crate) fn parse_field_attributes(attrs: &[syn::Attribute]) -> syn::Result<Method> {
	for attr in attrs {
		if attr.path.is_ident("locspan") {
			let tokens = attr.tokens.clone().into();
			let locspan_attr: FieldAttribute = syn::parse(tokens)?;

			return Ok(locspan_attr.method);
		}
	}

	Ok(Method::Normal)
}

struct FieldAttribute {
	_paren: token::Paren,
	method: Method,
	_method_ident: syn::Ident,
}

impl parse::Parse for FieldAttribute {
	fn parse(input: parse::ParseStream) -> syn::Result<Self> {
		let content;
		let _paren = syn::parenthesized!(content in input);
		let _method_ident = syn::Ident::parse(&content)?;

		let method = if _method_ident == "stripped" {
			Method::Stripped
		} else if _method_ident == "ignore" {
			Method::Ignore
		} else if _method_ident == "deref_stripped" {
			Method::DerefThenStripped
		} else if _method_ident == "deref2_stripped" {
			Method::Deref2ThenStripped
		} else if _method_ident == "unwrap_stripped" {
			Method::UnwrapThenStripped
		} else if _method_ident == "unwrap_deref_stripped" {
			Method::UnwrapThenDerefThenStripped
		} else if _method_ident == "unwrap_deref2_stripped" {
			Method::UnwrapThenDeref2ThenStripped
		} else {
			return Err(syn::Error::new_spanned(
				_method_ident,
				"invalid locspan-derive attribute",
			));
		};

		Ok(Self {
			_paren,
			method,
			_method_ident,
		})
	}
}

pub(crate) fn parse_type_attributes(
	attrs: Vec<syn::Attribute>,
) -> HashMap<proc_macro2::Ident, ParamConfig> {
	let mut params = HashMap::new();

	for attr in attrs {
		if attr.path.is_ident("locspan") {
			let tokens = attr.tokens.into();
			let locspan_attrs: TypeAttributes = syn::parse(tokens).unwrap();

			for ty_attr in locspan_attrs.list {
				for ident in ty_attr.idents {
					let conf: &mut ParamConfig = params.entry(ident).or_default();
					match ty_attr.kind {
						TypeAttributeKind::Ignore => conf.ignore = true,
						TypeAttributeKind::Stripped => conf.stripped = true,
						TypeAttributeKind::Fixed => conf.fixed = true,
					}
				}
			}
		}
	}

	params
}

struct TypeAttributes {
	_paren: token::Paren,
	list: Punctuated<TypeAttribute, token::Comma>,
}

impl parse::Parse for TypeAttributes {
	fn parse(input: parse::ParseStream) -> syn::Result<Self> {
		let content;
		Ok(Self {
			_paren: syn::parenthesized!(content in input),
			list: Punctuated::parse_terminated(&content)?,
		})
	}
}

pub enum TypeAttributeKind {
	Ignore,
	Stripped,
	Fixed,
}

pub struct TypeAttribute {
	kind: TypeAttributeKind,
	_kind_ident: syn::Ident,
	_paren: token::Paren,
	idents: Punctuated<syn::Ident, token::Comma>,
}

impl parse::Parse for TypeAttribute {
	fn parse(input: parse::ParseStream) -> syn::Result<Self> {
		let kind_ident = syn::Ident::parse(input)?;

		let kind = if kind_ident == "ignore" {
			TypeAttributeKind::Ignore
		} else if kind_ident == "stripped" {
			TypeAttributeKind::Stripped
		} else if kind_ident == "fixed" {
			TypeAttributeKind::Fixed
		} else {
			return Err(syn::Error::new_spanned(
				kind_ident,
				"invalid locspan-derive attribute",
			));
		};

		let content;
		Ok(Self {
			kind,
			_kind_ident: kind_ident,
			_paren: syn::parenthesized!(content in input),
			idents: Punctuated::parse_terminated(&content)?,
		})
	}
}