Merge pull request #3215 from youknowone/cleanup-derive

clean up derive
This commit is contained in:
Jeong YunWon
2021-10-04 16:19:21 +09:00
committed by GitHub
9 changed files with 81 additions and 96 deletions

View File

@@ -15,17 +15,22 @@
use crate::{extract_spans, Diagnostic};
use once_cell::sync::Lazy;
use proc_macro2::{Span, TokenStream as TokenStream2};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use rustpython_bytecode::{CodeObject, FrozenModule};
use rustpython_compiler as compile;
use std::collections::HashMap;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use syn::parse::{Parse, ParseStream, Result as ParseResult};
use syn::spanned::Spanned;
use syn::{self, parse2, Lit, LitByteStr, LitStr, Macro, Meta, MetaNameValue, Token};
use std::{
collections::HashMap,
env, fs,
path::{Path, PathBuf},
};
use syn::{
self,
parse::{Parse, ParseStream, Result as ParseResult},
parse2,
spanned::Spanned,
Lit, LitByteStr, LitStr, Macro, Meta, MetaNameValue, Token,
};
static CARGO_MANIFEST_DIR: Lazy<PathBuf> = Lazy::new(|| {
PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not present"))
@@ -281,7 +286,7 @@ impl PyCompileInput {
}
let source = source.ok_or_else(|| {
Diagnostic::span_error(
syn::Error::new(
self.span,
"Must have either file or source in py_compile!()/py_freeze!()",
)
@@ -335,7 +340,7 @@ struct PyCompileArgs {
crate_name: syn::Path,
}
pub fn impl_py_compile(input: TokenStream2) -> Result<TokenStream2, Diagnostic> {
pub fn impl_py_compile(input: TokenStream) -> Result<TokenStream, Diagnostic> {
let input: PyCompileInput = parse2(input)?;
let args = input.parse(false)?;
@@ -353,7 +358,7 @@ pub fn impl_py_compile(input: TokenStream2) -> Result<TokenStream2, Diagnostic>
Ok(output)
}
pub fn impl_py_freeze(input: TokenStream2) -> Result<TokenStream2, Diagnostic> {
pub fn impl_py_freeze(input: TokenStream) -> Result<TokenStream, Diagnostic> {
let input: PyCompileInput = parse2(input)?;
let args = input.parse(true)?;

View File

@@ -33,7 +33,7 @@ use syn::parse::Error;
macro_rules! err_span {
($span:expr, $($msg:tt)*) => (
$crate::Diagnostic::spanned_error(&$span, format!($($msg)*))
syn::Error::new_spanned(&$span, format!($($msg)*))
)
}
@@ -84,16 +84,7 @@ impl Diagnostic {
}
}
pub fn span_error<T: Into<String>>(span: Span, text: T) -> Diagnostic {
Diagnostic {
inner: Repr::Single {
text: text.into(),
span: Some((span, span)),
},
}
}
pub fn spans_error<T: Into<String>>(spans: (Span, Span), text: T) -> Diagnostic {
pub(crate) fn spans_error<T: Into<String>>(spans: (Span, Span), text: T) -> Diagnostic {
Diagnostic {
inner: Repr::Single {
text: text.into(),
@@ -102,15 +93,6 @@ impl Diagnostic {
}
}
pub fn spanned_error<T: Into<String>>(node: &dyn ToTokens, text: T) -> Diagnostic {
Diagnostic {
inner: Repr::Single {
text: text.into(),
span: extract_spans(node),
},
}
}
pub fn from_vec(diagnostics: Vec<Diagnostic>) -> Result<(), Diagnostic> {
if diagnostics.is_empty() {
Ok(())

View File

@@ -1,8 +1,9 @@
use crate::util::path_eq;
use crate::Diagnostic;
use proc_macro2::TokenStream as TokenStream2;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse_quote, Attribute, Data, DeriveInput, Expr, Field, Ident, Lit, Meta, NestedMeta};
use syn::{
parse_quote, Attribute, Data, DeriveInput, Expr, Field, Ident, Lit, Meta, NestedMeta, Result,
};
/// The kind of the python parameter, this corresponds to the value of Parameter.kind
/// (https://docs.python.org/3/library/inspect.html#inspect.Parameter.kind)
@@ -34,7 +35,7 @@ struct ArgAttribute {
type DefaultValue = Option<Expr>;
impl ArgAttribute {
fn from_attribute(attr: &Attribute) -> Option<Result<ArgAttribute, Diagnostic>> {
fn from_attribute(attr: &Attribute) -> Option<Result<ArgAttribute>> {
if !attr.path.is_ident("pyarg") {
return None;
}
@@ -75,7 +76,7 @@ impl ArgAttribute {
Some(inner())
}
fn parse_argument(&mut self, arg: &NestedMeta) -> Result<(), Diagnostic> {
fn parse_argument(&mut self, arg: &NestedMeta) -> Result<()> {
if let ParameterKind::Flatten = self.kind {
bail_span!(arg, "can't put additional arguments on a flatten arg")
}
@@ -119,12 +120,12 @@ impl ArgAttribute {
}
}
fn generate_field((i, field): (usize, &Field)) -> Result<TokenStream2, Diagnostic> {
fn generate_field((i, field): (usize, &Field)) -> Result<TokenStream> {
let mut pyarg_attrs = field
.attrs
.iter()
.filter_map(ArgAttribute::from_attribute)
.collect::<Result<Vec<_>, _>>()?;
.collect::<std::result::Result<Vec<_>, _>>()?;
let attr = if pyarg_attrs.is_empty() {
ArgAttribute {
name: None,
@@ -202,13 +203,13 @@ fn generate_field((i, field): (usize, &Field)) -> Result<TokenStream2, Diagnosti
Ok(file_output)
}
pub fn impl_from_args(input: DeriveInput) -> Result<TokenStream2, Diagnostic> {
pub fn impl_from_args(input: DeriveInput) -> Result<TokenStream> {
let fields = match input.data {
Data::Struct(syn::DataStruct { fields, .. }) => fields
.iter()
.enumerate()
.map(generate_field)
.collect::<Result<TokenStream2, Diagnostic>>()?,
.collect::<Result<TokenStream>>()?,
_ => bail_span!(input, "FromArgs input must be a struct"),
};

View File

@@ -21,23 +21,28 @@ mod pystructseq;
mod pyvalue;
use error::{extract_spans, Diagnostic};
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{parse_macro_input, AttributeArgs, DeriveInput, Item};
fn result_to_tokens(result: Result<TokenStream2, Diagnostic>) -> TokenStream {
result.unwrap_or_else(ToTokens::into_token_stream).into()
fn result_to_tokens(result: Result<TokenStream, impl Into<Diagnostic>>) -> proc_macro::TokenStream {
result
.map_err(|e| e.into())
.unwrap_or_else(ToTokens::into_token_stream)
.into()
}
#[proc_macro_derive(FromArgs, attributes(pyarg))]
pub fn derive_from_args(input: TokenStream) -> TokenStream {
pub fn derive_from_args(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
result_to_tokens(from_args::impl_from_args(input))
}
#[proc_macro_attribute]
pub fn pyclass(attr: TokenStream, item: TokenStream) -> TokenStream {
pub fn pyclass(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let attr = parse_macro_input!(attr as AttributeArgs);
let item = parse_macro_input!(item as Item);
result_to_tokens(pyclass::impl_pyclass(attr, item))
@@ -54,7 +59,7 @@ pub fn pyclass(attr: TokenStream, item: TokenStream) -> TokenStream {
/// So, we use `extend_class!` macro as the second
/// step in exception type definition.
#[proc_macro]
pub fn define_exception(input: TokenStream) -> TokenStream {
pub fn define_exception(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let exc_def = parse_macro_input!(input as pyclass::PyExceptionDef);
result_to_tokens(pyclass::impl_define_exception(exc_def))
}
@@ -62,44 +67,53 @@ pub fn define_exception(input: TokenStream) -> TokenStream {
/// Helper macro to define `Exception` types.
/// More-or-less is an alias to `pyclass` macro.
#[proc_macro_attribute]
pub fn pyexception(attr: TokenStream, item: TokenStream) -> TokenStream {
pub fn pyexception(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let attr = parse_macro_input!(attr as AttributeArgs);
let item = parse_macro_input!(item as Item);
result_to_tokens(pyclass::impl_pyexception(attr, item))
}
#[proc_macro_attribute]
pub fn pyimpl(attr: TokenStream, item: TokenStream) -> TokenStream {
pub fn pyimpl(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let attr = parse_macro_input!(attr as AttributeArgs);
let item = parse_macro_input!(item as Item);
result_to_tokens(pyclass::impl_pyimpl(attr, item))
}
#[proc_macro_attribute]
pub fn pymodule(attr: TokenStream, item: TokenStream) -> TokenStream {
pub fn pymodule(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let attr = parse_macro_input!(attr as AttributeArgs);
let item = parse_macro_input!(item as Item);
result_to_tokens(pymodule::impl_pymodule(attr, item))
}
#[proc_macro_derive(PyStructSequence)]
pub fn pystruct_sequence(input: TokenStream) -> TokenStream {
pub fn pystruct_sequence(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
result_to_tokens(pystructseq::impl_pystruct_sequence(input))
}
#[proc_macro]
pub fn py_compile(input: TokenStream) -> TokenStream {
pub fn py_compile(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
result_to_tokens(compile_bytecode::impl_py_compile(input.into()))
}
#[proc_macro]
pub fn py_freeze(input: TokenStream) -> TokenStream {
pub fn py_freeze(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
result_to_tokens(compile_bytecode::impl_py_freeze(input.into()))
}
#[proc_macro_derive(PyValue)]
pub fn pyvalue(input: TokenStream) -> TokenStream {
pub fn pyvalue(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
result_to_tokens(pyvalue::impl_pyvalue(input))
}

View File

@@ -6,10 +6,11 @@ use crate::util::{
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned, ToTokens};
use std::collections::HashMap;
use syn::parse::{Parse, ParseStream, Result as ParsingResult};
use syn::{
parse_quote, spanned::Spanned, Attribute, AttributeArgs, Ident, Item, LitStr, Meta, NestedMeta,
Result, Token,
parse::{Parse, ParseStream, Result as ParsingResult},
parse_quote,
spanned::Spanned,
Attribute, AttributeArgs, Ident, Item, LitStr, Meta, NestedMeta, Result, Token,
};
use syn_ext::ext::*;
@@ -47,10 +48,7 @@ fn extract_items_into_context<'a, Item>(
context.errors.ok_or_push(context.getset_items.validate());
}
pub(crate) fn impl_pyimpl(
attr: AttributeArgs,
item: Item,
) -> std::result::Result<TokenStream, Diagnostic> {
pub(crate) fn impl_pyimpl(attr: AttributeArgs, item: Item) -> Result<TokenStream> {
let mut context = ImplContext::default();
let mut tokens = match item {
Item::Impl(mut imp) => {
@@ -145,7 +143,7 @@ fn generate_class_def(
base: Option<String>,
metaclass: Option<String>,
attrs: &[Attribute],
) -> std::result::Result<TokenStream, Diagnostic> {
) -> Result<TokenStream> {
let doc = attrs.doc().or_else(|| {
let module_name = module_name.unwrap_or("builtins");
crate::doc::try_module_item(module_name, name)
@@ -181,8 +179,7 @@ fn generate_class_def(
return Err(syn::Error::new_spanned(
ident,
"PyStructSequence cannot have `base` class attr",
)
.into());
));
}
let base_class = if is_pystruct {
Some(quote! { rustpython_vm::builtins::PyTuple })
@@ -235,10 +232,7 @@ fn generate_class_def(
Ok(tokens)
}
pub(crate) fn impl_pyclass(
attr: AttributeArgs,
item: Item,
) -> std::result::Result<TokenStream, Diagnostic> {
pub(crate) fn impl_pyclass(attr: AttributeArgs, item: Item) -> Result<TokenStream> {
let (ident, attrs) = pyclass_ident_and_attrs(&item)?;
let fake_ident = Ident::new("pyclass", item.span());
let class_meta = ClassItemMeta::from_nested(ident.clone(), fake_ident, attr.into_iter())?;
@@ -270,10 +264,7 @@ pub(crate) fn impl_pyclass(
/// But, inside `macro_rules` we don't have an opportunity
/// to add non-literal attributes to `pyclass`.
/// That's why we have to use this proxy.
pub(crate) fn impl_pyexception(
attr: AttributeArgs,
item: Item,
) -> std::result::Result<TokenStream, Diagnostic> {
pub(crate) fn impl_pyexception(attr: AttributeArgs, item: Item) -> Result<TokenStream> {
let class_name = parse_vec_ident(&attr, &item, 0, "first 'class_name'")?;
let base_class_name = parse_vec_ident(&attr, &item, 1, "second 'base_class_name'")?;
@@ -292,9 +283,7 @@ pub(crate) fn impl_pyexception(
Ok(ret)
}
pub(crate) fn impl_define_exception(
exc_def: PyExceptionDef,
) -> std::result::Result<TokenStream, Diagnostic> {
pub(crate) fn impl_define_exception(exc_def: PyExceptionDef) -> Result<TokenStream> {
let PyExceptionDef {
class_name,
base_class,
@@ -871,10 +860,7 @@ struct ExtractedImplAttrs {
flags: TokenStream,
}
fn extract_impl_attrs(
attr: AttributeArgs,
item: &Ident,
) -> std::result::Result<ExtractedImplAttrs, Diagnostic> {
fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result<ExtractedImplAttrs> {
let mut withs = Vec::new();
let mut with_slots = Vec::new();
let mut flags = vec![quote! { ::rustpython_vm::slots::PyTypeFlags::DEFAULT.bits() }];
@@ -1090,7 +1076,7 @@ fn parse_vec_ident(
item: &Item,
index: usize,
message: &str,
) -> std::result::Result<String, Diagnostic> {
) -> Result<String> {
Ok(attr
.get(index)
.ok_or_else(|| {

View File

@@ -16,10 +16,7 @@ struct ModuleContext {
errors: Vec<syn::Error>,
}
pub fn impl_pymodule(
attr: AttributeArgs,
module_item: Item,
) -> std::result::Result<TokenStream, Diagnostic> {
pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStream> {
let (doc, mut module_item) = match module_item {
Item::Mod(m) => (m.attrs.doc(), m),
other => bail_span!(other, "#[pymodule] can only be on a full module"),

View File

@@ -1,11 +1,8 @@
use super::Diagnostic;
use proc_macro2::TokenStream;
use quote::quote;
use syn::DeriveInput;
use syn::{DeriveInput, Result};
pub(crate) fn impl_pystruct_sequence(
input: DeriveInput,
) -> std::result::Result<TokenStream, Diagnostic> {
pub(crate) fn impl_pystruct_sequence(input: DeriveInput) -> Result<TokenStream> {
let fields = if let syn::Data::Struct(ref struc) = input.data {
&struc.fields
} else {

View File

@@ -1,9 +1,8 @@
use super::Diagnostic;
use proc_macro2::TokenStream;
use quote::quote;
use syn::DeriveInput;
use syn::{DeriveInput, Result};
pub(crate) fn impl_pyvalue(input: DeriveInput) -> std::result::Result<TokenStream, Diagnostic> {
pub(crate) fn impl_pyvalue(input: DeriveInput) -> Result<TokenStream> {
let ty = &input.ident;
let ret = quote! {

View File

@@ -2,10 +2,14 @@ use indexmap::map::IndexMap;
use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use std::collections::HashMap;
use syn::Signature;
use syn::{spanned::Spanned, Attribute, Ident, Meta, MetaList, NestedMeta, Path, Result, UseTree};
use syn_ext::ext::{AttributeExt as SynAttributeExt, *};
use syn_ext::types::PunctuatedNestedMeta;
use syn::{
spanned::Spanned, Attribute, Ident, Meta, MetaList, NestedMeta, Path, Result, Signature,
UseTree,
};
use syn_ext::{
ext::{AttributeExt as SynAttributeExt, *},
types::PunctuatedNestedMeta,
};
pub(crate) const ALL_ALLOWED_NAMES: &[&str] = &[
"pymethod",