Skip to content

Commit c501103

Browse files
authored
Merge pull request RustPython#2233 from youknowone/iomodule
_io uses pymodule
2 parents 01e974e + c9a890d commit c501103

5 files changed

Lines changed: 1433 additions & 1217 deletions

File tree

derive/src/pyclass.rs

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::Diagnostic;
22
use crate::util::{
33
path_eq, pyclass_ident_and_attrs, ClassItemMeta, ContentItem, ContentItemInner, ErrorVec,
4-
ItemMeta, ItemMetaInner, ItemNursery, ALL_ALLOWED_NAMES,
4+
ItemMeta, ItemMetaInner, ItemNursery, SimpleItemMeta, ALL_ALLOWED_NAMES,
55
};
66
use proc_macro2::TokenStream;
77
use quote::{quote, quote_spanned, ToTokens};
@@ -216,6 +216,11 @@ struct SlotItem {
216216
inner: ContentItemInner,
217217
}
218218

219+
/// #[pyattr]
220+
struct AttributeItem {
221+
inner: ContentItemInner,
222+
}
223+
219224
/// #[extend_class]
220225
struct ExtendClassItem {
221226
inner: ContentItemInner,
@@ -236,6 +241,11 @@ impl ContentItem for SlotItem {
236241
&self.inner
237242
}
238243
}
244+
impl ContentItem for AttributeItem {
245+
fn inner(&self) -> &ContentItemInner {
246+
&self.inner
247+
}
248+
}
239249
impl ContentItem for ExtendClassItem {
240250
fn inner(&self) -> &ContentItemInner {
241251
&self.inner
@@ -357,6 +367,51 @@ where
357367
Ok(())
358368
}
359369
}
370+
371+
impl<Item> ImplItem<Item> for AttributeItem
372+
where
373+
Item: ItemLike + ToTokens + GetIdent,
374+
{
375+
fn gen_impl_item(&self, args: ImplItemArgs<'_, Item>) -> Result<()> {
376+
let cfgs = args.cfgs.to_vec();
377+
let attr = args.attrs.remove(self.index());
378+
379+
let get_py_name = |attr: &Attribute, ident: &Ident| -> Result<_> {
380+
let item_meta = SimpleItemMeta::from_attr(ident.clone(), attr)?;
381+
let py_name = item_meta.simple_name()?;
382+
Ok(py_name)
383+
};
384+
let (py_name, tokens) = if args.item.is_function_or_method() || args.item.is_const() {
385+
let ident = args.item.get_ident().unwrap();
386+
let py_name = get_py_name(&attr, &ident)?;
387+
388+
let value = if args.item.is_const() {
389+
// TODO: ctx.new_value
390+
quote_spanned!(ident.span() => ctx.new_int(Self::#ident))
391+
} else {
392+
quote_spanned!(ident.span() => Self::#ident(ctx))
393+
};
394+
(
395+
py_name.clone(),
396+
quote! {
397+
class.set_str_attr(#py_name, #value);
398+
},
399+
)
400+
} else {
401+
return Err(self.new_syn_error(
402+
args.item.span(),
403+
"can only be on a const or an associated method without argument",
404+
));
405+
};
406+
407+
args.context
408+
.impl_extend_items
409+
.add_item(py_name, cfgs, tokens)?;
410+
411+
Ok(())
412+
}
413+
}
414+
360415
impl<Item> ImplItem<Item> for ExtendClassItem
361416
where
362417
Item: ItemLike + ToTokens + GetIdent,
@@ -631,18 +686,27 @@ fn extract_impl_attrs(attr: AttributeArgs) -> std::result::Result<ExtractedImplA
631686
NestedMeta::Meta(Meta::List(syn::MetaList { path, nested, .. })) => {
632687
if path_eq(&path, "with") {
633688
for meta in nested {
634-
match meta {
635-
NestedMeta::Meta(Meta::Path(path)) => {
636-
withs.push(quote! {
637-
<Self as #path>::__extend_py_class(ctx, class);
638-
});
639-
with_slots.push(quote! {
640-
<Self as #path>::__extend_slots(slots);
641-
});
642-
}
689+
let path = match meta {
690+
NestedMeta::Meta(Meta::Path(path)) => path,
643691
meta => {
644692
bail_span!(meta, "#[pyimpl(with(...))] arguments should be paths")
645693
}
694+
};
695+
if path_eq(&path, "PyRef") {
696+
// special handling for PyRef
697+
withs.push(quote! {
698+
PyRef::<Self>::impl_extend_class(ctx, class);
699+
});
700+
with_slots.push(quote! {
701+
PyRef::<Self>::extend_slots(slots);
702+
});
703+
} else {
704+
withs.push(quote! {
705+
<Self as #path>::__extend_py_class(ctx, class);
706+
});
707+
with_slots.push(quote! {
708+
<Self as #path>::__extend_slots(slots);
709+
});
646710
}
647711
}
648712
} else if path_eq(&path, "flags") {
@@ -705,6 +769,9 @@ where
705769
"pyslot" => Box::new(SlotItem {
706770
inner: ContentItemInner { index, attr_name },
707771
}),
772+
"pyattr" => Box::new(AttributeItem {
773+
inner: ContentItemInner { index, attr_name },
774+
}),
708775
"extend_class" => Box::new(ExtendClassItem {
709776
inner: ContentItemInner { index, attr_name },
710777
}),

derive/src/pymodule.rs

Lines changed: 22 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::error::Diagnostic;
22
use crate::util::{
3-
pyclass_ident_and_attrs, AttributeExt, ClassItemMeta, ContentItem, ContentItemInner, ErrorVec,
4-
ItemMeta, ItemNursery, SimpleItemMeta, ALL_ALLOWED_NAMES,
3+
iter_use_idents, pyclass_ident_and_attrs, AttributeExt, ClassItemMeta, ContentItem,
4+
ContentItemInner, ErrorVec, ItemMeta, ItemNursery, SimpleItemMeta, ALL_ALLOWED_NAMES,
55
};
66
use proc_macro2::TokenStream;
77
use quote::{quote, quote_spanned, ToTokens};
8-
use syn::{parse_quote, spanned::Spanned, Attribute, AttributeArgs, Ident, Item, Result, UseTree};
8+
use syn::{parse_quote, spanned::Spanned, Attribute, AttributeArgs, Ident, Item, Result};
99
use syn_ext::ext::*;
1010

1111
#[derive(Default)]
@@ -367,60 +367,28 @@ impl ModuleItem for AttributeItem {
367367
},
368368
)
369369
}
370-
Item::Use(syn::ItemUse {
371-
tree: UseTree::Path(path),
372-
..
373-
}) => {
374-
let ident = match &*path.tree {
375-
UseTree::Name(name) => &name.ident,
376-
UseTree::Rename(rename) => &rename.rename,
377-
UseTree::Group(syn::UseGroup { items, .. }) => {
378-
for item in items {
379-
let ident = match item {
380-
UseTree::Name(name) => &name.ident,
381-
UseTree::Rename(rename) => &rename.rename,
382-
other => {
383-
return Err(self.new_syn_error(
384-
other.span(),
385-
"can only contains a simple use or a group of simple uses",
386-
));
387-
}
388-
};
389-
let item_meta = SimpleItemMeta::from_attr(ident.clone(), &attr)?;
390-
if item_meta.optional_name().is_some() {
391-
// this check actually doesn't need to be placed in loop
392-
return Err(self.new_syn_error(
393-
ident.span(),
394-
"`name` attribute is not allowed for multiple use items",
395-
));
396-
}
397-
let py_name = ident.to_string();
398-
let tokens = quote! {
399-
vm.__module_set_attr(&module, #py_name, vm.new_pyobj(#ident)).unwrap();
400-
};
401-
args.context.module_extend_items.add_item(
402-
py_name,
403-
cfgs.clone(),
404-
tokens,
405-
)?;
406-
}
407-
return Ok(());
408-
}
409-
other => {
370+
Item::Use(item) => {
371+
return iter_use_idents(item, |ident, is_unique| {
372+
let item_meta = SimpleItemMeta::from_attr(ident.clone(), &attr)?;
373+
let py_name = if is_unique {
374+
item_meta.simple_name()?
375+
} else if item_meta.optional_name().is_some() {
376+
// this check actually doesn't need to be placed in loop
410377
return Err(self.new_syn_error(
411-
other.span(),
412-
"can only contains a simple use or a group of simple uses",
378+
ident.span(),
379+
"`name` attribute is not allowed for multiple use items",
413380
));
414-
}
415-
};
416-
417-
let py_name = get_py_name(&attr, &ident)?;
418-
(
419-
py_name.clone(),
420-
quote! {
381+
} else {
382+
ident.to_string()
383+
};
384+
let tokens = quote! {
421385
vm.__module_set_attr(&module, #py_name, vm.new_pyobj(#ident)).unwrap();
422-
},
423-
)
386+
};
387+
args.context
388+
.module_extend_items
389+
.add_item(py_name, cfgs.clone(), tokens)?;
390+
Ok(())
391+
});
424392
}
425393
other => {
426394
return Err(

derive/src/util.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use proc_macro2::{Span, TokenStream};
22
use quote::{quote, ToTokens};
33
use std::collections::HashMap;
4-
use syn::{spanned::Spanned, Attribute, Ident, Meta, MetaList, NestedMeta, Path, Result};
4+
use syn::{spanned::Spanned, Attribute, Ident, Meta, MetaList, NestedMeta, Path, Result, UseTree};
55
use syn_ext::ext::{AttributeExt as SynAttributeExt, *};
66
use syn_ext::types::PunctuatedNestedMeta;
77

@@ -456,3 +456,41 @@ macro_rules! iter_chain {
456456
$(.chain(::std::iter::once($it)))*
457457
};
458458
}
459+
460+
pub(crate) fn iter_use_idents<F>(item_use: &syn::ItemUse, mut f: F) -> Result<()>
461+
where
462+
F: FnMut(&syn::Ident, bool) -> Result<()>,
463+
{
464+
match &item_use.tree {
465+
UseTree::Name(name) => f(&name.ident, true)?,
466+
UseTree::Rename(rename) => f(&rename.rename, true)?,
467+
UseTree::Path(path) => match &*path.tree {
468+
UseTree::Name(name) => f(&name.ident, true)?,
469+
UseTree::Rename(rename) => f(&rename.rename, true)?,
470+
UseTree::Path(_) => unreachable!(),
471+
other => iter_use_tree_idents(other, &mut f)?,
472+
},
473+
other => iter_use_tree_idents(other, &mut f)?,
474+
}
475+
Ok(())
476+
}
477+
478+
fn iter_use_tree_idents<F>(tree: &syn::UseTree, f: &mut F) -> Result<()>
479+
where
480+
F: FnMut(&syn::Ident, bool) -> Result<()>,
481+
{
482+
match tree {
483+
UseTree::Name(name) => f(&name.ident, false)?,
484+
UseTree::Rename(rename) => f(&rename.rename, false)?,
485+
UseTree::Path(path) => iter_use_tree_idents(&*path.tree, f)?,
486+
UseTree::Group(syn::UseGroup { items, .. }) => {
487+
for subtree in items {
488+
iter_use_tree_idents(subtree, f)?;
489+
}
490+
}
491+
UseTree::Glob(glob) => {
492+
return Err(syn::Error::new_spanned(glob, "#[py*] doesn't allow '*'"))
493+
}
494+
}
495+
Ok(())
496+
}

vm/src/pyobject.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,11 +1300,11 @@ pub trait PyClassImpl: PyClassDef {
13001300
}
13011301

13021302
fn make_class(ctx: &PyContext) -> PyClassRef {
1303-
Self::make_class_with_base(ctx, Self::NAME, Self::base_class(ctx))
1303+
Self::make_class_with_base(ctx, Self::base_class(ctx))
13041304
}
13051305

1306-
fn make_class_with_base(ctx: &PyContext, name: &str, base: PyClassRef) -> PyClassRef {
1307-
let py_class = ctx.new_class(name, base, Self::make_slots());
1306+
fn make_class_with_base(ctx: &PyContext, base: PyClassRef) -> PyClassRef {
1307+
let py_class = ctx.new_class(Self::NAME, base, Self::make_slots());
13081308
Self::extend_class(ctx, &py_class);
13091309
py_class
13101310
}

0 commit comments

Comments
 (0)