Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions derive/src/compile_bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand Down Expand Up @@ -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!()",
)
Expand Down Expand Up @@ -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)?;

Expand All @@ -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)?;

Expand Down
22 changes: 2 additions & 20 deletions derive/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)*))
)
}

Expand Down Expand Up @@ -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(),
Expand All @@ -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(())
Expand Down
19 changes: 10 additions & 9 deletions derive/src/from_args.rs
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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")
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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"),
};

Expand Down
42 changes: 28 additions & 14 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -54,52 +59,61 @@ 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))
}

/// 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))
}
38 changes: 12 additions & 26 deletions derive/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;

Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 })
Expand Down Expand Up @@ -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())?;
Expand Down Expand Up @@ -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'")?;

Expand All @@ -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,
Expand Down Expand Up @@ -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() }];
Expand Down Expand Up @@ -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(|| {
Expand Down
5 changes: 1 addition & 4 deletions derive/src/pymodule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
7 changes: 2 additions & 5 deletions derive/src/pystructseq.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
Loading