mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
multiple error tracking
This commit is contained in:
1 parent
2458307dc3
commit
29dc4dabbb
3 files changed
+138
-103
No files matched your search
+65
-60
@@ -16,92 +16,99 @@ use syn_ext::ext::*;
|
||||
struct ImplContext {
|
||||
impl_extend_items: ItemNursery,
|
||||
getset_items: GetSetNursery,
|
||||
errors: Vec<syn::Error>,
|
||||
}
|
||||
|
||||
pub(crate) fn impl_pyimpl(
|
||||
attr: AttributeArgs,
|
||||
item: Item,
|
||||
) -> std::result::Result<TokenStream, Diagnostic> {
|
||||
match item {
|
||||
let mut context = ImplContext::default();
|
||||
let mut tokens = match item {
|
||||
Item::Impl(mut imp) => {
|
||||
let mut context = ImplContext::default();
|
||||
for item in imp.items.iter_mut() {
|
||||
item.try_split_attr_mut(|attrs, item| {
|
||||
let r = item.try_split_attr_mut(|attrs, item| {
|
||||
let (pyitems, cfgs) =
|
||||
attrs_to_content_items(&attrs, new_impl_item::<syn::ImplItem>)?;
|
||||
for pyitem in pyitems.iter().rev() {
|
||||
pyitem.gen_impl_item(ImplItemArgs {
|
||||
let r = pyitem.gen_impl_item(ImplItemArgs {
|
||||
item,
|
||||
attrs,
|
||||
context: &mut context,
|
||||
cfgs: cfgs.as_slice(),
|
||||
})?;
|
||||
});
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
});
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
context.getset_items.validate()?;
|
||||
context.errors.ok_or_push(context.getset_items.validate());
|
||||
|
||||
let tokens = {
|
||||
let (with_impl, flags) = extract_impl_attrs(attr)?;
|
||||
let ty = &imp.self_ty;
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
quote! {
|
||||
#imp
|
||||
impl ::rustpython_vm::pyobject::PyClassImpl for #ty {
|
||||
const TP_FLAGS: ::rustpython_vm::slots::PyTpFlags = ::rustpython_vm::slots::PyTpFlags::from_bits_truncate(#flags);
|
||||
let (with_impl, flags) = extract_impl_attrs(attr)?;
|
||||
let ty = &imp.self_ty;
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
quote! {
|
||||
#imp
|
||||
impl ::rustpython_vm::pyobject::PyClassImpl for #ty {
|
||||
const TP_FLAGS: ::rustpython_vm::slots::PyTpFlags = ::rustpython_vm::slots::PyTpFlags::from_bits_truncate(#flags);
|
||||
|
||||
fn impl_extend_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext,
|
||||
class: &::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) {
|
||||
#getset_impl
|
||||
#extend_impl
|
||||
#with_impl
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(tokens)
|
||||
}
|
||||
Item::Trait(mut trai) => {
|
||||
let mut context = ImplContext::default();
|
||||
for item in trai.items.iter_mut() {
|
||||
item.try_split_attr_mut(|attrs, item| {
|
||||
let (pyitems, cfgs) =
|
||||
attrs_to_content_items(&attrs, new_impl_item::<syn::TraitItem>)?;
|
||||
for pyitem in pyitems.iter().rev() {
|
||||
pyitem.gen_impl_item(ImplItemArgs {
|
||||
item,
|
||||
attrs,
|
||||
context: &mut context,
|
||||
cfgs: cfgs.as_slice(),
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
context.getset_items.validate()?;
|
||||
|
||||
let tokens = {
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
trai.items.push(parse_quote! {
|
||||
fn __extend_py_class(
|
||||
fn impl_extend_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext,
|
||||
class: &::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) {
|
||||
#getset_impl
|
||||
#extend_impl
|
||||
#with_impl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item::Trait(mut trai) => {
|
||||
let mut context = ImplContext::default();
|
||||
for item in trai.items.iter_mut() {
|
||||
let r = item.try_split_attr_mut(|attrs, item| {
|
||||
let (pyitems, cfgs) =
|
||||
attrs_to_content_items(&attrs, new_impl_item::<syn::TraitItem>)?;
|
||||
for pyitem in pyitems.iter().rev() {
|
||||
let r = pyitem.gen_impl_item(ImplItemArgs {
|
||||
item,
|
||||
attrs,
|
||||
context: &mut context,
|
||||
cfgs: cfgs.as_slice(),
|
||||
});
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
trai.into_token_stream()
|
||||
};
|
||||
Ok(tokens)
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
context.errors.ok_or_push(context.getset_items.validate());
|
||||
|
||||
let getset_impl = &context.getset_items;
|
||||
let extend_impl = &context.impl_extend_items;
|
||||
trai.items.push(parse_quote! {
|
||||
fn __extend_py_class(
|
||||
ctx: &::rustpython_vm::pyobject::PyContext,
|
||||
class: &::rustpython_vm::obj::objtype::PyClassRef,
|
||||
) {
|
||||
#getset_impl
|
||||
#extend_impl
|
||||
}
|
||||
});
|
||||
trai.into_token_stream()
|
||||
}
|
||||
item => quote!(#item),
|
||||
};
|
||||
if let Some(error) = context.errors.into_error() {
|
||||
let error = Diagnostic::from(error);
|
||||
tokens = quote! {
|
||||
#tokens
|
||||
#error
|
||||
}
|
||||
item => Ok(quote!(#item)),
|
||||
}
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
fn generate_class_def(
|
||||
@@ -478,9 +485,7 @@ impl GetSetNursery {
|
||||
));
|
||||
};
|
||||
}
|
||||
if !errors.is_empty() {
|
||||
return Err(errors.into_error());
|
||||
}
|
||||
errors.into_result()?;
|
||||
self.validated = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+56
-36
@@ -1,6 +1,6 @@
|
||||
use crate::error::Diagnostic;
|
||||
use crate::util::{
|
||||
AttributeExt, ClassItemMeta, ContentItem, ContentItemInner, ItemMeta, ItemNursery,
|
||||
AttributeExt, ClassItemMeta, ContentItem, ContentItemInner, ErrorVec, ItemMeta, ItemNursery,
|
||||
SimpleItemMeta, ALL_ALLOWED_NAMES,
|
||||
};
|
||||
use proc_macro2::TokenStream;
|
||||
@@ -8,9 +8,11 @@ use quote::{quote, quote_spanned, ToTokens};
|
||||
use syn::{parse_quote, spanned::Spanned, Attribute, AttributeArgs, Ident, Item, Result, UseTree};
|
||||
use syn_ext::ext::*;
|
||||
|
||||
#[derive(Default)]
|
||||
struct ModuleContext {
|
||||
name: String,
|
||||
module_extend_items: ItemNursery,
|
||||
errors: Vec<syn::Error>,
|
||||
}
|
||||
|
||||
pub fn impl_pymodule(
|
||||
@@ -19,16 +21,16 @@ pub fn impl_pymodule(
|
||||
) -> 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 fake_ident = Ident::new("pymodule", module_item.span());
|
||||
let module_meta =
|
||||
SimpleItemMeta::from_nested(module_item.ident.clone(), fake_ident, attr.into_iter())?;
|
||||
|
||||
// generation resources
|
||||
let mut module_context = ModuleContext {
|
||||
let mut context = ModuleContext {
|
||||
name: module_meta.simple_name()?,
|
||||
module_extend_items: ItemNursery::default(),
|
||||
..Default::default()
|
||||
};
|
||||
let items = module_item.items_mut().ok_or_else(|| {
|
||||
module_meta.new_meta_error("requires actual module, not a module declaration")
|
||||
@@ -36,23 +38,25 @@ pub fn impl_pymodule(
|
||||
|
||||
// collect to context
|
||||
for item in items.iter_mut() {
|
||||
item.try_split_attr_mut(|attrs, item| {
|
||||
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() {
|
||||
pyitem.gen_module_item(ModuleItemArgs {
|
||||
let r = pyitem.gen_module_item(ModuleItemArgs {
|
||||
item,
|
||||
attrs,
|
||||
module: &mut module_context,
|
||||
context: &mut context,
|
||||
cfgs: cfgs.as_slice(),
|
||||
})?;
|
||||
});
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
});
|
||||
context.errors.ok_or_push(r);
|
||||
}
|
||||
|
||||
// append additional items
|
||||
let module_name = module_context.name.as_str();
|
||||
let module_extend_items = module_context.module_extend_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: &'static str = #module_name;
|
||||
@@ -77,7 +81,15 @@ pub fn impl_pymodule(
|
||||
},
|
||||
]);
|
||||
|
||||
Ok(module_item.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(
|
||||
@@ -219,13 +231,13 @@ impl ContentItem for AttributeItem {
|
||||
struct ModuleItemArgs<'a> {
|
||||
item: &'a Item,
|
||||
attrs: &'a mut Vec<Attribute>,
|
||||
module: &'a mut ModuleContext,
|
||||
context: &'a mut ModuleContext,
|
||||
cfgs: &'a [Attribute],
|
||||
}
|
||||
|
||||
impl<'a> ModuleItemArgs<'a> {
|
||||
fn module_name(&'a self) -> &'a str {
|
||||
self.module.name.as_str()
|
||||
self.context.name.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +270,7 @@ impl ModuleItem for FunctionItem {
|
||||
}
|
||||
};
|
||||
|
||||
args.module
|
||||
args.context
|
||||
.module_extend_items
|
||||
.add_item(py_name, args.cfgs.to_vec(), item)?;
|
||||
Ok(())
|
||||
@@ -284,7 +296,7 @@ impl ModuleItem for ClassItem {
|
||||
class_attr,
|
||||
format!(
|
||||
"#[{name}] requires #[pyattr] to be a module attribute. \
|
||||
To keep it free type, try #[{name}(noattr)]",
|
||||
To keep it free type, try #[{name}(noattr)]",
|
||||
name = self.attr_name()
|
||||
),
|
||||
));
|
||||
@@ -296,7 +308,7 @@ impl ModuleItem for ClassItem {
|
||||
class_attr.get_ident().unwrap().clone(),
|
||||
class_attr.promoted_nested()?.into_iter(),
|
||||
)?;
|
||||
let module_name = args.module.name.clone();
|
||||
let module_name = args.context.name.clone();
|
||||
class_attr.fill_nested_meta("module", || {
|
||||
parse_quote! {module = #module_name}
|
||||
})?;
|
||||
@@ -304,26 +316,34 @@ impl ModuleItem for ClassItem {
|
||||
(module_name, class_name)
|
||||
};
|
||||
for attr_index in self.pyattrs.iter().rev() {
|
||||
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 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();
|
||||
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(())
|
||||
};
|
||||
|
||||
args.module
|
||||
.module_extend_items
|
||||
.add_item(py_name.clone(), args.cfgs.to_vec(), item)?;
|
||||
let r = loop_unit();
|
||||
args.context.errors.ok_or_push(r);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -386,7 +406,7 @@ impl ModuleItem for AttributeItem {
|
||||
};
|
||||
args.attrs.remove(self.index());
|
||||
|
||||
args.module
|
||||
args.context
|
||||
.module_extend_items
|
||||
.add_item(py_name, args.cfgs.to_vec(), tokens)?;
|
||||
|
||||
|
||||
+17
-7
@@ -397,19 +397,29 @@ impl AttributeExt for Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait ErrorVec {
|
||||
fn into_error(self) -> syn::Error;
|
||||
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(())
|
||||
}
|
||||
}
|
||||
fn ok_or_push<T>(&mut self, r: Result<T>) -> Option<T>;
|
||||
}
|
||||
|
||||
impl ErrorVec for Vec<syn::Error> {
|
||||
fn into_error(self) -> syn::Error {
|
||||
fn into_error(self) -> Option<syn::Error> {
|
||||
let mut iter = self.into_iter();
|
||||
let mut first = iter.next().expect("Cannot convert empty vec to syn::Error");
|
||||
for err in iter {
|
||||
first.combine(err);
|
||||
if let Some(mut first) = iter.next() {
|
||||
for err in iter {
|
||||
first.combine(err);
|
||||
}
|
||||
Some(first)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
first
|
||||
}
|
||||
fn ok_or_push<T>(&mut self, r: Result<T>) -> Option<T> {
|
||||
match r {
|
||||
|
||||
Reference in new issue
Block a user