mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 11:14:38 +08:00
5 files changed
+1500
-1284
No files matched your search
+77
-10
@@ -1,7 +1,7 @@
|
||||
use super::Diagnostic;
|
||||
use crate::util::{
|
||||
path_eq, pyclass_ident_and_attrs, ClassItemMeta, ContentItem, ContentItemInner, ErrorVec,
|
||||
ItemMeta, ItemMetaInner, ItemNursery, ALL_ALLOWED_NAMES,
|
||||
ItemMeta, ItemMetaInner, ItemNursery, SimpleItemMeta, ALL_ALLOWED_NAMES,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, quote_spanned, ToTokens};
|
||||
@@ -216,6 +216,11 @@ struct SlotItem {
|
||||
inner: ContentItemInner,
|
||||
}
|
||||
|
||||
/// #[pyattr]
|
||||
struct AttributeItem {
|
||||
inner: ContentItemInner,
|
||||
}
|
||||
|
||||
/// #[extend_class]
|
||||
struct ExtendClassItem {
|
||||
inner: ContentItemInner,
|
||||
@@ -236,6 +241,11 @@ impl ContentItem for SlotItem {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
impl ContentItem for AttributeItem {
|
||||
fn inner(&self) -> &ContentItemInner {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
impl ContentItem for ExtendClassItem {
|
||||
fn inner(&self) -> &ContentItemInner {
|
||||
&self.inner
|
||||
@@ -357,6 +367,51 @@ where
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Item> ImplItem<Item> for AttributeItem
|
||||
where
|
||||
Item: ItemLike + ToTokens + GetIdent,
|
||||
{
|
||||
fn gen_impl_item(&self, args: ImplItemArgs<'_, Item>) -> Result<()> {
|
||||
let cfgs = args.cfgs.to_vec();
|
||||
let attr = args.attrs.remove(self.index());
|
||||
|
||||
let get_py_name = |attr: &Attribute, ident: &Ident| -> Result<_> {
|
||||
let item_meta = SimpleItemMeta::from_attr(ident.clone(), attr)?;
|
||||
let py_name = item_meta.simple_name()?;
|
||||
Ok(py_name)
|
||||
};
|
||||
let (py_name, tokens) = if args.item.is_function_or_method() || args.item.is_const() {
|
||||
let ident = args.item.get_ident().unwrap();
|
||||
let py_name = get_py_name(&attr, &ident)?;
|
||||
|
||||
let value = if args.item.is_const() {
|
||||
// TODO: ctx.new_value
|
||||
quote_spanned!(ident.span() => ctx.new_int(Self::#ident))
|
||||
} else {
|
||||
quote_spanned!(ident.span() => Self::#ident(ctx))
|
||||
};
|
||||
(
|
||||
py_name.clone(),
|
||||
quote! {
|
||||
class.set_str_attr(#py_name, #value);
|
||||
},
|
||||
)
|
||||
} else {
|
||||
return Err(self.new_syn_error(
|
||||
args.item.span(),
|
||||
"can only be on a const or an associated method without argument",
|
||||
));
|
||||
};
|
||||
|
||||
args.context
|
||||
.impl_extend_items
|
||||
.add_item(py_name, cfgs, tokens)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Item> ImplItem<Item> for ExtendClassItem
|
||||
where
|
||||
Item: ItemLike + ToTokens + GetIdent,
|
||||
@@ -631,18 +686,27 @@ fn extract_impl_attrs(attr: AttributeArgs) -> std::result::Result<ExtractedImplA
|
||||
NestedMeta::Meta(Meta::List(syn::MetaList { path, nested, .. })) => {
|
||||
if path_eq(&path, "with") {
|
||||
for meta in nested {
|
||||
match meta {
|
||||
NestedMeta::Meta(Meta::Path(path)) => {
|
||||
withs.push(quote! {
|
||||
<Self as #path>::__extend_py_class(ctx, class);
|
||||
});
|
||||
with_slots.push(quote! {
|
||||
<Self as #path>::__extend_slots(slots);
|
||||
});
|
||||
}
|
||||
let path = match meta {
|
||||
NestedMeta::Meta(Meta::Path(path)) => path,
|
||||
meta => {
|
||||
bail_span!(meta, "#[pyimpl(with(...))] arguments should be paths")
|
||||
}
|
||||
};
|
||||
if path_eq(&path, "PyRef") {
|
||||
// special handling for PyRef
|
||||
withs.push(quote! {
|
||||
PyRef::<Self>::impl_extend_class(ctx, class);
|
||||
});
|
||||
with_slots.push(quote! {
|
||||
PyRef::<Self>::extend_slots(slots);
|
||||
});
|
||||
} else {
|
||||
withs.push(quote! {
|
||||
<Self as #path>::__extend_py_class(ctx, class);
|
||||
});
|
||||
with_slots.push(quote! {
|
||||
<Self as #path>::__extend_slots(slots);
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if path_eq(&path, "flags") {
|
||||
@@ -705,6 +769,9 @@ where
|
||||
"pyslot" => Box::new(SlotItem {
|
||||
inner: ContentItemInner { index, attr_name },
|
||||
}),
|
||||
"pyattr" => Box::new(AttributeItem {
|
||||
inner: ContentItemInner { index, attr_name },
|
||||
}),
|
||||
"extend_class" => Box::new(ExtendClassItem {
|
||||
inner: ContentItemInner { index, attr_name },
|
||||
}),
|
||||
|
||||
+22
-54
@@ -1,11 +1,11 @@
|
||||
use crate::error::Diagnostic;
|
||||
use crate::util::{
|
||||
pyclass_ident_and_attrs, AttributeExt, ClassItemMeta, ContentItem, ContentItemInner, ErrorVec,
|
||||
ItemMeta, ItemNursery, SimpleItemMeta, ALL_ALLOWED_NAMES,
|
||||
iter_use_idents, pyclass_ident_and_attrs, AttributeExt, ClassItemMeta, ContentItem,
|
||||
ContentItemInner, ErrorVec, ItemMeta, ItemNursery, SimpleItemMeta, ALL_ALLOWED_NAMES,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, quote_spanned, ToTokens};
|
||||
use syn::{parse_quote, spanned::Spanned, Attribute, AttributeArgs, Ident, Item, Result, UseTree};
|
||||
use syn::{parse_quote, spanned::Spanned, Attribute, AttributeArgs, Ident, Item, Result};
|
||||
use syn_ext::ext::*;
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -367,60 +367,28 @@ impl ModuleItem for AttributeItem {
|
||||
},
|
||||
)
|
||||
}
|
||||
Item::Use(syn::ItemUse {
|
||||
tree: UseTree::Path(path),
|
||||
..
|
||||
}) => {
|
||||
let ident = match &*path.tree {
|
||||
UseTree::Name(name) => &name.ident,
|
||||
UseTree::Rename(rename) => &rename.rename,
|
||||
UseTree::Group(syn::UseGroup { items, .. }) => {
|
||||
for item in items {
|
||||
let ident = match item {
|
||||
UseTree::Name(name) => &name.ident,
|
||||
UseTree::Rename(rename) => &rename.rename,
|
||||
other => {
|
||||
return Err(self.new_syn_error(
|
||||
other.span(),
|
||||
"can only contains a simple use or a group of simple uses",
|
||||
));
|
||||
}
|
||||
};
|
||||
let item_meta = SimpleItemMeta::from_attr(ident.clone(), &attr)?;
|
||||
if item_meta.optional_name().is_some() {
|
||||
// this check actually doesn't need to be placed in loop
|
||||
return Err(self.new_syn_error(
|
||||
ident.span(),
|
||||
"`name` attribute is not allowed for multiple use items",
|
||||
));
|
||||
}
|
||||
let py_name = ident.to_string();
|
||||
let tokens = quote! {
|
||||
vm.__module_set_attr(&module, #py_name, vm.new_pyobj(#ident)).unwrap();
|
||||
};
|
||||
args.context.module_extend_items.add_item(
|
||||
py_name,
|
||||
cfgs.clone(),
|
||||
tokens,
|
||||
)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
other => {
|
||||
Item::Use(item) => {
|
||||
return iter_use_idents(item, |ident, is_unique| {
|
||||
let item_meta = SimpleItemMeta::from_attr(ident.clone(), &attr)?;
|
||||
let py_name = if is_unique {
|
||||
item_meta.simple_name()?
|
||||
} else if item_meta.optional_name().is_some() {
|
||||
// this check actually doesn't need to be placed in loop
|
||||
return Err(self.new_syn_error(
|
||||
other.span(),
|
||||
"can only contains a simple use or a group of simple uses",
|
||||
ident.span(),
|
||||
"`name` attribute is not allowed for multiple use items",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let py_name = get_py_name(&attr, &ident)?;
|
||||
(
|
||||
py_name.clone(),
|
||||
quote! {
|
||||
} else {
|
||||
ident.to_string()
|
||||
};
|
||||
let tokens = quote! {
|
||||
vm.__module_set_attr(&module, #py_name, vm.new_pyobj(#ident)).unwrap();
|
||||
},
|
||||
)
|
||||
};
|
||||
args.context
|
||||
.module_extend_items
|
||||
.add_item(py_name, cfgs.clone(), tokens)?;
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
other => {
|
||||
return Err(
|
||||
|
||||
+39
-1
@@ -1,7 +1,7 @@
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use std::collections::HashMap;
|
||||
use syn::{spanned::Spanned, Attribute, Ident, Meta, MetaList, NestedMeta, Path, Result};
|
||||
use syn::{spanned::Spanned, Attribute, Ident, Meta, MetaList, NestedMeta, Path, Result, UseTree};
|
||||
use syn_ext::ext::{AttributeExt as SynAttributeExt, *};
|
||||
use syn_ext::types::PunctuatedNestedMeta;
|
||||
|
||||
@@ -456,3 +456,41 @@ macro_rules! iter_chain {
|
||||
$(.chain(::std::iter::once($it)))*
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn iter_use_idents<F>(item_use: &syn::ItemUse, mut f: F) -> Result<()>
|
||||
where
|
||||
F: FnMut(&syn::Ident, bool) -> Result<()>,
|
||||
{
|
||||
match &item_use.tree {
|
||||
UseTree::Name(name) => f(&name.ident, true)?,
|
||||
UseTree::Rename(rename) => f(&rename.rename, true)?,
|
||||
UseTree::Path(path) => match &*path.tree {
|
||||
UseTree::Name(name) => f(&name.ident, true)?,
|
||||
UseTree::Rename(rename) => f(&rename.rename, true)?,
|
||||
UseTree::Path(_) => unreachable!(),
|
||||
other => iter_use_tree_idents(other, &mut f)?,
|
||||
},
|
||||
other => iter_use_tree_idents(other, &mut f)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn iter_use_tree_idents<F>(tree: &syn::UseTree, f: &mut F) -> Result<()>
|
||||
where
|
||||
F: FnMut(&syn::Ident, bool) -> Result<()>,
|
||||
{
|
||||
match tree {
|
||||
UseTree::Name(name) => f(&name.ident, false)?,
|
||||
UseTree::Rename(rename) => f(&rename.rename, false)?,
|
||||
UseTree::Path(path) => iter_use_tree_idents(&*path.tree, f)?,
|
||||
UseTree::Group(syn::UseGroup { items, .. }) => {
|
||||
for subtree in items {
|
||||
iter_use_tree_idents(subtree, f)?;
|
||||
}
|
||||
}
|
||||
UseTree::Glob(glob) => {
|
||||
return Err(syn::Error::new_spanned(glob, "#[py*] doesn't allow '*'"))
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
+3
-3
@@ -1300,11 +1300,11 @@ pub trait PyClassImpl: PyClassDef {
|
||||
}
|
||||
|
||||
fn make_class(ctx: &PyContext) -> PyClassRef {
|
||||
Self::make_class_with_base(ctx, Self::NAME, Self::base_class(ctx))
|
||||
Self::make_class_with_base(ctx, Self::base_class(ctx))
|
||||
}
|
||||
|
||||
fn make_class_with_base(ctx: &PyContext, name: &str, base: PyClassRef) -> PyClassRef {
|
||||
let py_class = ctx.new_class(name, base, Self::make_slots());
|
||||
fn make_class_with_base(ctx: &PyContext, base: PyClassRef) -> PyClassRef {
|
||||
let py_class = ctx.new_class(Self::NAME, base, Self::make_slots());
|
||||
Self::extend_class(ctx, &py_class);
|
||||
py_class
|
||||
}
|
||||
|
||||
+1359
-1216
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user