mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Add sys.flags by creating a pystruct_sequence macro
This commit is contained in:
1 parent
8359c6e031
commit
2ca96c8ae1
5 files changed
+162
-14
No files matched your search
@@ -1,3 +1,5 @@
|
||||
#![recursion_limit = "128"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
#[macro_use]
|
||||
@@ -38,3 +40,10 @@ pub fn pyimpl(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let item = parse_macro_input!(item as Item);
|
||||
result_to_tokens(pyclass::impl_pyimpl(attr, item))
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn pystruct_sequence(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let attr = parse_macro_input!(attr as AttributeArgs);
|
||||
let item = parse_macro_input!(item as Item);
|
||||
result_to_tokens(pyclass::impl_pystruct_sequence(attr, item))
|
||||
}
|
||||
+114
-13
@@ -2,7 +2,9 @@ use super::Diagnostic;
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use quote::quote;
|
||||
use std::collections::HashMap;
|
||||
use syn::{Attribute, AttributeArgs, Ident, ImplItem, Item, Lit, Meta, MethodSig, NestedMeta};
|
||||
use syn::{
|
||||
Attribute, AttributeArgs, Ident, ImplItem, Index, Item, Lit, Meta, MethodSig, NestedMeta,
|
||||
};
|
||||
|
||||
enum ClassItem {
|
||||
Method {
|
||||
@@ -266,16 +268,12 @@ pub fn impl_pyimpl(_attr: AttributeArgs, item: Item) -> Result<TokenStream2, Dia
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub fn impl_pyclass(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diagnostic> {
|
||||
let (item, ident, attrs) = match item {
|
||||
Item::Struct(struc) => (quote!(#struc), struc.ident, struc.attrs),
|
||||
Item::Enum(enu) => (quote!(#enu), enu.ident, enu.attrs),
|
||||
other => bail_span!(
|
||||
other,
|
||||
"#[pyclass] can only be on a struct or enum declaration"
|
||||
),
|
||||
};
|
||||
|
||||
fn generate_class_def(
|
||||
ident: &Ident,
|
||||
attr_name: &'static str,
|
||||
attr: AttributeArgs,
|
||||
attrs: &Vec<Attribute>,
|
||||
) -> Result<TokenStream2, Diagnostic> {
|
||||
let mut class_name = None;
|
||||
for attr in attr {
|
||||
if let NestedMeta::Meta(meta) = attr {
|
||||
@@ -284,7 +282,11 @@ pub fn impl_pyclass(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Dia
|
||||
if let Lit::Str(s) = name_value.lit {
|
||||
class_name = Some(s.value());
|
||||
} else {
|
||||
bail_span!(name_value.lit, "#[pyclass(name = ...)] must be a string");
|
||||
bail_span!(
|
||||
name_value.lit,
|
||||
"#[{}(name = ...)] must be a string",
|
||||
attr_name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,7 +318,6 @@ pub fn impl_pyclass(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Dia
|
||||
};
|
||||
|
||||
let ret = quote! {
|
||||
#item
|
||||
impl ::rustpython_vm::pyobject::PyClassDef for #ident {
|
||||
const NAME: &'static str = #class_name;
|
||||
const DOC: Option<&'static str> = #doc;
|
||||
@@ -324,3 +325,103 @@ pub fn impl_pyclass(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Dia
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub fn impl_pyclass(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diagnostic> {
|
||||
let (item, ident, attrs) = match item {
|
||||
Item::Struct(struc) => (quote!(#struc), struc.ident, struc.attrs),
|
||||
Item::Enum(enu) => (quote!(#enu), enu.ident, enu.attrs),
|
||||
other => bail_span!(
|
||||
other,
|
||||
"#[pyclass] can only be on a struct or enum declaration"
|
||||
),
|
||||
};
|
||||
|
||||
let class_def = generate_class_def(&ident, "pyclass", attr, &attrs)?;
|
||||
|
||||
let ret = quote! {
|
||||
#item
|
||||
#class_def
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub fn impl_pystruct_sequence(attr: AttributeArgs, item: Item) -> Result<TokenStream2, Diagnostic> {
|
||||
if let Item::Struct(struc) = item {
|
||||
let class_def = generate_class_def(&struc.ident, "pystruct_sequence", attr, &struc.attrs)?;
|
||||
let mut methods = Vec::new();
|
||||
let mut method_references = Vec::new();
|
||||
let mut field_names = Vec::new();
|
||||
for (i, field) in struc.fields.iter().enumerate() {
|
||||
let idx = Index::from(i);
|
||||
if let Some(ref field_name) = field.ident {
|
||||
let method_name = format!("get_{}", field_name);
|
||||
let method_ident = Ident::new(&method_name, field_name.span());
|
||||
|
||||
let method = quote! {
|
||||
fn #method_ident(
|
||||
zelf: &::rustpython_vm::obj::objtuple::PyTuple,
|
||||
_vm: &::rustpython_vm::vm::VirtualMachine)
|
||||
-> ::rustpython_vm::pyobject::PyObjectRef {
|
||||
zelf.fast_getitem(#idx)
|
||||
}
|
||||
};
|
||||
methods.push(method);
|
||||
let field_name_str = field_name.to_string();
|
||||
let method_reference = quote! {
|
||||
class.set_str_attr(
|
||||
#field_name_str,
|
||||
::rustpython_vm::obj::objproperty::PropertyBuilder::new(ctx)
|
||||
.add_getter(Self::#method_ident)
|
||||
.create(),
|
||||
);
|
||||
};
|
||||
method_references.push(method_reference);
|
||||
field_names.push(quote!(#field_name));
|
||||
} else {
|
||||
field_names.push(quote!(#idx));
|
||||
}
|
||||
}
|
||||
|
||||
let ty = &struc.ident;
|
||||
let ret = quote! {
|
||||
#struc
|
||||
#class_def
|
||||
impl #ty {
|
||||
fn into_struct_sequence(&self,
|
||||
vm: &::rustpython_vm::vm::VirtualMachine,
|
||||
cls: ::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) -> ::rustpython_vm::pyobject::PyResult<::rustpython_vm::obj::objtuple::PyTupleRef> {
|
||||
let tuple: ::rustpython_vm::obj::objtuple::PyTuple =
|
||||
vec![#(::rustpython_vm::pyobject::IntoPyObject
|
||||
::into_pyobject(self.#field_names, vm)?
|
||||
),*].into();
|
||||
::rustpython_vm::pyobject::PyValue::into_ref_with_type(tuple, vm, cls)
|
||||
}
|
||||
|
||||
#(#methods)*
|
||||
}
|
||||
impl ::rustpython_vm::pyobject::PyClassImpl for #ty {
|
||||
fn impl_extend_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext,
|
||||
class: &::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) {
|
||||
#(#method_references)*
|
||||
}
|
||||
|
||||
fn make_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext
|
||||
) -> ::rustpython_vm::obj::objtype::PyClassRef {
|
||||
let py_class = ctx.new_class(<Self as ::rustpython_vm::pyobject::PyClassDef>::NAME, ctx.tuple_type());
|
||||
Self::extend_class(ctx, &py_class);
|
||||
py_class
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(ret)
|
||||
} else {
|
||||
bail_span!(
|
||||
item,
|
||||
"#[pystruct_sequence] can only be on a struct declaration"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -7,3 +7,8 @@ assert sys.platform == "linux" or sys.platform == "darwin" or sys.platform == "w
|
||||
|
||||
assert isinstance(sys.builtin_module_names, tuple)
|
||||
assert 'sys' in sys.builtin_module_names
|
||||
|
||||
assert isinstance(sys.flags, tuple)
|
||||
assert type(sys.flags).__name__ == "flags"
|
||||
assert type(sys.flags.optimize) is int
|
||||
assert sys.flags[3] == sys.flags.optimize
|
||||
@@ -40,6 +40,12 @@ impl PyValue for PyTuple {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyTuple {
|
||||
pub fn fast_getitem(&self, idx: usize) -> PyObjectRef {
|
||||
self.elements.borrow()[idx].clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub type PyTupleRef = PyRef<PyTuple>;
|
||||
|
||||
impl PyTupleRef {
|
||||
|
||||
+28
-1
@@ -4,7 +4,7 @@ use std::{env, mem};
|
||||
use crate::frame::FrameRef;
|
||||
use crate::function::{OptionalArg, PyFuncArgs};
|
||||
use crate::obj::objstr::PyStringRef;
|
||||
use crate::pyobject::{IntoPyObject, ItemProtocol, PyContext, PyObjectRef, PyResult};
|
||||
use crate::pyobject::{IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyResult};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
/*
|
||||
@@ -27,6 +27,26 @@ fn getframe(offset: OptionalArg<usize>, vm: &VirtualMachine) -> PyResult<FrameRe
|
||||
Ok(frame.clone())
|
||||
}
|
||||
|
||||
#[pystruct_sequence(name = "flags")]
|
||||
#[derive(Default, Debug)]
|
||||
struct SysFlags {
|
||||
debug: bool,
|
||||
inspect: bool,
|
||||
interactive: bool,
|
||||
optimize: u8,
|
||||
dont_write_bytecode: bool,
|
||||
no_user_site: bool,
|
||||
no_site: bool,
|
||||
ignore_environment: bool,
|
||||
verbose: bool,
|
||||
bytes_warning: bool,
|
||||
quiet: bool,
|
||||
hash_randomization: bool,
|
||||
isolated: bool,
|
||||
dev_mode: bool,
|
||||
utf8_mode: bool,
|
||||
}
|
||||
|
||||
fn sys_getrefcount(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
|
||||
arg_check!(vm, args, required = [(object, None)]);
|
||||
let size = Rc::strong_count(&object);
|
||||
@@ -48,6 +68,12 @@ fn sys_intern(value: PyStringRef, _vm: &VirtualMachine) -> PyStringRef {
|
||||
pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectRef) {
|
||||
let ctx = &vm.ctx;
|
||||
|
||||
let flags_type = SysFlags::make_class(ctx);
|
||||
// TODO parse command line arguments and environment variables to populate SysFlags
|
||||
let flags = SysFlags::default()
|
||||
.into_struct_sequence(vm, flags_type)
|
||||
.unwrap();
|
||||
|
||||
let path_list = match env::var_os("PYTHONPATH") {
|
||||
Some(paths) => env::split_paths(&paths)
|
||||
.map(|path| {
|
||||
@@ -152,6 +178,7 @@ settrace() -- set the global debug tracing function
|
||||
extend_module!(vm, module, {
|
||||
"argv" => argv(ctx),
|
||||
"builtin_module_names" => ctx.new_tuple(module_names.iter().map(|v| v.into_pyobject(vm).unwrap()).collect()),
|
||||
"flags" => flags,
|
||||
"getrefcount" => ctx.new_rustfunc(sys_getrefcount),
|
||||
"getsizeof" => ctx.new_rustfunc(sys_getsizeof),
|
||||
"intern" => ctx.new_rustfunc(sys_intern),
|
||||
|
||||
Reference in new issue
Block a user