mirror of
https://git.proxmox.com/git/perlmod
synced 2025-10-04 20:11:21 +00:00
update to syn-2
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
b32c4fd40a
commit
cb86559d13
@ -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" }
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)?;
|
||||
|
@ -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:
|
||||
|
@ -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(),
|
||||
|
Loading…
Reference in New Issue
Block a user