pyo3/pyo3-derive-backend/src/method.rs

384 lines
13 KiB
Rust
Raw Normal View History

2017-05-20 06:14:59 +00:00
// Copyright (c) 2017-present PyO3 Project and Contributors
use syn;
2018-07-03 20:28:40 +00:00
use args::{parse_arguments, Argument};
use proc_macro2::TokenStream;
use quote::ToTokens;
2017-05-20 06:14:59 +00:00
#[derive(Clone, PartialEq, Debug)]
2017-05-20 06:14:59 +00:00
pub struct FnArg<'a> {
pub name: &'a syn::Ident,
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,
2017-06-24 22:28:53 +00:00
pub reference: bool,
2017-05-20 06:14:59 +00:00
}
#[derive(Clone, PartialEq, Debug)]
pub enum FnType {
Getter(Option<String>),
Setter(Option<String>),
Fn,
FnNew,
2017-07-27 23:14:54 +00:00
FnInit,
2017-05-20 06:14:59 +00:00
FnCall,
2017-06-08 18:29:40 +00:00
FnClass,
FnStatic,
2017-05-20 06:14:59 +00:00
}
#[derive(Clone, PartialEq, Debug)]
2017-05-20 06:14:59 +00:00
pub struct FnSpec<'a> {
pub tp: FnType,
2017-06-14 05:37:26 +00:00
pub attrs: Vec<Argument>,
2017-05-20 06:14:59 +00:00
pub args: Vec<FnArg<'a>>,
pub output: syn::Type,
2017-05-20 06:14:59 +00:00
}
pub fn get_return_info(output: &syn::ReturnType) -> syn::Type {
match output {
2019-01-08 19:18:06 +00:00
syn::ReturnType::Default => syn::Type::Infer(parse_quote! {_}),
2018-07-03 20:28:40 +00:00
syn::ReturnType::Type(_, ref ty) => *ty.clone(),
}
}
2017-05-20 06:14:59 +00:00
impl<'a> FnSpec<'a> {
2017-06-19 21:05:14 +00:00
/// Parser function signature and function attributes
2018-07-03 20:28:40 +00:00
pub fn parse(
name: &'a syn::Ident,
sig: &'a syn::MethodSig,
meth_attrs: &'a mut Vec<syn::Attribute>,
) -> FnSpec<'a> {
2017-05-20 06:14:59 +00:00
let (fn_type, fn_attrs) = parse_attributes(meth_attrs);
2017-06-08 18:29:40 +00:00
let mut has_self = false;
2017-05-20 06:14:59 +00:00
let mut arguments = Vec::new();
2017-06-08 18:29:40 +00:00
for input in sig.decl.inputs.iter() {
2017-05-20 06:14:59 +00:00
match input {
&syn::FnArg::SelfRef(_) => {
2017-06-08 18:29:40 +00:00
has_self = true;
2018-07-03 20:28:40 +00:00
}
2017-05-20 06:14:59 +00:00
&syn::FnArg::SelfValue(_) => {
2017-06-08 18:29:40 +00:00
has_self = true;
2017-05-20 06:14:59 +00:00
}
2018-07-03 20:28:40 +00:00
&syn::FnArg::Captured(syn::ArgCaptured {
ref pat, ref ty, ..
}) => {
2017-06-08 18:29:40 +00:00
// skip first argument (cls)
if (fn_type == FnType::FnClass || fn_type == FnType::FnNew) && !has_self {
has_self = true;
2018-07-03 20:28:40 +00:00
continue;
2017-06-08 18:29:40 +00:00
}
let (ident, by_ref, mutability) = match pat {
2018-07-03 20:28:40 +00:00
&syn::Pat::Ident(syn::PatIdent {
ref ident,
ref by_ref,
ref mutability,
..
}) => (ident, by_ref, mutability),
_ => panic!("unsupported argument: {:?}", pat),
2017-05-20 06:14:59 +00:00
};
2017-06-08 18:29:40 +00:00
let py = match ty {
2018-07-03 20:28:40 +00:00
&syn::Type::Path(syn::TypePath { ref path, .. }) => {
if let Some(segment) = path.segments.last() {
segment.value().ident == "Python"
} else {
false
2018-07-03 20:28:40 +00:00
}
}
_ => false,
};
2017-06-08 18:29:40 +00:00
let opt = check_arg_ty_and_optional(name, ty);
2018-07-03 20:28:40 +00:00
arguments.push(FnArg {
name: ident,
by_ref,
mutability,
// mode: mode,
ty: ty,
optional: opt,
py: py,
reference: is_ref(name, ty),
});
2017-05-20 06:14:59 +00:00
}
2018-07-03 20:28:40 +00:00
&syn::FnArg::Ignored(_) => panic!("ignored argument: {:?}", name),
&syn::FnArg::Inferred(_) => panic!("ingerred argument: {:?}", name),
2017-05-20 06:14:59 +00:00
}
}
let ty = get_return_info(&sig.decl.output);
2017-05-26 23:51:33 +00:00
2017-05-20 06:14:59 +00:00
FnSpec {
tp: fn_type,
attrs: fn_attrs,
2017-05-26 23:51:33 +00:00
args: arguments,
output: ty,
2017-05-20 06:14:59 +00:00
}
}
pub fn is_args(&self, name: &syn::Ident) -> bool {
for s in self.attrs.iter() {
match *s {
2018-07-03 20:28:40 +00:00
Argument::VarArgs(ref ident) => return name == ident,
2017-05-20 06:14:59 +00:00
_ => (),
}
}
false
}
pub fn accept_args(&self) -> bool {
for s in self.attrs.iter() {
match *s {
2017-06-14 05:37:26 +00:00
Argument::VarArgs(_) => return true,
Argument::VarArgsSeparator => return true,
2017-05-20 06:14:59 +00:00
_ => (),
}
}
false
}
pub fn is_kwargs(&self, name: &syn::Ident) -> bool {
for s in self.attrs.iter() {
match *s {
2018-07-03 20:28:40 +00:00
Argument::KeywordArgs(ref ident) => return name == ident,
2017-05-20 06:14:59 +00:00
_ => (),
}
}
false
}
pub fn accept_kwargs(&self) -> bool {
for s in self.attrs.iter() {
match *s {
2017-06-14 05:37:26 +00:00
Argument::KeywordArgs(_) => return true,
2017-05-20 06:14:59 +00:00
_ => (),
}
}
false
}
pub fn default_value(&self, name: &syn::Ident) -> Option<TokenStream> {
2017-05-20 06:14:59 +00:00
for s in self.attrs.iter() {
match *s {
2017-06-14 05:37:26 +00:00
Argument::Arg(ref ident, ref opt) => {
if ident == name {
2017-06-14 05:37:26 +00:00
if let &Some(ref val) = opt {
let i: syn::Expr = syn::parse_str(&val).unwrap();
2018-07-03 20:28:40 +00:00
return Some(i.into_token_stream());
2017-06-14 05:37:26 +00:00
}
}
2018-07-03 20:28:40 +00:00
}
2017-06-14 05:37:26 +00:00
Argument::Kwarg(ref ident, ref opt) => {
if ident == name {
let i: syn::Expr = syn::parse_str(&opt).unwrap();
2018-07-03 20:28:40 +00:00
return Some(quote!(#i));
2017-05-20 06:14:59 +00:00
}
2018-07-03 20:28:40 +00:00
}
2017-05-20 06:14:59 +00:00
_ => (),
}
}
None
}
2017-06-14 05:37:26 +00:00
pub fn is_kw_only(&self, name: &syn::Ident) -> bool {
for s in self.attrs.iter() {
match *s {
Argument::Kwarg(ref ident, _) => {
if ident == name {
2018-07-03 20:28:40 +00:00
return true;
2017-06-14 05:37:26 +00:00
}
2018-07-03 20:28:40 +00:00
}
2017-06-14 05:37:26 +00:00
_ => (),
}
}
false
}
2017-05-20 06:14:59 +00:00
}
pub fn is_ref<'a>(name: &'a syn::Ident, ty: &'a syn::Type) -> bool {
2017-06-24 22:28:53 +00:00
match ty {
2018-07-03 20:28:40 +00:00
&syn::Type::Reference(_) => return true,
&syn::Type::Path(syn::TypePath { ref path, .. }) => {
2017-06-24 22:28:53 +00:00
if let Some(segment) = path.segments.last() {
match segment.value().ident.to_string().as_str() {
2018-07-03 20:28:40 +00:00
"Option" => match segment.value().arguments {
syn::PathArguments::AngleBracketed(ref params) => {
if params.args.len() != 1 {
panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
name,
ty,
path);
2017-06-24 22:28:53 +00:00
}
2018-07-03 20:28:40 +00:00
match &params.args[params.args.len() - 1] {
&syn::GenericArgument::Type(syn::Type::Reference(_)) => return true,
_ => (),
}
}
_ => {
panic!(
"argument type is not supported by python method: {:?} ({:?}) {:?}",
name, ty, path
);
2017-06-24 22:28:53 +00:00
}
},
_ => (),
}
}
2018-07-03 20:28:40 +00:00
}
_ => (),
2017-06-24 22:28:53 +00:00
}
false
}
2018-07-03 20:28:40 +00:00
pub fn check_arg_ty_and_optional<'a>(
name: &'a syn::Ident,
ty: &'a syn::Type,
) -> Option<&'a syn::Type> {
2017-05-20 06:14:59 +00:00
match ty {
2018-07-03 20:28:40 +00:00
&syn::Type::Path(syn::TypePath { ref path, .. }) => {
2017-05-25 05:43:07 +00:00
//if let &Some(ref qs) = qs {
// panic!("explicit Self type in a 'qualified path' is not supported: {:?} - {:?}",
// name, qs);
//}
2017-05-20 06:14:59 +00:00
if let Some(segment) = path.segments.last() {
match segment.value().ident.to_string().as_str() {
2018-07-03 20:28:40 +00:00
"Option" => match segment.value().arguments {
syn::PathArguments::AngleBracketed(ref params) => {
if params.args.len() != 1 {
panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
name,
ty,
path);
2018-07-03 20:28:40 +00:00
}
2018-07-03 20:28:40 +00:00
match &params.args[0] {
&syn::GenericArgument::Type(ref ty) => Some(ty),
_ => panic!("argument type is not supported by python method: {:?} ({:?}) {:?}",
name,
ty,
path),
}
2018-07-03 20:28:40 +00:00
}
_ => {
panic!(
"argument type is not supported by python method: {:?} ({:?}) {:?}",
name, ty, path
);
2017-05-20 06:14:59 +00:00
}
},
_ => None,
}
} else {
None
}
2018-07-03 20:28:40 +00:00
}
2017-05-20 06:14:59 +00:00
_ => {
None
//panic!("argument type is not supported by python method: {:?} ({:?})",
//name,
//ty);
2018-07-03 20:28:40 +00:00
}
2017-05-20 06:14:59 +00:00
}
}
2017-06-14 05:37:26 +00:00
fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> (FnType, Vec<Argument>) {
2017-05-20 06:14:59 +00:00
let mut new_attrs = Vec::new();
let mut spec = Vec::new();
let mut res: Option<FnType> = None;
for attr in attrs.iter() {
match attr.interpret_meta().unwrap() {
2018-07-03 20:28:40 +00:00
syn::Meta::Word(ref name) => match name.to_string().as_ref() {
"new" | "__new__" => res = Some(FnType::FnNew),
"init" | "__init__" => res = Some(FnType::FnInit),
"call" | "__call__" => res = Some(FnType::FnCall),
"classmethod" => res = Some(FnType::FnClass),
"staticmethod" => res = Some(FnType::FnStatic),
"setter" | "getter" => {
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 name == "setter" {
res = Some(FnType::Setter(None))
} else {
res = Some(FnType::Getter(None))
2017-05-20 06:14:59 +00:00
}
}
2018-07-03 20:28:40 +00:00
_ => new_attrs.push(attr.clone()),
2017-05-20 06:14:59 +00:00
},
2018-07-03 20:28:40 +00:00
syn::Meta::List(syn::MetaList {
ref ident,
ref nested,
..
}) => match ident.to_string().as_str() {
"new" => res = Some(FnType::FnNew),
"init" => res = Some(FnType::FnInit),
"call" => res = Some(FnType::FnCall),
"setter" | "getter" => {
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 nested.len() != 1 {
panic!("setter/getter requires one value");
}
match nested.first().unwrap().value() {
syn::NestedMeta::Meta(syn::Meta::Word(ref w)) => {
if ident == "setter" {
res = Some(FnType::Setter(Some(w.to_string())))
} else {
res = Some(FnType::Getter(Some(w.to_string())))
}
2017-05-20 06:14:59 +00:00
}
2018-07-03 20:28:40 +00:00
syn::NestedMeta::Literal(ref lit) => match *lit {
syn::Lit::Str(ref s) => {
if ident == "setter" {
2018-07-03 20:28:40 +00:00
res = Some(FnType::Setter(Some(s.value())))
2017-05-20 06:14:59 +00:00
} else {
2018-07-03 20:28:40 +00:00
res = Some(FnType::Getter(Some(s.value())))
2017-05-20 06:14:59 +00:00
}
}
_ => {
2018-07-03 20:28:40 +00:00
panic!("setter/getter attribute requires str value");
}
},
_ => {
println!("cannot parse {:?} attribute: {:?}", ident, nested);
2017-05-20 06:14:59 +00:00
}
}
}
2018-07-03 20:28:40 +00:00
"args" => {
let args = nested.iter().cloned().collect::<Vec<_>>();
spec.extend(parse_arguments(args.as_slice()))
}
_ => new_attrs.push(attr.clone()),
2017-05-20 06:14:59 +00:00
},
2018-07-03 20:28:40 +00:00
syn::Meta::NameValue(_) => new_attrs.push(attr.clone()),
2017-05-20 06:14:59 +00:00
}
}
attrs.clear();
attrs.extend(new_attrs);
match res {
Some(tp) => (tp, spec),
None => (FnType::Fn, spec),
}
}