Merge pull request #2120 from youknowone/derive

Rework derive
This commit is contained in:
Jeong YunWon authored and GitHub committed 2020-08-23 20:23:10 +09:00
commit 5fd934d561
70 files changed
+1638 -1273

No files matched your search

Generated
+10
View File
@@ -1340,6 +1340,7 @@ dependencies = [
"rustpython-bytecode",
"rustpython-compiler",
"syn",
"syn-ext",
]
[[package]]
@@ -1688,6 +1689,15 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "syn-ext"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da910e9ec6f88d3f591893025a3040fe2659b7f7ea4eacce5469b7ebe5287339"
dependencies = [
"syn",
]
[[package]]
name = "term"
version = "0.5.2"
+1
View File
@@ -12,6 +12,7 @@ proc-macro = true
[dependencies]
syn = { version = "1.0", features = ["full"] }
syn-ext = { version = "0.2.1", features = ["full"] }
quote = "1.0"
proc-macro2 = "1.0"
rustpython-compiler = { path = "../compiler", version = "0.1.1" }
+12 -12
View File
@@ -43,19 +43,19 @@ macro_rules! bail_span {
)
}
macro_rules! push_err_span {
($diagnostics:expr, $($t:tt)*) => {
$diagnostics.push(err_span!($($t)*))
};
}
// macro_rules! push_err_span {
// ($diagnostics:expr, $($t:tt)*) => {
// $diagnostics.push(err_span!($($t)*))
// };
// }
macro_rules! push_diag_result {
($diags:expr, $x:expr $(,)?) => {
if let Err(e) = $x {
$diags.push(e);
}
};
}
// macro_rules! push_diag_result {
// ($diags:expr, $x:expr $(,)?) => {
// if let Err(e) = $x {
// $diags.push(e);
// }
// };
// }
#[derive(Debug)]
pub struct Diagnostic {
+619 -427
View File
File diff suppressed because it is too large. Load diff
+373 -420
View File
@@ -1,443 +1,72 @@
use super::Diagnostic;
use crate::error::Diagnostic;
use crate::util::{
def_to_name, meta_into_nesteds, optional_attribute_arg, ItemIdent, ItemMeta, ItemType,
pyclass_ident_and_attrs, AttributeExt, ClassItemMeta, ContentItem, ContentItemInner, ErrorVec,
ItemMeta, ItemNursery, SimpleItemMeta, ALL_ALLOWED_NAMES,
};
use proc_macro2::{Span, TokenStream as TokenStream2};
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned, ToTokens};
use std::collections::HashMap;
use syn::{parse_quote, spanned::Spanned, AttributeArgs, Ident, Item, Meta, NestedMeta, UseTree};
use syn::{parse_quote, spanned::Spanned, Attribute, AttributeArgs, Ident, Item, Result, UseTree};
use syn_ext::ext::*;
struct Module {
#[derive(Default)]
struct ModuleContext {
name: String,
items: HashMap<(String, Vec<Meta>), ModuleItem>,
module_extend_items: ItemNursery,
errors: Vec<syn::Error>,
}
#[derive(PartialEq, Eq, Hash)]
enum ModuleItem {
Function {
item_ident: Ident,
py_name: String,
},
EvaluatedAttr {
item_ident: Ident,
py_name: String,
},
ConstAttr {
item_ident: Ident,
py_name: String,
},
ClassAttr {
item_ident: Ident,
py_name: Option<String>,
},
Class {
item_ident: Ident,
py_name: String,
},
}
impl ModuleItem {
fn name(&self) -> String {
use ModuleItem::*;
match self {
Function { py_name, .. } => py_name.clone(),
EvaluatedAttr { py_name, .. } => py_name.clone(),
ConstAttr { py_name, .. } => py_name.clone(),
ClassAttr { py_name, .. } => py_name.clone().unwrap_or_else(String::new),
Class { py_name, .. } => py_name.clone(),
}
}
}
impl Module {
fn add_item(
&mut self,
item: ModuleItem,
cfgs: Vec<Meta>,
span: Span,
) -> Result<(), Diagnostic> {
if let Some(existing) = self.items.insert((item.name(), cfgs), item) {
Err(Diagnostic::span_error(
span,
format!(
"Duplicate #[py*] attribute on pymodule: {}",
existing.name()
),
))
} else {
Ok(())
}
}
fn extract_function(ident: &Ident, nesteds: Vec<NestedMeta>) -> Result<ModuleItem, Diagnostic> {
let item_meta =
ItemMeta::from_nested_meta("pyfunction", &ident, &nesteds, ItemMeta::SIMPLE_NAMES)?;
Ok(ModuleItem::Function {
item_ident: ident.clone(),
py_name: item_meta.simple_name()?,
})
}
fn extract_class(ident: &Ident, nesteds: Vec<NestedMeta>) -> Result<ModuleItem, Diagnostic> {
let item_meta =
ItemMeta::from_nested_meta("pyclass", &ident, &nesteds, ItemMeta::SIMPLE_NAMES)?;
Ok(ModuleItem::Class {
item_ident: ident.clone(),
py_name: item_meta.simple_name()?,
})
}
fn extract_struct_sequence(
ident: &Ident,
nesteds: Vec<NestedMeta>,
) -> Result<ModuleItem, Diagnostic> {
let item_meta = ItemMeta::from_nested_meta(
"pystruct_sequence",
&ident,
&nesteds,
ItemMeta::STRUCT_SEQUENCE_NAMES,
)?;
Ok(ModuleItem::Class {
item_ident: ident.clone(),
py_name: item_meta.simple_name()?,
})
}
fn extract_evaluated_attr(
ident: &Ident,
nesteds: Vec<NestedMeta>,
) -> Result<ModuleItem, Diagnostic> {
let item_meta =
ItemMeta::from_nested_meta("pyattr", &ident, &nesteds, ItemMeta::SIMPLE_NAMES)?;
Ok(ModuleItem::EvaluatedAttr {
item_ident: ident.clone(),
py_name: item_meta.simple_name()?,
})
}
fn extract_const_attr(
ident: &Ident,
nesteds: Vec<NestedMeta>,
) -> Result<ModuleItem, Diagnostic> {
let item_meta =
ItemMeta::from_nested_meta("pyattr", &ident, &nesteds, ItemMeta::SIMPLE_NAMES)?;
Ok(ModuleItem::ConstAttr {
item_ident: ident.clone(),
py_name: item_meta.simple_name()?,
})
}
fn extract_class_attr(
ident: &Ident,
nesteds: Vec<NestedMeta>,
) -> Result<ModuleItem, Diagnostic> {
let item_meta =
ItemMeta::from_nested_meta("pyattr", &ident, &nesteds, ItemMeta::SIMPLE_NAMES)?;
Ok(ModuleItem::ClassAttr {
item_ident: ident.clone(),
py_name: item_meta.optional_name(),
})
}
fn extract_item_from_syn(&mut self, item: &mut ItemIdent) -> Result<(), Diagnostic> {
let mut attr_idxs = Vec::new();
let mut items = Vec::new();
let mut cfgs = Vec::new();
let mut has_class = false;
for (i, attr) in item.attrs.iter_mut().enumerate() {
let meta = attr.parse_meta()?;
let meta_span = meta.span();
let name = match meta.path().get_ident() {
Some(name) => name.clone(),
None => continue,
};
let into_nested = || {
meta_into_nesteds(meta.clone()).map_err(|meta| {
err_span!(
meta,
"#[{name} = \"...\"] cannot be a name/value, you probably meant \
#[{name}(name = \"...\")]",
name = name.to_string(),
)
})
};
match name.to_string().as_str() {
"pyfunction" => {
assert!(item.typ == ItemType::Fn);
attr_idxs.push(i);
items.push((
Self::extract_function(item.ident, into_nested()?)?,
meta_span,
));
}
"pyattr" => {
attr_idxs.push(i);
let item = match item.typ {
ItemType::Fn => Self::extract_evaluated_attr(item.ident, into_nested()?)?,
ItemType::Const => Self::extract_const_attr(item.ident, into_nested()?)?,
ItemType::Struct | ItemType::Enum => {
if has_class {
return Err(err_span!(
meta,
"#[pyattr] must be placed on top of #[pyclass] or #[pystruct_sequence]",
));
}
Self::extract_class_attr(item.ident, into_nested()?)?
}
ItemType::Use => Self::extract_const_attr(item.ident, into_nested()?)?,
ItemType::Method => unreachable!(),
};
items.push((item, meta_span));
}
attr_name @ "pyclass" | attr_name @ "pystruct_sequence" => {
assert!(item.typ == ItemType::Struct);
let nested_or = into_nested();
let mut metalist = match &meta {
Meta::Path(path) => parse_quote!(#path()),
Meta::List(metalist) => metalist.clone(),
_ => unreachable!(),
};
if let Ok(nested) = &nested_or {
if optional_attribute_arg("py..", "module", &nested)?.is_none() {
let module_name = &self.name;
metalist.nested.push(parse_quote! {module = #module_name});
*attr = parse_quote!(#[#metalist]);
}
}
if has_class {
Err(err_span!(
meta,
"#[{}] in module cannot be duplicated",
attr_name,
))
} else if !items
.iter()
.all(|(item, _span)| matches!(item, ModuleItem::ClassAttr{..}))
{
Err(err_span!(
meta,
"#[{}] is allowed to have only #[pyattr] as siblings",
attr_name,
))
} else {
has_class = true;
Ok(())
}?;
let class = match attr_name {
"pyclass" => Self::extract_class(item.ident, nested_or?)?,
"pystruct_sequence" => {
// TODO: validate pystruct_sequence doesn't have module
Self::extract_struct_sequence(item.ident, nested_or?)?
}
_ => unreachable!(),
};
if items.is_empty() {
items.push((class, meta_span));
} else {
for (attr, _) in items.iter_mut() {
match attr {
ModuleItem::ClassAttr { py_name, .. } => {
if py_name.is_none() {
*py_name = Some(class.name());
}
}
_ => unreachable!(),
}
}
}
}
"cfg" => {
cfgs.push(meta);
continue;
}
_ => {
continue;
}
};
}
for (item, meta) in items {
self.add_item(item, cfgs.clone(), meta)?;
}
let mut i = 0;
let mut attr_idxs = &*attr_idxs;
item.attrs.retain(|_| {
let drop = attr_idxs.first().copied() == Some(i);
if drop {
attr_idxs = &attr_idxs[1..];
}
i += 1;
!drop
});
for (i, idx) in attr_idxs.iter().enumerate() {
item.attrs.remove(idx - i);
}
// TODO: Add module to pystruct_sequence
Ok(())
}
}
fn extract_module_items(
mut items: Vec<ItemIdent>,
module_name: &str,
) -> Result<TokenStream2, Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = Vec::new();
let mut module = Module {
name: module_name.to_owned(),
items: Default::default(),
};
for item in items.iter_mut() {
push_diag_result!(diagnostics, module.extract_item_from_syn(item),);
}
let items = module
.items
.into_iter()
.map(|((_name, cfgs), item)| match item {
ModuleItem::Function {
item_ident,
py_name,
} => {
let new_func = quote_spanned!(
item_ident.span() =>
vm.ctx.new_function_named(#item_ident, #module_name.to_owned(), #py_name.to_owned()));
quote! {
#( #[ #cfgs ])*
vm.__module_set_attr(&module, #py_name, #new_func).unwrap();
}
}
ModuleItem::EvaluatedAttr {
item_ident,
py_name,
} => {
let new_attr = quote_spanned!(
item_ident.span() =>
vm.new_pyobj(#item_ident(vm)));
quote! {
#( #[ #cfgs ])*
vm.__module_set_attr(&module, #py_name, #new_attr).unwrap();
}
}
ModuleItem::ConstAttr {
item_ident,
py_name,
} => {
let new_attr = quote_spanned!(
item_ident.span() =>
vm.new_pyobj(#item_ident));
quote! {
#( #[ #cfgs ])*
vm.__module_set_attr(&module, #py_name, #new_attr).unwrap();
}
}
class => {
let (item_ident, py_name) = match class {
ModuleItem::ClassAttr {
item_ident,
py_name: Some(py_name),
} => (item_ident, py_name),
ModuleItem::Class {
item_ident,
py_name,
} => (item_ident, py_name),
_ => unreachable!()
};
let new_class = quote_spanned!(
item_ident.span() =>
#item_ident::make_class(&vm.ctx));
quote! {
#( #[ #cfgs ])*
vm.__module_set_attr(&module, #py_name, #new_class).unwrap();
}
}
});
Diagnostic::from_vec(diagnostics)?;
Ok(quote! {
#(#items)*
})
}
pub fn impl_pymodule(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diagnostic> {
let mut module = match item {
pub fn impl_pymodule(
attr: AttributeArgs,
module_item: Item,
) -> std::result::Result<TokenStream, Diagnostic> {
let mut module_item = match module_item {
Item::Mod(m) => m,
other => bail_span!(other, "#[pymodule] can only be on a module declaration"),
other => bail_span!(other, "#[pymodule] can only be on a full module"),
};
let module_name = def_to_name("pymodule", &module.ident, &attr)?;
let fake_ident = Ident::new("pymodule", module_item.span());
let module_meta =
SimpleItemMeta::from_nested(module_item.ident.clone(), fake_ident, attr.into_iter())?;
let (_, content) = match module.content.as_mut() {
Some(c) => c,
None => bail_span!(
module,
"#[pymodule] can only be on a module declaration with body"
),
// generation resources
let mut context = ModuleContext {
name: module_meta.simple_name()?,
..Default::default()
};
let items = module_item.items_mut().ok_or_else(|| {
module_meta.new_meta_error("requires actual module, not a module declaration")
})?;
let items = content
.iter_mut()
.filter_map(|item| {
let item = match item {
Item::Fn(syn::ItemFn { attrs, sig, .. }) => ItemIdent {
typ: ItemType::Fn,
// collect to context
for item in items.iter_mut() {
let r = item.try_split_attr_mut(|attrs, item| {
let (pyitems, cfgs) = attrs_to_module_items(&attrs, new_module_item)?;
for pyitem in pyitems.iter().rev() {
let r = pyitem.gen_module_item(ModuleItemArgs {
item,
attrs,
ident: &sig.ident,
},
Item::Struct(syn::ItemStruct { attrs, ident, .. }) => ItemIdent {
typ: ItemType::Struct,
attrs,
ident,
},
Item::Enum(syn::ItemEnum { attrs, ident, .. }) => ItemIdent {
typ: ItemType::Enum,
attrs,
ident,
},
Item::Const(syn::ItemConst { attrs, ident, .. }) => ItemIdent {
typ: ItemType::Const,
attrs,
ident,
},
Item::Use(syn::ItemUse { attrs, tree, .. }) => {
let ident = match tree {
UseTree::Path(path) => match &*path.tree {
UseTree::Name(name) => &name.ident,
UseTree::Rename(rename) => &rename.rename,
_ => return None,
},
_ => return None,
};
ItemIdent {
typ: ItemType::Use,
attrs,
ident,
}
}
_ => return None,
};
Some(item)
})
.collect();
context: &mut context,
cfgs: cfgs.as_slice(),
});
context.errors.ok_or_push(r);
}
Ok(())
});
context.errors.ok_or_push(r);
}
let extend_mod = extract_module_items(items, &module_name)?;
content.extend(vec![
// append additional items
let module_name = context.name.as_str();
let module_extend_items = context.module_extend_items;
items.extend(vec![
parse_quote! {
pub(crate) const MODULE_NAME: &str = #module_name;
pub(crate) const MODULE_NAME: &'static str = #module_name;
},
parse_quote! {
pub(crate) fn extend_module(
vm: &::rustpython_vm::vm::VirtualMachine,
module: &::rustpython_vm::pyobject::PyObjectRef,
) {
#extend_mod
#module_extend_items
}
},
parse_quote! {
@@ -452,5 +81,329 @@ pub fn impl_pymodule(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Di
},
]);
Ok(module.into_token_stream())
Ok(if let Some(error) = context.errors.into_error() {
let error = Diagnostic::from(error);
quote! {
#module_item
#error
}
} else {
module_item.into_token_stream()
})
}
fn new_module_item(
index: usize,
attr_name: String,
pyattrs: Option<Vec<usize>>,
) -> Box<dyn ModuleItem> {
assert!(ALL_ALLOWED_NAMES.contains(&attr_name.as_str()));
match attr_name.as_str() {
"pyfunction" => Box::new(FunctionItem {
inner: ContentItemInner { index, attr_name },
}),
"pyattr" => Box::new(AttributeItem {
inner: ContentItemInner { index, attr_name },
}),
"pystruct_sequence" | "pyclass" => Box::new(ClassItem {
inner: ContentItemInner { index, attr_name },
pyattrs: pyattrs.unwrap_or_else(Vec::new),
}),
other => unreachable!("#[pymodule] doesn't accept #[{}]", other),
}
}
fn attrs_to_module_items<F, R>(attrs: &[Attribute], new_item: F) -> Result<(Vec<R>, Vec<Attribute>)>
where
F: Fn(usize, String, Option<Vec<usize>>) -> R,
{
let mut cfgs: Vec<Attribute> = Vec::new();
let mut result = Vec::new();
let mut iter = attrs.iter().enumerate().peekable();
while let Some((_, attr)) = iter.peek() {
// take all cfgs but no py items
let attr = *attr;
let attr_name = if let Some(ident) = attr.get_ident() {
ident.to_string()
} else {
continue;
};
if attr_name == "cfg" {
cfgs.push(attr.clone());
} else if ALL_ALLOWED_NAMES.contains(&attr_name.as_str()) {
break;
}
iter.next();
}
let mut closed = false;
let mut pyattrs = Vec::new();
for (i, attr) in iter {
// take py items but no cfgs
let attr_name = if let Some(ident) = attr.get_ident() {
ident.to_string()
} else {
continue;
};
if attr_name == "cfg" {
return Err(syn::Error::new_spanned(
attr,
"#[py*] items must be placed under `cfgs`",
));
}
if !ALL_ALLOWED_NAMES.contains(&attr_name.as_str()) {
continue;
} else if closed {
return Err(syn::Error::new_spanned(
attr,
"Only one #[pyattr] annotated #[py*] item can exist",
));
}
if attr_name == "pyattr" {
if !result.is_empty() {
return Err(syn::Error::new_spanned(
attr,
"#[pyattr] must be placed on top of other #[py*] items",
));
}
pyattrs.push((i, attr_name));
continue;
}
if pyattrs.is_empty() {
result.push(new_item(i, attr_name, None));
} else {
if !["pyclass", "pystruct_sequence"].contains(&attr_name.as_str()) {
return Err(syn::Error::new_spanned(
attr,
"#[pyattr] #[pyclass] is the only supported composition",
));
}
let pyattr_indexes = pyattrs.iter().map(|(i, _)| i).copied().collect();
result.push(new_item(i, attr_name, Some(pyattr_indexes)));
pyattrs = Vec::new();
closed = true;
}
}
for (index, attr_name) in pyattrs {
assert!(!closed);
result.push(new_item(index, attr_name, None));
}
Ok((result, cfgs))
}
/// #[pyfunction]
struct FunctionItem {
inner: ContentItemInner,
}
/// #[pyclass] or #[pystruct_sequence]
struct ClassItem {
inner: ContentItemInner,
pyattrs: Vec<usize>,
}
/// #[pyattr]
struct AttributeItem {
inner: ContentItemInner,
}
impl ContentItem for FunctionItem {
fn inner(&self) -> &ContentItemInner {
&self.inner
}
}
impl ContentItem for ClassItem {
fn inner(&self) -> &ContentItemInner {
&self.inner
}
}
impl ContentItem for AttributeItem {
fn inner(&self) -> &ContentItemInner {
&self.inner
}
}
struct ModuleItemArgs<'a> {
item: &'a Item,
attrs: &'a mut Vec<Attribute>,
context: &'a mut ModuleContext,
cfgs: &'a [Attribute],
}
impl<'a> ModuleItemArgs<'a> {
fn module_name(&'a self) -> &'a str {
self.context.name.as_str()
}
}
trait ModuleItem: ContentItem {
fn gen_module_item(&self, args: ModuleItemArgs<'_>) -> Result<()>;
}
impl ModuleItem for FunctionItem {
fn gen_module_item(&self, args: ModuleItemArgs<'_>) -> Result<()> {
let ident = match args.item {
Item::Fn(syn::ItemFn { sig, .. }) => sig.ident.clone(),
other => return Err(self.new_syn_error(other.span(), "can only be on a function")),
};
let item_attr = args.attrs.remove(self.index());
let item_meta = SimpleItemMeta::from_nested(
ident.clone(),
item_attr.get_ident().unwrap().clone(),
item_attr.promoted_nested()?.into_iter(),
)?;
let py_name = item_meta.simple_name()?;
let item = {
let module = args.module_name();
let new_func = quote_spanned!(
ident.span() => vm.ctx.new_function_named(#ident, #module.to_owned(), #py_name.to_owned())
);
quote! {
vm.__module_set_attr(&module, #py_name, #new_func).unwrap();
}
};
args.context
.module_extend_items
.add_item(py_name, args.cfgs.to_vec(), item)?;
Ok(())
}
}
impl ModuleItem for ClassItem {
fn gen_module_item(&self, args: ModuleItemArgs<'_>) -> Result<()> {
let (ident, _) = pyclass_ident_and_attrs(&args.item)?;
let (module_name, class_name) = {
let class_attr = &mut args.attrs[self.inner.index];
if self.pyattrs.is_empty() {
// check noattr before ClassItemMeta::from_nested
let noattr = class_attr.try_remove_name("noattr")?;
if noattr.is_none() {
return Err(syn::Error::new_spanned(
class_attr,
format!(
"#[{name}] requires #[pyattr] to be a module attribute. \
To keep it free type, try #[{name}(noattr)]",
name = self.attr_name()
),
));
}
}
let class_meta = ClassItemMeta::from_nested(
ident.clone(),
class_attr.get_ident().unwrap().clone(),
class_attr.promoted_nested()?.into_iter(),
)?;
let module_name = args.context.name.clone();
class_attr.fill_nested_meta("module", || {
parse_quote! {module = #module_name}
})?;
let class_name = class_meta.class_name()?;
(module_name, class_name)
};
for attr_index in self.pyattrs.iter().rev() {
let mut loop_unit = || {
let attr_attr = args.attrs.remove(*attr_index);
let (meta_ident, nested) = attr_attr.ident_and_promoted_nested()?;
let item_meta = SimpleItemMeta::from_nested(
ident.clone(),
meta_ident.clone(),
nested.into_iter(),
)?;
let py_name = item_meta
.optional_name()
.unwrap_or_else(|| class_name.clone());
let new_class = quote_spanned!(ident.span() =>
#ident::make_class(&vm.ctx);
);
let item = quote! {
let new_class = #new_class;
new_class.set_str_attr("__module__", vm.ctx.new_str(#module_name));
vm.__module_set_attr(&module, #py_name, new_class).unwrap();
};
args.context
.module_extend_items
.add_item(py_name, args.cfgs.to_vec(), item)?;
Ok(())
};
let r = loop_unit();
args.context.errors.ok_or_push(r);
}
Ok(())
}
}
impl ModuleItem for AttributeItem {
fn gen_module_item(&self, args: ModuleItemArgs<'_>) -> Result<()> {
let get_py_name = |attrs: &mut Vec<Attribute>, ident: &Ident| -> Result<_> {
let (meta_ident, nested) = attrs[self.inner.index].ident_and_promoted_nested()?;
let item_meta =
SimpleItemMeta::from_nested(ident.clone(), meta_ident.clone(), nested.into_iter())?;
let py_name = item_meta.simple_name()?;
Ok(py_name)
};
let (py_name, tokens) = match args.item {
Item::Fn(syn::ItemFn { sig, .. }) => {
let ident = &sig.ident;
let py_name = get_py_name(args.attrs, &ident)?;
(
py_name.clone(),
quote! {
vm.__module_set_attr(&module, #py_name, vm.new_pyobj(#ident(vm))).unwrap();
},
)
}
Item::Const(syn::ItemConst { ident, .. }) => {
let py_name = get_py_name(args.attrs, &ident)?;
(
py_name.clone(),
quote! {
vm.__module_set_attr(&module, #py_name, vm.new_pyobj(#ident)).unwrap();
},
)
}
Item::Use(syn::ItemUse {
tree: UseTree::Path(path),
..
}) => {
let ident = match &*path.tree {
UseTree::Name(name) => &name.ident,
UseTree::Rename(rename) => &rename.rename,
other => {
return Err(self.new_syn_error(other.span(), "can only be a simple use"));
}
};
let py_name = get_py_name(args.attrs, &ident)?;
(
py_name.clone(),
quote! {
vm.__module_set_attr(&module, #py_name, vm.new_pyobj(#ident)).unwrap();
},
)
}
other => {
return Err(
self.new_syn_error(other.span(), "can only be on a function, const and use")
)
}
};
args.attrs.remove(self.index());
args.context
.module_extend_items
.add_item(py_name, args.cfgs.to_vec(), tokens)?;
Ok(())
}
}
+425 -249
View File
@@ -1,269 +1,445 @@
use super::Diagnostic;
use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use std::collections::HashMap;
use syn::{Attribute, Ident, Lit, Meta, NestedMeta, Path};
use syn::{spanned::Spanned, Attribute, Ident, Meta, MetaList, NestedMeta, Path, Result};
use syn_ext::ext::{AttributeExt as SynAttributeExt, *};
use syn_ext::types::PunctuatedNestedMeta;
pub(crate) const ALL_ALLOWED_NAMES: &[&str] = &[
"pymethod",
"pyclassmethod",
"pyproperty",
"pyfunction",
"pyclass",
"pystruct_sequence",
"pyattr",
"pyslot",
];
#[derive(Default)]
pub(crate) struct ItemNursery(HashMap<(String, Vec<Attribute>), TokenStream>);
impl ItemNursery {
pub fn add_item(
&mut self,
name: String,
cfgs: Vec<Attribute>,
tokens: TokenStream,
) -> Result<()> {
if let Some(existing) = self.0.insert((name, cfgs), tokens) {
Err(syn::Error::new_spanned(
existing,
"Duplicated #[py*] attribute found",
))
} else {
Ok(())
}
}
}
impl ToTokens for ItemNursery {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(self.0.iter().map(|((_, cfgs), item)| {
quote! {
#( #cfgs )*
{
#item
}
}
}))
}
}
#[derive(Clone)]
pub(crate) struct ContentItemInner {
pub index: usize,
pub attr_name: String,
}
pub(crate) trait ContentItem {
fn inner(&self) -> &ContentItemInner;
fn index(&self) -> usize {
self.inner().index
}
fn attr_name(&self) -> &str {
self.inner().attr_name.as_str()
}
fn new_syn_error(&self, span: Span, message: &str) -> syn::Error {
syn::Error::new(span, format!("#[{}] {}", self.attr_name(), message))
}
}
pub(crate) struct ItemMetaInner {
pub item_ident: Ident,
pub meta_ident: Ident,
pub meta_map: HashMap<String, (usize, Meta)>,
}
impl ItemMetaInner {
pub fn from_nested<I>(
item_ident: Ident,
meta_ident: Ident,
nested: I,
allowed_names: &[&'static str],
) -> Result<Self>
where
I: std::iter::Iterator<Item = NestedMeta>,
{
let (meta_map, lits) = nested.into_unique_map_and_lits(|path| {
if let Some(ident) = path.get_ident() {
let name = ident.to_string();
if allowed_names.contains(&name.as_str()) {
Ok(Some(name))
} else {
Err(syn::Error::new_spanned(
ident,
format!(
"#[{}({})] is not one of allowed attributes {}",
meta_ident.to_string(),
name,
allowed_names.join(", ")
),
))
}
} else {
Ok(None)
}
})?;
if !lits.is_empty() {
return Err(syn::Error::new_spanned(
&meta_ident,
format!("#[{}(..)] cannot contain literal", meta_ident.to_string()),
));
}
Ok(Self {
item_ident,
meta_ident,
meta_map,
})
}
pub fn item_name(&self) -> String {
self.item_ident.to_string()
}
pub fn meta_name(&self) -> String {
self.meta_ident.to_string()
}
pub fn _optional_str(&self, key: &str) -> Result<Option<String>> {
let value = if let Some((_, meta)) = self.meta_map.get(key) {
match meta {
Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Str(lit),
..
}) => Some(lit.value()),
other => {
return Err(syn::Error::new_spanned(
other,
format!(
"#[{}({} = ...)] must exist as a string",
self.meta_name(),
key
),
));
}
}
} else {
None
};
Ok(value)
}
pub fn _bool(&self, key: &str) -> Result<bool> {
let value = if let Some((_, meta)) = self.meta_map.get(key) {
match meta {
Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Bool(lit),
..
}) => lit.value,
Meta::Path(_) => true,
other => {
return Err(syn::Error::new_spanned(
other,
format!("#[{}({})] is expected", self.meta_name(), key),
))
}
}
} else {
false
};
Ok(value)
}
}
pub(crate) trait ItemMeta: Sized {
const ALLOWED_NAMES: &'static [&'static str];
fn from_nested<I>(item_ident: Ident, meta_ident: Ident, nested: I) -> Result<Self>
where
I: std::iter::Iterator<Item = NestedMeta>,
{
Ok(Self::from_inner(ItemMetaInner::from_nested(
item_ident,
meta_ident,
nested,
Self::ALLOWED_NAMES,
)?))
}
fn from_inner(inner: ItemMetaInner) -> Self;
fn inner(&self) -> &ItemMetaInner;
fn simple_name(&self) -> Result<String> {
let inner = self.inner();
Ok(inner
._optional_str("name")?
.unwrap_or_else(|| inner.item_name()))
}
fn optional_name(&self) -> Option<String> {
self.inner()._optional_str("name").ok().flatten()
}
fn new_meta_error(&self, msg: &str) -> syn::Error {
let inner = self.inner();
syn::Error::new_spanned(
&inner.meta_ident,
format!("#[{}] {}", inner.meta_name(), msg),
)
}
}
pub(crate) struct SimpleItemMeta(pub ItemMetaInner);
impl ItemMeta for SimpleItemMeta {
const ALLOWED_NAMES: &'static [&'static str] = &["name"];
fn from_inner(inner: ItemMetaInner) -> Self {
Self(inner)
}
fn inner(&self) -> &ItemMetaInner {
&self.0
}
}
pub(crate) struct ClassItemMeta(ItemMetaInner);
impl ItemMeta for ClassItemMeta {
const ALLOWED_NAMES: &'static [&'static str] = &["module", "name"];
fn from_inner(inner: ItemMetaInner) -> Self {
Self(inner)
}
fn inner(&self) -> &ItemMetaInner {
&self.0
}
}
impl ClassItemMeta {
pub fn class_name(&self) -> Result<String> {
const KEY: &str = "name";
let inner = self.inner();
let value = if let Some((_, meta)) = inner.meta_map.get(KEY) {
match meta {
Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Str(lit),
..
}) => Some(lit.value()),
Meta::Path(_) => Some(inner.item_name()),
_ => None,
}
} else {
None
}.ok_or_else(|| syn::Error::new_spanned(
&inner.meta_ident,
format!(
"#[{attr_name}(name = ...)] must exist as a string. Try #[{attr_name}(name)] to use rust type name.",
attr_name=inner.meta_name()
),
))?;
Ok(value)
}
pub fn module(&self) -> Result<Option<String>> {
const KEY: &str = "module";
let inner = self.inner();
let value = if let Some((_, meta)) = inner.meta_map.get(KEY) {
match meta {
Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Str(lit),
..
}) => Ok(Some(lit.value())),
Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Bool(lit),
..
}) => if lit.value {
Err(lit.span())
} else {
Ok(None)
}
other => Err(other.span()),
}
} else {
Err(inner.item_ident.span())
}.map_err(|span| syn::Error::new(
span,
format!(
"#[{attr_name}(module = ...)] must exist as a string or false. Try #[{attr_name}(module=false)] for built-in types.",
attr_name=inner.meta_name()
),
))?;
Ok(value)
}
pub fn mandatory_module(&self) -> Result<String> {
let inner = self.inner();
let value = self.module().ok().flatten().
ok_or_else(|| syn::Error::new_spanned(
&inner.meta_ident,
format!(
"#[{attr_name}(module = ...)] must exist as a string. Built-in module is not allowed here.",
attr_name=inner.meta_name()
),
))?;
Ok(value)
}
}
pub(crate) fn path_eq(path: &Path, s: &str) -> bool {
path.get_ident().map_or(false, |id| id == s)
}
pub(crate) fn def_to_name(
attr_name: &'static str,
ident: &Ident,
attrs: &[NestedMeta],
) -> Result<String, Diagnostic> {
optional_attribute_arg(attr_name, "name", attrs)
.transpose()
.unwrap_or_else(|| Ok(ident.to_string()))
pub(crate) trait AttributeExt: SynAttributeExt {
fn promoted_nested(&self) -> Result<PunctuatedNestedMeta>;
fn ident_and_promoted_nested(&self) -> Result<(&Ident, PunctuatedNestedMeta)>;
fn try_remove_name(&mut self, name: &str) -> Result<Option<syn::NestedMeta>>;
fn fill_nested_meta<F>(&mut self, name: &str, new_item: F) -> Result<()>
where
F: Fn() -> NestedMeta;
}
pub(crate) fn attribute_arg(
attr_name: &'static str,
arg_name: &'static str,
attrs: &[NestedMeta],
) -> Result<String, Diagnostic> {
if let Some(r) = optional_attribute_arg(attr_name, arg_name, attrs).transpose() {
r
} else {
bail_span!(
attrs[0],
"#[{}({} = ...)] must exist but not found",
attr_name,
arg_name
)
impl AttributeExt for Attribute {
fn promoted_nested(&self) -> Result<PunctuatedNestedMeta> {
let list = self.promoted_list().map_err(|mut e| {
let name = self.get_ident().unwrap().to_string();
e.combine(syn::Error::new_spanned(
self,
format!(
"#[{name} = \"...\"] cannot be a name/value, you probably meant \
#[{name}(name = \"...\")]",
name = name,
),
));
e
})?;
Ok(list.nested)
}
fn ident_and_promoted_nested(&self) -> Result<(&Ident, PunctuatedNestedMeta)> {
Ok((self.get_ident().unwrap(), self.promoted_nested()?))
}
fn try_remove_name(&mut self, item_name: &str) -> Result<Option<syn::NestedMeta>> {
self.try_meta_mut(|meta| {
let nested = match meta {
Meta::List(MetaList { ref mut nested, .. }) => Ok(nested),
other => Err(syn::Error::new(
other.span(),
format!(
"#[{name}(...)] doesn't contain '{item}' to remove",
name = other.get_ident().unwrap().to_string(),
item = item_name
),
)),
}?;
let mut found = None;
for (i, item) in nested.iter().enumerate() {
let ident = if let Some(ident) = item.get_ident() {
ident
} else {
continue;
};
if *ident != item_name {
continue;
}
if found.is_some() {
return Err(syn::Error::new(
item.span(),
format!(
"#[py..({}...)] must be unique but found multiple times",
item_name,
),
));
}
found = Some(i);
}
Ok(found.map(|idx| nested.remove(idx).into_value()))
})
}
fn fill_nested_meta<F>(&mut self, name: &str, new_item: F) -> Result<()>
where
F: Fn() -> NestedMeta,
{
self.try_meta_mut(|meta| {
let list = meta.promote_to_list(Default::default())?;
let has_name = list
.nested
.iter()
.any(|nmeta| nmeta.get_path().map_or(false, |p| path_eq(p, name)));
if !has_name {
list.nested.push(new_item())
}
Ok(())
})
}
}
pub(crate) fn optional_attribute_arg(
attr_name: &'static str,
arg_name: &'static str,
attrs: &[NestedMeta],
) -> Result<Option<String>, Diagnostic> {
let mut arg_value = None;
for attr in attrs {
match attr {
NestedMeta::Meta(Meta::NameValue(name_value))
if path_eq(&name_value.path, arg_name) =>
{
if let Lit::Str(lit) = &name_value.lit {
if arg_value.is_some() {
bail_span!(
name_value.lit,
"#[{}({} = ...)] must be unique but found multiple times",
attr_name,
arg_name
);
}
arg_value = Some(lit.value());
} else {
bail_span!(
name_value.lit,
"#[{}({} = ...)] must be a string",
attr_name,
arg_name
);
}
}
_ => continue,
pub(crate) fn pyclass_ident_and_attrs(item: &syn::Item) -> Result<(&Ident, &[Attribute])> {
use syn::Item::*;
match item {
Struct(syn::ItemStruct { ident, attrs, .. }) => Ok((ident, attrs)),
Enum(syn::ItemEnum { ident, attrs, .. }) => Ok((ident, attrs)),
other => Err(syn::Error::new_spanned(
other,
"#[pyclass] can only be on a struct or enum declaration",
)),
}
}
pub(crate) trait ErrorVec: Sized {
fn into_error(self) -> Option<syn::Error>;
fn into_result(self) -> Result<()> {
if let Some(error) = self.into_error() {
Err(error)
} else {
Ok(())
}
}
Ok(arg_value)
fn ok_or_push<T>(&mut self, r: Result<T>) -> Option<T>;
}
pub(crate) fn meta_into_nesteds(meta: Meta) -> Result<Vec<NestedMeta>, Meta> {
match meta {
Meta::Path(_) => Ok(Vec::new()),
Meta::List(list) => Ok(list.nested.into_iter().collect()),
Meta::NameValue(_) => Err(meta),
}
}
#[derive(PartialEq)]
pub(crate) enum ItemType {
Fn,
Method,
Struct,
Enum,
Const,
Use,
}
pub(crate) struct ItemIdent<'a> {
pub typ: ItemType,
pub attrs: &'a mut Vec<Attribute>,
pub ident: &'a Ident,
}
pub(crate) struct ItemMeta<'a> {
ident: &'a Ident,
parent_type: &'static str,
meta: HashMap<String, Option<Lit>>,
}
impl<'a> ItemMeta<'a> {
pub const SIMPLE_NAMES: &'static [&'static str] = &["name"];
pub const STRUCT_SEQUENCE_NAMES: &'static [&'static str] = &["module", "name"];
pub const ATTRIBUTE_NAMES: &'static [&'static str] = &["name", "magic"];
pub const PROPERTY_NAMES: &'static [&'static str] = &["name", "magic", "setter"];
pub fn from_nested_meta(
parent_type: &'static str,
ident: &'a Ident,
nested_meta: &[NestedMeta],
names: &[&'static str],
) -> Result<Self, Diagnostic> {
let mut extracted = Self {
ident,
parent_type,
meta: HashMap::new(),
};
let validate_name = |name: &str, extracted: &Self| -> Result<(), Diagnostic> {
if names.contains(&name) {
if extracted.meta.contains_key(name) {
bail_span!(ident, "#[{}] must have only one '{}'", parent_type, name);
} else {
Ok(())
}
} else {
bail_span!(
ident,
"#[{}({})] is not one of allowed attributes {}",
parent_type,
name,
names.join(", ")
);
impl ErrorVec for Vec<syn::Error> {
fn into_error(self) -> Option<syn::Error> {
let mut iter = self.into_iter();
if let Some(mut first) = iter.next() {
for err in iter {
first.combine(err);
}
};
for meta in nested_meta {
let meta = match meta {
NestedMeta::Meta(meta) => meta,
NestedMeta::Lit(_) => continue,
};
match meta {
Meta::NameValue(name_value) => {
if let Some(ident) = name_value.path.get_ident() {
let name = ident.to_string();
validate_name(&name, &extracted)?;
extracted.meta.insert(name, Some(name_value.lit.clone()));
}
}
Meta::Path(path) => {
if let Some(ident) = path.get_ident() {
let name = ident.to_string();
validate_name(&name, &extracted)?;
extracted.meta.insert(name, None);
} else {
continue;
}
}
_ => (),
Some(first)
} else {
None
}
}
fn ok_or_push<T>(&mut self, r: Result<T>) -> Option<T> {
match r {
Ok(v) => Some(v),
Err(e) => {
self.push(e);
None
}
}
Ok(extracted)
}
fn _str(&self, key: &str) -> Result<Option<String>, Diagnostic> {
Ok(match self.meta.get(key) {
Some(Some(lit)) => {
if let Lit::Str(s) = lit {
Some(s.value())
} else {
bail_span!(
&self.ident,
"#[{}({} = ...)] must be a string",
self.parent_type,
key
);
}
}
Some(None) => {
bail_span!(
&self.ident,
"#[{}({} = ...)] is expected",
self.parent_type,
key,
);
}
None => None,
})
}
fn _bool(&self, key: &str) -> Result<bool, Diagnostic> {
Ok(match self.meta.get(key) {
Some(Some(_)) => {
bail_span!(&self.ident, "#[{}({})] is expected", self.parent_type, key,);
}
Some(None) => true,
None => false,
})
}
pub fn simple_name(&self) -> Result<String, Diagnostic> {
Ok(self._str("name")?.unwrap_or_else(|| self.ident.to_string()))
}
pub fn optional_name(&self) -> Option<String> {
self.simple_name().ok()
}
pub fn method_name(&self) -> Result<String, Diagnostic> {
let name = self._str("name")?;
let magic = self._bool("magic")?;
Ok(if let Some(name) = name {
name
} else {
let name = self.ident.to_string();
if magic {
format!("__{}__", name)
} else {
name
}
})
}
pub fn property_name(&self) -> Result<String, Diagnostic> {
let magic = self._bool("magic")?;
let setter = self._bool("setter")?;
let name = self._str("name")?;
Ok(if let Some(name) = name {
name
} else {
let sig_name = self.ident.to_string();
let name = if setter {
if let Some(name) = sig_name.strip_prefix("set_") {
if name.is_empty() {
bail_span!(
&self.ident,
"A #[{}(setter)] fn with a set_* name must \
have something after \"set_\"",
self.parent_type
)
}
name.to_string()
} else {
bail_span!(
&self.ident,
"A #[{}(setter)] fn must either have a `name` \
parameter or a fn name along the lines of \"set_*\"",
self.parent_type
)
}
} else {
sig_name
};
if magic {
format!("__{}__", name)
} else {
name
}
})
}
pub fn setter(&self) -> Result<bool, Diagnostic> {
self._bool("setter")
}
}
+1 -1
View File
@@ -21,7 +21,7 @@ use std::io::{self, BufRead, BufReader};
use crossbeam_utils::atomic::AtomicCell;
#[pyclass(name = "BaseException")]
#[pyclass(module = false, name = "BaseException")]
pub struct PyBaseException {
traceback: PyRwLock<Option<PyTracebackRef>>,
cause: PyRwLock<Option<PyBaseExceptionRef>>,
+1 -1
View File
@@ -87,7 +87,7 @@ struct FrameState {
blocks: Vec<Block>,
}
#[pyclass(name = "frame")]
#[pyclass(module = false, name = "frame")]
pub struct Frame {
pub code: PyCodeRef,
pub scope: Scope,
+4 -4
View File
@@ -9,7 +9,7 @@ use crate::vm::VirtualMachine;
use crossbeam_utils::atomic::AtomicCell;
#[pyclass(name = "async_generator")]
#[pyclass(name = "async_generator", module = false)]
#[derive(Debug)]
pub struct PyAsyncGen {
inner: Coro,
@@ -114,7 +114,7 @@ impl PyAsyncGen {
}
}
#[pyclass(name = "async_generator_wrapped_value")]
#[pyclass(module = false, name = "async_generator_wrapped_value")]
#[derive(Debug)]
pub(crate) struct PyAsyncGenWrappedValue(pub PyObjectRef);
impl PyValue for PyAsyncGenWrappedValue {
@@ -158,7 +158,7 @@ enum AwaitableState {
Closed,
}
#[pyclass(name = "async_generator_asend")]
#[pyclass(module = false, name = "async_generator_asend")]
#[derive(Debug)]
pub(crate) struct PyAsyncGenASend {
ag: PyAsyncGenRef,
@@ -253,7 +253,7 @@ impl PyAsyncGenASend {
}
}
#[pyclass(name = "async_generator_athrow")]
#[pyclass(module = false, name = "async_generator_athrow")]
#[derive(Debug)]
pub(crate) struct PyAsyncGenAThrow {
ag: PyAsyncGenRef,
+1 -1
View File
@@ -81,7 +81,7 @@ pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<bool> {
/// Returns True when the argument x is true, False otherwise.
/// The builtins True and False are the only two instances of the class bool.
/// The class bool is a subclass of the class int, and cannot be subclassed.
#[pyclass(name = "bool")]
#[pyclass(name = "bool", module = false)]
pub(crate) struct PyBool;
#[pyimpl]
+2 -2
View File
@@ -9,7 +9,7 @@ use crate::pyobject::{
use crate::slots::{SlotCall, SlotDescriptor};
use crate::vm::VirtualMachine;
#[pyclass(name = "builtin_function_or_method")]
#[pyclass(name = "builtin_function_or_method", module = false)]
pub struct PyBuiltinFunction {
value: PyNativeFunc,
module: Option<PyStringRef>,
@@ -70,7 +70,7 @@ impl PyBuiltinFunction {
}
}
#[pyclass(name = "method_descriptor")]
#[pyclass(module = false, name = "method_descriptor")]
pub struct PyBuiltinMethod {
function: PyBuiltinFunction,
}
+2 -2
View File
@@ -33,7 +33,7 @@ use crate::vm::VirtualMachine;
/// - a bytes or a buffer object\n \
/// - any object implementing the buffer API.\n \
/// - an integer";
#[pyclass(name = "bytearray")]
#[pyclass(module = false, name = "bytearray")]
#[derive(Debug)]
pub struct PyByteArray {
inner: PyRwLock<PyBytesInner>,
@@ -606,7 +606,7 @@ impl PyByteArray {
// obj.borrow_mut().kind = PyObjectPayload::Bytes { value };
// }
#[pyclass(name = "bytearray_iterator")]
#[pyclass(module = false, name = "bytearray_iterator")]
#[derive(Debug)]
pub struct PyByteArrayIterator {
position: AtomicCell<usize>,
+2 -2
View File
@@ -32,7 +32,7 @@ use rustpython_common::hash::PyHash;
/// - a text string encoded using the specified encoding\n \
/// - any object implementing the buffer API.\n \
/// - an integer";
#[pyclass(name = "bytes")]
#[pyclass(module = false, name = "bytes")]
#[derive(Clone, Debug)]
pub struct PyBytes {
inner: PyBytesInner,
@@ -488,7 +488,7 @@ impl PyBytes {
}
}
#[pyclass(name = "bytes_iterator")]
#[pyclass(module = false, name = "bytes_iterator")]
#[derive(Debug)]
pub struct PyBytesIterator {
position: AtomicCell<usize>,
+1 -1
View File
@@ -26,7 +26,7 @@ use crate::vm::VirtualMachine;
///
/// Class methods are different than C++ or Java static methods.
/// If you want those, see the staticmethod builtin.
#[pyclass(name = "classmethod")]
#[pyclass(module = false, name = "classmethod")]
#[derive(Clone, Debug)]
pub struct PyClassMethod {
callable: PyObjectRef,
+1 -1
View File
@@ -12,7 +12,7 @@ use crate::vm::VirtualMachine;
pub type PyCodeRef = PyRef<PyCode>;
#[pyclass(name = "code")]
#[pyclass(module = false, name = "code")]
pub struct PyCode {
pub code: bytecode::CodeObject,
}
+1 -1
View File
@@ -14,7 +14,7 @@ use rustpython_common::{float_ops, hash};
/// Create a complex number from a real part and an optional imaginary part.
///
/// This is equivalent to (real + imag*1j) where imag defaults to 0.
#[pyclass(name = "complex")]
#[pyclass(module = false, name = "complex")]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PyComplex {
value: Complex64,
+2 -2
View File
@@ -9,7 +9,7 @@ use crate::vm::VirtualMachine;
pub type PyCoroutineRef = PyRef<PyCoroutine>;
#[pyclass(name = "coroutine")]
#[pyclass(module = false, name = "coroutine")]
#[derive(Debug)]
pub struct PyCoroutine {
inner: Coro,
@@ -95,7 +95,7 @@ impl PyCoroutine {
}
}
#[pyclass(name = "coroutine_wrapper")]
#[pyclass(module = false, name = "coroutine_wrapper")]
#[derive(Debug)]
pub struct PyCoroutineWrapper {
coro: PyCoroutineRef,
+3 -3
View File
@@ -18,7 +18,7 @@ use std::mem::size_of;
pub type DictContentType = dictdatatype::Dict;
#[pyclass(name = "dict")]
#[pyclass(module = false, name = "dict")]
#[derive(Default)]
pub struct PyDict {
entries: DictContentType,
@@ -553,7 +553,7 @@ impl Iterator for DictIter {
macro_rules! dict_iterator {
( $name: ident, $iter_name: ident, $class: ident, $iter_class: ident, $class_name: literal, $iter_class_name: literal, $result_fn: expr) => {
#[pyclass(name = $class_name)]
#[pyclass(module=false,name = $class_name)]
#[derive(Debug)]
pub(crate) struct $name {
pub dict: PyDictRef,
@@ -598,7 +598,7 @@ macro_rules! dict_iterator {
}
}
#[pyclass(name = $iter_class_name)]
#[pyclass(module=false,name = $iter_class_name)]
#[derive(Debug)]
pub(crate) struct $iter_name {
pub dict: PyDictRef,
+1 -1
View File
@@ -6,7 +6,7 @@ pub(crate) fn init(context: &PyContext) {
PyEllipsis::extend_class(context, &context.ellipsis_type());
}
#[pyclass(name = "EllipsisType")]
#[pyclass(module = false, name = "EllipsisType")]
#[derive(Debug)]
pub struct PyEllipsis;
+1 -1
View File
@@ -11,7 +11,7 @@ use crate::function::OptionalArg;
use crate::pyobject::{BorrowValue, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
use crate::vm::VirtualMachine;
#[pyclass(name = "enumerate")]
#[pyclass(module = false, name = "enumerate")]
#[derive(Debug)]
pub struct PyEnumerate {
counter: PyRwLock<BigInt>,
+1 -1
View File
@@ -10,7 +10,7 @@ pub type PyFilterRef = PyRef<PyFilter>;
///
/// Return an iterator yielding those items of iterable for which function(item)
/// is true. If function is None, return the items that are true.
#[pyclass(name = "filter")]
#[pyclass(module = false, name = "filter")]
#[derive(Debug)]
pub struct PyFilter {
predicate: PyObjectRef,
+1 -1
View File
@@ -19,7 +19,7 @@ use crate::vm::VirtualMachine;
use rustpython_common::{float_ops, hash};
/// Convert a string or number to a floating point number, if possible.
#[pyclass(name = "float")]
#[pyclass(module = false, name = "float")]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PyFloat {
value: f64,
+2 -2
View File
@@ -20,7 +20,7 @@ use itertools::Itertools;
pub type PyFunctionRef = PyRef<PyFunction>;
#[pyclass(name = "function")]
#[pyclass(module = false, name = "function")]
#[derive(Debug)]
pub struct PyFunction {
code: PyCodeRef,
@@ -287,7 +287,7 @@ impl PyFunction {
}
}
#[pyclass(name = "method")]
#[pyclass(module = false, name = "method")]
#[derive(Debug)]
pub struct PyBoundMethod {
// TODO: these shouldn't be public
+1 -1
View File
@@ -12,7 +12,7 @@ use crate::vm::VirtualMachine;
pub type PyGeneratorRef = PyRef<PyGenerator>;
#[pyclass(name = "generator")]
#[pyclass(module = false, name = "generator")]
#[derive(Debug)]
pub struct PyGenerator {
inner: Coro,
+1 -1
View File
@@ -144,7 +144,7 @@ where
}
}
#[pyclass(name = "getset_descriptor")]
#[pyclass(module = false, name = "getset_descriptor")]
pub struct PyGetSet {
name: String,
getter: Option<PyGetterFunc>,
+1 -1
View File
@@ -40,7 +40,7 @@ use rustpython_common::hash;
/// Base 0 means to interpret the base from the string as an integer literal.
/// >>> int('0b100', base=0)
/// 4
#[pyclass(name = "int")]
#[pyclass(module = false, name = "int")]
#[derive(Debug)]
pub struct PyInt {
value: BigInt,
+2 -2
View File
@@ -149,7 +149,7 @@ pub fn length_hint(vm: &VirtualMachine, iter: PyObjectRef) -> PyResult<Option<us
Ok(Some(hint))
}
#[pyclass(name = "iter")]
#[pyclass(module = false, name = "iter")]
#[derive(Debug)]
pub struct PySequenceIterator {
pub position: AtomicCell<isize>,
@@ -222,7 +222,7 @@ pub fn seq_iter_method(obj: PyObjectRef) -> PySequenceIterator {
PySequenceIterator::new_forward(obj)
}
#[pyclass(name = "callable_iterator")]
#[pyclass(module = false, name = "callable_iterator")]
#[derive(Debug)]
pub struct PyCallableIterator {
callable: PyCallable,
+3 -3
View File
@@ -27,7 +27,7 @@ use crate::vm::{ReprGuard, VirtualMachine};
///
/// If no argument is given, the constructor creates a new empty list.
/// The argument must be an iterable if specified.
#[pyclass(name = "list")]
#[pyclass(module = false, name = "list")]
#[derive(Default)]
pub struct PyList {
elements: PyRwLock<Vec<PyObjectRef>>,
@@ -825,7 +825,7 @@ fn do_sort(
Ok(())
}
#[pyclass(name = "list_iterator")]
#[pyclass(module = false, name = "list_iterator")]
#[derive(Debug)]
pub struct PyListIterator {
pub position: AtomicCell<usize>,
@@ -864,7 +864,7 @@ impl PyListIterator {
}
}
#[pyclass(name = "list_reverseiterator")]
#[pyclass(module = false, name = "list_reverseiterator")]
#[derive(Debug)]
pub struct PyListReverseIterator {
pub position: AtomicCell<isize>,
+1 -1
View File
@@ -8,7 +8,7 @@ use crate::vm::VirtualMachine;
///
/// Make an iterator that computes the function using arguments from
/// each of the iterables. Stops when the shortest iterable is exhausted.
#[pyclass(name = "map")]
#[pyclass(module = false, name = "map")]
#[derive(Debug)]
pub struct PyMap {
mapper: PyObjectRef,
+1 -1
View File
@@ -9,7 +9,7 @@ use crate::pyobject::{
};
use crate::vm::VirtualMachine;
#[pyclass(name = "mappingproxy")]
#[pyclass(module = false, name = "mappingproxy")]
#[derive(Debug)]
pub struct PyMappingProxy {
mapping: MappingProxyInner,
+1 -1
View File
@@ -6,7 +6,7 @@ use crate::pyobject::{
use crate::stdlib::array::PyArray;
use crate::vm::VirtualMachine;
#[pyclass(name = "memoryview")]
#[pyclass(module = false, name = "memoryview")]
#[derive(Debug)]
pub struct PyMemoryView {
obj_ref: PyObjectRef,
+1 -1
View File
@@ -7,7 +7,7 @@ use crate::pyobject::{
};
use crate::vm::VirtualMachine;
#[pyclass(name = "module")]
#[pyclass(module = false, name = "module")]
#[derive(Debug)]
pub struct PyModule {}
pub type PyModuleRef = PyRef<PyModule>;
+1 -1
View File
@@ -6,7 +6,7 @@ use crate::vm::VirtualMachine;
/// A simple attribute-based namespace.
///
/// SimpleNamespace(**kwargs)
#[pyclass(name = "SimpleNamespace")]
#[pyclass(module = false, name = "SimpleNamespace")]
#[derive(Debug)]
pub struct PyNamespace;
+1 -1
View File
@@ -4,7 +4,7 @@ use crate::pyobject::{
};
use crate::vm::VirtualMachine;
#[pyclass(name = "NoneType")]
#[pyclass(module = false, name = "NoneType")]
#[derive(Debug)]
pub struct PyNone;
pub type PyNoneRef = PyRef<PyNone>;
+1 -1
View File
@@ -13,7 +13,7 @@ use crate::pyobject::{
use crate::vm::VirtualMachine;
/// The most base type
#[pyclass(name = "object")]
#[pyclass(module = false, name = "object")]
#[derive(Debug)]
pub struct PyBaseObject;
+1 -1
View File
@@ -43,7 +43,7 @@ use crate::vm::VirtualMachine;
/// @x.deleter
/// def x(self):
/// del self._x
#[pyclass(name = "property")]
#[pyclass(module = false, name = "property")]
#[derive(Debug)]
pub struct PyProperty {
getter: Option<PyObjectRef>,
+2 -2
View File
@@ -25,7 +25,7 @@ use rustpython_common::hash::PyHash;
/// start defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3.
/// These are exactly the valid indices for a list of 4 elements.
/// When step is given, it specifies the increment (or decrement).
#[pyclass(name = "range")]
#[pyclass(module = false, name = "range")]
#[derive(Debug, Clone)]
pub struct PyRange {
pub start: PyIntRef,
@@ -400,7 +400,7 @@ impl PyRange {
}
}
#[pyclass(name = "range_iterator")]
#[pyclass(module = false, name = "range_iterator")]
#[derive(Debug)]
pub struct PyRangeIterator {
position: AtomicCell<usize>,
+3 -3
View File
@@ -21,7 +21,7 @@ pub type SetContentType = dictdatatype::Dict<()>;
/// set(iterable) -> new set object
///
/// Build an unordered collection of unique elements.
#[pyclass(name = "set")]
#[pyclass(module = false, name = "set")]
#[derive(Default)]
pub struct PySet {
inner: PySetInner,
@@ -32,7 +32,7 @@ pub type PySetRef = PyRef<PySet>;
/// frozenset(iterable) -> frozenset object
///
/// Build an immutable unordered collection of unique elements.
#[pyclass(name = "frozenset")]
#[pyclass(module = false, name = "frozenset")]
#[derive(Default)]
pub struct PyFrozenSet {
inner: PySetInner,
@@ -824,7 +824,7 @@ struct SetSizeInfo {
position: usize,
}
#[pyclass(name = "set_iterator")]
#[pyclass(module = false, name = "set_iterator")]
pub(crate) struct PySetIterator {
dict: PyRc<SetContentType>,
size_info: crossbeam_utils::atomic::AtomicCell<SetSizeInfo>,
+1 -1
View File
@@ -9,7 +9,7 @@ use crate::vm::VirtualMachine;
use num_bigint::{BigInt, ToBigInt};
use num_traits::{One, Signed, Zero};
#[pyclass(name = "slice")]
#[pyclass(module = false, name = "slice")]
#[derive(Debug)]
pub struct PySlice {
pub start: Option<PyObjectRef>,
+1 -1
View File
@@ -4,7 +4,7 @@ use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyVa
use crate::slots::SlotDescriptor;
use crate::vm::VirtualMachine;
#[pyclass(name = "staticmethod")]
#[pyclass(module = false, name = "staticmethod")]
#[derive(Clone, Debug)]
pub struct PyStaticMethod {
pub callable: PyObjectRef,
+3 -3
View File
@@ -41,7 +41,7 @@ use rustpython_common::hash;
/// or repr(object).
/// encoding defaults to sys.getdefaultencoding().
/// errors defaults to 'strict'."
#[pyclass(name = "str")]
#[pyclass(module = false, name = "str")]
#[derive(Debug)]
pub struct PyString {
value: String,
@@ -102,7 +102,7 @@ impl TryIntoRef<PyString> for &str {
}
}
#[pyclass(name = "str_iterator")]
#[pyclass(module = false, name = "str_iterator")]
#[derive(Debug)]
pub struct PyStringIterator {
pub string: PyStringRef,
@@ -135,7 +135,7 @@ impl PyStringIterator {
}
}
#[pyclass(name = "str_reverseiterator")]
#[pyclass(module = false, name = "str_reverseiterator")]
#[derive(Debug)]
pub struct PyStringReverseIterator {
pub position: AtomicCell<isize>,
+1 -1
View File
@@ -21,7 +21,7 @@ use itertools::Itertools;
pub type PySuperRef = PyRef<PySuper>;
#[pyclass(name = "super")]
#[pyclass(module = false, name = "super")]
#[derive(Debug)]
pub struct PySuper {
typ: PyClassRef,
+1 -1
View File
@@ -3,7 +3,7 @@ use crate::obj::objtype::PyClassRef;
use crate::pyobject::{PyClassImpl, PyContext, PyRef, PyValue};
use crate::vm::VirtualMachine;
#[pyclass(name = "traceback")]
#[pyclass(module = false, name = "traceback")]
#[derive(Debug)]
pub struct PyTraceback {
pub next: Option<PyTracebackRef>, // TODO: Make mutable
+2 -2
View File
@@ -18,7 +18,7 @@ use rustpython_common::hash::PyHash;
/// tuple(iterable) -> tuple initialized from iterable's items
///
/// If the argument is a tuple, the return value is the same object.
#[pyclass(name = "tuple")]
#[pyclass(module = false, name = "tuple")]
pub struct PyTuple {
elements: Vec<PyObjectRef>,
}
@@ -255,7 +255,7 @@ impl PyTuple {
}
}
#[pyclass(name = "tuple_iterator")]
#[pyclass(module = false, name = "tuple_iterator")]
#[derive(Debug)]
pub struct PyTupleIterator {
position: AtomicCell<usize>,
+1 -1
View File
@@ -24,7 +24,7 @@ use std::ops::Deref;
/// type(object_or_name, bases, dict)
/// type(object) -> the object's type
/// type(name, bases, dict) -> a new type
#[pyclass(name = "type")]
#[pyclass(module = false, name = "type")]
pub struct PyClass {
pub name: String,
pub base: Option<PyClassRef>,
+1 -1
View File
@@ -4,7 +4,7 @@ use crate::function::OptionalArg;
use crate::pyobject::{PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue};
use crate::vm::VirtualMachine;
#[pyclass(name = "weakproxy")]
#[pyclass(module = false, name = "weakproxy")]
#[derive(Debug)]
pub struct PyWeakProxy {
weak: PyWeak,
+1 -1
View File
@@ -11,7 +11,7 @@ use rustpython_common::rc::{PyRc, PyWeak as Weak};
use crossbeam_utils::atomic::AtomicCell;
#[pyclass(name = "ref")]
#[pyclass(module = false, name = "ref")]
#[derive(Debug)]
pub struct PyWeak {
referent: Weak<PyObject<dyn PyObjectPayload>>,
+1 -1
View File
@@ -6,7 +6,7 @@ use crate::vm::VirtualMachine;
pub type PyZipRef = PyRef<PyZip>;
#[pyclass(name = "zip")]
#[pyclass(module = false, name = "zip")]
#[derive(Debug)]
pub struct PyZip {
iterators: Vec<PyObjectRef>,
+4 -4
View File
@@ -464,8 +464,8 @@ impl PyContext {
.unwrap()
}
pub fn new_class(&self, name: &str, base: PyClassRef, flags: PyTpFlags) -> PyClassRef {
create_type_with_flags(name, &self.type_type(), &base, flags)
pub fn new_class(&self, name: &str, base: &PyClassRef, flags: PyTpFlags) -> PyClassRef {
create_type_with_flags(name, &self.type_type(), base, flags)
}
pub fn new_namespace(&self) -> PyObjectRef {
@@ -1481,10 +1481,10 @@ pub trait PyClassImpl: PyClassDef {
}
fn make_class(ctx: &PyContext) -> PyClassRef {
Self::make_class_with_base(ctx, Self::NAME, ctx.object())
Self::make_class_with_base(ctx, Self::NAME, &ctx.object())
}
fn make_class_with_base(ctx: &PyContext, name: &str, base: PyClassRef) -> PyClassRef {
fn make_class_with_base(ctx: &PyContext, name: &str, base: &PyClassRef) -> PyClassRef {
let py_class = ctx.new_class(name, base, Self::TP_FLAGS);
Self::extend_class(ctx, &py_class);
py_class
+2 -2
View File
@@ -246,7 +246,7 @@ def_array_enum!(
(Double, f64, 'd'),
);
#[pyclass(name = "array")]
#[pyclass(module = "array", name = "array")]
#[derive(Debug)]
pub struct PyArray {
array: PyRwLock<ArrayContentType>,
@@ -530,7 +530,7 @@ impl PyArray {
}
}
#[pyclass(name = "array_iterator")]
#[pyclass(module = "array", name = "array_iterator")]
#[derive(Debug)]
pub struct PyArrayIter {
position: AtomicCell<usize>,
+64 -64
View File
@@ -644,72 +644,72 @@ pub(crate) fn parse(vm: &VirtualMachine, source: &str, mode: Mode) -> PyResult {
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
let ctx = &vm.ctx;
let ast_base = py_class!(ctx, "AST", ctx.object(), PyTpFlags::HAS_DICT, {});
let ast_base = py_class!(ctx, "AST", &ctx.object(), PyTpFlags::HAS_DICT, {});
py_module!(vm, MODULE_NAME, {
// TODO: There's got to be a better way!
"alias" => py_class!(ctx, "alias", ast_base.clone(), {}),
"arg" => py_class!(ctx, "arg", ast_base.clone(), {}),
"arguments" => py_class!(ctx, "arguments", ast_base.clone(), {}),
"AnnAssign" => py_class!(ctx, "AnnAssign", ast_base.clone(), {}),
"Assign" => py_class!(ctx, "Assign", ast_base.clone(), {}),
"AugAssign" => py_class!(ctx, "AugAssign", ast_base.clone(), {}),
"AsyncFor" => py_class!(ctx, "AsyncFor", ast_base.clone(), {}),
"AsyncFunctionDef" => py_class!(ctx, "AsyncFunctionDef", ast_base.clone(), {}),
"AsyncWith" => py_class!(ctx, "AsyncWith", ast_base.clone(), {}),
"Assert" => py_class!(ctx, "Assert", ast_base.clone(), {}),
"Attribute" => py_class!(ctx, "Attribute", ast_base.clone(), {}),
"Await" => py_class!(ctx, "Await", ast_base.clone(), {}),
"BinOp" => py_class!(ctx, "BinOp", ast_base.clone(), {}),
"BoolOp" => py_class!(ctx, "BoolOp", ast_base.clone(), {}),
"Break" => py_class!(ctx, "Break", ast_base.clone(), {}),
"Bytes" => py_class!(ctx, "Bytes", ast_base.clone(), {}),
"Call" => py_class!(ctx, "Call", ast_base.clone(), {}),
"ClassDef" => py_class!(ctx, "ClassDef", ast_base.clone(), {}),
"Compare" => py_class!(ctx, "Compare", ast_base.clone(), {}),
"comprehension" => py_class!(ctx, "comprehension", ast_base.clone(), {}),
"Continue" => py_class!(ctx, "Continue", ast_base.clone(), {}),
"Delete" => py_class!(ctx, "Delete", ast_base.clone(), {}),
"Dict" => py_class!(ctx, "Dict", ast_base.clone(), {}),
"DictComp" => py_class!(ctx, "DictComp", ast_base.clone(), {}),
"Ellipsis" => py_class!(ctx, "Ellipsis", ast_base.clone(), {}),
"Expr" => py_class!(ctx, "Expr", ast_base.clone(), {}),
"ExceptHandler" => py_class!(ctx, "ExceptHandler", ast_base.clone(), {}),
"For" => py_class!(ctx, "For", ast_base.clone(), {}),
"FormattedValue" => py_class!(ctx, "FormattedValue", ast_base.clone(), {}),
"FunctionDef" => py_class!(ctx, "FunctionDef", ast_base.clone(), {}),
"GeneratorExp" => py_class!(ctx, "GeneratorExp", ast_base.clone(), {}),
"Global" => py_class!(ctx, "Global", ast_base.clone(), {}),
"If" => py_class!(ctx, "If", ast_base.clone(), {}),
"IfExp" => py_class!(ctx, "IfExp", ast_base.clone(), {}),
"Import" => py_class!(ctx, "Import", ast_base.clone(), {}),
"ImportFrom" => py_class!(ctx, "ImportFrom", ast_base.clone(), {}),
"JoinedStr" => py_class!(ctx, "JoinedStr", ast_base.clone(), {}),
"keyword" => py_class!(ctx, "keyword", ast_base.clone(), {}),
"Lambda" => py_class!(ctx, "Lambda", ast_base.clone(), {}),
"List" => py_class!(ctx, "List", ast_base.clone(), {}),
"ListComp" => py_class!(ctx, "ListComp", ast_base.clone(), {}),
"Module" => py_class!(ctx, "Module", ast_base.clone(), {}),
"Name" => py_class!(ctx, "Name", ast_base.clone(), {}),
"NameConstant" => py_class!(ctx, "NameConstant", ast_base.clone(), {}),
"Nonlocal" => py_class!(ctx, "Nonlocal", ast_base.clone(), {}),
"Num" => py_class!(ctx, "Num", ast_base.clone(), {}),
"Pass" => py_class!(ctx, "Pass", ast_base.clone(), {}),
"Raise" => py_class!(ctx, "Raise", ast_base.clone(), {}),
"Return" => py_class!(ctx, "Return", ast_base.clone(), {}),
"Set" => py_class!(ctx, "Set", ast_base.clone(), {}),
"SetComp" => py_class!(ctx, "SetComp", ast_base.clone(), {}),
"Starred" => py_class!(ctx, "Starred", ast_base.clone(), {}),
"Starred" => py_class!(ctx, "Starred", ast_base.clone(), {}),
"Str" => py_class!(ctx, "Str", ast_base.clone(), {}),
"Subscript" => py_class!(ctx, "Subscript", ast_base.clone(), {}),
"Try" => py_class!(ctx, "Try", ast_base.clone(), {}),
"Tuple" => py_class!(ctx, "Tuple", ast_base.clone(), {}),
"UnaryOp" => py_class!(ctx, "UnaryOp", ast_base.clone(), {}),
"While" => py_class!(ctx, "While", ast_base.clone(), {}),
"With" => py_class!(ctx, "With", ast_base.clone(), {}),
"withitem" => py_class!(ctx, "withitem", ast_base.clone(), {}),
"Yield" => py_class!(ctx, "Yield", ast_base.clone(), {}),
"YieldFrom" => py_class!(ctx, "YieldFrom", ast_base.clone(), {}),
"alias" => py_class!(ctx, "alias", &ast_base, {}),
"arg" => py_class!(ctx, "arg", &ast_base, {}),
"arguments" => py_class!(ctx, "arguments", &ast_base, {}),
"AnnAssign" => py_class!(ctx, "AnnAssign", &ast_base, {}),
"Assign" => py_class!(ctx, "Assign", &ast_base, {}),
"AugAssign" => py_class!(ctx, "AugAssign", &ast_base, {}),
"AsyncFor" => py_class!(ctx, "AsyncFor", &ast_base, {}),
"AsyncFunctionDef" => py_class!(ctx, "AsyncFunctionDef", &ast_base, {}),
"AsyncWith" => py_class!(ctx, "AsyncWith", &ast_base, {}),
"Assert" => py_class!(ctx, "Assert", &ast_base, {}),
"Attribute" => py_class!(ctx, "Attribute", &ast_base, {}),
"Await" => py_class!(ctx, "Await", &ast_base, {}),
"BinOp" => py_class!(ctx, "BinOp", &ast_base, {}),
"BoolOp" => py_class!(ctx, "BoolOp", &ast_base, {}),
"Break" => py_class!(ctx, "Break", &ast_base, {}),
"Bytes" => py_class!(ctx, "Bytes", &ast_base, {}),
"Call" => py_class!(ctx, "Call", &ast_base, {}),
"ClassDef" => py_class!(ctx, "ClassDef", &ast_base, {}),
"Compare" => py_class!(ctx, "Compare", &ast_base, {}),
"comprehension" => py_class!(ctx, "comprehension", &ast_base, {}),
"Continue" => py_class!(ctx, "Continue", &ast_base, {}),
"Delete" => py_class!(ctx, "Delete", &ast_base, {}),
"Dict" => py_class!(ctx, "Dict", &ast_base, {}),
"DictComp" => py_class!(ctx, "DictComp", &ast_base, {}),
"Ellipsis" => py_class!(ctx, "Ellipsis", &ast_base, {}),
"Expr" => py_class!(ctx, "Expr", &ast_base, {}),
"ExceptHandler" => py_class!(ctx, "ExceptHandler", &ast_base, {}),
"For" => py_class!(ctx, "For", &ast_base, {}),
"FormattedValue" => py_class!(ctx, "FormattedValue", &ast_base, {}),
"FunctionDef" => py_class!(ctx, "FunctionDef", &ast_base, {}),
"GeneratorExp" => py_class!(ctx, "GeneratorExp", &ast_base, {}),
"Global" => py_class!(ctx, "Global", &ast_base, {}),
"If" => py_class!(ctx, "If", &ast_base, {}),
"IfExp" => py_class!(ctx, "IfExp", &ast_base, {}),
"Import" => py_class!(ctx, "Import", &ast_base, {}),
"ImportFrom" => py_class!(ctx, "ImportFrom", &ast_base, {}),
"JoinedStr" => py_class!(ctx, "JoinedStr", &ast_base, {}),
"keyword" => py_class!(ctx, "keyword", &ast_base, {}),
"Lambda" => py_class!(ctx, "Lambda", &ast_base, {}),
"List" => py_class!(ctx, "List", &ast_base, {}),
"ListComp" => py_class!(ctx, "ListComp", &ast_base, {}),
"Module" => py_class!(ctx, "Module", &ast_base, {}),
"Name" => py_class!(ctx, "Name", &ast_base, {}),
"NameConstant" => py_class!(ctx, "NameConstant", &ast_base, {}),
"Nonlocal" => py_class!(ctx, "Nonlocal", &ast_base, {}),
"Num" => py_class!(ctx, "Num", &ast_base, {}),
"Pass" => py_class!(ctx, "Pass", &ast_base, {}),
"Raise" => py_class!(ctx, "Raise", &ast_base, {}),
"Return" => py_class!(ctx, "Return", &ast_base, {}),
"Set" => py_class!(ctx, "Set", &ast_base, {}),
"SetComp" => py_class!(ctx, "SetComp", &ast_base, {}),
"Starred" => py_class!(ctx, "Starred", &ast_base, {}),
"Starred" => py_class!(ctx, "Starred", &ast_base, {}),
"Str" => py_class!(ctx, "Str", &ast_base, {}),
"Subscript" => py_class!(ctx, "Subscript", &ast_base, {}),
"Try" => py_class!(ctx, "Try", &ast_base, {}),
"Tuple" => py_class!(ctx, "Tuple", &ast_base, {}),
"UnaryOp" => py_class!(ctx, "UnaryOp", &ast_base, {}),
"While" => py_class!(ctx, "While", &ast_base, {}),
"With" => py_class!(ctx, "With", &ast_base, {}),
"withitem" => py_class!(ctx, "withitem", &ast_base, {}),
"Yield" => py_class!(ctx, "Yield", &ast_base, {}),
"YieldFrom" => py_class!(ctx, "YieldFrom", &ast_base, {}),
"AST" => ast_base,
"PyCF_ONLY_AST" => ctx.new_int(PY_COMPILE_FLAG_AST_ONLY),
})
+2
View File
@@ -17,6 +17,7 @@ mod _collections {
use crossbeam_utils::atomic::AtomicCell;
#[pyattr]
#[pyclass(name = "deque")]
#[derive(Debug)]
struct PyDeque {
@@ -402,6 +403,7 @@ mod _collections {
}
}
#[pyattr]
#[pyclass(name = "_deque_iterator")]
#[derive(Debug)]
struct PyDequeIterator {
+1 -1
View File
@@ -124,7 +124,7 @@ impl ReadState {
}
}
#[pyclass(name = "Reader")]
#[pyclass(module = "csv", name = "Reader")]
struct Reader {
state: PyRwLock<ReadState>,
}
+1 -1
View File
@@ -14,7 +14,7 @@ use sha1::Sha1;
use sha2::{Sha224, Sha256, Sha384, Sha512};
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512}; // TODO: , Shake128, Shake256};
#[pyclass(name = "hasher")]
#[pyclass(module = "hashlib", name = "hasher")]
struct PyHasher {
name: String,
buffer: PyRwLock<HashWrapper>,
+11 -11
View File
@@ -647,7 +647,7 @@ mod fileio {
flag as u32
}
#[pyclass]
#[pyclass(module = "io", name)]
#[derive(Debug)]
struct FileIO {
fd: AtomicCell<i64>,
@@ -877,7 +877,7 @@ mod fileio {
}
pub fn make_fileio(ctx: &crate::pyobject::PyContext, raw_io_base: PyClassRef) -> PyClassRef {
FileIO::make_class_with_base(ctx, FileIO::NAME, raw_io_base)
FileIO::make_class_with_base(ctx, FileIO::NAME, &raw_io_base)
}
}
@@ -1268,7 +1268,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
let ctx = &vm.ctx;
// IOBase the abstract base class of the IO Module
let io_base = py_class!(ctx, "_IOBase", ctx.object(), {
let io_base = py_class!(ctx, "_IOBase", &ctx.object(), {
"__enter__" => ctx.new_method(io_base_cm_enter),
"__exit__" => ctx.new_method(io_base_cm_exit),
"seekable" => ctx.new_method(io_base_seekable),
@@ -1289,17 +1289,17 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
});
// IOBase Subclasses
let raw_io_base = py_class!(ctx, "_RawIOBase", io_base.clone(), {
let raw_io_base = py_class!(ctx, "_RawIOBase", &io_base, {
"read" => ctx.new_method(raw_io_base_read),
});
let buffered_io_base = py_class!(ctx, "_BufferedIOBase", io_base.clone(), {});
let buffered_io_base = py_class!(ctx, "_BufferedIOBase", &io_base, {});
//TextIO Base has no public constructor
let text_io_base = py_class!(ctx, "_TextIOBase", io_base.clone(), {});
let text_io_base = py_class!(ctx, "_TextIOBase", &io_base, {});
// BufferedIOBase Subclasses
let buffered_reader = py_class!(ctx, "BufferedReader", buffered_io_base.clone(), {
let buffered_reader = py_class!(ctx, "BufferedReader", &buffered_io_base, {
//workaround till the buffered classes can be fixed up to be more
//consistent with the python model
//For more info see: https://github.com/RustPython/RustPython/issues/547
@@ -1314,7 +1314,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
"mode" => ctx.new_readonly_getset("mode", buffered_io_base_mode),
});
let buffered_writer = py_class!(ctx, "BufferedWriter", buffered_io_base.clone(), {
let buffered_writer = py_class!(ctx, "BufferedWriter", &buffered_io_base, {
//workaround till the buffered classes can be fixed up to be more
//consistent with the python model
//For more info see: https://github.com/RustPython/RustPython/issues/547
@@ -1330,7 +1330,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
});
//TextIOBase Subclass
let text_io_wrapper = py_class!(ctx, "TextIOWrapper", text_io_base.clone(), {
let text_io_wrapper = py_class!(ctx, "TextIOWrapper", &text_io_base, {
"__init__" => ctx.new_method(text_io_wrapper_init),
"seekable" => ctx.new_method(text_io_wrapper_seekable),
"seek" => ctx.new_method(text_io_wrapper_seek),
@@ -1344,7 +1344,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
});
//StringIO: in-memory text
let string_io = py_class!(ctx, "StringIO", text_io_base.clone(), {
let string_io = py_class!(ctx, "StringIO", &text_io_base, {
"__module__" => ctx.new_str("_io"),
(slot new) => string_io_new,
"seek" => ctx.new_method(PyStringIORef::seek),
@@ -1360,7 +1360,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
});
//BytesIO: in-memory bytes
let bytes_io = py_class!(ctx, "BytesIO", buffered_io_base.clone(), {
let bytes_io = py_class!(ctx, "BytesIO", &buffered_io_base, {
(slot new) => bytes_io_new,
"read" => ctx.new_method(PyBytesIORef::read),
"read1" => ctx.new_method(PyBytesIORef::read),
+19
View File
@@ -22,6 +22,7 @@ mod decl {
};
use crate::vm::VirtualMachine;
#[pyattr]
#[pyclass(name = "chain")]
#[derive(Debug)]
struct PyItertoolsChain {
@@ -107,6 +108,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "compress")]
#[derive(Debug)]
struct PyItertoolsCompress {
@@ -158,6 +160,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "count")]
#[derive(Debug)]
struct PyItertoolsCount {
@@ -210,6 +213,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "cycle")]
#[derive(Debug)]
struct PyItertoolsCycle {
@@ -271,6 +275,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "repeat")]
#[derive(Debug)]
struct PyItertoolsRepeat {
@@ -328,6 +333,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "starmap")]
#[derive(Debug)]
struct PyItertoolsStarmap {
@@ -369,6 +375,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "takewhile")]
#[derive(Debug)]
struct PyItertoolsTakewhile {
@@ -428,6 +435,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "dropwhile")]
#[derive(Debug)]
struct PyItertoolsDropwhile {
@@ -512,6 +520,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "groupby")]
struct PyItertoolsGroupBy {
iterable: PyObjectRef,
@@ -620,6 +629,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "_grouper")]
#[derive(Debug)]
struct PyItertoolsGrouper {
@@ -671,6 +681,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "islice")]
#[derive(Debug)]
struct PyItertoolsIslice {
@@ -797,6 +808,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "filterfalse")]
#[derive(Debug)]
struct PyItertoolsFilterFalse {
@@ -853,6 +865,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "accumulate")]
#[derive(Debug)]
struct PyItertoolsAccumulate {
@@ -937,6 +950,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "tee")]
#[derive(Debug)]
struct PyItertoolsTee {
@@ -1015,6 +1029,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "product")]
#[derive(Debug)]
struct PyItertoolsProduct {
@@ -1132,6 +1147,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "combinations")]
#[derive(Debug)]
struct PyItertoolsCombinations {
@@ -1231,6 +1247,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "combinations_with_replacement")]
#[derive(Debug)]
struct PyItertoolsCombinationsWithReplacement {
@@ -1325,6 +1342,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "permutations")]
#[derive(Debug)]
struct PyItertoolsPermutations {
@@ -1455,6 +1473,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "zip_longest")]
#[derive(Debug)]
struct PyItertoolsZipLongest {
+8 -3
View File
@@ -293,8 +293,8 @@ mod _os {
rust_file(fileno);
}
#[pyfunction]
#[cfg(any(unix, windows, target_os = "wasi"))]
#[pyfunction]
pub(crate) fn open(
name: PyPathLike,
flags: OpenFlags,
@@ -350,8 +350,8 @@ mod _os {
Ok(raw_file_number(handle))
}
#[pyfunction]
#[cfg(not(any(unix, windows, target_os = "wasi")))]
#[pyfunction]
pub(crate) fn open(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
Err(vm.new_os_error("os.open not implemented on this platform".to_owned()))
}
@@ -474,7 +474,8 @@ mod _os {
mode.process_path(path, vm)
}
#[pyclass]
#[pyattr]
#[pyclass(name)]
#[derive(Debug)]
struct DirEntry {
entry: fs::DirEntry,
@@ -557,6 +558,7 @@ mod _os {
}
}
#[pyattr]
#[pyclass(name = "ScandirIter")]
#[derive(Debug)]
struct ScandirIterator {
@@ -634,6 +636,7 @@ mod _os {
.into_object())
}
#[pyattr]
#[pystruct_sequence(module = "os", name = "stat_result")]
#[derive(Debug)]
pub(super) struct StatResult {
@@ -830,6 +833,7 @@ mod _os {
.into_owned()
}
#[pyattr]
#[pystruct_sequence(module = "os", name = "terminal_size")]
#[allow(dead_code)]
pub(super) struct PyTerminalSize {
@@ -1739,6 +1743,7 @@ mod posix {
Ok(ret_mask)
}
#[pyattr]
#[pystruct_sequence(module = "os", name = "uname_result")]
#[derive(Debug)]
struct UnameResult {
+3 -1
View File
@@ -786,6 +786,7 @@ mod _struct {
.with_ref(|buf| format_spec.unpack(&buf[offset..offset + size], vm))
}
#[pyattr]
#[pyclass(name = "unpack_iterator")]
#[derive(Debug)]
struct UnpackIterator {
@@ -870,6 +871,7 @@ mod _struct {
Ok(format_spec.size())
}
#[pyattr]
#[pyclass(name = "Struct")]
#[derive(Debug)]
struct PyStruct {
@@ -970,7 +972,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef {
let struct_error = ctx.new_class(
"struct.error",
ctx.exceptions.exception_type.clone(),
&ctx.exceptions.exception_type,
Default::default(),
);
+1
View File
@@ -53,6 +53,7 @@ mod _random {
}
}
#[pyattr]
#[pyclass(name = "Random")]
#[derive(Debug)]
struct PyRandom {
+2 -2
View File
@@ -16,7 +16,7 @@ use crate::obj::objtype::PyClassRef;
use crate::pyobject::{BorrowValue, PyClassImpl, PyObjectRef, PyResult, PyValue, TryFromObject};
use crate::vm::VirtualMachine;
#[pyclass(name = "Pattern")]
#[pyclass(module = "re", name = "Pattern")]
#[derive(Debug)]
struct PyPattern {
regex: Regex,
@@ -69,7 +69,7 @@ impl PyValue for PyPattern {
}
/// Inner data for a match object.
#[pyclass(name = "Match")]
#[pyclass(module = "re", name = "Match")]
struct PyMatch {
haystack: PyStringRef,
captures: Vec<Option<Range<usize>>>,
+3 -3
View File
@@ -54,7 +54,7 @@ mod c {
};
}
#[pyclass(name = "socket")]
#[pyclass(module = "socket", name = "socket")]
#[derive(Debug)]
pub struct PySocket {
kind: AtomicCell<i32>,
@@ -654,12 +654,12 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
let ctx = &vm.ctx;
let socket_timeout = ctx.new_class(
"socket.timeout",
vm.ctx.exceptions.os_error.clone(),
&vm.ctx.exceptions.os_error,
Default::default(),
);
let socket_gaierror = ctx.new_class(
"socket.gaierror",
vm.ctx.exceptions.os_error.clone(),
&vm.ctx.exceptions.os_error,
Default::default(),
);
+2 -2
View File
@@ -228,7 +228,7 @@ fn ssl_rand_pseudo_bytes(n: i32, vm: &VirtualMachine) -> PyResult<(Vec<u8>, bool
}
}
#[pyclass(name = "_SSLContext")]
#[pyclass(module = "ssl", name = "_SSLContext")]
struct PySslContext {
ctx: PyRwLock<SslContextBuilder>,
check_hostname: bool,
@@ -504,7 +504,7 @@ struct LoadVerifyLocationsArgs {
cadata: Option<Either<PyStringRef, PyBytesLike>>,
}
#[pyclass(name = "_SSLSocket")]
#[pyclass(module = "ssl", name = "_SSLSocket")]
struct PySslSocket {
ctx: PyRef<PySslContext>,
stream: PyRwLock<Option<ssl::SslStreamBuilder<PySocketRef>>>,
+2
View File
@@ -60,6 +60,7 @@ mod decl {
type PySymbolTableRef = PyRef<PySymbolTable>;
type PySymbolRef = PyRef<PySymbol>;
#[pyattr]
#[pyclass(name = "SymbolTable")]
struct PySymbolTable {
symtable: symboltable::SymbolTable,
@@ -176,6 +177,7 @@ mod decl {
}
}
#[pyattr]
#[pyclass(name = "Symbol")]
struct PySymbol {
symbol: symboltable::Symbol,
+3 -3
View File
@@ -92,7 +92,7 @@ macro_rules! repr_lock_impl {
}};
}
#[pyclass(name = "lock")]
#[pyclass(module = "thread", name = "lock")]
struct PyLock {
mu: RawMutex,
}
@@ -146,7 +146,7 @@ impl PyLock {
}
pub type RawRMutex = RawReentrantMutex<RawMutex, RawThreadId>;
#[pyclass(name = "RLock")]
#[pyclass(module = "thread", name = "RLock")]
struct PyRLock {
mu: RawRMutex,
}
@@ -277,7 +277,7 @@ fn thread_count(vm: &VirtualMachine) -> usize {
vm.state.thread_count.load()
}
#[pyclass(name = "_local")]
#[pyclass(module = "thread", name = "_local")]
#[derive(Debug)]
struct PyLocal {
data: ThreadLocal<PyDictRef>,
+1 -1
View File
@@ -54,7 +54,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
module
}
#[pyclass(name = "UCD")]
#[pyclass(module = "unicodedata", name = "UCD")]
#[derive(Debug)]
struct PyUCD {
unic_version: UnicodeVersion,
+1 -1
View File
@@ -14,7 +14,7 @@ use std::io;
use winapi::shared::winerror;
use winreg::{enums::RegType, RegKey, RegValue};
#[pyclass(name = "HKEYType")]
#[pyclass(module = "winreg", name = "HKEYType")]
#[derive(Debug)]
struct PyHKEY {
key: PyRwLock<RegKey>,
+2
View File
@@ -213,6 +213,7 @@ mod decl {
unconsumed_tail: PyMutex::new(PyBytes::from(vec![]).into_ref(vm)),
}
}
#[pyattr]
#[pyclass(name = "Decompress")]
#[derive(Debug)]
struct PyDecompress {
@@ -373,6 +374,7 @@ mod decl {
unconsumed: Vec<u8>,
}
#[pyattr]
#[pyclass(name = "Compress")]
#[derive(Debug)]
struct PyCompress {
+3 -3
View File
@@ -162,7 +162,7 @@ fn browser_cancel_animation_frame(id: i32, vm: &VirtualMachine) -> PyResult {
Ok(vm.get_none())
}
#[pyclass(name = "Promise")]
#[pyclass(module = "browser", name = "Promise")]
#[derive(Debug)]
pub struct PyPromise {
value: Promise,
@@ -248,7 +248,7 @@ impl PyPromise {
}
}
#[pyclass]
#[pyclass(module = "browser", name)]
#[derive(Debug)]
struct Document {
doc: web_sys::Document,
@@ -276,7 +276,7 @@ impl Document {
}
}
#[pyclass]
#[pyclass(module = "browser", name)]
#[derive(Debug)]
struct Element {
elem: web_sys::Element,
+1 -1
View File
@@ -30,7 +30,7 @@ extern "C" {
fn instance_of(lhs: &JsValue, rhs: &JsValue) -> Result<bool, JsValue>;
}
#[pyclass(name = "JsValue")]
#[pyclass(module = "_js", name = "JsValue")]
#[derive(Debug)]
pub struct PyJsValue {
value: JsValue,
+1 -1
View File
@@ -32,7 +32,7 @@ pub fn make_stdout_object(
let flush_method = ctx.new_method(|_self: PyObjectRef| {});
// there's not really any point to storing this class so that there's a consistent type object,
// we just want a half-decent repr() output
let cls = py_class!(ctx, "JSStdout", vm.ctx.object(), {
let cls = py_class!(ctx, "JSStdout", &vm.ctx.object(), {
"write" => write_method,
"flush" => flush_method,
});