Upgrade to syn 1.0
This commit is contained in:
parent
be22d9e5bb
commit
39f151c3bd
24
Cargo.toml
24
Cargo.toml
|
@ -19,25 +19,25 @@ travis-ci = { repository = "PyO3/pyo3", branch = "master" }
|
||||||
appveyor = { repository = "fafhrd91/pyo3" }
|
appveyor = { repository = "fafhrd91/pyo3" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.54"
|
libc = "0.2.62"
|
||||||
spin = "0.5.0"
|
spin = "0.5.1"
|
||||||
num-traits = "0.2.6"
|
num-traits = "0.2.8"
|
||||||
pyo3cls = { path = "pyo3cls", version = "=0.7.0" }
|
pyo3cls = { path = "pyo3cls", version = "=0.7.0" }
|
||||||
num-complex = { version = "0.2.1", optional = true }
|
num-complex = { version = "0.2.3", optional = true }
|
||||||
inventory = "0.1.3"
|
inventory = "0.1.4"
|
||||||
indoc = "0.3.3"
|
indoc = "0.3.4"
|
||||||
unindent = "0.1.3"
|
unindent = "0.1.4"
|
||||||
paste = "0.1.5"
|
paste = "0.1.6"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_approx_eq = "1.1.0"
|
assert_approx_eq = "1.1.0"
|
||||||
trybuild = "1.0"
|
trybuild = "1.0.11"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
regex = "1.1.6"
|
regex = "1.2.1"
|
||||||
version_check = "0.9.1"
|
version_check = "0.9.1"
|
||||||
serde = { version = "1.0.91", features = ["derive"] }
|
serde = { version = "1.0.99", features = ["derive"] }
|
||||||
serde_json = "1.0.39"
|
serde_json = "1.0.40"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|
|
@ -11,9 +11,9 @@ license = "Apache-2.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quote = "0.6.12"
|
quote = "1"
|
||||||
proc-macro2 = "0.4.30"
|
proc-macro2 = "1"
|
||||||
syn = { version = "0.15.34", features = ["full", "extra-traits"] }
|
syn = { version = "1", features = ["full", "extra-traits"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
unsound-subclass = []
|
unsound-subclass = []
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
use crate::utils::print_err;
|
use crate::utils::print_err;
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
use syn::Token;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// Add lifetime support for args with Rptr
|
// Add lifetime support for args with Rptr
|
||||||
|
@ -70,7 +71,7 @@ impl PartialEq<str> for MethodProto {
|
||||||
|
|
||||||
pub fn impl_method_proto(
|
pub fn impl_method_proto(
|
||||||
cls: &syn::Type,
|
cls: &syn::Type,
|
||||||
sig: &mut syn::MethodSig,
|
sig: &mut syn::Signature,
|
||||||
meth: &MethodProto,
|
meth: &MethodProto,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
if let MethodProto::Free { proto, .. } = meth {
|
if let MethodProto::Free { proto, .. } = meth {
|
||||||
|
@ -80,7 +81,7 @@ pub fn impl_method_proto(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = &*if let syn::ReturnType::Type(_, ref ty) = sig.decl.output {
|
let ty = &*if let syn::ReturnType::Type(_, ref ty) = sig.output {
|
||||||
ty.clone()
|
ty.clone()
|
||||||
} else {
|
} else {
|
||||||
panic!("fn return type is not supported")
|
panic!("fn return type is not supported")
|
||||||
|
@ -95,7 +96,7 @@ pub fn impl_method_proto(
|
||||||
let tmp: syn::ItemFn = syn::parse_quote! {
|
let tmp: syn::ItemFn = syn::parse_quote! {
|
||||||
fn test(&self) -> <#cls as #p<'p>>::Result {}
|
fn test(&self) -> <#cls as #p<'p>>::Result {}
|
||||||
};
|
};
|
||||||
sig.decl.output = tmp.decl.output;
|
sig.output = tmp.sig.output;
|
||||||
modify_self_ty(sig);
|
modify_self_ty(sig);
|
||||||
|
|
||||||
if pyres {
|
if pyres {
|
||||||
|
@ -119,7 +120,7 @@ pub fn impl_method_proto(
|
||||||
pyres,
|
pyres,
|
||||||
proto,
|
proto,
|
||||||
} => {
|
} => {
|
||||||
if sig.decl.inputs.len() <= 1 {
|
if sig.inputs.len() <= 1 {
|
||||||
println!("Not enough arguments for {}", name);
|
println!("Not enough arguments for {}", name);
|
||||||
return TokenStream::new();
|
return TokenStream::new();
|
||||||
}
|
}
|
||||||
|
@ -164,7 +165,7 @@ pub fn impl_method_proto(
|
||||||
pyres,
|
pyres,
|
||||||
proto,
|
proto,
|
||||||
} => {
|
} => {
|
||||||
if sig.decl.inputs.len() <= 1 {
|
if sig.inputs.len() <= 1 {
|
||||||
print_err(format!("Not enough arguments {}", name), quote!(sig));
|
print_err(format!("Not enough arguments {}", name), quote!(sig));
|
||||||
return TokenStream::new();
|
return TokenStream::new();
|
||||||
}
|
}
|
||||||
|
@ -213,7 +214,7 @@ pub fn impl_method_proto(
|
||||||
pyres,
|
pyres,
|
||||||
proto,
|
proto,
|
||||||
} => {
|
} => {
|
||||||
if sig.decl.inputs.len() <= 2 {
|
if sig.inputs.len() <= 2 {
|
||||||
print_err(format!("Not enough arguments {}", name), quote!(sig));
|
print_err(format!("Not enough arguments {}", name), quote!(sig));
|
||||||
return TokenStream::new();
|
return TokenStream::new();
|
||||||
}
|
}
|
||||||
|
@ -266,7 +267,7 @@ pub fn impl_method_proto(
|
||||||
pyres,
|
pyres,
|
||||||
proto,
|
proto,
|
||||||
} => {
|
} => {
|
||||||
if sig.decl.inputs.len() <= 2 {
|
if sig.inputs.len() <= 2 {
|
||||||
print_err(format!("Not enough arguments {}", name), quote!(sig));
|
print_err(format!("Not enough arguments {}", name), quote!(sig));
|
||||||
return TokenStream::new();
|
return TokenStream::new();
|
||||||
}
|
}
|
||||||
|
@ -322,7 +323,7 @@ pub fn impl_method_proto(
|
||||||
arg3,
|
arg3,
|
||||||
proto,
|
proto,
|
||||||
} => {
|
} => {
|
||||||
if sig.decl.inputs.len() <= 3 {
|
if sig.inputs.len() <= 3 {
|
||||||
print_err(format!("Not enough arguments {}", name), quote!(sig));
|
print_err(format!("Not enough arguments {}", name), quote!(sig));
|
||||||
return TokenStream::new();
|
return TokenStream::new();
|
||||||
}
|
}
|
||||||
|
@ -367,26 +368,26 @@ pub fn impl_method_proto(
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: better arg ty detection
|
// TODO: better arg ty detection
|
||||||
fn get_arg_ty(sig: &syn::MethodSig, idx: usize) -> syn::Type {
|
fn get_arg_ty(sig: &syn::Signature, idx: usize) -> syn::Type {
|
||||||
let mut ty = match sig.decl.inputs[idx] {
|
let mut ty = match sig.inputs[idx] {
|
||||||
syn::FnArg::Captured(ref cap) => {
|
syn::FnArg::Typed(ref cap) => {
|
||||||
match cap.ty {
|
match *cap.ty {
|
||||||
syn::Type::Path(ref ty) => {
|
syn::Type::Path(ref ty) => {
|
||||||
// use only last path segment for Option<>
|
// use only last path segment for Option<>
|
||||||
let seg = *ty.path.segments.last().unwrap().value();
|
let seg = ty.path.segments.last().unwrap().clone();
|
||||||
if seg.ident == "Option" {
|
if seg.ident == "Option" {
|
||||||
if let syn::PathArguments::AngleBracketed(ref data) = seg.arguments {
|
if let syn::PathArguments::AngleBracketed(ref data) = seg.arguments {
|
||||||
if let Some(pair) = data.args.last() {
|
if let Some(pair) = data.args.last() {
|
||||||
match pair.value() {
|
match pair {
|
||||||
syn::GenericArgument::Type(ref ty) => return ty.clone(),
|
syn::GenericArgument::Type(ref ty) => return ty.clone(),
|
||||||
_ => panic!("Option only accepted for concrete types"),
|
_ => panic!("Option only accepted for concrete types"),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cap.ty.clone()
|
*cap.ty.clone()
|
||||||
}
|
}
|
||||||
_ => cap.ty.clone(),
|
_ => *cap.ty.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("fn arg type is not supported"),
|
_ => panic!("fn arg type is not supported"),
|
||||||
|
@ -408,9 +409,9 @@ fn get_res_success(ty: &syn::Type) -> (TokenStream, syn::GenericArgument) {
|
||||||
match ty {
|
match ty {
|
||||||
syn::Type::Path(ref typath) => {
|
syn::Type::Path(ref typath) => {
|
||||||
if let Some(segment) = typath.path.segments.last() {
|
if let Some(segment) = typath.path.segments.last() {
|
||||||
match segment.value().ident.to_string().as_str() {
|
match segment.ident.to_string().as_str() {
|
||||||
// check for PyResult<T>
|
// check for PyResult<T>
|
||||||
"PyResult" => match segment.value().arguments {
|
"PyResult" => match segment.arguments {
|
||||||
syn::PathArguments::AngleBracketed(ref data) => {
|
syn::PathArguments::AngleBracketed(ref data) => {
|
||||||
result = true;
|
result = true;
|
||||||
succ = data.args[0].clone();
|
succ = data.args[0].clone();
|
||||||
|
@ -420,10 +421,10 @@ fn get_res_success(ty: &syn::Type) -> (TokenStream, syn::GenericArgument) {
|
||||||
data.args[0]
|
data.args[0]
|
||||||
{
|
{
|
||||||
if let Some(segment) = typath.path.segments.last() {
|
if let Some(segment) = typath.path.segments.last() {
|
||||||
if "Option" == segment.value().ident.to_string().as_str() {
|
if "Option" == segment.ident.to_string().as_str() {
|
||||||
// get T from Option<T>
|
// get T from Option<T>
|
||||||
if let syn::PathArguments::AngleBracketed(ref data) =
|
if let syn::PathArguments::AngleBracketed(ref data) =
|
||||||
segment.value().arguments
|
segment.arguments
|
||||||
{
|
{
|
||||||
result = false;
|
result = false;
|
||||||
succ = data.args[0].clone();
|
succ = data.args[0].clone();
|
||||||
|
@ -436,7 +437,7 @@ fn get_res_success(ty: &syn::Type) -> (TokenStream, syn::GenericArgument) {
|
||||||
},
|
},
|
||||||
_ => panic!(
|
_ => panic!(
|
||||||
"fn result type has to be PyResult or (), got {:?}",
|
"fn result type has to be PyResult or (), got {:?}",
|
||||||
segment.value().ident
|
segment.ident
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -456,50 +457,55 @@ fn get_res_success(ty: &syn::Type) -> (TokenStream, syn::GenericArgument) {
|
||||||
(res, succ)
|
(res, succ)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_decl(spec: syn::Item) -> syn::FnDecl {
|
fn extract_decl(spec: syn::Item) -> syn::Signature {
|
||||||
match spec {
|
match spec {
|
||||||
syn::Item::Fn(f) => *f.decl,
|
syn::Item::Fn(f) => f.sig,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// modify method signature
|
// modify method signature
|
||||||
fn modify_arg_ty(sig: &mut syn::MethodSig, idx: usize, decl1: &syn::FnDecl, decl2: &syn::FnDecl) {
|
fn modify_arg_ty(
|
||||||
let arg = sig.decl.inputs[idx].clone();
|
sig: &mut syn::Signature,
|
||||||
|
idx: usize,
|
||||||
|
decl1: &syn::Signature,
|
||||||
|
decl2: &syn::Signature,
|
||||||
|
) {
|
||||||
|
let arg = sig.inputs[idx].clone();
|
||||||
match arg {
|
match arg {
|
||||||
syn::FnArg::Captured(ref cap) => match cap.ty {
|
syn::FnArg::Typed(ref cap) => match *cap.ty {
|
||||||
syn::Type::Path(ref typath) => {
|
syn::Type::Path(ref typath) => {
|
||||||
let seg = *typath.path.segments.last().unwrap().value();
|
let seg = typath.path.segments.last().unwrap().clone();
|
||||||
if seg.ident == "Option" {
|
if seg.ident == "Option" {
|
||||||
sig.decl.inputs[idx] = fix_name(&cap.pat, &decl2.inputs[idx]);
|
sig.inputs[idx] = fix_name(&cap.pat, &decl2.inputs[idx]);
|
||||||
} else {
|
} else {
|
||||||
sig.decl.inputs[idx] = fix_name(&cap.pat, &decl1.inputs[idx]);
|
sig.inputs[idx] = fix_name(&cap.pat, &decl1.inputs[idx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
sig.decl.inputs[idx] = fix_name(&cap.pat, &decl1.inputs[idx]);
|
sig.inputs[idx] = fix_name(&cap.pat, &decl1.inputs[idx]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => panic!("not supported"),
|
_ => panic!("not supported"),
|
||||||
}
|
}
|
||||||
|
|
||||||
sig.decl.output = decl1.output.clone();
|
sig.output = decl1.output.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modify_self_ty(sig: &mut syn::MethodSig) {
|
fn modify_self_ty(sig: &mut syn::Signature) {
|
||||||
match sig.decl.inputs[0] {
|
match sig.inputs[0] {
|
||||||
syn::FnArg::SelfRef(ref mut slf) => {
|
syn::FnArg::Receiver(ref mut slf) => {
|
||||||
slf.lifetime = Some(syn::parse_quote! {'p});
|
slf.reference = Some((Token![&](Span::call_site()), syn::parse_quote! {'p}));
|
||||||
}
|
}
|
||||||
syn::FnArg::Captured(_) => {}
|
syn::FnArg::Typed(_) => {}
|
||||||
_ => panic!("not supported"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fix_name(pat: &syn::Pat, arg: &syn::FnArg) -> syn::FnArg {
|
fn fix_name(pat: &syn::Pat, arg: &syn::FnArg) -> syn::FnArg {
|
||||||
if let syn::FnArg::Captured(ref cap) = arg {
|
if let syn::FnArg::Typed(ref cap) = arg {
|
||||||
syn::FnArg::Captured(syn::ArgCaptured {
|
syn::FnArg::Typed(syn::PatType {
|
||||||
pat: pat.clone(),
|
attrs: cap.attrs.clone(),
|
||||||
|
pat: Box::new(pat.clone()),
|
||||||
colon_token: cap.colon_token,
|
colon_token: cap.colon_token,
|
||||||
ty: cap.ty.clone(),
|
ty: cap.ty.clone(),
|
||||||
})
|
})
|
||||||
|
|
|
@ -49,22 +49,19 @@ impl<'a> FnSpec<'a> {
|
||||||
/// Parser function signature and function attributes
|
/// Parser function signature and function attributes
|
||||||
pub fn parse(
|
pub fn parse(
|
||||||
name: &'a syn::Ident,
|
name: &'a syn::Ident,
|
||||||
sig: &'a syn::MethodSig,
|
sig: &'a syn::Signature,
|
||||||
meth_attrs: &'a mut Vec<syn::Attribute>,
|
meth_attrs: &'a mut Vec<syn::Attribute>,
|
||||||
) -> syn::Result<FnSpec<'a>> {
|
) -> syn::Result<FnSpec<'a>> {
|
||||||
let (mut fn_type, fn_attrs) = parse_attributes(meth_attrs)?;
|
let (mut fn_type, fn_attrs) = parse_attributes(meth_attrs)?;
|
||||||
|
|
||||||
let mut has_self = false;
|
let mut has_self = false;
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
for input in sig.decl.inputs.iter() {
|
for input in sig.inputs.iter() {
|
||||||
match input {
|
match input {
|
||||||
syn::FnArg::SelfRef(_) => {
|
syn::FnArg::Receiver(_) => {
|
||||||
has_self = true;
|
has_self = true;
|
||||||
}
|
}
|
||||||
syn::FnArg::SelfValue(_) => {
|
syn::FnArg::Typed(syn::PatType {
|
||||||
has_self = true;
|
|
||||||
}
|
|
||||||
syn::FnArg::Captured(syn::ArgCaptured {
|
|
||||||
ref pat, ref ty, ..
|
ref pat, ref ty, ..
|
||||||
}) => {
|
}) => {
|
||||||
// skip first argument (cls)
|
// skip first argument (cls)
|
||||||
|
@ -73,7 +70,7 @@ impl<'a> FnSpec<'a> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (ident, by_ref, mutability) = match pat {
|
let (ident, by_ref, mutability) = match **pat {
|
||||||
syn::Pat::Ident(syn::PatIdent {
|
syn::Pat::Ident(syn::PatIdent {
|
||||||
ref ident,
|
ref ident,
|
||||||
ref by_ref,
|
ref by_ref,
|
||||||
|
@ -99,16 +96,10 @@ impl<'a> FnSpec<'a> {
|
||||||
reference: is_ref(name, ty),
|
reference: is_ref(name, ty),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
syn::FnArg::Ignored(_) => {
|
|
||||||
return Err(syn::Error::new_spanned(name, "ignored argument"));
|
|
||||||
}
|
|
||||||
syn::FnArg::Inferred(_) => {
|
|
||||||
return Err(syn::Error::new_spanned(name, "inferred argument"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = get_return_info(&sig.decl.output);
|
let ty = get_return_info(&sig.output);
|
||||||
|
|
||||||
if fn_type == FnType::Fn && !has_self {
|
if fn_type == FnType::Fn && !has_self {
|
||||||
if arguments.is_empty() {
|
if arguments.is_empty() {
|
||||||
|
@ -131,8 +122,8 @@ impl<'a> FnSpec<'a> {
|
||||||
|
|
||||||
pub fn is_args(&self, name: &syn::Ident) -> bool {
|
pub fn is_args(&self, name: &syn::Ident) -> bool {
|
||||||
for s in self.attrs.iter() {
|
for s in self.attrs.iter() {
|
||||||
if let Argument::VarArgs(ref ident) = s {
|
if let Argument::VarArgs(ref path) = s {
|
||||||
return name == ident;
|
return path.is_ident(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
@ -151,8 +142,8 @@ impl<'a> FnSpec<'a> {
|
||||||
|
|
||||||
pub fn is_kwargs(&self, name: &syn::Ident) -> bool {
|
pub fn is_kwargs(&self, name: &syn::Ident) -> bool {
|
||||||
for s in self.attrs.iter() {
|
for s in self.attrs.iter() {
|
||||||
if let Argument::KeywordArgs(ref ident) = s {
|
if let Argument::KeywordArgs(ref path) = s {
|
||||||
return name == ident;
|
return path.is_ident(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
|
@ -170,16 +161,16 @@ impl<'a> FnSpec<'a> {
|
||||||
pub fn default_value(&self, name: &syn::Ident) -> Option<TokenStream> {
|
pub fn default_value(&self, name: &syn::Ident) -> Option<TokenStream> {
|
||||||
for s in self.attrs.iter() {
|
for s in self.attrs.iter() {
|
||||||
match *s {
|
match *s {
|
||||||
Argument::Arg(ref ident, ref opt) => {
|
Argument::Arg(ref path, ref opt) => {
|
||||||
if ident == name {
|
if path.is_ident(name) {
|
||||||
if let Some(ref val) = opt {
|
if let Some(ref val) = opt {
|
||||||
let i: syn::Expr = syn::parse_str(&val).unwrap();
|
let i: syn::Expr = syn::parse_str(&val).unwrap();
|
||||||
return Some(i.into_token_stream());
|
return Some(i.into_token_stream());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Argument::Kwarg(ref ident, ref opt) => {
|
Argument::Kwarg(ref path, ref opt) => {
|
||||||
if ident == name {
|
if path.is_ident(name) {
|
||||||
let i: syn::Expr = syn::parse_str(&opt).unwrap();
|
let i: syn::Expr = syn::parse_str(&opt).unwrap();
|
||||||
return Some(quote!(#i));
|
return Some(quote!(#i));
|
||||||
}
|
}
|
||||||
|
@ -192,8 +183,8 @@ impl<'a> FnSpec<'a> {
|
||||||
|
|
||||||
pub fn is_kw_only(&self, name: &syn::Ident) -> bool {
|
pub fn is_kw_only(&self, name: &syn::Ident) -> bool {
|
||||||
for s in self.attrs.iter() {
|
for s in self.attrs.iter() {
|
||||||
if let Argument::Kwarg(ref ident, _) = s {
|
if let Argument::Kwarg(ref path, _) = s {
|
||||||
if ident == name {
|
if path.is_ident(name) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,8 +198,8 @@ pub fn is_ref(name: &syn::Ident, ty: &syn::Type) -> bool {
|
||||||
syn::Type::Reference(_) => return true,
|
syn::Type::Reference(_) => return true,
|
||||||
syn::Type::Path(syn::TypePath { ref path, .. }) => {
|
syn::Type::Path(syn::TypePath { ref path, .. }) => {
|
||||||
if let Some(segment) = path.segments.last() {
|
if let Some(segment) = path.segments.last() {
|
||||||
if "Option" == segment.value().ident.to_string().as_str() {
|
if "Option" == segment.ident.to_string().as_str() {
|
||||||
match segment.value().arguments {
|
match segment.arguments {
|
||||||
syn::PathArguments::AngleBracketed(ref params) => {
|
syn::PathArguments::AngleBracketed(ref params) => {
|
||||||
if params.args.len() != 1 {
|
if params.args.len() != 1 {
|
||||||
panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
|
panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
|
||||||
|
@ -248,8 +239,8 @@ pub fn check_arg_ty_and_optional<'a>(
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if let Some(segment) = path.segments.last() {
|
if let Some(segment) = path.segments.last() {
|
||||||
match segment.value().ident.to_string().as_str() {
|
match segment.ident.to_string().as_str() {
|
||||||
"Option" => match segment.value().arguments {
|
"Option" => match segment.arguments {
|
||||||
syn::PathArguments::AngleBracketed(ref params) => {
|
syn::PathArguments::AngleBracketed(ref params) => {
|
||||||
if params.args.len() != 1 {
|
if params.args.len() != 1 {
|
||||||
panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
|
panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
|
||||||
|
@ -294,40 +285,46 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> syn::Result<(FnType, Vec
|
||||||
let mut res: Option<FnType> = None;
|
let mut res: Option<FnType> = None;
|
||||||
|
|
||||||
for attr in attrs.iter() {
|
for attr in attrs.iter() {
|
||||||
match attr.interpret_meta().unwrap() {
|
match attr.parse_meta().unwrap() {
|
||||||
syn::Meta::Word(ref name) => match name.to_string().as_ref() {
|
syn::Meta::Path(ref name) => {
|
||||||
"new" | "__new__" => res = Some(FnType::FnNew),
|
if name.is_ident("new") || name.is_ident("__new__") {
|
||||||
"init" | "__init__" => res = Some(FnType::FnInit),
|
res = Some(FnType::FnNew)
|
||||||
"call" | "__call__" => res = Some(FnType::FnCall),
|
} else if name.is_ident("init") || name.is_ident("__init__") {
|
||||||
"classmethod" => res = Some(FnType::FnClass),
|
res = Some(FnType::FnInit)
|
||||||
"staticmethod" => res = Some(FnType::FnStatic),
|
} else if name.is_ident("call") || name.is_ident("__call__") {
|
||||||
"setter" | "getter" => {
|
res = Some(FnType::FnCall)
|
||||||
|
} else if name.is_ident("classmethod") {
|
||||||
|
res = Some(FnType::FnClass)
|
||||||
|
} else if name.is_ident("staticmethod") {
|
||||||
|
res = Some(FnType::FnStatic)
|
||||||
|
} else if name.is_ident("setter") || name.is_ident("getter") {
|
||||||
if let syn::AttrStyle::Inner(_) = attr.style {
|
if let syn::AttrStyle::Inner(_) = attr.style {
|
||||||
panic!(
|
panic!("Inner style attribute is not supported for setter and getter");
|
||||||
"Inner style attribute is not
|
|
||||||
supported for setter and getter"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if res != None {
|
if res != None {
|
||||||
panic!("setter/getter attribute can not be used mutiple times");
|
panic!("setter/getter attribute can not be used mutiple times");
|
||||||
}
|
}
|
||||||
if name == "setter" {
|
if name.is_ident("setter") {
|
||||||
res = Some(FnType::Setter(None))
|
res = Some(FnType::Setter(None))
|
||||||
} else {
|
} else {
|
||||||
res = Some(FnType::Getter(None))
|
res = Some(FnType::Getter(None))
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
new_attrs.push(attr.clone())
|
||||||
}
|
}
|
||||||
_ => new_attrs.push(attr.clone()),
|
}
|
||||||
},
|
|
||||||
syn::Meta::List(syn::MetaList {
|
syn::Meta::List(syn::MetaList {
|
||||||
ref ident,
|
ref path,
|
||||||
ref nested,
|
ref nested,
|
||||||
..
|
..
|
||||||
}) => match ident.to_string().as_str() {
|
}) => {
|
||||||
"new" => res = Some(FnType::FnNew),
|
if path.is_ident("new") {
|
||||||
"init" => res = Some(FnType::FnInit),
|
res = Some(FnType::FnNew)
|
||||||
"call" => res = Some(FnType::FnCall),
|
} else if path.is_ident("init") {
|
||||||
"setter" | "getter" => {
|
res = Some(FnType::FnInit)
|
||||||
|
} else if path.is_ident("call") {
|
||||||
|
res = Some(FnType::FnCall)
|
||||||
|
} else if path.is_ident("setter") || path.is_ident("getter") {
|
||||||
if let syn::AttrStyle::Inner(_) = attr.style {
|
if let syn::AttrStyle::Inner(_) = attr.style {
|
||||||
panic!(
|
panic!(
|
||||||
"Inner style attribute is not
|
"Inner style attribute is not
|
||||||
|
@ -340,17 +337,17 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> syn::Result<(FnType, Vec
|
||||||
if nested.len() != 1 {
|
if nested.len() != 1 {
|
||||||
panic!("setter/getter requires one value");
|
panic!("setter/getter requires one value");
|
||||||
}
|
}
|
||||||
match nested.first().unwrap().value() {
|
match nested.first().unwrap() {
|
||||||
syn::NestedMeta::Meta(syn::Meta::Word(ref w)) => {
|
syn::NestedMeta::Meta(syn::Meta::Path(ref w)) => {
|
||||||
if ident == "setter" {
|
if path.is_ident("setter") {
|
||||||
res = Some(FnType::Setter(Some(w.to_string())))
|
res = Some(FnType::Setter(Some(w.segments[0].ident.to_string())))
|
||||||
} else {
|
} else {
|
||||||
res = Some(FnType::Getter(Some(w.to_string())))
|
res = Some(FnType::Getter(Some(w.segments[0].ident.to_string())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syn::NestedMeta::Literal(ref lit) => match *lit {
|
syn::NestedMeta::Lit(ref lit) => match *lit {
|
||||||
syn::Lit::Str(ref s) => {
|
syn::Lit::Str(ref s) => {
|
||||||
if ident == "setter" {
|
if path.is_ident("setter") {
|
||||||
res = Some(FnType::Setter(Some(s.value())))
|
res = Some(FnType::Setter(Some(s.value())))
|
||||||
} else {
|
} else {
|
||||||
res = Some(FnType::Getter(Some(s.value())))
|
res = Some(FnType::Getter(Some(s.value())))
|
||||||
|
@ -361,16 +358,16 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> syn::Result<(FnType, Vec
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
println!("cannot parse {:?} attribute: {:?}", ident, nested);
|
println!("cannot parse {:?} attribute: {:?}", path, nested);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if path.is_ident("args") {
|
||||||
"args" => {
|
|
||||||
let attrs = PyFunctionAttr::from_meta(nested)?;
|
let attrs = PyFunctionAttr::from_meta(nested)?;
|
||||||
spec.extend(attrs.arguments)
|
spec.extend(attrs.arguments)
|
||||||
|
} else {
|
||||||
|
new_attrs.push(attr.clone())
|
||||||
}
|
}
|
||||||
_ => new_attrs.push(attr.clone()),
|
}
|
||||||
},
|
|
||||||
syn::Meta::NameValue(_) => new_attrs.push(attr.clone()),
|
syn::Meta::NameValue(_) => new_attrs.push(attr.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,7 @@ use crate::pymethod;
|
||||||
use crate::pymethod::get_arg_names;
|
use crate::pymethod::get_arg_names;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::quote;
|
use quote::{format_ident, quote};
|
||||||
use syn::ext::IdentExt;
|
|
||||||
use syn::Ident;
|
use syn::Ident;
|
||||||
|
|
||||||
/// Generates the function that is called by the python interpreter to initialize the native
|
/// Generates the function that is called by the python interpreter to initialize the native
|
||||||
|
@ -38,7 +37,7 @@ pub fn process_functions_in_module(func: &mut syn::ItemFn) {
|
||||||
extract_pyfn_attrs(&mut func.attrs)
|
extract_pyfn_attrs(&mut func.attrs)
|
||||||
{
|
{
|
||||||
let function_to_python = add_fn_to_module(func, &python_name, pyfn_attrs);
|
let function_to_python = add_fn_to_module(func, &python_name, pyfn_attrs);
|
||||||
let function_wrapper_ident = function_wrapper_ident(&func.ident);
|
let function_wrapper_ident = function_wrapper_ident(&func.sig.ident);
|
||||||
let item: syn::ItemFn = syn::parse_quote! {
|
let item: syn::ItemFn = syn::parse_quote! {
|
||||||
fn block_wrapper() {
|
fn block_wrapper() {
|
||||||
#function_to_python
|
#function_to_python
|
||||||
|
@ -57,9 +56,9 @@ pub fn process_functions_in_module(func: &mut syn::ItemFn) {
|
||||||
/// Transforms a rust fn arg parsed with syn into a method::FnArg
|
/// Transforms a rust fn arg parsed with syn into a method::FnArg
|
||||||
fn wrap_fn_argument<'a>(input: &'a syn::FnArg, name: &'a Ident) -> Option<method::FnArg<'a>> {
|
fn wrap_fn_argument<'a>(input: &'a syn::FnArg, name: &'a Ident) -> Option<method::FnArg<'a>> {
|
||||||
match input {
|
match input {
|
||||||
syn::FnArg::SelfRef(_) | &syn::FnArg::SelfValue(_) => None,
|
syn::FnArg::Receiver(_) => None,
|
||||||
syn::FnArg::Captured(ref cap) => {
|
syn::FnArg::Typed(ref cap) => {
|
||||||
let (mutability, by_ref, ident) = match cap.pat {
|
let (mutability, by_ref, ident) = match *cap.pat {
|
||||||
syn::Pat::Ident(ref patid) => (&patid.mutability, &patid.by_ref, &patid.ident),
|
syn::Pat::Ident(ref patid) => (&patid.mutability, &patid.by_ref, &patid.ident),
|
||||||
_ => panic!("unsupported argument: {:?}", cap.pat),
|
_ => panic!("unsupported argument: {:?}", cap.pat),
|
||||||
};
|
};
|
||||||
|
@ -76,15 +75,13 @@ fn wrap_fn_argument<'a>(input: &'a syn::FnArg, name: &'a Ident) -> Option<method
|
||||||
reference: method::is_ref(&name, &cap.ty),
|
reference: method::is_ref(&name, &cap.ty),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
syn::FnArg::Ignored(_) => panic!("ignored argument: {:?}", name),
|
|
||||||
syn::FnArg::Inferred(_) => panic!("inferred argument: {:?}", name),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts the data from the #[pyfn(...)] attribute of a function
|
/// Extracts the data from the #[pyfn(...)] attribute of a function
|
||||||
fn extract_pyfn_attrs(
|
fn extract_pyfn_attrs(
|
||||||
attrs: &mut Vec<syn::Attribute>,
|
attrs: &mut Vec<syn::Attribute>,
|
||||||
) -> Option<(Ident, Ident, Vec<pyfunction::Argument>)> {
|
) -> Option<(syn::Path, Ident, Vec<pyfunction::Argument>)> {
|
||||||
let mut new_attrs = Vec::new();
|
let mut new_attrs = Vec::new();
|
||||||
let mut fnname = None;
|
let mut fnname = None;
|
||||||
let mut modname = None;
|
let mut modname = None;
|
||||||
|
@ -92,19 +89,19 @@ fn extract_pyfn_attrs(
|
||||||
|
|
||||||
for attr in attrs.iter() {
|
for attr in attrs.iter() {
|
||||||
match attr.parse_meta() {
|
match attr.parse_meta() {
|
||||||
Ok(syn::Meta::List(ref list)) if list.ident == "pyfn" => {
|
Ok(syn::Meta::List(ref list)) if list.path.is_ident("pyfn") => {
|
||||||
let meta: Vec<_> = list.nested.iter().cloned().collect();
|
let meta: Vec<_> = list.nested.iter().cloned().collect();
|
||||||
if meta.len() >= 2 {
|
if meta.len() >= 2 {
|
||||||
// read module name
|
// read module name
|
||||||
match meta[0] {
|
match meta[0] {
|
||||||
syn::NestedMeta::Meta(syn::Meta::Word(ref ident)) => {
|
syn::NestedMeta::Meta(syn::Meta::Path(ref path)) => {
|
||||||
modname = Some(ident.clone())
|
modname = Some(path.clone())
|
||||||
}
|
}
|
||||||
_ => panic!("The first parameter of pyfn must be a MetaItem"),
|
_ => panic!("The first parameter of pyfn must be a MetaItem"),
|
||||||
}
|
}
|
||||||
// read Python function name
|
// read Python function name
|
||||||
match meta[1] {
|
match meta[1] {
|
||||||
syn::NestedMeta::Literal(syn::Lit::Str(ref lits)) => {
|
syn::NestedMeta::Lit(syn::Lit::Str(ref lits)) => {
|
||||||
fnname = Some(syn::Ident::new(&lits.value(), lits.span()));
|
fnname = Some(syn::Ident::new(&lits.value(), lits.span()));
|
||||||
}
|
}
|
||||||
_ => panic!("The second parameter of pyfn must be a Literal"),
|
_ => panic!("The second parameter of pyfn must be a Literal"),
|
||||||
|
@ -130,10 +127,7 @@ fn extract_pyfn_attrs(
|
||||||
/// Coordinates the naming of a the add-function-to-python-module function
|
/// Coordinates the naming of a the add-function-to-python-module function
|
||||||
fn function_wrapper_ident(name: &Ident) -> Ident {
|
fn function_wrapper_ident(name: &Ident) -> Ident {
|
||||||
// Make sure this ident matches the one of wrap_pyfunction
|
// Make sure this ident matches the one of wrap_pyfunction
|
||||||
Ident::new(
|
format_ident!("__pyo3_get_function_{}", name)
|
||||||
&format!("__pyo3_get_function_{}", name.unraw().to_string()),
|
|
||||||
Span::call_site(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates python wrapper over a function that allows adding it to a python module as a python
|
/// Generates python wrapper over a function that allows adding it to a python module as a python
|
||||||
|
@ -145,13 +139,13 @@ pub fn add_fn_to_module(
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
for input in func.decl.inputs.iter() {
|
for input in func.sig.inputs.iter() {
|
||||||
if let Some(fn_arg) = wrap_fn_argument(input, &func.ident) {
|
if let Some(fn_arg) = wrap_fn_argument(input, &func.sig.ident) {
|
||||||
arguments.push(fn_arg);
|
arguments.push(fn_arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = method::get_return_info(&func.decl.output);
|
let ty = method::get_return_info(&func.sig.output);
|
||||||
|
|
||||||
let spec = method::FnSpec {
|
let spec = method::FnSpec {
|
||||||
tp: method::FnType::Fn,
|
tp: method::FnType::Fn,
|
||||||
|
@ -160,9 +154,9 @@ pub fn add_fn_to_module(
|
||||||
output: ty,
|
output: ty,
|
||||||
};
|
};
|
||||||
|
|
||||||
let function_wrapper_ident = function_wrapper_ident(&func.ident);
|
let function_wrapper_ident = function_wrapper_ident(&func.sig.ident);
|
||||||
|
|
||||||
let wrapper = function_c_wrapper(&func.ident, &spec);
|
let wrapper = function_c_wrapper(&func.sig.ident, &spec);
|
||||||
let doc = utils::get_doc(&func.attrs, true);
|
let doc = utils::get_doc(&func.attrs, true);
|
||||||
|
|
||||||
let tokens = quote! {
|
let tokens = quote! {
|
||||||
|
|
|
@ -59,7 +59,7 @@ impl PyClassArgs {
|
||||||
fn add_assign(&mut self, assign: &syn::ExprAssign) -> syn::Result<()> {
|
fn add_assign(&mut self, assign: &syn::ExprAssign) -> syn::Result<()> {
|
||||||
let key = match *assign.left {
|
let key = match *assign.left {
|
||||||
syn::Expr::Path(ref exp) if exp.path.segments.len() == 1 => {
|
syn::Expr::Path(ref exp) if exp.path.segments.len() == 1 => {
|
||||||
exp.path.segments.first().unwrap().value().ident.to_string()
|
exp.path.segments.first().unwrap().ident.to_string()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(syn::Error::new_spanned(assign, "could not parse argument"));
|
return Err(syn::Error::new_spanned(assign, "could not parse argument"));
|
||||||
|
@ -123,7 +123,7 @@ impl PyClassArgs {
|
||||||
|
|
||||||
/// Match a key/value flag
|
/// Match a key/value flag
|
||||||
fn add_path(&mut self, exp: &syn::ExprPath) -> syn::Result<()> {
|
fn add_path(&mut self, exp: &syn::ExprPath) -> syn::Result<()> {
|
||||||
let flag = exp.path.segments.first().unwrap().value().ident.to_string();
|
let flag = exp.path.segments.first().unwrap().ident.to_string();
|
||||||
let path = match flag.as_str() {
|
let path = match flag.as_str() {
|
||||||
"gc" => {
|
"gc" => {
|
||||||
parse_quote! {pyo3::type_object::PY_TYPE_FLAG_GC}
|
parse_quote! {pyo3::type_object::PY_TYPE_FLAG_GC}
|
||||||
|
@ -184,28 +184,23 @@ fn parse_descriptors(item: &mut syn::Field) -> syn::Result<Vec<FnType>> {
|
||||||
let mut new_attrs = Vec::new();
|
let mut new_attrs = Vec::new();
|
||||||
for attr in item.attrs.iter() {
|
for attr in item.attrs.iter() {
|
||||||
if let Ok(syn::Meta::List(ref list)) = attr.parse_meta() {
|
if let Ok(syn::Meta::List(ref list)) = attr.parse_meta() {
|
||||||
match list.ident.to_string().as_str() {
|
if list.path.is_ident("pyo3") {
|
||||||
"pyo3" => {
|
for meta in list.nested.iter() {
|
||||||
for meta in list.nested.iter() {
|
if let syn::NestedMeta::Meta(ref metaitem) = meta {
|
||||||
if let syn::NestedMeta::Meta(ref metaitem) = meta {
|
if metaitem.path().is_ident("get") {
|
||||||
match metaitem.name().to_string().as_str() {
|
descs.push(FnType::Getter(None));
|
||||||
"get" => {
|
} else if metaitem.path().is_ident("set") {
|
||||||
descs.push(FnType::Getter(None));
|
descs.push(FnType::Setter(None));
|
||||||
}
|
} else {
|
||||||
"set" => {
|
return Err(syn::Error::new_spanned(
|
||||||
descs.push(FnType::Setter(None));
|
metaitem,
|
||||||
}
|
"Only get and set are supported",
|
||||||
_ => {
|
));
|
||||||
return Err(syn::Error::new_spanned(
|
|
||||||
metaitem,
|
|
||||||
"Only get and set are supported",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => new_attrs.push(attr.clone()),
|
} else {
|
||||||
|
new_attrs.push(attr.clone())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
new_attrs.push(attr.clone());
|
new_attrs.push(attr.clone());
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
|
|
||||||
use syn::parse::ParseBuffer;
|
use syn::parse::ParseBuffer;
|
||||||
use syn::punctuated::Punctuated;
|
use syn::punctuated::Punctuated;
|
||||||
use syn::{Ident, NestedMeta};
|
use syn::{NestedMeta, Path};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Argument {
|
pub enum Argument {
|
||||||
VarArgsSeparator,
|
VarArgsSeparator,
|
||||||
VarArgs(syn::Ident),
|
VarArgs(syn::Path),
|
||||||
KeywordArgs(syn::Ident),
|
KeywordArgs(syn::Path),
|
||||||
Arg(syn::Ident, Option<String>),
|
Arg(syn::Path, Option<String>),
|
||||||
Kwarg(syn::Ident, String),
|
Kwarg(syn::Path, String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The attributes of the pyfunction macro
|
/// The attributes of the pyfunction macro
|
||||||
|
@ -41,11 +41,11 @@ impl PyFunctionAttr {
|
||||||
|
|
||||||
pub fn add_item(&mut self, item: &NestedMeta) -> syn::Result<()> {
|
pub fn add_item(&mut self, item: &NestedMeta) -> syn::Result<()> {
|
||||||
match item {
|
match item {
|
||||||
NestedMeta::Meta(syn::Meta::Word(ref ident)) => self.add_work(item, ident)?,
|
NestedMeta::Meta(syn::Meta::Path(ref ident)) => self.add_work(item, ident)?,
|
||||||
NestedMeta::Meta(syn::Meta::NameValue(ref nv)) => {
|
NestedMeta::Meta(syn::Meta::NameValue(ref nv)) => {
|
||||||
self.add_name_value(item, nv)?;
|
self.add_name_value(item, nv)?;
|
||||||
}
|
}
|
||||||
NestedMeta::Literal(ref lit) => {
|
NestedMeta::Lit(ref lit) => {
|
||||||
self.add_literal(item, lit)?;
|
self.add_literal(item, lit)?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -89,7 +89,7 @@ impl PyFunctionAttr {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_work(&mut self, item: &NestedMeta, ident: &Ident) -> syn::Result<()> {
|
fn add_work(&mut self, item: &NestedMeta, path: &Path) -> syn::Result<()> {
|
||||||
// self.arguments in form somename
|
// self.arguments in form somename
|
||||||
if self.has_kwargs {
|
if self.has_kwargs {
|
||||||
return Err(syn::Error::new_spanned(
|
return Err(syn::Error::new_spanned(
|
||||||
|
@ -103,7 +103,7 @@ impl PyFunctionAttr {
|
||||||
"syntax error, argument is not allowed after keyword argument",
|
"syntax error, argument is not allowed after keyword argument",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
self.arguments.push(Argument::Arg(ident.clone(), None));
|
self.arguments.push(Argument::Arg(path.clone(), None));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ impl PyFunctionAttr {
|
||||||
return Err(syn::Error::new_spanned(item, "*(var args) is defined"));
|
return Err(syn::Error::new_spanned(item, "*(var args) is defined"));
|
||||||
}
|
}
|
||||||
self.has_varargs = true;
|
self.has_varargs = true;
|
||||||
self.arguments.push(Argument::VarArgs(nv.ident.clone()));
|
self.arguments.push(Argument::VarArgs(nv.path.clone()));
|
||||||
} else if litstr.value() == "**" {
|
} else if litstr.value() == "**" {
|
||||||
// kwargs="**"
|
// kwargs="**"
|
||||||
if self.has_kwargs {
|
if self.has_kwargs {
|
||||||
|
@ -132,10 +132,10 @@ impl PyFunctionAttr {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
self.has_kwargs = true;
|
self.has_kwargs = true;
|
||||||
self.arguments.push(Argument::KeywordArgs(nv.ident.clone()));
|
self.arguments.push(Argument::KeywordArgs(nv.path.clone()));
|
||||||
} else if self.has_varargs {
|
} else if self.has_varargs {
|
||||||
self.arguments
|
self.arguments
|
||||||
.push(Argument::Kwarg(nv.ident.clone(), litstr.value().clone()))
|
.push(Argument::Kwarg(nv.path.clone(), litstr.value()))
|
||||||
} else {
|
} else {
|
||||||
if self.has_kwargs {
|
if self.has_kwargs {
|
||||||
return Err(syn::Error::new_spanned(
|
return Err(syn::Error::new_spanned(
|
||||||
|
@ -144,18 +144,14 @@ impl PyFunctionAttr {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
self.has_kw = true;
|
self.has_kw = true;
|
||||||
self.arguments.push(Argument::Arg(
|
self.arguments
|
||||||
nv.ident.clone(),
|
.push(Argument::Arg(nv.path.clone(), Some(litstr.value())))
|
||||||
Some(litstr.value().clone()),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syn::Lit::Int(ref litint) => {
|
syn::Lit::Int(ref litint) => {
|
||||||
if self.has_varargs {
|
if self.has_varargs {
|
||||||
self.arguments.push(Argument::Kwarg(
|
self.arguments
|
||||||
nv.ident.clone(),
|
.push(Argument::Kwarg(nv.path.clone(), format!("{}", litint)));
|
||||||
format!("{}", litint.value()),
|
|
||||||
));
|
|
||||||
} else {
|
} else {
|
||||||
if self.has_kwargs {
|
if self.has_kwargs {
|
||||||
return Err(syn::Error::new_spanned(
|
return Err(syn::Error::new_spanned(
|
||||||
|
@ -164,16 +160,14 @@ impl PyFunctionAttr {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
self.has_kw = true;
|
self.has_kw = true;
|
||||||
self.arguments.push(Argument::Arg(
|
self.arguments
|
||||||
nv.ident.clone(),
|
.push(Argument::Arg(nv.path.clone(), Some(format!("{}", litint))));
|
||||||
Some(format!("{}", litint.value())),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syn::Lit::Bool(ref litb) => {
|
syn::Lit::Bool(ref litb) => {
|
||||||
if self.has_varargs {
|
if self.has_varargs {
|
||||||
self.arguments
|
self.arguments
|
||||||
.push(Argument::Kwarg(nv.ident.clone(), format!("{}", litb.value)));
|
.push(Argument::Kwarg(nv.path.clone(), format!("{}", litb.value)));
|
||||||
} else {
|
} else {
|
||||||
if self.has_kwargs {
|
if self.has_kwargs {
|
||||||
return Err(syn::Error::new_spanned(
|
return Err(syn::Error::new_spanned(
|
||||||
|
@ -183,7 +177,7 @@ impl PyFunctionAttr {
|
||||||
}
|
}
|
||||||
self.has_kw = true;
|
self.has_kw = true;
|
||||||
self.arguments.push(Argument::Arg(
|
self.arguments.push(Argument::Arg(
|
||||||
nv.ident.clone(),
|
nv.path.clone(),
|
||||||
Some(format!("{}", litb.value)),
|
Some(format!("{}", litb.value)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use quote::quote;
|
||||||
pub fn gen_py_method(
|
pub fn gen_py_method(
|
||||||
cls: &syn::Type,
|
cls: &syn::Type,
|
||||||
name: &syn::Ident,
|
name: &syn::Ident,
|
||||||
sig: &mut syn::MethodSig,
|
sig: &mut syn::Signature,
|
||||||
meth_attrs: &mut Vec<syn::Attribute>,
|
meth_attrs: &mut Vec<syn::Attribute>,
|
||||||
) -> syn::Result<TokenStream> {
|
) -> syn::Result<TokenStream> {
|
||||||
check_generic(name, sig)?;
|
check_generic(name, sig)?;
|
||||||
|
@ -49,14 +49,14 @@ pub fn gen_py_method(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_generic(name: &syn::Ident, sig: &syn::MethodSig) -> syn::Result<()> {
|
fn check_generic(name: &syn::Ident, sig: &syn::Signature) -> syn::Result<()> {
|
||||||
let err_msg = |typ| {
|
let err_msg = |typ| {
|
||||||
format!(
|
format!(
|
||||||
"A Python method can't have a generic {} parameter: {}",
|
"A Python method can't have a generic {} parameter: {}",
|
||||||
name, typ
|
name, typ
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
for param in &sig.decl.generics.params {
|
for param in &sig.generics.params {
|
||||||
match param {
|
match param {
|
||||||
syn::GenericParam::Lifetime(_) => {}
|
syn::GenericParam::Lifetime(_) => {}
|
||||||
syn::GenericParam::Type(_) => {
|
syn::GenericParam::Type(_) => {
|
||||||
|
|
|
@ -12,7 +12,7 @@ use quote::ToTokens;
|
||||||
pub fn build_py_proto(ast: &mut syn::ItemImpl) -> syn::Result<TokenStream> {
|
pub fn build_py_proto(ast: &mut syn::ItemImpl) -> syn::Result<TokenStream> {
|
||||||
if let Some((_, ref mut path, _)) = ast.trait_ {
|
if let Some((_, ref mut path, _)) = ast.trait_ {
|
||||||
let proto = if let Some(ref mut segment) = path.segments.last() {
|
let proto = if let Some(ref mut segment) = path.segments.last() {
|
||||||
match segment.value().ident.to_string().as_str() {
|
match segment.ident.to_string().as_str() {
|
||||||
"PyObjectProtocol" => &defs::OBJECT,
|
"PyObjectProtocol" => &defs::OBJECT,
|
||||||
"PyAsyncProtocol" => &defs::ASYNC,
|
"PyAsyncProtocol" => &defs::ASYNC,
|
||||||
"PyMappingProtocol" => &defs::MAPPING,
|
"PyMappingProtocol" => &defs::MAPPING,
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub fn if_type_is_python(ty: &syn::Type) -> bool {
|
||||||
.path
|
.path
|
||||||
.segments
|
.segments
|
||||||
.last()
|
.last()
|
||||||
.map(|seg| seg.value().ident == "Python")
|
.map(|seg| seg.ident == "Python")
|
||||||
.unwrap_or(false),
|
.unwrap_or(false),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,8 @@ pub fn get_doc(attrs: &[syn::Attribute], null_terminated: bool) -> syn::Lit {
|
||||||
// let mut span = None;
|
// let mut span = None;
|
||||||
|
|
||||||
for attr in attrs.iter() {
|
for attr in attrs.iter() {
|
||||||
if let Some(syn::Meta::NameValue(ref metanv)) = attr.interpret_meta() {
|
if let Ok(syn::Meta::NameValue(ref metanv)) = attr.parse_meta() {
|
||||||
if metanv.ident == "doc" {
|
if metanv.path.is_ident("doc") {
|
||||||
// span = Some(metanv.span());
|
// span = Some(metanv.span());
|
||||||
if let syn::Lit::Str(ref litstr) = metanv.lit {
|
if let syn::Lit::Str(ref litstr) = metanv.lit {
|
||||||
let d = litstr.value();
|
let d = litstr.value();
|
||||||
|
|
|
@ -14,9 +14,9 @@ edition = "2018"
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quote= "0.6.12"
|
quote = "1"
|
||||||
proc-macro2 = "0.4.30"
|
proc-macro2 = "1"
|
||||||
syn = { version = "0.15.34", features = ["full", "extra-traits"] }
|
syn = { version = "1", features = ["full", "extra-traits"] }
|
||||||
pyo3-derive-backend = { path = "../pyo3-derive-backend", version = "=0.7.0" }
|
pyo3-derive-backend = { path = "../pyo3-derive-backend", version = "=0.7.0" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -20,14 +20,14 @@ pub fn pymodule(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let mut ast = parse_macro_input!(input as syn::ItemFn);
|
let mut ast = parse_macro_input!(input as syn::ItemFn);
|
||||||
|
|
||||||
let modname = if attr.is_empty() {
|
let modname = if attr.is_empty() {
|
||||||
ast.ident.clone()
|
ast.sig.ident.clone()
|
||||||
} else {
|
} else {
|
||||||
parse_macro_input!(attr as syn::Ident)
|
parse_macro_input!(attr as syn::Ident)
|
||||||
};
|
};
|
||||||
|
|
||||||
process_functions_in_module(&mut ast);
|
process_functions_in_module(&mut ast);
|
||||||
|
|
||||||
let expanded = py_init(&ast.ident, &modname, get_doc(&ast.attrs, false));
|
let expanded = py_init(&ast.sig.ident, &modname, get_doc(&ast.attrs, false));
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
#ast
|
#ast
|
||||||
|
@ -78,7 +78,7 @@ pub fn pyfunction(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let ast = parse_macro_input!(input as syn::ItemFn);
|
let ast = parse_macro_input!(input as syn::ItemFn);
|
||||||
let args = parse_macro_input!(attr as PyFunctionAttr);
|
let args = parse_macro_input!(attr as PyFunctionAttr);
|
||||||
|
|
||||||
let python_name = syn::Ident::new(&ast.ident.unraw().to_string(), Span::call_site());
|
let python_name = syn::Ident::new(&ast.sig.ident.unraw().to_string(), Span::call_site());
|
||||||
let expanded = add_fn_to_module(&ast, &python_name, args.arguments);
|
let expanded = add_fn_to_module(&ast, &python_name, args.arguments);
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
|
|
Loading…
Reference in a new issue