PySlots::flags

This commit is contained in:
Jeong YunWon
2020-01-27 13:46:15 +09:00
parent 421d78ee1b
commit 1ecc8228d9
5 changed files with 84 additions and 23 deletions

View File

@@ -371,10 +371,7 @@ struct ItemSig<'a> {
sig: &'a Signature,
}
fn extract_impl_items(
attr: AttributeArgs,
mut items: Vec<ItemSig>,
) -> Result<TokenStream2, Diagnostic> {
fn extract_impl_items(mut items: Vec<ItemSig>) -> Result<TokenStream2, Diagnostic> {
let mut diagnostics: Vec<Diagnostic> = Vec::new();
let mut class = Class::default();
@@ -468,33 +465,68 @@ fn extract_impl_items(
Diagnostic::from_vec(diagnostics)?;
Ok(quote! {
#(#methods)*
#(#properties)*
})
}
fn extract_impl_attrs(attr: AttributeArgs) -> Result<(TokenStream2, TokenStream2), Diagnostic> {
let mut withs = Vec::new();
let mut flags = vec![quote! { rustpython_vm::slots::PyTpFlags::DEFAULT }];
for attr in attr {
match attr {
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);
});
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);
});
}
meta => {
bail_span!(meta, "#[pyimpl(with(...))] arguments should be paths")
}
}
meta => bail_span!(meta, "#[pyimpl(with(...))] arguments should be paths"),
}
} else if path_eq(&path, "flags") {
for meta in nested {
match meta {
NestedMeta::Meta(Meta::Path(path)) => {
if let Some(ident) = path.get_ident() {
flags.push(quote! {
| rustpython_vm::slots::PyTpFlags::#ident
});
} else {
bail_span!(
path,
"#[pyimpl(flags(...))] arguments should be ident"
)
}
}
meta => {
bail_span!(meta, "#[pyimpl(flags(...))] arguments should be ident")
}
}
}
} else {
bail_span!(path, "Unknown pyimpl attribute")
}
}
attr => bail_span!(attr, "Unknown pyimpl attribute"),
}
}
Ok(quote! {
#(#methods)*
#(#properties)*
#(#withs)*
})
Ok((
quote! {
#(#withs)*
},
quote! {
#(#flags)*
},
))
}
pub fn impl_pyimpl(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diagnostic> {
@@ -510,16 +542,20 @@ pub fn impl_pyimpl(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diag
_ => None,
})
.collect();
let extend_impl = extract_impl_items(attr, items)?;
let extend_impl = extract_impl_items(items)?;
let (with_impl, flags) = extract_impl_attrs(attr)?;
let ty = &imp.self_ty;
let ret = quote! {
#imp
impl ::rustpython_vm::pyobject::PyClassImpl for #ty {
const TP_FLAGS: u64 = #flags;
fn impl_extend_class(
ctx: &::rustpython_vm::pyobject::PyContext,
class: &::rustpython_vm::obj::objtype::PyClassRef,
) {
#extend_impl
#with_impl
}
}
};
@@ -536,7 +572,7 @@ pub fn impl_pyimpl(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diag
_ => None,
})
.collect();
let extend_impl = extract_impl_items(attr, items)?;
let extend_impl = extract_impl_items(items)?;
let item = parse_quote! {
fn __extend_py_class(
ctx: &::rustpython_vm::pyobject::PyContext,
@@ -683,6 +719,8 @@ pub fn impl_pystruct_sequence(attr: AttributeArgs, item: Item) -> Result<TokenSt
}
}
impl ::rustpython_vm::pyobject::PyClassImpl for #ty {
const TP_FLAGS: u64 = ::rustpython_vm::slots::PyTpFlags::DEFAULT;
fn impl_extend_class(
ctx: &::rustpython_vm::pyobject::PyContext,
class: &::rustpython_vm::obj::objtype::PyClassRef,

View File

@@ -72,7 +72,7 @@ mod pyhash;
pub mod pyobject;
pub mod scope;
mod sequence;
mod slots;
pub mod slots;
pub mod stdlib;
mod sysmodule;
pub mod types;

View File

@@ -1196,10 +1196,12 @@ where
}
pub trait PyClassImpl: PyClassDef {
const TP_FLAGS: u64;
fn impl_extend_class(ctx: &PyContext, class: &PyClassRef);
fn extend_class(ctx: &PyContext, class: &PyClassRef) {
Self::impl_extend_class(ctx, class);
class.slots.borrow_mut().flags = crate::slots::PyTpFlags { 0: Self::TP_FLAGS };
if let Some(doc) = Self::DOC {
class.set_str_attr("__doc__", ctx.new_str(doc.into()));
}

View File

@@ -2,8 +2,29 @@ use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc};
use crate::pyobject::{IdProtocol, PyObjectRef, PyRef, PyResult, PyValue};
use crate::VirtualMachine;
#[derive(Copy, Clone)]
pub struct PyTpFlags(pub u64);
impl PyTpFlags {
pub const DEFAULT: u64 = 0;
pub const BASETYPE: u64 = 1 << 10;
pub fn has_feature(&self, flag: u64) -> bool {
(self.0 | flag) != 0
}
}
impl Default for PyTpFlags {
fn default() -> Self {
Self {
0: PyTpFlags::DEFAULT,
}
}
}
#[derive(Default)]
pub struct PyClassSlots {
pub flags: PyTpFlags,
pub new: Option<PyNativeFunc>,
pub call: Option<PyNativeFunc>,
pub descr_get: Option<PyNativeFunc>,

View File

@@ -944,7 +944,7 @@ pub fn io_open(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
let ctx = &vm.ctx;
//IOBase the abstract base class of the IO Module
// IOBase the abstract base class of the IO Module
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),