update to syn-2

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2023-10-02 10:33:32 +02:00
parent b32c4fd40a
commit cb86559d13
6 changed files with 107 additions and 76 deletions

View File

@ -21,7 +21,7 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0", features = [ "full" ] }
syn = { version = "2", features = [ "full" ] }
[dev-dependencies]
perlmod = { path = "../perlmod" }

View File

@ -1,7 +1,7 @@
use proc_macro2::{Ident, Span};
use syn::AttributeArgs;
use syn::Error;
use syn::punctuated::Punctuated;
use syn::{Error, Meta, Token};
pub struct ModuleAttrs {
pub package_name: String,
@ -22,10 +22,10 @@ fn is_ident_check_dup<T>(path: &syn::Path, var: &Option<T>, what: &'static str)
}
}
impl TryFrom<AttributeArgs> for ModuleAttrs {
impl TryFrom<Punctuated<Meta, Token![,]>> for ModuleAttrs {
type Error = Error;
fn try_from(args: AttributeArgs) -> Result<Self, Self::Error> {
fn try_from(args: Punctuated<Meta, Token![,]>) -> Result<Self, Self::Error> {
let mut package_name = None;
let mut file_name = None;
let mut lib_name = None;
@ -33,36 +33,31 @@ impl TryFrom<AttributeArgs> for ModuleAttrs {
let mut boot = None;
for arg in args {
match arg {
syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
path,
lit: syn::Lit::Str(litstr),
..
})) => {
if is_ident_check_dup(&path, &package_name, "name") {
package_name = Some(expand_env_vars(&litstr)?);
} else if is_ident_check_dup(&path, &file_name, "file") {
file_name = Some(expand_env_vars(&litstr)?);
} else if is_ident_check_dup(&path, &lib_name, "lib") {
lib_name = Some(expand_env_vars(&litstr)?);
} else if is_ident_check_dup(&path, &boot, "boot") {
boot = Some(litstr.parse::<syn::Path>()?);
} else {
error!(path => "unknown argument");
}
let (path, value) = match arg {
syn::Meta::NameValue(syn::MetaNameValue { path, value, .. }) => (path, value),
_ => {
error!(Span::call_site(), "unexpected attribute argument");
continue;
}
syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
path,
lit: syn::Lit::Bool(litbool),
..
})) => {
if is_ident_check_dup(&path, &write, "write") {
write = Some(litbool.value());
} else {
error!(path => "unknown argument");
}
}
_ => error!(Span::call_site(), "unexpected attribute argument"),
};
if is_ident_check_dup(&path, &package_name, "name") {
let Some(litstr) = expect_lit_str(value) else { continue };
package_name = Some(expand_env_vars(&litstr)?);
} else if is_ident_check_dup(&path, &file_name, "file") {
let Some(litstr) = expect_lit_str(value) else { continue };
file_name = Some(expand_env_vars(&litstr)?);
} else if is_ident_check_dup(&path, &lib_name, "lib") {
let Some(litstr) = expect_lit_str(value) else { continue };
lib_name = Some(expand_env_vars(&litstr)?);
} else if is_ident_check_dup(&path, &boot, "boot") {
let Some(litstr) = expect_lit_str(value) else { continue };
boot = Some(litstr.parse::<syn::Path>()?);
} else if is_ident_check_dup(&path, &write, "write") {
let Some(litbool) = expect_lit_bool(value) else { continue };
write = Some(litbool.value());
} else {
error!(path => "unknown argument");
}
}
@ -137,19 +132,16 @@ pub struct FunctionAttrs {
pub errno: bool,
}
impl TryFrom<AttributeArgs> for FunctionAttrs {
impl TryFrom<Punctuated<Meta, Token![,]>> for FunctionAttrs {
type Error = Error;
fn try_from(args: AttributeArgs) -> Result<Self, Self::Error> {
fn try_from(args: Punctuated<Meta, Token![,]>) -> Result<Self, Self::Error> {
let mut attrs = FunctionAttrs::default();
for arg in args {
match arg {
syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
path,
lit: syn::Lit::Str(litstr),
..
})) => {
syn::Meta::NameValue(syn::MetaNameValue { path, value, .. }) => {
let Some(litstr) = expect_lit_str(value) else { continue };
if is_ident_check_dup(&path, &attrs.xs_name, "xs_name") {
attrs.xs_name = Some(Ident::new(&litstr.value(), litstr.span()));
} else if is_ident_check_dup(&path, &attrs.perl_name, "name") {
@ -161,7 +153,7 @@ impl TryFrom<AttributeArgs> for FunctionAttrs {
continue;
}
}
syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
syn::Meta::Path(path) => {
if path.is_ident("raw_return") {
attrs.raw_return = true;
} else if path.is_ident("serialize_error") {
@ -179,3 +171,29 @@ impl TryFrom<AttributeArgs> for FunctionAttrs {
Ok(attrs)
}
}
fn expect_lit_str(value: syn::Expr) -> Option<syn::LitStr> {
match value {
syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
..
}) => Some(lit),
_ => {
error!(value => "value must be a literal string");
None
}
}
}
fn expect_lit_bool(value: syn::Expr) -> Option<syn::LitBool> {
match value {
syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Bool(lit),
..
}) => Some(lit),
_ => {
error!(value => "value must be a literal boolean");
None
}
}
}

View File

@ -2,7 +2,7 @@ use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use syn::spanned::Spanned;
use syn::Error;
use syn::{Error, Meta};
use crate::attribs::FunctionAttrs;
@ -41,6 +41,17 @@ impl ArgumentAttrs {
true
}
fn handle_attr(&mut self, attr: &syn::Attribute) -> bool {
if self.handle_path(attr.path()) {
if !matches!(attr.meta, Meta::Path(_)) {
error!(&attr.meta => "attribute does not take any value or parameter");
}
true
} else {
false
}
}
fn validate(&self, span: Span) -> Result<(), Error> {
if self.raw as usize + self.try_from_ref as usize + self.cv.is_some() as usize > 1 {
bail!(
@ -104,8 +115,7 @@ pub fn handle_function(
let pat_ty = match arg {
syn::FnArg::Receiver(_) => bail!(arg => "cannot export self-taking methods as xsubs"),
syn::FnArg::Typed(ref mut pt) => {
pt.attrs
.retain(|attr| !argument_attrs.handle_path(&attr.path));
pt.attrs.retain(|attr| !argument_attrs.handle_attr(&attr));
argument_attrs.validate(pt.span())?;
&*pt
}

View File

@ -10,9 +10,9 @@ use std::cell::RefCell;
use proc_macro::TokenStream as TokenStream_1;
use proc_macro2::TokenStream;
use syn::parse_macro_input;
use syn::AttributeArgs;
use syn::Error;
use syn::parse::Parser;
use syn::punctuated::Punctuated;
use syn::{Error, Meta, Token};
macro_rules! format_err {
($span:expr => $($msg:tt)*) => { Error::new_spanned($span, format!($($msg)*)) };
@ -86,7 +86,6 @@ pub(crate) fn pthx_param() -> TokenStream {
#[proc_macro_attribute]
pub fn package(attr: TokenStream_1, item: TokenStream_1) -> TokenStream_1 {
let _error_guard = init_local_error();
let attr = parse_macro_input!(attr as AttributeArgs);
let item: TokenStream = item.into();
handle_error(perlmod_impl(attr, item)).into()
}
@ -96,12 +95,12 @@ pub fn package(attr: TokenStream_1, item: TokenStream_1) -> TokenStream_1 {
#[proc_macro_attribute]
pub fn export(attr: TokenStream_1, item: TokenStream_1) -> TokenStream_1 {
let _error_guard = init_local_error();
let attr = parse_macro_input!(attr as AttributeArgs);
let item: TokenStream = item.into();
handle_error(export_impl(attr, item)).into()
}
fn perlmod_impl(attr: AttributeArgs, item: TokenStream) -> Result<TokenStream, Error> {
fn perlmod_impl(attr: TokenStream_1, item: TokenStream) -> Result<TokenStream, Error> {
let attr = Punctuated::<Meta, Token![,]>::parse_terminated.parse(attr)?;
let item: syn::Item = syn::parse2(item)?;
match item {
@ -111,7 +110,8 @@ fn perlmod_impl(attr: AttributeArgs, item: TokenStream) -> Result<TokenStream, E
}
}
fn export_impl(attr: AttributeArgs, item: TokenStream) -> Result<TokenStream, Error> {
fn export_impl(attr: TokenStream_1, item: TokenStream) -> Result<TokenStream, Error> {
let attr = Punctuated::<Meta, Token![,]>::parse_terminated.parse(attr)?;
let func: syn::ItemFn = syn::parse2(item)?;
let attr = attribs::FunctionAttrs::try_from(attr)?;

View File

@ -2,13 +2,15 @@ use proc_macro2::TokenStream;
use quote::quote;
use syn::punctuated::Punctuated;
use syn::Error;
use syn::{AttributeArgs, Token};
use syn::{Error, Meta, Token};
use crate::attribs::FunctionAttrs;
use crate::package::Package;
pub fn handle_module(attr: AttributeArgs, mut module: syn::ItemMod) -> Result<TokenStream, Error> {
pub fn handle_module(
attr: Punctuated<Meta, Token![,]>,
mut module: syn::ItemMod,
) -> Result<TokenStream, Error> {
let mut package = Package::with_attrs(attr)?;
let mangled_package_name = package.mangle_package_name();
@ -18,27 +20,28 @@ pub fn handle_module(attr: AttributeArgs, mut module: syn::ItemMod) -> Result<To
syn::Item::Fn(mut func) => {
let mut attribs = None;
for attr in std::mem::take(&mut func.attrs) {
if attr.path.is_ident("export") {
if attribs.is_some() {
error!(attr => "multiple 'export' attributes not allowed");
continue;
}
let args: AttributeArgs = if attr.tokens.is_empty() {
Default::default()
} else {
attr.parse_args_with(
Punctuated::<syn::NestedMeta, Token![,]>::parse_terminated,
)?
.into_iter()
.collect()
};
attribs = Some(FunctionAttrs::try_from(args)?);
} else {
if !attr.path().is_ident("export") {
// retain the attribute
func.attrs.push(attr);
continue;
}
if attribs.is_some() {
error!(attr => "multiple 'export' attributes not allowed");
continue;
}
let args = match attr.meta {
Meta::Path(_) => Default::default(),
Meta::List(list) => list.parse_args_with(
Punctuated::<syn::Meta, Token![,]>::parse_terminated,
)?,
_ => {
error!(attr => "invalid 'export' attribute syntax");
continue;
}
};
attribs = Some(FunctionAttrs::try_from(args)?);
}
// if we removed an #[export] macro this is an exported function:

View File

@ -3,8 +3,8 @@ use std::env;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use syn::AttributeArgs;
use syn::Error;
use syn::punctuated::Punctuated;
use syn::{Error, Meta, Token};
use crate::attribs::ModuleAttrs;
@ -55,7 +55,7 @@ pub struct Package {
}
impl Package {
pub fn with_attrs(attr: AttributeArgs) -> Result<Self, Error> {
pub fn with_attrs(attr: Punctuated<Meta, Token![,]>) -> Result<Self, Error> {
Ok(Self {
attrs: ModuleAttrs::try_from(attr)?,
exported: Vec::new(),