From cb86559d13d6819b88d78f64ccab010599ca888a Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Mon, 2 Oct 2023 10:33:32 +0200 Subject: [PATCH] update to syn-2 Signed-off-by: Wolfgang Bumiller --- perlmod-macro/Cargo.toml | 2 +- perlmod-macro/src/attribs.rs | 100 ++++++++++++++++++++-------------- perlmod-macro/src/function.rs | 16 +++++- perlmod-macro/src/lib.rs | 14 ++--- perlmod-macro/src/module.rs | 45 ++++++++------- perlmod-macro/src/package.rs | 6 +- 6 files changed, 107 insertions(+), 76 deletions(-) diff --git a/perlmod-macro/Cargo.toml b/perlmod-macro/Cargo.toml index 3b945df..4db6ad4 100644 --- a/perlmod-macro/Cargo.toml +++ b/perlmod-macro/Cargo.toml @@ -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" } diff --git a/perlmod-macro/src/attribs.rs b/perlmod-macro/src/attribs.rs index e821f36..e5e396c 100644 --- a/perlmod-macro/src/attribs.rs +++ b/perlmod-macro/src/attribs.rs @@ -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(path: &syn::Path, var: &Option, what: &'static str) } } -impl TryFrom for ModuleAttrs { +impl TryFrom> for ModuleAttrs { type Error = Error; - fn try_from(args: AttributeArgs) -> Result { + fn try_from(args: Punctuated) -> Result { let mut package_name = None; let mut file_name = None; let mut lib_name = None; @@ -33,36 +33,31 @@ impl TryFrom 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::()?); - } 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::()?); + } 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 for FunctionAttrs { +impl TryFrom> for FunctionAttrs { type Error = Error; - fn try_from(args: AttributeArgs) -> Result { + fn try_from(args: Punctuated) -> Result { 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 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 for FunctionAttrs { Ok(attrs) } } + +fn expect_lit_str(value: syn::Expr) -> Option { + 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 { + match value { + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Bool(lit), + .. + }) => Some(lit), + _ => { + error!(value => "value must be a literal boolean"); + None + } + } +} diff --git a/perlmod-macro/src/function.rs b/perlmod-macro/src/function.rs index 52aec1f..3e40828 100644 --- a/perlmod-macro/src/function.rs +++ b/perlmod-macro/src/function.rs @@ -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 } diff --git a/perlmod-macro/src/lib.rs b/perlmod-macro/src/lib.rs index 61f0205..3fafb87 100644 --- a/perlmod-macro/src/lib.rs +++ b/perlmod-macro/src/lib.rs @@ -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 { +fn perlmod_impl(attr: TokenStream_1, item: TokenStream) -> Result { + let attr = Punctuated::::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 Result { +fn export_impl(attr: TokenStream_1, item: TokenStream) -> Result { + let attr = Punctuated::::parse_terminated.parse(attr)?; let func: syn::ItemFn = syn::parse2(item)?; let attr = attribs::FunctionAttrs::try_from(attr)?; diff --git a/perlmod-macro/src/module.rs b/perlmod-macro/src/module.rs index 9b5843f..4e8eff3 100644 --- a/perlmod-macro/src/module.rs +++ b/perlmod-macro/src/module.rs @@ -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 { +pub fn handle_module( + attr: Punctuated, + mut module: syn::ItemMod, +) -> Result { 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 { 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::::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::::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: diff --git a/perlmod-macro/src/package.rs b/perlmod-macro/src/package.rs index 96d01c9..517dc43 100644 --- a/perlmod-macro/src/package.rs +++ b/perlmod-macro/src/package.rs @@ -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 { + pub fn with_attrs(attr: Punctuated) -> Result { Ok(Self { attrs: ModuleAttrs::try_from(attr)?, exported: Vec::new(),