Merge #154 and #155 changed with `syn13`

This commit is contained in:
Martin Larralde 2018-05-13 21:24:40 +02:00
parent 103bde7db1
commit b43b481980
12 changed files with 521 additions and 529 deletions

View File

@ -10,9 +10,9 @@ categories = ["api-bindings", "development-tools::ffi"]
license = "Apache-2.0"
[dependencies]
quote="0.3"
log="0.4"
quote="0.5"
[dependencies.syn]
version="0.11"
features=["full"]
version="0.13"
features=["full", "parsing", "printing", "extra-traits"]

View File

@ -10,7 +10,7 @@ pub enum Argument {
Kwarg(String, String),
}
pub fn parse_arguments(items: &[syn::NestedMetaItem]) -> Vec<Argument> {
pub fn parse_arguments(items: &[syn::NestedMeta]) -> Vec<Argument> {
let mut arguments = Vec::new();
let mut has_kw = false;
let mut has_varargs = false;
@ -22,7 +22,7 @@ pub fn parse_arguments(items: &[syn::NestedMetaItem]) -> Vec<Argument> {
for item in items.iter() {
match item {
&syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(ref ident)) => {
&syn::NestedMeta::Meta(syn::Meta::Word(ref ident)) => {
// arguments in form #[args(somename)]
if has_kwargs {
println!("syntax error, keyword arguments is defined: {:?}", args_str);
@ -35,11 +35,11 @@ pub fn parse_arguments(items: &[syn::NestedMetaItem]) -> Vec<Argument> {
}
arguments.push(Argument::Arg(ident.as_ref().to_owned(), None))
}
&syn::NestedMetaItem::MetaItem(syn::MetaItem::NameValue(ref ident, ref lit)) => {
let name = ident.as_ref().to_owned();
match lit {
&syn::Lit::Str(ref s, _) => {
if s == "*" { // #[args(args="*")]
&syn::NestedMeta::Meta(syn::Meta::NameValue(ref nv)) => {
let name = nv.ident.as_ref().to_owned();
match nv.lit {
syn::Lit::Str(ref litstr) => {
if litstr.value() == "*" { // #[args(args="*")]
if has_kwargs {
println!("* - syntax error, keyword arguments is defined: {:?}",
args_str);
@ -51,8 +51,7 @@ pub fn parse_arguments(items: &[syn::NestedMetaItem]) -> Vec<Argument> {
}
has_varargs = true;
arguments.push(Argument::VarArgs(name));
}
else if s == "**" { // #[args(kwargs="**")]
} else if litstr.value() == "**" { // #[args(kwargs="**")]
if has_kwargs {
println!("arguments already define ** (kw args): {:?}",
args_str);
@ -62,7 +61,7 @@ pub fn parse_arguments(items: &[syn::NestedMetaItem]) -> Vec<Argument> {
arguments.push(Argument::KeywordArgs(name));
} else {
if has_varargs {
arguments.push(Argument::Kwarg(name, s.clone()))
arguments.push(Argument::Kwarg(name, litstr.value().clone()))
} else {
if has_kwargs {
println!("syntax error, keyword arguments is defined: {:?}",
@ -70,13 +69,13 @@ pub fn parse_arguments(items: &[syn::NestedMetaItem]) -> Vec<Argument> {
return Vec::new()
}
has_kw = true;
arguments.push(Argument::Arg(name, Some(s.clone())))
arguments.push(Argument::Arg(name, Some(litstr.value().clone())))
}
}
}
&syn::Lit::Int(ref s, _) => {
syn::Lit::Int(ref litint) => {
if has_varargs {
arguments.push(Argument::Kwarg(name, format!("{}", s)));
arguments.push(Argument::Kwarg(name, format!("{}", litint.value())));
} else {
if has_kwargs {
println!("syntax error, keyword arguments is defined: {:?}",
@ -84,12 +83,12 @@ pub fn parse_arguments(items: &[syn::NestedMetaItem]) -> Vec<Argument> {
return Vec::new()
}
has_kw = true;
arguments.push(Argument::Arg(name, Some(format!("{}", s))));
arguments.push(Argument::Arg(name, Some(format!("{}", litint.value()))));
}
}
&syn::Lit::Bool(ref b) => {
syn::Lit::Bool(ref litb) => {
if has_varargs {
arguments.push(Argument::Kwarg(name, format!("{}", b)));
arguments.push(Argument::Kwarg(name, format!("{}", litb.value)));
} else {
if has_kwargs {
println!("syntax error, keyword arguments is defined: {:?}",
@ -97,20 +96,20 @@ pub fn parse_arguments(items: &[syn::NestedMetaItem]) -> Vec<Argument> {
return Vec::new()
}
has_kw = true;
arguments.push(Argument::Arg(name, Some(format!("{}", b))));
arguments.push(Argument::Arg(name, Some(format!("{}", litb.value))));
}
}
_ => {
println!("Only string literal is supported, got: {:?}", lit);
println!("Only string literal is supported, got: {:?}", nv.lit);
return Vec::new()
}
}
}
&syn::NestedMetaItem::Literal(ref lit) => {
&syn::NestedMeta::Literal(ref lit) => {
match lit {
&syn::Lit::Str(ref s, _) => {
&syn::Lit::Str(ref lits) => {
// #[args("*")]
if s == "*" {
if lits.value() == "*" {
if has_kwargs {
println!(
"syntax error, keyword arguments is defined: {:?}",
@ -127,7 +126,7 @@ pub fn parse_arguments(items: &[syn::NestedMetaItem]) -> Vec<Argument> {
arguments.push(Argument::VarArgsSeparator);
} else {
println!("Unknown string literal, got: {:?} args: {:?}",
s, args_str);
lits.value(), args_str);
return Vec::new()
}
}
@ -154,11 +153,11 @@ mod test {
use syn;
use args::{Argument, parse_arguments};
fn items(s: &'static str) -> Vec<syn::NestedMetaItem> {
fn items(s: &'static str) -> Vec<syn::NestedMeta> {
let i = syn::parse_outer_attr(s).unwrap();
match i.value {
syn::MetaItem::List(_, items) => {
syn::Meta::List(_, items) => {
items
}
_ => unreachable!()

View File

@ -45,14 +45,17 @@ impl MethodProto {
}
pub fn impl_method_proto(cls: &Box<syn::Ty>,
sig: &mut syn::MethodSig,
meth: &MethodProto) -> Tokens {
pub fn impl_method_proto(
cls: &Box<syn::Type>,
sig: &mut syn::MethodSig,
meth: &MethodProto
) -> Tokens {
let decl = sig.decl.clone();
match *meth {
MethodProto::Free{name: _, proto} => {
let p = syn::Ident::from(proto);
let p: syn::Path = syn::parse_str(proto).unwrap();
return quote! {
impl<'p> #p<'p> for #cls {}
}
@ -61,16 +64,16 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
};
match decl.output {
syn::FunctionRetTy::Ty(ref ty) => {
syn::ReturnType::Type(_, ref ty) => {
match *meth {
MethodProto::Free{name: _, proto: _} => unreachable!(),
MethodProto::Unary{name: _, pyres, proto} => {
let p = syn::Ident::from(proto);
let p: syn::Path = syn::parse_str(proto).unwrap();
let (ty, succ) = get_res_success(ty);
let tmp = extract_decl(syn::parse_item(
quote! {fn test(&self)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
let tmp = extract_decl(parse_quote!{
fn test(&self) -> <#cls as #p<'p>>::Result {}
});
sig.decl.output = tmp.output.clone();
modify_self_ty(sig);
@ -90,25 +93,27 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
}
},
MethodProto::Binary{name: n, arg, pyres, proto} => {
if sig.decl.inputs.len() <= 1 {
println!("Not enough arguments for {}", n);
return Tokens::new();
}
let p = syn::Ident::from(proto);
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg_name = syn::Ident::from(arg);
let arg_ty = get_arg_ty(sig, 1);
let (ty, succ) = get_res_success(ty);
let tmp = extract_decl(syn::parse_item(
quote! {fn test(
&self,
arg: <#cls as #p<'p>>::#arg_name)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
let tmp2 = extract_decl(syn::parse_item(
quote! {fn test(
&self,
arg: Option<<#cls as #p<'p>>::#arg_name>)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
let tmp = extract_decl(
parse_quote!{
fn test(&self,arg: <#cls as #p<'p>>::#arg_name)-> <#cls as #p<'p>>::Result {}
});
let tmp2 = extract_decl(
parse_quote!{
fn test( &self, arg: Option<<#cls as #p<'p>>::#arg_name>) -> <#cls as #p<'p>>::Result {}
});
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_self_ty(sig);
@ -134,7 +139,7 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new();
}
let p = syn::Ident::from(proto);
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 0);
let arg2_name = syn::Ident::from(arg2);
@ -142,16 +147,16 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(syn::parse_item(
quote! {fn test(
let tmp = extract_decl(
parse_quote!{fn test(
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
let tmp2 = extract_decl(syn::parse_item(
quote! {fn test(
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote!{fn test(
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 0, &tmp, &tmp2);
modify_arg_ty(sig, 1, &tmp, &tmp2);
@ -179,7 +184,7 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new();
}
let p = syn::Ident::from(proto);
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 1);
let arg2_name = syn::Ident::from(arg2);
@ -187,18 +192,18 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(syn::parse_item(
quote! {fn test(
let tmp = extract_decl(
parse_quote! {fn test(
&self,
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
let tmp2 = extract_decl(syn::parse_item(
quote! {fn test(
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote! {fn test(
&self,
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_arg_ty(sig, 2, &tmp, &tmp2);
modify_self_ty(sig);
@ -227,7 +232,7 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new();
}
let p = syn::Ident::from(proto);
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 0);
let arg2_name = syn::Ident::from(arg2);
@ -237,18 +242,18 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(syn::parse_item(
quote! {fn test(
let tmp = extract_decl(
parse_quote! {fn test(
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name,
arg3: <#cls as #p<'p>>::#arg3_name)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
let tmp2 = extract_decl(syn::parse_item(
quote! {fn test(
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote! {fn test(
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>,
arg3: Option<<#cls as #p<'p>>::#arg3_name>)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 0, &tmp, &tmp2);
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_arg_ty(sig, 2, &tmp, &tmp2);
@ -279,7 +284,7 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
print_err(format!("Not enough arguments {}", n), quote!(sig));
return Tokens::new();
}
let p = syn::Ident::from(proto);
let p: syn::Path = syn::parse_str(proto).unwrap();
let arg1_name = syn::Ident::from(arg1);
let arg1_ty = get_arg_ty(sig, 1);
let arg2_name = syn::Ident::from(arg2);
@ -289,20 +294,20 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
let (ty, succ) = get_res_success(ty);
// rewrite ty
let tmp = extract_decl(syn::parse_item(
quote! {fn test(
let tmp = extract_decl(
parse_quote! {fn test(
&self,
arg1: <#cls as #p<'p>>::#arg1_name,
arg2: <#cls as #p<'p>>::#arg2_name,
arg3: <#cls as #p<'p>>::#arg3_name)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
let tmp2 = extract_decl(syn::parse_item(
quote! {fn test(
-> <#cls as #p<'p>>::Result {}});
let tmp2 = extract_decl(
parse_quote! {fn test(
&self,
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
arg2: Option<<#cls as #p<'p>>::#arg2_name>,
arg3: Option<<#cls as #p<'p>>::#arg3_name>)
-> <#cls as #p<'p>>::Result {}}.as_str()).unwrap());
-> <#cls as #p<'p>>::Result {}});
modify_arg_ty(sig, 1, &tmp, &tmp2);
modify_arg_ty(sig, 2, &tmp, &tmp2);
modify_arg_ty(sig, 3, &tmp, &tmp2);
@ -326,72 +331,68 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
// TODO: better arg ty detection
fn get_arg_ty(sig: &syn::MethodSig, idx: usize) -> syn::Ty {
fn get_arg_ty(sig: &syn::MethodSig, idx: usize) -> syn::Type {
let mut ty = match sig.decl.inputs[idx] {
syn::FnArg::Captured(_, ref arg_ty) => {
match arg_ty {
&syn::Ty::Path(_, ref path) => {
syn::FnArg::Captured(ref cap) => {
match cap.ty {
syn::Type::Path(ref ty) => {
// use only last path segment for Option<>
let seg = path.segments.last().unwrap().clone();
let seg = ty.path.segments.last().unwrap().value().clone();
if seg.ident.as_ref() == "Option" {
match seg.parameters {
syn::PathParameters::AngleBracketed(ref data) => {
if let Some(ty) = data.types.last() {
return ty.clone()
}
match seg.arguments {
syn::PathArguments::AngleBracketed(ref data) => {
if let Some(pair) = data.args.last() {
match pair.value() {
syn::GenericArgument::Type(ref ty) => return ty.clone(),
_ => panic!("Option only accepted for concrete types"),
}
};
}
_ => (),
}
}
arg_ty.clone()
cap.ty.clone()
},
_ => arg_ty.clone()
_ => cap.ty.clone()
}
},
_ => panic!("fn arg type is not supported"),
};
match ty {
syn::Ty::Rptr(ref mut lifetime, _) => {
match lifetime {
&mut None => {
*lifetime = Some(syn::Lifetime {ident: syn::Ident::from("'p")})
}
_ => (),
}
}
_ => ()
if let syn::Type::Reference(ref mut r) = ty {
r.lifetime.get_or_insert(parse_quote!{'p});
}
ty
}
// Success
fn get_res_success(ty: &syn::Ty) -> (Tokens, syn::Ty) {
fn get_res_success(ty: &syn::Type) -> (Tokens, syn::GenericArgument) {
let mut result;
let mut succ;
match ty {
&syn::Ty::Path(_, ref path) => {
if let Some(segment) = path.segments.last() {
match segment.ident.as_ref() {
&syn::Type::Path(ref typath) => {
if let Some(segment) = typath.path.segments.last() {
match segment.value().ident.as_ref() {
// check for PyResult<T>
"PyResult" => match segment.parameters {
syn::PathParameters::AngleBracketed(ref data) => {
"PyResult" => match segment.value().arguments {
syn::PathArguments::AngleBracketed(ref data) => {
result = true;
succ = data.types[0].clone();
succ = data.args[0].clone();
// check for PyResult<Option<T>>
match data.types[0] {
syn::Ty::Path(_, ref path) =>
if let Some(segment) = path.segments.last() {
match segment.ident.as_ref() {
match data.args[0] {
syn::GenericArgument::Type(syn::Type::Path(ref typath)) =>
if let Some(segment) = typath.path.segments.last() {
match segment.value().ident.as_ref() {
// get T from Option<T>
"Option" => match segment.parameters {
syn::PathParameters::AngleBracketed(ref data) =>
"Option" => match segment.value().arguments {
syn::PathArguments::AngleBracketed(ref data) =>
{
result = false;
succ = data.types[0].clone();
succ = data.args[0].clone();
},
_ => (),
},
@ -404,10 +405,10 @@ fn get_res_success(ty: &syn::Ty) -> (Tokens, syn::Ty) {
_ => panic!("fn result type is not supported"),
},
_ => panic!("fn result type has to be PyResult or (), got {:?}",
segment.ident.as_ref())
segment.value().ident.as_ref())
}
} else {
panic!("fn result is not supported {:?}", path)
panic!("fn result is not supported {:?}", typath)
}
}
_ => panic!("not supported: {:?}", ty),
@ -425,8 +426,8 @@ fn get_res_success(ty: &syn::Ty) -> (Tokens, syn::Ty) {
fn extract_decl(spec: syn::Item) -> syn::FnDecl {
match spec.node {
syn::ItemKind::Fn(decl, _, _, _, _, _) => *decl,
match spec {
syn::Item::Fn(f) => *f.decl,
_ => panic!()
}
}
@ -437,18 +438,18 @@ fn modify_arg_ty(sig: &mut syn::MethodSig, idx: usize,
{
let arg = sig.decl.inputs[idx].clone();
match arg {
syn::FnArg::Captured(ref pat, ref arg_ty) => {
match arg_ty {
&syn::Ty::Path(_, ref path) => {
let seg = path.segments.last().unwrap().clone();
syn::FnArg::Captured(ref cap) => {
match cap.ty {
syn::Type::Path(ref typath) => {
let seg = typath.path.segments.last().unwrap().value().clone();
if seg.ident.as_ref() == "Option" {
sig.decl.inputs[idx] = fix_name(pat, &decl2.inputs[idx]);
sig.decl.inputs[idx] = fix_name(&cap.pat, &decl2.inputs[idx]);
} else {
sig.decl.inputs[idx] = fix_name(pat, &decl1.inputs[idx]);
sig.decl.inputs[idx] = fix_name(&cap.pat, &decl1.inputs[idx]);
}
},
_ => {
sig.decl.inputs[idx] = fix_name(pat, &decl1.inputs[idx]);
sig.decl.inputs[idx] = fix_name(&cap.pat, &decl1.inputs[idx]);
}
}
},
@ -458,20 +459,22 @@ fn modify_arg_ty(sig: &mut syn::MethodSig, idx: usize,
sig.decl.output = decl1.output.clone();
}
fn modify_self_ty(sig: &mut syn::MethodSig)
{
match sig.decl.inputs[0] {
syn::FnArg::SelfRef(ref mut lifetime, _) => {
*lifetime = Some(syn::Lifetime {ident: syn::Ident::from("'p")})
},
_ => panic!("not supported"),
fn modify_self_ty(sig: &mut syn::MethodSig) {
if let syn::FnArg::SelfRef(ref mut r) = sig.decl.inputs[0] {
r.lifetime = Some(parse_quote!{'p});
} else {
panic!("not supported")
}
}
fn fix_name(pat: &syn::Pat, arg: &syn::FnArg) -> syn::FnArg {
match arg {
&syn::FnArg::Captured(_, ref arg_ty) =>
syn::FnArg::Captured(pat.clone(), arg_ty.clone()),
_ => panic!("func.rs::296"),
if let syn::FnArg::Captured(ref cap) = arg {
syn::FnArg::Captured(syn::ArgCaptured {
pat: pat.clone(),
colon_token: cap.colon_token,
ty: cap.ty.clone(),
})
} else {
panic!("func.rs::296")
}
}

View File

@ -6,6 +6,7 @@
extern crate log;
#[macro_use]
extern crate quote;
#[macro_use]
extern crate syn;
extern crate proc_macro;

View File

@ -1,17 +1,20 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use args::{Argument, parse_arguments};
use quote::{Ident, Tokens};
use syn;
use quote::Tokens;
use quote::ToTokens;
use args::{Argument, parse_arguments};
use utils::for_err_msg;
#[derive(Clone, PartialEq, Debug)]
pub struct FnArg<'a> {
pub name: &'a syn::Ident,
pub mode: &'a syn::BindingMode,
pub ty: &'a syn::Ty,
pub optional: Option<&'a syn::Ty>,
pub by_ref: &'a Option<syn::token::Ref>,
pub mutability: &'a Option<syn::token::Mut>,
pub ty: &'a syn::Type,
pub optional: Option<&'a syn::Type>,
pub py: bool,
pub reference: bool,
}
@ -33,16 +36,18 @@ pub struct FnSpec<'a> {
pub tp: FnType,
pub attrs: Vec<Argument>,
pub args: Vec<FnArg<'a>>,
pub output: syn::Ty,
pub output: syn::Type,
}
pub fn get_return_info(output: &syn::FunctionRetTy) -> syn::Ty {
pub fn get_return_info(output: &syn::ReturnType) -> syn::Type {
match output {
&syn::FunctionRetTy::Default => syn::Ty::Tup(vec![]),
&syn::FunctionRetTy::Ty(ref ty) => ty.clone()
syn::ReturnType::Default => syn::Type::Infer(parse_quote!{_}),
syn::ReturnType::Type(_, ref ty) => *ty.clone()
}
}
impl<'a> FnSpec<'a> {
/// Parser function signature and function attributes
pub fn parse(name: &'a syn::Ident,
@ -55,30 +60,30 @@ impl<'a> FnSpec<'a> {
for input in sig.decl.inputs.iter() {
match input {
&syn::FnArg::SelfRef(_, _) => {
&syn::FnArg::SelfRef(_) => {
has_self = true;
},
&syn::FnArg::SelfValue(_) => {
has_self = true;
}
&syn::FnArg::Captured(ref pat, ref ty) => {
&syn::FnArg::Captured(syn::ArgCaptured {ref pat, ref ty, ..}) => {
// skip first argument (cls)
if (fn_type == FnType::FnClass || fn_type == FnType::FnNew) && !has_self {
has_self = true;
continue
}
let (mode, ident) = match pat {
&syn::Pat::Ident(ref mode, ref ident, _) =>
(mode, ident),
let (ident, by_ref, mutability) = match pat {
&syn::Pat::Ident(syn::PatIdent {ref ident, ref by_ref, ref mutability, .. }) =>
(ident, by_ref, mutability),
_ =>
panic!("unsupported argument: {:?}", pat),
};
let py = match ty {
&syn::Ty::Path(_, ref path) =>
&syn::Type::Path(syn::TypePath {ref path, ..}) =>
if let Some(segment) = path.segments.last() {
segment.ident.as_ref() == "Python"
segment.value().ident.as_ref() == "Python"
} else {
false
},
@ -89,7 +94,9 @@ impl<'a> FnSpec<'a> {
arguments.push(
FnArg {
name: ident,
mode: mode,
by_ref,
mutability,
// mode: mode,
ty: ty,
optional: opt,
py: py,
@ -99,6 +106,8 @@ impl<'a> FnSpec<'a> {
}
&syn::FnArg::Ignored(_) =>
panic!("ignored argument: {:?}", name),
&syn::FnArg::Inferred(_) =>
panic!("ingerred argument: {:?}", name),
}
}
@ -161,15 +170,15 @@ impl<'a> FnSpec<'a> {
Argument::Arg(ref ident, ref opt) => {
if ident.as_str() == name.as_ref() {
if let &Some(ref val) = opt {
let i = Ident::from(val.as_str());
return Some(quote!(#i))
let i: syn::Expr = syn::parse_str(&val).unwrap();
return Some(i.into_tokens())
}
}
},
Argument::Kwarg(ref ident, ref opt) => {
if ident.as_str() == name.as_ref() {
let i = Ident::from(opt.as_str());
return Some(quote!(#i))
let i: syn::Expr = syn::parse_str(&opt).unwrap();
return Some(i.into_tokens())
}
},
_ => (),
@ -193,25 +202,25 @@ impl<'a> FnSpec<'a> {
}
}
pub fn is_ref<'a>(name: &'a syn::Ident, ty: &'a syn::Ty) -> bool {
pub fn is_ref<'a>(name: &'a syn::Ident, ty: &'a syn::Type) -> bool {
match ty {
&syn::Ty::Rptr(_, _) => {
&syn::Type::Reference(_) => {
return true
}
&syn::Ty::Path(_, ref path) => {
&syn::Type::Path(syn::TypePath {ref path, ..}) => {
if let Some(segment) = path.segments.last() {
match segment.ident.as_ref() {
match segment.value().ident.as_ref() {
"Option" => {
match segment.parameters {
syn::PathParameters::AngleBracketed(ref params) => {
if params.types.len() != 1 {
match segment.value().arguments {
syn::PathArguments::AngleBracketed(ref params) => {
if params.args.len() != 1 {
panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
for_err_msg(name),
for_err_msg(ty),
for_err_msg(path));
}
match &params.types[params.types.len()-1] {
&syn::Ty::Rptr(_, _) => {
match &params.args[params.args.len()-1] {
&syn::GenericArgument::Type(syn::Type::Reference(_)) => {
return true
},
_ => ()
@ -234,28 +243,36 @@ pub fn is_ref<'a>(name: &'a syn::Ident, ty: &'a syn::Ty) -> bool {
false
}
pub fn check_arg_ty_and_optional<'a>(name: &'a syn::Ident, ty: &'a syn::Ty)
-> Option<&'a syn::Ty>
pub fn check_arg_ty_and_optional<'a>(name: &'a syn::Ident, ty: &'a syn::Type)
-> Option<&'a syn::Type>
{
match ty {
&syn::Ty::Path(_, ref path) => {
&syn::Type::Path(syn::TypePath {ref path, ..}) => {
//if let &Some(ref qs) = qs {
// panic!("explicit Self type in a 'qualified path' is not supported: {:?} - {:?}",
// name, qs);
//}
if let Some(segment) = path.segments.last() {
match segment.ident.as_ref() {
match segment.value().ident.as_ref() {
"Option" => {
match segment.parameters {
syn::PathParameters::AngleBracketed(ref params) => {
if params.types.len() != 1 {
match segment.value().arguments {
syn::PathArguments::AngleBracketed(ref params) => {
if params.args.len() != 1 {
panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
for_err_msg(name),
for_err_msg(ty),
for_err_msg(path));
}
Some(&params.types[0])
match &params.args[0] {
&syn::GenericArgument::Type(ref ty) => Some(ty),
_ => panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
for_err_msg(name),
for_err_msg(ty),
for_err_msg(path)),
}
},
_ => {
panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
@ -286,8 +303,8 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> (FnType, Vec<Argument>)
let mut res: Option<FnType> = None;
for attr in attrs.iter() {
match attr.value {
syn::MetaItem::Word(ref name) => {
match attr.interpret_meta().unwrap() {
syn::Meta::Word(ref name) => {
match name.as_ref() {
"new" | "__new__" => {
res = Some(FnType::FnNew)
@ -305,7 +322,7 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> (FnType, Vec<Argument>)
res = Some(FnType::FnStatic)
},
"setter" | "getter" => {
if attr.style == syn::AttrStyle::Inner {
if let syn::AttrStyle::Inner(_) = attr.style {
panic!("Inner style attribute is not
supported for setter and getter");
}
@ -323,8 +340,8 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> (FnType, Vec<Argument>)
}
}
},
syn::MetaItem::List(ref name, ref meta) => {
match name.as_ref() {
syn::Meta::List(syn::MetaList {ref ident, ref nested, ..}) => {
match ident.as_ref() {
"new" => {
res = Some(FnType::FnNew)
},
@ -335,31 +352,31 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> (FnType, Vec<Argument>)
res = Some(FnType::FnCall)
},
"setter" | "getter" => {
if attr.style == syn::AttrStyle::Inner {
if let syn::AttrStyle::Inner(_) = attr.style {
panic!("Inner style attribute is not
supported for setter and getter");
}
if res != None {
panic!("setter/getter attribute can not be used mutiple times");
}
if meta.len() != 1 {
if nested.len() != 1 {
panic!("setter/getter requires one value");
}
match *meta.first().unwrap() {
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(ref w)) => {
if name.as_ref() == "setter" {
match nested.first().unwrap().value() {
syn::NestedMeta::Meta(syn::Meta::Word(ref w)) => {
if ident.as_ref() == "setter" {
res = Some(FnType::Setter(Some(w.to_string())))
} else {
res = Some(FnType::Getter(Some(w.to_string())))
}
},
syn::NestedMetaItem::Literal(ref lit) => {
syn::NestedMeta::Literal(ref lit) => {
match *lit {
syn::Lit::Str(ref s, syn::StrStyle::Cooked) => {
if name.as_ref() == "setter" {
res = Some(FnType::Setter(Some(s.clone())))
syn::Lit::Str(ref s) => {
if ident.as_ref() == "setter" {
res = Some(FnType::Setter(Some(s.value())))
} else {
res = Some(FnType::Getter(Some(s.clone())))
res = Some(FnType::Getter(Some(s.value())))
}
},
_ => {
@ -368,19 +385,20 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> (FnType, Vec<Argument>)
}
}
_ => {
println!("cannot parse {:?} attribute: {:?}", name, meta);
println!("cannot parse {:?} attribute: {:?}", ident, nested);
},
}
},
"args" => {
spec.extend(parse_arguments(meta.as_slice()))
let args = nested.iter().cloned().collect::<Vec<_>>();
spec.extend(parse_arguments(args.as_slice()))
}
_ => {
new_attrs.push(attr.clone())
}
}
},
syn::MetaItem::NameValue(_, _) => {
syn::Meta::NameValue(_) => {
new_attrs.push(attr.clone())
},
}

View File

@ -10,8 +10,10 @@ use utils;
/// Generates the function that is called by the python interpreter to initialize the native
/// module
pub fn py3_init(fnname: &syn::Ident, name: &String, doc: syn::Lit) -> Tokens {
let m_name = syn::Ident::from(name.trim().as_ref());
let cb_name = syn::Ident::from(format!("PyInit_{}", name.trim()).as_ref());
let m_name: syn::Ident = syn::parse_str(name.trim().as_ref()).unwrap();
let cb_name: syn::Ident = syn::parse_str(&format!("PyInit_{}", name.trim())).unwrap();
quote! {
#[no_mangle]
#[allow(non_snake_case, unused_imports)]
@ -57,8 +59,8 @@ pub fn py3_init(fnname: &syn::Ident, name: &String, doc: syn::Lit) -> Tokens {
}
pub fn py2_init(fnname: &syn::Ident, name: &String, doc: syn::Lit) -> Tokens {
let m_name = syn::Ident::from(name.trim().as_ref());
let cb_name = syn::Ident::from(format!("init{}", name.trim()).as_ref());
let m_name: syn::Ident = syn::parse_str(name.trim().as_ref()).unwrap();
let cb_name: syn::Ident = syn::parse_str(&format!("PyInit_{}", name.trim())).unwrap();
quote! {
#[no_mangle]
@ -96,35 +98,29 @@ pub fn py2_init(fnname: &syn::Ident, name: &String, doc: syn::Lit) -> Tokens {
/// Finds and takes care of the #[pyfn(...)] in #[modinit(...)]
pub fn process_functions_in_module(ast: &mut syn::Item) {
if let syn::ItemKind::Fn(_, _, _, _, _, ref mut block) = ast.node {
if let syn::Item::Fn(ref mut func) = ast {
let mut stmts: Vec<syn::Stmt> = Vec::new();
for stmt in block.stmts.iter_mut() {
if let &mut syn::Stmt::Item(ref mut item) = stmt {
for stmt in func.block.stmts.iter_mut() {
if let syn::Stmt::Item(syn::Item::Fn(ref mut func)) = stmt {
if let Some((module_name, python_name, pyfn_attrs)) =
extract_pyfn_attrs(&mut item.attrs)
extract_pyfn_attrs(&mut func.attrs)
{
let function_to_python = add_fn_to_module(item, &python_name, pyfn_attrs);
let function_wrapper_ident = function_wrapper_ident(&item.ident);
let tokens = quote! {
let function_to_python = add_fn_to_module(func, &python_name, pyfn_attrs);
let function_wrapper_ident = function_wrapper_ident(&func.ident);
let item: syn::ItemFn = parse_quote!{
fn block_wrapper() {
#function_to_python
#module_name.add_function(&#function_wrapper_ident);
}
}.to_string();
let item = syn::parse_item(tokens.as_str()).unwrap();
let block = match item.node {
syn::ItemKind::Fn(_, _, _, _, _, ref block) => block.clone(),
_ => unreachable!(),
};
stmts.extend(block.stmts.into_iter());
stmts.extend(item.block.stmts.into_iter());
}
};
stmts.push(stmt.clone());
}
block.stmts = stmts;
func.block.stmts = stmts;
} else {
panic!("#[modinit] can only be used with fn block");
}
@ -133,33 +129,38 @@ pub fn process_functions_in_module(ast: &mut syn::Item) {
/// Transforms a rust fn arg parsed with syn into a method::FnArg
fn wrap_fn_argument<'a>(input: &'a syn::FnArg, name: &'a syn::Ident) -> Option<method::FnArg<'a>> {
match input {
&syn::FnArg::SelfRef(_, _) | &syn::FnArg::SelfValue(_) => None,
&syn::FnArg::Captured(ref pat, ref ty) => {
let (mode, ident) = match pat {
&syn::Pat::Ident(ref mode, ref ident, _) => (mode, ident),
_ => panic!("unsupported argument: {:?}", pat),
&syn::FnArg::SelfRef(_) | &syn::FnArg::SelfValue(_) => None,
&syn::FnArg::Captured(ref cap) => {
let (mutability, by_ref, ident) = match cap.pat {
syn::Pat::Ident(ref patid) =>
(&patid.mutability, &patid.by_ref, &patid.ident),
_ =>
panic!("unsupported argument: {:?}", cap.pat),
};
let py = match ty {
&syn::Ty::Path(_, ref path) => if let Some(segment) = path.segments.last() {
segment.ident.as_ref() == "Python"
} else {
false
},
let py = match cap.ty {
syn::Type::Path(ref typath) => {
typath.path.segments.last()
.map(|seg| seg.value().ident == "Python")
.unwrap_or(false)
}
_ => false,
};
let opt = method::check_arg_ty_and_optional(&name, ty);
let opt = method::check_arg_ty_and_optional(&name, &cap.ty);
Some(method::FnArg {
name: ident,
mode,
ty,
mutability: mutability,
by_ref: by_ref,
ty: &cap.ty,
optional: opt,
py,
reference: method::is_ref(&name, ty),
reference: method::is_ref(&name, &cap.ty),
})
}
&syn::FnArg::Ignored(_) => panic!("ignored argument: {:?}", name),
&syn::FnArg::Inferred(_) => panic!("inferred argument: {:?}", name),
}
}
@ -173,67 +174,64 @@ fn extract_pyfn_attrs(
let mut fn_attrs = Vec::new();
for attr in attrs.iter() {
if let syn::MetaItem::List(ref name, ref meta) = attr.value {
if name.as_ref() == "pyfn" {
match attr.interpret_meta() {
Some(syn::Meta::List(ref list)) if list.ident == "pyfn" => {
let meta: Vec<_> = list.nested.iter().cloned().collect();
if meta.len() >= 2 {
// read module name
match meta[0] {
syn::NestedMetaItem::MetaItem(syn::MetaItem::Word(ref ident)) => {
modname = Some(ident.clone());
}
syn::NestedMeta::Meta(syn::Meta::Word(ref ident)) =>
modname = Some(ident.clone()),
_ => panic!("The first parameter of pyfn must be a MetaItem"),
}
// read Python fonction name
match meta[1] {
syn::NestedMetaItem::Literal(syn::Lit::Str(ref s, _)) => {
fnname = Some(syn::Ident::from(s.as_str()));
syn::NestedMeta::Literal(syn::Lit::Str(ref lits)) => {
fnname = Some(syn::parse_str(&lits.value()).unwrap());
}
_ => panic!("The second parameter of pyfn must be a Literal"),
}
if meta.len() >= 3 {
// Read additional arguments
if list.nested.len() >= 3 {
fn_attrs = args::parse_arguments(&meta[2..meta.len()]);
}
} else {
panic!("can not parse 'pyfn' params {:?}", attr);
}
continue;
}
};
new_attrs.push(attr.clone())
_ => new_attrs.push(attr.clone()),
}
}
attrs.clear();
attrs.extend(new_attrs);
*attrs = new_attrs;
// attrs.clear();
// attrs.extend(new_attrs);
Some((modname?, fnname?, fn_attrs))
}
/// Coordinates the naming of a the add-function-to-python-module function
fn function_wrapper_ident(name: &syn::Ident) -> syn::Ident {
// Make sure this ident matches the one of wrap_function
syn::Ident::new("__pyo3_get_function_".to_string() + &name.to_string())
syn::parse_str(&format!("__pyo3_get_function_{}", &name)).unwrap()
}
/// Generates python wrapper over a function that allows adding it to a python module as a python
/// function
pub fn add_fn_to_module(
item: &mut syn::Item,
func: &mut syn::ItemFn,
python_name: &syn::Ident,
pyfn_attrs: Vec<args::Argument>,
) -> Tokens {
let name = item.ident.clone();
let decl = if let syn::ItemKind::Fn(ref decl, _, _, _, _, _) = item.node {
decl.clone()
} else {
panic!("Expected a function")
};
let mut arguments = Vec::new();
for input in decl.inputs.iter() {
if let Some(fn_arg) = wrap_fn_argument(input, &name) {
for input in func.decl.inputs.iter() {
if let Some(fn_arg) = wrap_fn_argument(input, &func.ident) {
arguments.push(fn_arg);
}
}
let ty = method::get_return_info(&decl.output);
let ty = method::get_return_info(&func.decl.output);
let spec = method::FnSpec {
tp: method::FnType::Fn,
@ -242,12 +240,12 @@ pub fn add_fn_to_module(
output: ty,
};
let function_wrapper_ident = function_wrapper_ident(&name);
let function_wrapper_ident = function_wrapper_ident(&func.ident);
let wrapper = function_c_wrapper(&name, &spec);
let doc = utils::get_doc(&item.attrs, true);
let wrapper = function_c_wrapper(&func.ident, &spec);
let doc = utils::get_doc(&func.attrs, true);
let tokens = quote! (
let tokens = quote! {
fn #function_wrapper_ident(py: ::pyo3::Python) -> ::pyo3::PyObject {
use std;
use pyo3 as _pyo3;
@ -274,7 +272,7 @@ pub fn add_fn_to_module(
function
}
);
};
tokens
}

View File

@ -11,17 +11,22 @@ use method::{FnType, FnSpec, FnArg};
use py_method::{impl_wrap_getter, impl_wrap_setter, impl_py_getter_def, impl_py_setter_def};
pub fn build_py_class(ast: &mut syn::DeriveInput, attr: String) -> Tokens {
pub fn build_py_class(
ast: &mut syn::DeriveInput,
attr: &Vec<syn::Expr>
) -> Tokens {
let (params, flags, base) = parse_attribute(attr);
let doc = utils::get_doc(&ast.attrs, true);
let mut token: Option<syn::Ident> = None;
let mut descriptors = Vec::new();
match ast.body {
syn::Body::Struct(syn::VariantData::Struct(ref mut fields)) => {
for field in fields.iter_mut() {
if let syn::Data::Struct(ref mut struc) = ast.data {
if let syn::Fields::Named(ref mut fields) = struc.fields {
for field in fields.named.iter_mut() {
if is_python_token(field) {
token = field.ident.clone();
break
break;
} else {
let field_descs = parse_descriptors(field);
if !field_descs.is_empty() {
@ -29,11 +34,14 @@ pub fn build_py_class(ast: &mut syn::DeriveInput, attr: String) -> Tokens {
}
}
}
},
_ => panic!("#[class] can only be used with normal structs"),
} else {
panic!("#[class] can only be used with C-style structs")
}
} else {
panic!("#[class] can only be used with structs")
}
let dummy_const = syn::Ident::new(format!("_IMPL_PYO3_CLS_{}", ast.ident));
let dummy_const = syn::Ident::from(format!("_IMPL_PYO3_CLS_{}", ast.ident));
let tokens = impl_class(&ast.ident, &base, token, doc, params, flags, descriptors);
quote! {
@ -52,37 +60,29 @@ fn parse_descriptors(item: &mut syn::Field) -> Vec<FnType> {
let mut descs = Vec::new();
let mut new_attrs = Vec::new();
for attr in item.attrs.iter() {
match attr.value {
syn::MetaItem::List(ref name, ref metas) => {
match name.as_ref() {
"prop" => {
for meta in metas.iter() {
match *meta {
syn::NestedMetaItem::MetaItem(ref metaitem) => {
match metaitem.name() {
"get" => {
descs.push(FnType::Getter(None));
}
"set" => {
descs.push(FnType::Setter(None));
}
_ => {
panic!("Only getter and setter supported");
}
}
if let Some(syn::Meta::List(ref list)) = attr.interpret_meta() {
match list.ident.as_ref() {
"prop" => {
for meta in list.nested.iter() {
if let &syn::NestedMeta::Meta(ref metaitem) = meta {
match metaitem.name().as_ref() {
"get" => {
descs.push(FnType::Getter(None));
}
"set" => {
descs.push(FnType::Setter(None));
}
_ => {
panic!("Only getter and setter supported");
}
_ => ()
}
}
}
_ => {
new_attrs.push(attr.clone());
}
}
_ => new_attrs.push(attr.clone()),
}
_ => {
new_attrs.push(attr.clone());
}
} else {
new_attrs.push(attr.clone());
}
}
item.attrs.clear();
@ -90,14 +90,19 @@ fn parse_descriptors(item: &mut syn::Field) -> Vec<FnType> {
descs
}
fn impl_class(cls: &syn::Ident, base: &syn::Ident,
token: Option<syn::Ident>, doc: syn::Lit,
params: HashMap<&'static str, syn::Ident>,
flags: Vec<syn::Ident>,
descriptors: Vec<(syn::Field, Vec<FnType>)>) -> Tokens {
fn impl_class(
cls: &syn::Ident,
base: &syn::TypePath,
token: Option<syn::Ident>,
doc: syn::Lit,
params: HashMap<&'static str, syn::Expr>,
flags: Vec<syn::Expr>,
descriptors: Vec<(syn::Field, Vec<FnType>)>
) -> Tokens {
let cls_name = match params.get("name") {
Some(name) => quote! { #name }.as_str().to_string(),
None => quote! { #cls }.as_str().to_string()
Some(name) => quote! { #name }.to_string(),
None => quote! { #cls }.to_string()
};
let extra = if let Some(token) = token {
@ -197,7 +202,7 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
};
let extra = if !descriptors.is_empty() {
let ty = syn::parse::ty(cls.as_ref()).expect("no name");
let ty = syn::parse_str(cls.as_ref()).expect("no name");
let desc_impls = impl_descriptors(&ty, descriptors);
Some(quote! {
#desc_impls
@ -211,21 +216,23 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
let mut has_weakref = false;
let mut has_dict = false;
for f in flags.iter() {
if *f == syn::Ident::from("_pyo3::typeob::PY_TYPE_FLAG_WEAKREF") {
has_weakref = true;
} else if *f == syn::Ident::from("_pyo3::typeob::PY_TYPE_FLAG_DICT") {
has_dict = true;
if let syn::Expr::Path(ref epath) = f {
if epath.path == parse_quote!{_pyo3::typeob::PY_TYPE_FLAG_WEAKREF} {
has_weakref = true;
} else if epath.path == parse_quote!{_pyo3::typeob::PY_TYPE_FLAG_DICT} {
has_dict = true;
}
}
}
let weakref = if has_weakref {
syn::Ident::from("std::mem::size_of::<*const _pyo3::ffi::PyObject>()")
quote!{std::mem::size_of::<*const _pyo3::ffi::PyObject>()}
} else {
syn::Ident::from("0")
quote!{0}
};
let dict = if has_dict {
syn::Ident::from("std::mem::size_of::<*const _pyo3::ffi::PyObject>()")
quote!{std::mem::size_of::<*const _pyo3::ffi::PyObject>()}
} else {
syn::Ident::from("0")
quote!{0}
};
quote! {
@ -239,7 +246,7 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
const SIZE: usize = {
Self::OFFSET as usize +
std::mem::size_of::<#cls>() + #weakref + #dict
std::mem::size_of::<#cls>() + #weakref + #dict
};
const OFFSET: isize = {
// round base_size up to next multiple of align
@ -268,13 +275,11 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
let gil = _pyo3::Python::acquire_gil();
let py = gil.python();
let error_message = "An error occurred while initializing class ".to_string() +
<#cls as _pyo3::typeob::PyTypeInfo>::NAME.as_ref();
// automatically initialize the class on-demand
_pyo3::typeob::initialize_type::<#cls>(py, None)
.map_err(|e| e.print(py))
.expect(&error_message);
.expect(format!("An error occurred while initializing class {}",
<#cls as _pyo3::typeob::PyTypeInfo>::NAME).as_ref());
}
});
}
@ -284,7 +289,11 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
}
}
fn impl_descriptors(cls: &syn::Ty, descriptors: Vec<(syn::Field, Vec<FnType>)>) -> Tokens {
fn impl_descriptors(
cls: &syn::Type,
descriptors: Vec<(syn::Field, Vec<FnType>)>
) -> Tokens {
let methods: Vec<Tokens> = descriptors.iter().flat_map(|&(ref field, ref fns)| {
fns.iter().map(|desc| {
let name = field.ident.clone().unwrap();
@ -318,30 +327,37 @@ fn impl_descriptors(cls: &syn::Ty, descriptors: Vec<(syn::Field, Vec<FnType>)>)
let py_methods: Vec<Tokens> = descriptors.iter().flat_map(|&(ref field, ref fns)| {
fns.iter().map(|desc| {
let name = field.ident.clone().unwrap();
// FIXME better doc?
let doc = syn::Lit::from(name.as_ref());
let doc: syn::Lit = syn::parse_str(&format!("\"{}\"", name)).unwrap();
let field_ty = &field.ty;
match *desc {
FnType::Getter(ref getter) => {
impl_py_getter_def(&name, doc, getter, &impl_wrap_getter(&Box::new(cls.clone()), &name))
}
FnType::Setter(ref setter) => {
let mode = syn::BindingMode::ByValue(syn::Mutability::Immutable);
let setter_name = syn::Ident::from(format!("set_{}", name));
let spec = FnSpec {
tp: FnType::Setter(None),
attrs: Vec::new(),
args: vec![FnArg {
name: &name,
mode: &mode,
mutability: &None,
by_ref: &None,
ty: field_ty,
optional: None,
py: true,
reference: false
}],
output: syn::parse::ty("PyResult<()>").expect("error parse PyResult<()>"),
output: syn::parse_str("PyResult<()>").unwrap()
};
impl_py_setter_def(&name, doc, setter, &impl_wrap_setter(&Box::new(cls.clone()), &setter_name, &spec))
impl_py_setter_def(
&name,
doc,
setter,
&impl_wrap_setter(&Box::new(cls.clone()), &setter_name, &spec)
)
},
_ => unreachable!()
}
@ -362,13 +378,13 @@ fn impl_descriptors(cls: &syn::Ty, descriptors: Vec<(syn::Field, Vec<FnType>)>)
};
let n = match cls {
&syn::Ty::Path(_, ref p) => {
p.segments.last().as_ref().unwrap().ident.as_ref()
&syn::Type::Path(ref typath) => {
typath.path.segments.last().as_ref().unwrap().value().ident.as_ref()
}
_ => "CLS_METHODS"
};
let dummy_const = syn::Ident::new(format!("_IMPL_PYO3_DESCRIPTORS_{}", n));
let dummy_const = syn::Ident::from(format!("_IMPL_PYO3_DESCRIPTORS_{}", n));
quote! {
#[feature(specialization)]
#[allow(non_upper_case_globals, unused_attributes,
@ -383,9 +399,9 @@ fn impl_descriptors(cls: &syn::Ty, descriptors: Vec<(syn::Field, Vec<FnType>)>)
fn is_python_token(field: &syn::Field) -> bool {
match field.ty {
syn::Ty::Path(_, ref path) => {
if let Some(segment) = path.segments.last() {
return segment.ident.as_ref() == "PyToken"
syn::Type::Path(ref typath) => {
if let Some(segment) = typath.path.segments.last() {
return segment.value().ident.as_ref() == "PyToken"
}
}
_ => (),
@ -393,137 +409,95 @@ fn is_python_token(field: &syn::Field) -> bool {
return false
}
fn parse_attribute(mut attr: String) -> (HashMap<&'static str, syn::Ident>,
Vec<syn::Ident>, syn::Ident) {
fn parse_attribute(
args: &Vec<syn::Expr>,
) -> (
HashMap<&'static str, syn::Expr>,
Vec<syn::Expr>,
syn::TypePath
) {
let mut params = HashMap::new();
let mut flags = vec![syn::Ident::from("0")];
let mut base = syn::Ident::from("_pyo3::PyObjectRef");
let mut flags = vec![syn::Expr::Lit(parse_quote!{0})];
let mut base: syn::TypePath = parse_quote!{_pyo3::PyObjectRef};
// https://github.com/rust-lang/rust/pull/50120 removed the parantheses from
// the attr TokenStream, so we need to re-add them manually
// Old nightly (like 2018-04-05): ( name=CustomName )
// New nightly (like 2018-04-28): name=CustomName
if attr.len() > 0 && !attr.starts_with("(") {
attr = format!("({})", attr);
}
for expr in args.iter() {
match expr {
if let Ok(tts) = syn::parse_token_trees(&attr) {
let mut elem = Vec::new();
let mut elems = Vec::new();
for tt in tts.iter() {
match tt {
&syn::TokenTree::Token(ref token) => {
println!("Wrong format: Expected delimited, found token: {:?} {:?}", attr.to_string(), token);
}
&syn::TokenTree::Delimited(ref delimited) => {
for tt in delimited.tts.iter() {
match tt {
&syn::TokenTree::Token(syn::Token::Comma) => {
let el = std::mem::replace(&mut elem, Vec::new());
elems.push(el);
},
_ => elem.push(tt.clone())
}
// Match a single flag
syn::Expr::Path(ref exp) if exp.path.segments.len() == 1 => {
match exp.path.segments.first().unwrap().value().ident.as_ref() {
"gc" => {
flags.push(syn::Expr::Path(parse_quote!{_pyo3::typeob::PY_TYPE_FLAG_GC}));
}
"weakref" => {
flags.push(syn::Expr::Path(parse_quote!{_pyo3::typeob::PY_TYPE_FLAG_WEAKREF}));
}
"subclass" => {
flags.push(syn::Expr::Path(parse_quote!{_pyo3::typeob::PY_TYPE_FLAG_BASETYPE}));
}
"dict" => {
flags.push(syn::Expr::Path(parse_quote!{_pyo3::typeob::PY_TYPE_FLAG_DICT}));
}
param => {
println!("Unsupported parameter: {}", param);
}
}
}
}
if !elem.is_empty() {
elems.push(elem);
}
for elem in elems {
let key = match elem[0] {
syn::TokenTree::Token(syn::Token::Ident(ref ident)) => {
ident.as_ref().to_owned().to_lowercase()
},
_ => {
println!("Wrong format: Expected Token: {:?}", attr.to_string());
continue
}
};
// Match a key/value flag
syn::Expr::Assign(ref ass) => {
if elem.len() == 1 {
match key.as_ref() {
"gc" => {
flags.push(syn::Ident::from("_pyo3::typeob::PY_TYPE_FLAG_GC"));
continue
let key = match *ass.left {
syn::Expr::Path(ref exp) if exp.path.segments.len() == 1 => {
exp.path.segments.first().unwrap().value().ident.as_ref()
}
"weakref" => {
flags.push(syn::Ident::from("_pyo3::typeob::PY_TYPE_FLAG_WEAKREF"));
continue
}
"subclass" => {
flags.push(syn::Ident::from("_pyo3::typeob::PY_TYPE_FLAG_BASETYPE"));
continue
}
"dict" => {
flags.push(syn::Ident::from("_pyo3::typeob::PY_TYPE_FLAG_DICT"));
continue
_ => panic!("could not parse argument: {:?}", ass)
};
match key {
"freelist" => {
// TODO: check if int literal
params.insert("freelist", *ass.right.clone());
},
"name" => {
match *ass.right {
syn::Expr::Path(ref exp) if exp.path.segments.len() == 1 => {
params.insert("name", exp.clone().into());
},
_ => println!("Wrong 'name' format: {:?}", *ass.right),
}
},
"base" => {
match *ass.right {
syn::Expr::Path(ref exp) => {
base = syn::TypePath{
path: exp.path.clone(),
qself: None,
};
},
_ => println!("Wrong 'base' format: {:?}", *ass.right),
}
}
_ => {
println!("Unsupported parameter: {:?}", key);
}
}
}
if elem.len() < 3 {
println!("Wrong format: Less than three elements{:?}", elem);
continue
}
match elem[1] {
syn::TokenTree::Token(syn::Token::Eq) => (),
_ => {
println!("Wrong format: Expected a Token as fist element: {:?}", attr.to_string());
continue
}
}
match key.as_ref() {
"freelist" => {
if elem.len() != 3 {
println!("Wrong 'freelist' format: {:?}", elem);
} else {
match elem[2] {
syn::TokenTree::Token(
syn::Token::Literal(
syn::Lit::Int(val, _))) => {
params.insert("freelist", syn::Ident::from(val.to_string()));
}
_ => println!("Wrong 'freelist' format: {:?}", elem)
}
}
},
"name" => {
if elem.len() != 3 {
println!("Wrong 'name' format: {:?}", elem);
} else {
match elem[2] {
syn::TokenTree::Token(syn::Token::Ident(ref ident)) => {
params.insert("name", ident.clone());
},
_ => println!("Wrong 'name' format: {:?}", elem)
}
}
},
"base" => {
let mut m = String::new();
for el in elem[2..elem.len()].iter() {
let mut t = Tokens::new();
el.to_tokens(&mut t);
m += t.as_str().trim();
}
base = syn::Ident::from(m.as_str());
},
_ => {
println!("Unsupported parameter: {:?}", key);
}
}
_ => panic!("could not parse arguments"),
}
}
(params, flags, base)
}

View File

@ -7,29 +7,25 @@ use py_method;
pub fn build_py_methods(ast: &mut syn::Item) -> Tokens {
match ast.node {
syn::ItemKind::Impl(_, _, _, ref path, ref ty, ref mut impl_items) => {
if let &Some(_) = path {
panic!("#[methods] can not be used only with trait impl block");
} else {
impl_methods(ty, impl_items)
}
},
_ => panic!("#[methods] can only be used with Impl blocks"),
if let syn::Item::Impl(ref mut iimpl) = ast {
if iimpl.trait_.is_some() {
panic!("#[methods] can not be used only with trait impl block");
} else {
impl_methods(&iimpl.self_ty, &mut iimpl.items)
}
} else {
panic!("#[methods] can only be used with Impl blocks")
}
}
pub fn impl_methods(ty: &Box<syn::Ty>, impls: &mut Vec<syn::ImplItem>) -> Tokens {
pub fn impl_methods(ty: &Box<syn::Type>, impls: &mut Vec<syn::ImplItem>) -> Tokens {
// get method names in impl block
let mut methods = Vec::new();
for iimpl in impls.iter_mut() {
match iimpl.node {
syn::ImplItemKind::Method(ref mut sig, _) => {
methods.push(py_method::gen_py_method(
ty, &iimpl.ident, sig, &mut iimpl.attrs));
},
_ => (),
if let syn::ImplItem::Method(ref mut meth) = iimpl {
let name = meth.sig.ident.clone();
methods.push(py_method::gen_py_method(ty, &name, &mut meth.sig, &mut meth.attrs));
}
}
@ -44,14 +40,13 @@ pub fn impl_methods(ty: &Box<syn::Ty>, impls: &mut Vec<syn::ImplItem>) -> Tokens
}
};
let n = match ty.as_ref() {
&syn::Ty::Path(_, ref p) => {
p.segments.last().as_ref().unwrap().ident.as_ref()
}
_ => "CLS_METHODS"
let n = if let &syn::Type::Path(ref typath) = ty.as_ref() {
typath.path.segments.last().as_ref().unwrap().value().ident.as_ref()
} else {
"CLS_METHODS"
};
let dummy_const = syn::Ident::new(format!("_IMPL_PYO3_METHODS_{}", n));
let dummy_const = syn::Ident::from(format!("_IMPL_PYO3_METHODS_{}", n));
quote! {
#[feature(specialization)]
#[allow(non_upper_case_globals, unused_attributes,

View File

@ -7,9 +7,12 @@ use method::{FnArg, FnSpec, FnType};
use utils;
pub fn gen_py_method<'a>(cls: &Box<syn::Ty>, name: &syn::Ident,
sig: &mut syn::MethodSig, meth_attrs: &mut Vec<syn::Attribute>) -> Tokens
{
pub fn gen_py_method<'a>(
cls: &Box<syn::Type>,
name: &syn::Ident,
sig: &mut syn::MethodSig,
meth_attrs: &mut Vec<syn::Attribute>
) -> Tokens {
check_generic(name, sig);
let doc = utils::get_doc(&meth_attrs, true);
@ -37,7 +40,7 @@ pub fn gen_py_method<'a>(cls: &Box<syn::Ty>, name: &syn::Ident,
fn check_generic(name: &syn::Ident, sig: &syn::MethodSig) {
if !sig.generics.ty_params.is_empty() {
if !sig.decl.generics.params.is_empty() {
panic!("python method can not be generic: {:?}", name);
}
}
@ -54,7 +57,7 @@ pub fn body_to_result(body: &Tokens, spec: &FnSpec) -> Tokens {
}
/// Generate function wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec, noargs: bool) -> Tokens {
pub fn impl_wrap(cls: &Box<syn::Type>, name: &syn::Ident, spec: &FnSpec, noargs: bool) -> Tokens {
let body = impl_call(cls, name, &spec);
if spec.args.is_empty() && noargs {
@ -103,7 +106,7 @@ pub fn impl_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec, noargs: b
}
/// Generate function wrapper for protocol method (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_proto_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
pub fn impl_proto_wrap(cls: &Box<syn::Type>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
let cb = impl_call(cls, name, &spec);
let body = impl_arg_params(&spec, cb);
@ -131,7 +134,7 @@ pub fn impl_proto_wrap(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
}
/// Generate class method wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap_new(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
pub fn impl_wrap_new(cls: &Box<syn::Type>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
let names: Vec<syn::Ident> = spec.args.iter().enumerate().map(
|item| if item.1.py {syn::Ident::from("_py")} else {
syn::Ident::from(format!("arg{}", item.0))}).collect();
@ -180,7 +183,7 @@ pub fn impl_wrap_new(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> To
}
/// Generate function wrapper for ffi::initproc
fn impl_wrap_init(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
fn impl_wrap_init(cls: &Box<syn::Type>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
let cb = impl_call(cls, name, &spec);
let output = &spec.output;
if quote! {#output} != quote! {PyResult<()>} || quote! {#output} != quote! {()}{
@ -217,7 +220,7 @@ fn impl_wrap_init(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Token
}
/// Generate class method wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap_class(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
pub fn impl_wrap_class(cls: &Box<syn::Type>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
let names: Vec<syn::Ident> = spec.args.iter().enumerate().map(
|item| if item.1.py {syn::Ident::from("_py")} else {
syn::Ident::from(format!("arg{}", item.0))}).collect();
@ -250,7 +253,7 @@ pub fn impl_wrap_class(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
}
/// Generate static method wrapper (PyCFunction, PyCFunctionWithKeywords)
pub fn impl_wrap_static(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
pub fn impl_wrap_static(cls: &Box<syn::Type>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
let names: Vec<syn::Ident> = spec.args.iter().enumerate().map(
|item| if item.1.py {syn::Ident::from("_py")} else {
syn::Ident::from(format!("arg{}", item.0))}).collect();
@ -282,7 +285,7 @@ pub fn impl_wrap_static(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) ->
}
/// Generate functiona wrapper (PyCFunction, PyCFunctionWithKeywords)
pub(crate) fn impl_wrap_getter(cls: &Box<syn::Ty>, name: &syn::Ident) -> Tokens {
pub(crate) fn impl_wrap_getter(cls: &Box<syn::Type>, name: &syn::Ident) -> Tokens {
quote! {
unsafe extern "C" fn __wrap(
_slf: *mut _pyo3::ffi::PyObject, _: *mut _pyo3::c_void) -> *mut _pyo3::ffi::PyObject
@ -308,7 +311,7 @@ pub(crate) fn impl_wrap_getter(cls: &Box<syn::Ty>, name: &syn::Ident) -> Tokens
}
/// Generate functiona wrapper (PyCFunction, PyCFunctionWithKeywords)
pub(crate) fn impl_wrap_setter(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
pub(crate) fn impl_wrap_setter(cls: &Box<syn::Type>, name: &syn::Ident, spec: &FnSpec) -> Tokens {
if spec.args.len() < 1 {
println!("Not enough arguments for setter {}::{}", quote!{#cls}, name);
}
@ -342,7 +345,7 @@ pub(crate) fn impl_wrap_setter(cls: &Box<syn::Ty>, name: &syn::Ident, spec: &FnS
}
fn impl_call(_cls: &Box<syn::Ty>, fname: &syn::Ident, spec: &FnSpec) -> Tokens {
fn impl_call(_cls: &Box<syn::Type>, fname: &syn::Ident, spec: &FnSpec) -> Tokens {
let names: Vec<syn::Ident> = spec.args.iter().enumerate().map(
|item| if item.1.py {
syn::Ident::from("_py")

View File

@ -10,31 +10,33 @@ use func::impl_method_proto;
pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
match ast.node {
syn::ItemKind::Impl(_, _, ref mut gen, ref mut path, ref ty, ref mut impl_items) => {
if let &mut Some(ref mut path) = path {
match ast {
syn::Item::Impl(ref mut expr) => {
if let Some((_, ref mut path, _)) = expr.trait_ {
let tokens = if let Some(ref mut segment) = path.segments.last() {
match segment.ident.as_ref() {
let ty = &expr.self_ty;
let items = &mut expr.items;
match segment.value().ident.as_ref() {
"PyObjectProtocol" =>
impl_proto_impl(ty, impl_items, &defs::OBJECT),
impl_proto_impl(ty, items, &defs::OBJECT),
"PyAsyncProtocol" =>
impl_proto_impl(ty, impl_items, &defs::ASYNC),
impl_proto_impl(ty, items, &defs::ASYNC),
"PyMappingProtocol" =>
impl_proto_impl(ty, impl_items, &defs::MAPPING),
impl_proto_impl(ty, items, &defs::MAPPING),
"PyIterProtocol" =>
impl_proto_impl(ty, impl_items, &defs::ITER),
impl_proto_impl(ty, items, &defs::ITER),
"PyContextProtocol" =>
impl_proto_impl(ty, impl_items, &defs::CONTEXT),
impl_proto_impl(ty, items, &defs::CONTEXT),
"PySequenceProtocol" =>
impl_proto_impl(ty, impl_items, &defs::SEQ),
impl_proto_impl(ty, items, &defs::SEQ),
"PyNumberProtocol" =>
impl_proto_impl(ty, impl_items, &defs::NUM),
impl_proto_impl(ty, items, &defs::NUM),
"PyDescrProtocol" =>
impl_proto_impl(ty, impl_items, &defs::DESCR),
impl_proto_impl(ty, items, &defs::DESCR),
"PyBufferProtocol" =>
impl_proto_impl(ty, impl_items, &defs::BUFFER),
impl_proto_impl(ty, items, &defs::BUFFER),
"PyGCProtocol" =>
impl_proto_impl(ty, impl_items, &defs::GC),
impl_proto_impl(ty, items, &defs::GC),
_ => {
warn!("#[proto] can not be used with this block");
return Tokens::new()
@ -45,18 +47,10 @@ pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
};
// attach lifetime
gen.lifetimes = vec![syn::LifetimeDef {
attrs: vec![], bounds: vec![],
lifetime: syn::Lifetime { ident: syn::Ident::from("\'p") },
}];
let seg = path.segments.pop().unwrap();
path.segments.push(syn::PathSegment{
ident: seg.ident.clone(),
parameters: syn::PathParameters::AngleBracketed(
syn::AngleBracketedParameterData {
lifetimes: vec![syn::Lifetime { ident: syn::Ident::from("\'p") }],
types: vec![], bindings: vec![] })});
let mut seg = path.segments.pop().unwrap().into_value();
seg.arguments = syn::PathArguments::AngleBracketed(parse_quote!{<'p>});
path.segments.push(seg);
expr.generics.params = parse_quote!{'p};
tokens
} else {
@ -67,27 +61,31 @@ pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
}
}
fn impl_proto_impl(ty: &Box<syn::Ty>,
impls: &mut Vec<syn::ImplItem>, proto: &defs::Proto) -> Tokens
{
fn impl_proto_impl(
ty: &Box<syn::Type>,
impls: &mut Vec<syn::ImplItem>,
proto: &defs::Proto
) -> Tokens {
let mut tokens = Tokens::new();
let mut py_methods = Vec::new();
for iimpl in impls.iter_mut() {
match iimpl.node {
syn::ImplItemKind::Method(ref mut sig, _) => {
match iimpl {
syn::ImplItem::Method(ref mut met) => {
for m in proto.methods {
if m.eq(iimpl.ident.as_ref()) {
impl_method_proto(ty, sig, m).to_tokens(&mut tokens);
if m.eq(met.sig.ident.as_ref()) {
impl_method_proto(ty, &mut met.sig, m).to_tokens(&mut tokens);
}
}
for m in proto.py_methods {
if m.name == iimpl.ident.as_ref() {
let name = syn::Ident::from(m.name);
let proto = syn::Ident::from(m.proto);
let ident = met.sig.ident.clone();
if m.name == ident.as_ref() {
let fn_spec = FnSpec::parse(&iimpl.ident, sig, &mut iimpl.attrs);
let meth = py_method::impl_proto_wrap(ty, &iimpl.ident, &fn_spec);
let name: syn::Ident = syn::parse_str(m.name).unwrap();
let proto: syn::Path = syn::parse_str(m.proto).unwrap();
let fn_spec = FnSpec::parse(&ident, &mut met.sig, &mut met.attrs);
let meth = py_method::impl_proto_wrap(ty, &ident, &fn_spec);
py_methods.push(
quote! {
@ -115,14 +113,13 @@ fn impl_proto_impl(ty: &Box<syn::Ty>,
// unique mod name
let p = proto.name;
let n = match ty.as_ref() {
&syn::Ty::Path(_, ref p) => {
p.segments.last().as_ref().unwrap().ident.as_ref()
}
_ => "PROTO_METHODS"
let n = if let syn::Type::Path(ref typath) = ty.as_ref() {
typath.path.segments.last().as_ref().unwrap().value().ident.as_ref()
} else {
"PROTO_METHODS"
};
let dummy_const = syn::Ident::new(format!("_IMPL_PYO3_{}_{}", n, p));
let dummy_const: syn::Path = syn::parse_str(&format!("_IMPL_PYO3_{}_{}", n, p)).unwrap();
quote! {
#[feature(specialization)]
#[allow(non_upper_case_globals, unused_attributes,

View File

@ -1,5 +1,6 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use syn;
use syn::spanned::Spanned;
use quote::{Tokens, ToTokens};
use proc_macro::TokenStream;
@ -26,35 +27,37 @@ pub fn for_err_msg(i: &ToTokens) -> String {
let mut tokens = Tokens::new();
i.to_tokens(&mut tokens);
tokens.as_str().to_string()
format!("{:?}", tokens).to_string()
}
// FIXME(althonos): not sure the docstring formatting is on par here.
pub fn get_doc(attrs: &Vec<syn::Attribute>, null_terminated: bool) -> syn::Lit {
let mut doc = Vec::new();
let mut span = None;
for attr in attrs.iter() {
match attr.value {
syn::MetaItem::NameValue(ref ident, ref lit) => {
if ident.as_ref() == "doc" {
let s = quote!{ #lit }.to_string();
let mut s = s[1..s.len()-1].to_string();
if s.starts_with("/// ") {
// Remove leading whitespace and ///
s = s[4..].to_string();
} else {
// Remove only ///
s = s[3..].to_string();
}
doc.push(s)
if let Some(syn::Meta::NameValue(ref metanv)) = attr.interpret_meta() {
if metanv.ident == "doc" {
span = Some(metanv.span());
if let syn::Lit::Str(ref litstr) = metanv.lit {
let d = litstr.value();
doc.push(if d.starts_with(" ") { d[1..d.len()].to_string() } else {d});
} else {
panic!("could not parse doc");
}
}
_ => (),
}
}
let doc = doc.join("\n");
if null_terminated {
syn::Lit::Str(format!("{}\0", doc), syn::StrStyle::Cooked)
// FIXME: add span
syn::parse_str(&if null_terminated {
format!("\"{}\0\"", doc)
} else {
syn::Lit::Str(doc, syn::StrStyle::Cooked)
}
format!("\"{}\"", doc)
}).unwrap()
}

View File

@ -13,12 +13,13 @@ license = "Apache-2.0"
proc-macro = true
[dependencies]
quote="0.3"
quote="0.5"
[dependencies.syn]
version="0.11"
features=["full"]
version="0.13"
features=["full", "parsing", "printing", "extra-traits"]
[dependencies.pyo3-derive-backend]
path = "../pyo3-derive-backend"
version = "0.2.5"
version = "0.2.5"