diff --git a/Cargo.lock b/Cargo.lock index 2075ea3cbd..9d486786ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2056,7 +2056,7 @@ version = "0.4.0" dependencies = [ "rustpython-compiler", "rustpython-derive-impl", - "syn 1.0.109", + "syn 2.0.98", ] [[package]] @@ -2071,7 +2071,7 @@ dependencies = [ "rustpython-compiler-core", "rustpython-doc", "rustpython-parser-core", - "syn 1.0.109", + "syn 2.0.98", "syn-ext", "textwrap 0.16.1", ] @@ -2614,11 +2614,13 @@ dependencies = [ [[package]] name = "syn-ext" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b86cb2b68c5b3c078cac02588bc23f3c04bb828c5d3aedd17980876ec6a7be6" +checksum = "b126de4ef6c2a628a68609dd00733766c3b015894698a438ebdf374933fc31d1" dependencies = [ - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.98", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 446733d515..e352032de5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -177,7 +177,7 @@ schannel = "0.1.27" static_assertions = "1.1" strum = "0.27" strum_macros = "0.27" -syn = "1.0.109" +syn = "2" thiserror = "2.0" thread_local = "1.1.8" unicode_names2 = "1.3.0" diff --git a/derive-impl/Cargo.toml b/derive-impl/Cargo.toml index 83a4bc4214..debe58106b 100644 --- a/derive-impl/Cargo.toml +++ b/derive-impl/Cargo.toml @@ -20,7 +20,7 @@ syn = { workspace = true, features = ["full", "extra-traits"] } maplit = "1.0.2" proc-macro2 = "1.0.93" quote = "1.0.38" -syn-ext = { version = "0.4.0", features = ["full"] } +syn-ext = { version = "0.5.0", features = ["full"] } textwrap = { version = "0.16.1", default-features = false } [lints] diff --git a/derive-impl/src/compile_bytecode.rs b/derive-impl/src/compile_bytecode.rs index 6b5baef98c..34d5cb8d9d 100644 --- a/derive-impl/src/compile_bytecode.rs +++ b/derive-impl/src/compile_bytecode.rs @@ -13,7 +13,7 @@ //! ) //! ``` -use crate::{extract_spans, Diagnostic}; +use crate::Diagnostic; use once_cell::sync::Lazy; use proc_macro2::{Span, TokenStream}; use quote::quote; @@ -25,10 +25,9 @@ use std::{ }; use syn::{ self, - parse::{Parse, ParseStream, Result as ParseResult}, - parse2, + parse::{ParseStream, Parser, Result as ParseResult}, spanned::Spanned, - Lit, LitByteStr, LitStr, Macro, Meta, MetaNameValue, Token, + LitByteStr, LitStr, Macro, }; static CARGO_MANIFEST_DIR: Lazy = Lazy::new(|| { @@ -233,23 +232,17 @@ impl CompilationSource { } } -/// This is essentially just a comma-separated list of Meta nodes, aka the inside of a MetaList. -struct PyCompileInput { - span: Span, - metas: Vec, -} - -impl PyCompileInput { - fn parse(&self, allow_dir: bool) -> Result { +impl PyCompileArgs { + fn parse(input: TokenStream, allow_dir: bool) -> Result { let mut module_name = None; let mut mode = None; let mut source: Option = None; let mut crate_name = None; - fn assert_source_empty(source: &Option) -> Result<(), Diagnostic> { + fn assert_source_empty(source: &Option) -> Result<(), syn::Error> { if let Some(source) = source { - Err(Diagnostic::spans_error( - source.span, + Err(syn::Error::new( + source.span.0, "Cannot have more than one source", )) } else { @@ -257,59 +250,58 @@ impl PyCompileInput { } } - for meta in &self.metas { - if let Meta::NameValue(name_value) = meta { - let ident = match name_value.path.get_ident() { - Some(ident) => ident, - None => continue, - }; - let check_str = || match &name_value.lit { - Lit::Str(s) => Ok(s), - _ => Err(err_span!(name_value.lit, "{ident} must be a string")), - }; - if ident == "mode" { - let s = check_str()?; - match s.value().parse() { - Ok(mode_val) => mode = Some(mode_val), - Err(e) => bail_span!(s, "{}", e), - } - } else if ident == "module_name" { - module_name = Some(check_str()?.value()) - } else if ident == "source" { - assert_source_empty(&source)?; - let code = check_str()?.value(); - source = Some(CompilationSource { - kind: CompilationSourceKind::SourceCode(code), - span: extract_spans(&name_value).unwrap(), - }); - } else if ident == "file" { - assert_source_empty(&source)?; - let path = check_str()?.value().into(); - source = Some(CompilationSource { - kind: CompilationSourceKind::File(path), - span: extract_spans(&name_value).unwrap(), - }); - } else if ident == "dir" { - if !allow_dir { - bail_span!(ident, "py_compile doesn't accept dir") - } - - assert_source_empty(&source)?; - let path = check_str()?.value().into(); - source = Some(CompilationSource { - kind: CompilationSourceKind::Dir(path), - span: extract_spans(&name_value).unwrap(), - }); - } else if ident == "crate_name" { - let name = check_str()?.parse()?; - crate_name = Some(name); + syn::meta::parser(|meta| { + let ident = meta + .path + .get_ident() + .ok_or_else(|| meta.error("unknown arg"))?; + let check_str = || meta.value()?.call(parse_str); + if ident == "mode" { + let s = check_str()?; + match s.value().parse() { + Ok(mode_val) => mode = Some(mode_val), + Err(e) => bail_span!(s, "{}", e), + } + } else if ident == "module_name" { + module_name = Some(check_str()?.value()) + } else if ident == "source" { + assert_source_empty(&source)?; + let code = check_str()?.value(); + source = Some(CompilationSource { + kind: CompilationSourceKind::SourceCode(code), + span: (ident.span(), meta.input.cursor().span()), + }); + } else if ident == "file" { + assert_source_empty(&source)?; + let path = check_str()?.value().into(); + source = Some(CompilationSource { + kind: CompilationSourceKind::File(path), + span: (ident.span(), meta.input.cursor().span()), + }); + } else if ident == "dir" { + if !allow_dir { + bail_span!(ident, "py_compile doesn't accept dir") } + + assert_source_empty(&source)?; + let path = check_str()?.value().into(); + source = Some(CompilationSource { + kind: CompilationSourceKind::Dir(path), + span: (ident.span(), meta.input.cursor().span()), + }); + } else if ident == "crate_name" { + let name = check_str()?.parse()?; + crate_name = Some(name); + } else { + return Err(meta.error("unknown attr")); } - } + Ok(()) + }) + .parse2(input)?; let source = source.ok_or_else(|| { syn::Error::new( - self.span, + Span::call_site(), "Must have either file or source in py_compile!()/py_freeze!()", ) })?; @@ -323,38 +315,17 @@ impl PyCompileInput { } } -fn parse_meta(input: ParseStream) -> ParseResult { - let path = input.call(syn::Path::parse_mod_style)?; - let eq_token: Token![=] = input.parse()?; +fn parse_str(input: ParseStream) -> ParseResult { let span = input.span(); if input.peek(LitStr) { - Ok(Meta::NameValue(MetaNameValue { - path, - eq_token, - lit: Lit::Str(input.parse()?), - })) + input.parse() } else if let Ok(mac) = input.parse::() { - Ok(Meta::NameValue(MetaNameValue { - path, - eq_token, - lit: Lit::Str(LitStr::new(&mac.tokens.to_string(), mac.span())), - })) + Ok(LitStr::new(&mac.tokens.to_string(), mac.span())) } else { Err(syn::Error::new(span, "Expected string or stringify macro")) } } -impl Parse for PyCompileInput { - fn parse(input: ParseStream) -> ParseResult { - let span = input.cursor().span(); - let metas = input - .parse_terminated::(parse_meta)? - .into_iter() - .collect(); - Ok(PyCompileInput { span, metas }) - } -} - struct PyCompileArgs { source: CompilationSource, mode: Mode, @@ -366,8 +337,7 @@ pub fn impl_py_compile( input: TokenStream, compiler: &dyn Compiler, ) -> Result { - let input: PyCompileInput = parse2(input)?; - let args = input.parse(false)?; + let args = PyCompileArgs::parse(input, false)?; let crate_name = args.crate_name; let code = args @@ -388,8 +358,7 @@ pub fn impl_py_freeze( input: TokenStream, compiler: &dyn Compiler, ) -> Result { - let input: PyCompileInput = parse2(input)?; - let args = input.parse(true)?; + let args = PyCompileArgs::parse(input, true)?; let crate_name = args.crate_name; let code_map = args.source.compile(args.mode, args.module_name, compiler)?; diff --git a/derive-impl/src/from_args.rs b/derive-impl/src/from_args.rs index 7b5b684213..47b0530d88 100644 --- a/derive-impl/src/from_args.rs +++ b/derive-impl/src/from_args.rs @@ -1,9 +1,8 @@ use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::ext::IdentExt; -use syn::{ - parse_quote, Attribute, Data, DeriveInput, Expr, Field, Ident, Lit, Meta, NestedMeta, Result, -}; +use syn::meta::ParseNestedMeta; +use syn::{parse_quote, Attribute, Data, DeriveInput, Expr, Field, Ident, Result, Token}; /// The kind of the python parameter, this corresponds to the value of Parameter.kind /// (https://docs.python.org/3/library/inspect.html#inspect.Parameter.kind) @@ -36,84 +35,61 @@ type DefaultValue = Option; impl ArgAttribute { fn from_attribute(attr: &Attribute) -> Option> { - if !attr.path.is_ident("pyarg") { + if !attr.path().is_ident("pyarg") { return None; } let inner = move || { - let Meta::List(list) = attr.parse_meta()? else { - bail_span!(attr, "pyarg must be a list, like #[pyarg(...)]") - }; - let mut iter = list.nested.iter(); - let first_arg = iter.next().ok_or_else(|| { - err_span!(list, "There must be at least one argument to #[pyarg()]") + let mut arg_attr = None; + attr.parse_nested_meta(|meta| { + let Some(arg_attr) = &mut arg_attr else { + let kind = meta + .path + .get_ident() + .and_then(ParameterKind::from_ident) + .ok_or_else(|| { + meta.error( + "The first argument to #[pyarg()] must be the parameter type, \ + either 'positional', 'any', 'named', or 'flatten'.", + ) + })?; + arg_attr = Some(ArgAttribute { + name: None, + kind, + default: None, + }); + return Ok(()); + }; + arg_attr.parse_argument(meta) })?; - let kind = match first_arg { - NestedMeta::Meta(Meta::Path(path)) => { - path.get_ident().and_then(ParameterKind::from_ident) - } - _ => None, - }; - let kind = kind.ok_or_else(|| { - err_span!( - first_arg, - "The first argument to #[pyarg()] must be the parameter type, either \ - 'positional', 'any', 'named', or 'flatten'." - ) - })?; - - let mut attribute = ArgAttribute { - name: None, - kind, - default: None, - }; - - for arg in iter { - attribute.parse_argument(arg)?; - } - - Ok(attribute) + arg_attr + .ok_or_else(|| err_span!(attr, "There must be at least one argument to #[pyarg()]")) }; Some(inner()) } - fn parse_argument(&mut self, arg: &NestedMeta) -> Result<()> { + fn parse_argument(&mut self, meta: ParseNestedMeta<'_>) -> Result<()> { if let ParameterKind::Flatten = self.kind { - bail_span!(arg, "can't put additional arguments on a flatten arg") + return Err(meta.error("can't put additional arguments on a flatten arg")); } - match arg { - NestedMeta::Meta(Meta::Path(path)) => { - if path.is_ident("default") || path.is_ident("optional") { - if self.default.is_none() { - self.default = Some(None); - } - } else { - bail_span!(path, "Unrecognized pyarg attribute"); - } + if meta.path.is_ident("default") && meta.input.peek(Token![=]) { + if matches!(self.default, Some(Some(_))) { + return Err(meta.error("Default already set")); } - NestedMeta::Meta(Meta::NameValue(name_value)) => { - if name_value.path.is_ident("default") { - if matches!(self.default, Some(Some(_))) { - bail_span!(name_value, "Default already set"); - } - - match name_value.lit { - Lit::Str(ref val) => self.default = Some(Some(val.parse()?)), - _ => bail_span!(name_value, "Expected string value for default argument"), - } - } else if name_value.path.is_ident("name") { - if self.name.is_some() { - bail_span!(name_value, "already have a name") - } - - match &name_value.lit { - Lit::Str(val) => self.name = Some(val.value()), - _ => bail_span!(name_value, "Expected string value for name argument"), - } - } else { - bail_span!(name_value, "Unrecognized pyarg attribute"); - } + let val = meta.value()?; + let val = val.parse::()?; + self.default = Some(Some(val.parse()?)) + } else if meta.path.is_ident("default") || meta.path.is_ident("optional") { + if self.default.is_none() { + self.default = Some(None); + } + } else if meta.path.is_ident("name") { + if self.name.is_some() { + return Err(meta.error("already have a name")); } - _ => bail_span!(arg, "Unrecognized pyarg attribute"), + let val = meta.value()?.parse::()?; + self.name = Some(val.value()) + } else { + return Err(meta.error("Unrecognized pyarg attribute")); } Ok(()) diff --git a/derive-impl/src/lib.rs b/derive-impl/src/lib.rs index 35292e7de0..a1f97c96b0 100644 --- a/derive-impl/src/lib.rs +++ b/derive-impl/src/lib.rs @@ -20,11 +20,12 @@ mod pypayload; mod pystructseq; mod pytraverse; -use error::{extract_spans, Diagnostic}; +use error::Diagnostic; use proc_macro2::TokenStream; use quote::ToTokens; use rustpython_doc as doc; -use syn::{AttributeArgs, DeriveInput, Item}; +use syn::{DeriveInput, Item}; +use syn_ext::types::PunctuatedNestedMeta; pub use compile_bytecode::Compiler; @@ -38,7 +39,7 @@ pub fn derive_from_args(input: DeriveInput) -> TokenStream { result_to_tokens(from_args::impl_from_args(input)) } -pub fn pyclass(attr: AttributeArgs, item: Item) -> TokenStream { +pub fn pyclass(attr: PunctuatedNestedMeta, item: Item) -> TokenStream { if matches!(item, syn::Item::Impl(_) | syn::Item::Trait(_)) { result_to_tokens(pyclass::impl_pyclass_impl(attr, item)) } else { @@ -46,7 +47,7 @@ pub fn pyclass(attr: AttributeArgs, item: Item) -> TokenStream { } } -pub fn pyexception(attr: AttributeArgs, item: Item) -> TokenStream { +pub fn pyexception(attr: PunctuatedNestedMeta, item: Item) -> TokenStream { if matches!(item, syn::Item::Impl(_)) { result_to_tokens(pyclass::impl_pyexception_impl(attr, item)) } else { @@ -54,7 +55,7 @@ pub fn pyexception(attr: AttributeArgs, item: Item) -> TokenStream { } } -pub fn pymodule(attr: AttributeArgs, item: Item) -> TokenStream { +pub fn pymodule(attr: PunctuatedNestedMeta, item: Item) -> TokenStream { result_to_tokens(pymodule::impl_pymodule(attr, item)) } diff --git a/derive-impl/src/pyclass.rs b/derive-impl/src/pyclass.rs index c42069c31c..c3f148e2eb 100644 --- a/derive-impl/src/pyclass.rs +++ b/derive-impl/src/pyclass.rs @@ -8,10 +8,9 @@ use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree}; use quote::{quote, quote_spanned, ToTokens}; use std::collections::{HashMap, HashSet}; use std::str::FromStr; -use syn::{ - parse_quote, spanned::Spanned, Attribute, AttributeArgs, Ident, Item, Meta, NestedMeta, Result, -}; +use syn::{parse_quote, spanned::Spanned, Attribute, Ident, Item, Result}; use syn_ext::ext::*; +use syn_ext::types::*; #[derive(Copy, Clone, Debug)] enum AttrName { @@ -98,7 +97,7 @@ fn extract_items_into_context<'a, Item>( context.errors.ok_or_push(context.member_items.validate()); } -pub(crate) fn impl_pyclass_impl(attr: AttributeArgs, item: Item) -> Result { +pub(crate) fn impl_pyclass_impl(attr: PunctuatedNestedMeta, item: Item) -> Result { let mut context = ImplContext::default(); let mut tokens = match item { Item::Impl(mut imp) => { @@ -235,9 +234,7 @@ pub(crate) fn impl_pyclass_impl(attr: AttributeArgs, item: Item) -> Result { - &method.sig.ident.to_string() == "extend_slots" - } + syn::TraitItem::Fn(item) => item.sig.ident == "extend_slots", _ => false, }; if has { @@ -344,7 +341,7 @@ fn generate_class_def( }; let basicsize = quote!(std::mem::size_of::<#ident>()); let is_pystruct = attrs.iter().any(|attr| { - attr.path.is_ident("derive") + attr.path().is_ident("derive") && if let Ok(Meta::List(l)) = attr.parse_meta() { l.nested .into_iter() @@ -418,7 +415,7 @@ fn generate_class_def( Ok(tokens) } -pub(crate) fn impl_pyclass(attr: AttributeArgs, item: Item) -> Result { +pub(crate) fn impl_pyclass(attr: PunctuatedNestedMeta, item: Item) -> Result { if matches!(item, syn::Item::Use(_)) { return Ok(quote!(#item)); } @@ -534,7 +531,7 @@ pub(crate) fn impl_pyclass(attr: AttributeArgs, item: Item) -> Result Result { +pub(crate) fn impl_pyexception(attr: PunctuatedNestedMeta, item: Item) -> Result { let (ident, _attrs) = pyexception_ident_and_attrs(&item)?; let fake_ident = Ident::new("pyclass", item.span()); let class_meta = ExceptionItemMeta::from_nested(ident.clone(), fake_ident, attr.into_iter())?; @@ -573,7 +570,7 @@ pub(crate) fn impl_pyexception(attr: AttributeArgs, item: Item) -> Result Result { +pub(crate) fn impl_pyexception_impl(attr: PunctuatedNestedMeta, item: Item) -> Result { let Item::Impl(imp) = item else { return Ok(item.into_token_stream()); }; @@ -1454,7 +1451,7 @@ struct ExtractedImplAttrs { with_slots: TokenStream, } -fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result { +fn extract_impl_attrs(attr: PunctuatedNestedMeta, item: &Ident) -> Result { let mut withs = Vec::new(); let mut with_method_defs = Vec::new(); let mut with_slots = Vec::new(); @@ -1474,7 +1471,7 @@ fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result { + NestedMeta::Meta(Meta::List(MetaList { path, nested, .. })) => { if path.is_ident("with") { for meta in nested { let NestedMeta::Meta(Meta::Path(path)) = &meta else { @@ -1530,12 +1527,16 @@ fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result { + NestedMeta::Meta(Meta::NameValue(syn::MetaNameValue { path, value, .. })) => { if path.is_ident("payload") { - if let syn::Lit::Str(lit) = lit { + if let syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit), + .. + }) = value + { payload = Some(Ident::new(&lit.value(), lit.span())); } else { - bail_span!(lit, "payload must be a string literal") + bail_span!(value, "payload must be a string literal") } } else { bail_span!(path, "Unknown pyimpl attribute") diff --git a/derive-impl/src/pymodule.rs b/derive-impl/src/pymodule.rs index b9a59c8280..db65e24e21 100644 --- a/derive-impl/src/pymodule.rs +++ b/derive-impl/src/pymodule.rs @@ -7,8 +7,9 @@ use crate::util::{ use proc_macro2::{Delimiter, Group, TokenStream, TokenTree}; use quote::{quote, quote_spanned, ToTokens}; use std::{collections::HashSet, str::FromStr}; -use syn::{parse_quote, spanned::Spanned, Attribute, AttributeArgs, Ident, Item, Result}; +use syn::{parse_quote, spanned::Spanned, Attribute, Ident, Item, Result}; use syn_ext::ext::*; +use syn_ext::types::PunctuatedNestedMeta; #[derive(Clone, Copy, Eq, PartialEq)] enum AttrName { @@ -51,7 +52,7 @@ struct ModuleContext { errors: Vec, } -pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result { +pub fn impl_pymodule(attr: PunctuatedNestedMeta, module_item: Item) -> Result { let (doc, mut module_item) = match module_item { Item::Mod(m) => (m.attrs.doc(), m), other => bail_span!(other, "#[pymodule] can only be on a full module"), diff --git a/derive-impl/src/pytraverse.rs b/derive-impl/src/pytraverse.rs index 93aa233a18..d2fe2dac81 100644 --- a/derive-impl/src/pytraverse.rs +++ b/derive-impl/src/pytraverse.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream; use quote::quote; -use syn::{Attribute, DeriveInput, Field, Meta, MetaList, NestedMeta, Result}; +use syn::{Attribute, DeriveInput, Field, Result}; struct TraverseAttr { /// set to `true` if the attribute is `#[pytraverse(skip)]` @@ -9,47 +9,25 @@ struct TraverseAttr { const ATTR_TRAVERSE: &str = "pytraverse"; -/// get the `#[pytraverse(..)]` attribute from the struct -fn valid_get_traverse_attr_from_meta_list(list: &MetaList) -> Result { - let find_skip_and_only_skip = || { - let len = list.nested.len(); - if len != 1 { - return None; - } - let mut iter = list.nested.iter(); - // we have checked the length, so unwrap is safe - let first_arg = iter.next().unwrap(); - let skip = match first_arg { - NestedMeta::Meta(Meta::Path(path)) => match path.is_ident("skip") { - true => true, - false => return None, - }, - _ => return None, - }; - Some(skip) - }; - let skip = find_skip_and_only_skip().ok_or_else(|| { - err_span!( - list, - "only support attr is #[pytraverse(skip)], got arguments: {:?}", - list.nested - ) - })?; - Ok(TraverseAttr { skip }) -} - /// only accept `#[pytraverse(skip)]` for now fn pytraverse_arg(attr: &Attribute) -> Option> { - if !attr.path.is_ident(ATTR_TRAVERSE) { + if !attr.path().is_ident(ATTR_TRAVERSE) { return None; } let ret = || { - let parsed = attr.parse_meta()?; - if let Meta::List(list) = parsed { - valid_get_traverse_attr_from_meta_list(&list) - } else { - bail_span!(attr, "pytraverse must be a list, like #[pytraverse(skip)]") - } + let mut skip = false; + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("skip") { + if skip { + return Err(meta.error("already specified skip")); + } + skip = true; + } else { + return Err(meta.error("unknown attr")); + } + Ok(()) + })?; + Ok(TraverseAttr { skip }) }; Some(ret()) } diff --git a/derive-impl/src/util.rs b/derive-impl/src/util.rs index f016b0d1e9..bd568032c3 100644 --- a/derive-impl/src/util.rs +++ b/derive-impl/src/util.rs @@ -2,12 +2,10 @@ use itertools::Itertools; use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; use std::collections::{HashMap, HashSet}; -use syn::{ - spanned::Spanned, Attribute, Ident, Meta, MetaList, NestedMeta, Result, Signature, UseTree, -}; +use syn::{spanned::Spanned, Attribute, Ident, Result, Signature, UseTree}; use syn_ext::{ ext::{AttributeExt as SynAttributeExt, *}, - types::PunctuatedNestedMeta, + types::*, }; pub(crate) const ALL_ALLOWED_NAMES: &[&str] = &[ @@ -167,7 +165,11 @@ impl ItemMetaInner { pub fn _optional_str(&self, key: &str) -> Result> { let value = if let Some((_, meta)) = self.meta_map.get(key) { let Meta::NameValue(syn::MetaNameValue { - lit: syn::Lit::Str(lit), + value: + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit), + .. + }), .. }) = meta else { @@ -193,7 +195,11 @@ impl ItemMetaInner { let value = if let Some((_, meta)) = self.meta_map.get(key) { match meta { Meta::NameValue(syn::MetaNameValue { - lit: syn::Lit::Bool(lit), + value: + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Bool(lit), + .. + }), .. }) => lit.value, Meta::Path(_) => true, @@ -210,7 +216,7 @@ impl ItemMetaInner { key: &str, ) -> Result>> { let value = if let Some((_, meta)) = self.meta_map.get(key) { - let Meta::List(syn::MetaList { + let Meta::List(MetaList { path: _, nested, .. }) = meta else { @@ -350,7 +356,11 @@ impl ClassItemMeta { if let Some((_, meta)) = inner.meta_map.get(KEY) { match meta { Meta::NameValue(syn::MetaNameValue { - lit: syn::Lit::Str(lit), + value: + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit), + .. + }), .. }) => return Ok(lit.value()), Meta::Path(_) => return Ok(inner.item_name()), @@ -387,11 +397,11 @@ impl ClassItemMeta { let value = if let Some((_, meta)) = inner.meta_map.get(KEY) { match meta { Meta::NameValue(syn::MetaNameValue { - lit: syn::Lit::Str(lit), + value: syn::Expr::Lit(syn::ExprLit{lit:syn::Lit::Str(lit),..}), .. }) => Ok(Some(lit.value())), Meta::NameValue(syn::MetaNameValue { - lit: syn::Lit::Bool(lit), + value: syn::Expr::Lit(syn::ExprLit{lit:syn::Lit::Bool(lit),..}), .. }) => if lit.value { Err(lit.span()) @@ -448,7 +458,11 @@ impl ExceptionItemMeta { if let Some((_, meta)) = inner.meta_map.get(KEY) { match meta { Meta::NameValue(syn::MetaNameValue { - lit: syn::Lit::Str(lit), + value: + syn::Expr::Lit(syn::ExprLit { + lit: syn::Lit::Str(lit), + .. + }), .. }) => return Ok(lit.value()), Meta::Path(_) => { @@ -489,7 +503,7 @@ impl std::ops::Deref for ExceptionItemMeta { pub(crate) trait AttributeExt: SynAttributeExt { fn promoted_nested(&self) -> Result; fn ident_and_promoted_nested(&self) -> Result<(&Ident, PunctuatedNestedMeta)>; - fn try_remove_name(&mut self, name: &str) -> Result>; + fn try_remove_name(&mut self, name: &str) -> Result>; fn fill_nested_meta(&mut self, name: &str, new_item: F) -> Result<()> where F: Fn() -> NestedMeta; @@ -512,7 +526,7 @@ impl AttributeExt for Attribute { Ok((self.get_ident().unwrap(), self.promoted_nested()?)) } - fn try_remove_name(&mut self, item_name: &str) -> Result> { + fn try_remove_name(&mut self, item_name: &str) -> Result> { self.try_meta_mut(|meta| { let nested = match meta { Meta::List(MetaList { ref mut nested, .. }) => Ok(nested), diff --git a/derive/src/lib.rs b/derive/src/lib.rs index e59db12f90..9e94bf43cb 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -5,6 +5,7 @@ use proc_macro::TokenStream; use rustpython_derive_impl as derive_impl; use syn::parse_macro_input; +use syn::punctuated::Punctuated; #[proc_macro_derive(FromArgs, attributes(pyarg))] pub fn derive_from_args(input: TokenStream) -> TokenStream { @@ -132,7 +133,7 @@ pub fn derive_from_args(input: TokenStream) -> TokenStream { /// have a body, abstract functions should be wrapped before applying an annotation. #[proc_macro_attribute] pub fn pyclass(attr: TokenStream, item: TokenStream) -> TokenStream { - let attr = parse_macro_input!(attr); + let attr = parse_macro_input!(attr with Punctuated::parse_terminated); let item = parse_macro_input!(item); derive_impl::pyclass(attr, item).into() } @@ -147,7 +148,7 @@ pub fn pyclass(attr: TokenStream, item: TokenStream) -> TokenStream { /// #[proc_macro_attribute] pub fn pyexception(attr: TokenStream, item: TokenStream) -> TokenStream { - let attr = parse_macro_input!(attr); + let attr = parse_macro_input!(attr with Punctuated::parse_terminated); let item = parse_macro_input!(item); derive_impl::pyexception(attr, item).into() } @@ -219,7 +220,7 @@ pub fn pyexception(attr: TokenStream, item: TokenStream) -> TokenStream { /// - `name`: the name of the function in Python, by default it is the same as the associated Rust function. #[proc_macro_attribute] pub fn pymodule(attr: TokenStream, item: TokenStream) -> TokenStream { - let attr = parse_macro_input!(attr); + let attr = parse_macro_input!(attr with Punctuated::parse_terminated); let item = parse_macro_input!(item); derive_impl::pymodule(attr, item).into() }