diff options
Diffstat (limited to '')
-rw-r--r-- | src/boost/libs/python/src/object/function_doc_signature.cpp | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/src/boost/libs/python/src/object/function_doc_signature.cpp b/src/boost/libs/python/src/object/function_doc_signature.cpp new file mode 100644 index 000000000..41695285a --- /dev/null +++ b/src/boost/libs/python/src/object/function_doc_signature.cpp @@ -0,0 +1,344 @@ +// Copyright Nikolay Mladenov 2007. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// boost::python::make_tuple below are for gcc 4.4 -std=c++0x compatibility +// (Intel C++ 10 and 11 with -std=c++0x don't need the full qualification). + +#include <boost/python/converter/registrations.hpp> +#include <boost/python/object/function_doc_signature.hpp> +#include <boost/python/errors.hpp> +#include <boost/python/str.hpp> +#include <boost/python/args.hpp> +#include <boost/python/tuple.hpp> + +#include <boost/python/detail/signature.hpp> + +#include <vector> + +namespace boost { namespace python { namespace objects { + + bool function_doc_signature_generator::arity_cmp( function const *f1, function const *f2 ) + { + return f1->m_fn.max_arity() < f2->m_fn.max_arity(); + } + + bool function_doc_signature_generator::are_seq_overloads( function const *f1, function const *f2 , bool check_docs) + { + py_function const & impl1 = f1->m_fn; + py_function const & impl2 = f2->m_fn; + + //the number of parameters differs by 1 + if (impl2.max_arity()-impl1.max_arity() != 1) + return false; + + // if check docs then f1 shold not have docstring or have the same docstring as f2 + if (check_docs && f2->doc() != f1->doc() && f1->doc()) + return false; + + python::detail::signature_element const* s1 = impl1.signature(); + python::detail::signature_element const* s2 = impl2.signature(); + + unsigned size = impl1.max_arity()+1; + + for (unsigned i = 0; i != size; ++i) + { + //check if the argument types are the same + if (s1[i].basename != s2[i].basename) + return false; + + //return type + if (!i) continue; + + //check if the argument default values are the same + bool f1_has_names = bool(f1->m_arg_names); + bool f2_has_names = bool(f2->m_arg_names); + if ( (f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=f1->m_arg_names[i-1]) + || (f1_has_names && !f2_has_names) + || (!f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=python::object()) + ) + return false; + } + return true; + } + + std::vector<function const*> function_doc_signature_generator::flatten(function const *f) + { + object name = f->name(); + + std::vector<function const*> res; + + while (f) { + + //this if takes out the not_implemented_function + if (f->name() == name) + res.push_back(f); + + f=f->m_overloads.get(); + } + + //std::sort(res.begin(),res.end(), &arity_cmp); + + return res; + } + std::vector<function const*> function_doc_signature_generator::split_seq_overloads( const std::vector<function const *> &funcs, bool split_on_doc_change) + { + std::vector<function const*> res; + + std::vector<function const*>::const_iterator fi = funcs.begin(); + + function const * last = *fi; + + while (++fi != funcs.end()){ + + //check if fi starts a new chain of overloads + if (!are_seq_overloads( last, *fi, split_on_doc_change )) + res.push_back(last); + + last = *fi; + } + + if (last) + res.push_back(last); + + return res; + } + + str function_doc_signature_generator::raw_function_pretty_signature(function const *f, size_t n_overloads, bool cpp_types ) + { + str res("object"); + + res = str("%s %s(%s)" % make_tuple( res, f->m_name, str("tuple args, dict kwds")) ); + + return res; + } + + const char * function_doc_signature_generator::py_type_str(const python::detail::signature_element &s) + { + if (s.basename==std::string("void")){ + static const char * none = "None"; + return none; + } + + PyTypeObject const * py_type = s.pytype_f?s.pytype_f():0; + if ( py_type ) + return py_type->tp_name; + else{ + static const char * object = "object"; + return object; + } + } + + str function_doc_signature_generator::parameter_string(py_function const &f, size_t n, object arg_names, bool cpp_types) + { + str param; + + python::detail::signature_element const * s = f.signature(); + if (cpp_types) + { + if(!n) + s = &f.get_return_type(); + if (s[n].basename == 0) + { + return str("..."); + } + + param = str(s[n].basename); + + if (s[n].lvalue) + param += " {lvalue}"; + + } + else + { + if (n) //we are processing an argument and trying to come up with a name for it + { + object kv; + if ( arg_names && (kv = arg_names[n-1]) ) + param = str( " (%s)%s" % make_tuple(py_type_str(s[n]),kv[0]) ); + else + param = str(" (%s)%s%d" % make_tuple(py_type_str(s[n]),"arg", n) ); + } + else //we are processing the return type + param = py_type_str(f.get_return_type()); + } + + //an argument - check for default value and append it + if(n && arg_names) + { + object kv(arg_names[n-1]); + if (kv && len(kv) == 2) + { + param = str("%s=%r" % make_tuple(param, kv[1])); + } + } + return param; + } + + str function_doc_signature_generator::pretty_signature(function const *f, size_t n_overloads, bool cpp_types ) + { + py_function + const& impl = f->m_fn; + ; + + + unsigned arity = impl.max_arity(); + + if(arity == unsigned(-1))// is this the proper raw function test? + { + return raw_function_pretty_signature(f,n_overloads,cpp_types); + } + + list formal_params; + + size_t n_extra_default_args=0; + + for (unsigned n = 0; n <= arity; ++n) + { + str param; + + formal_params.append( + parameter_string(impl, n, f->m_arg_names, cpp_types) + ); + + // find all the arguments with default values preceeding the arity-n_overloads + if (n && f->m_arg_names) + { + object kv(f->m_arg_names[n-1]); + + if (kv && len(kv) == 2) + { + //default argument preceeding the arity-n_overloads + if( n <= arity-n_overloads) + ++n_extra_default_args; + } + else + //argument without default, preceeding the arity-n_overloads + if( n <= arity-n_overloads) + n_extra_default_args = 0; + } + } + + n_overloads+=n_extra_default_args; + + if (!arity && cpp_types) + formal_params.append("void"); + + str ret_type (formal_params.pop(0)); + if (cpp_types ) + { + return str( + "%s %s(%s%s%s%s)" + % boost::python::make_tuple // workaround, see top + ( ret_type + , f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + )); + }else{ + return str( + "%s(%s%s%s%s) -> %s" + % boost::python::make_tuple // workaround, see top + ( f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + , ret_type + )); + } + + return str( + "%s %s(%s%s%s%s) %s" + % boost::python::make_tuple // workaround, see top + ( cpp_types?ret_type:str("") + , f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + , cpp_types?str(""):ret_type + )); + + } + + namespace detail { + char py_signature_tag[] = "PY signature :"; + char cpp_signature_tag[] = "C++ signature :"; + } + + list function_doc_signature_generator::function_doc_signatures( function const * f) + { + list signatures; + std::vector<function const*> funcs = flatten( f); + std::vector<function const*> split_funcs = split_seq_overloads( funcs, true); + std::vector<function const*>::const_iterator sfi=split_funcs.begin(), fi; + size_t n_overloads=0; + for (fi=funcs.begin(); fi!=funcs.end(); ++fi) + { + if(*sfi == *fi){ + if((*fi)->doc()) + { + str func_doc = str((*fi)->doc()); + + int doc_len = len(func_doc); + + bool show_py_signature = doc_len >= int(sizeof(detail::py_signature_tag)/sizeof(char)-1) + && str(detail::py_signature_tag) == func_doc.slice(0, int(sizeof(detail::py_signature_tag)/sizeof(char))-1); + if(show_py_signature) + { + func_doc = str(func_doc.slice(int(sizeof(detail::py_signature_tag)/sizeof(char))-1, _)); + doc_len = len(func_doc); + } + + bool show_cpp_signature = doc_len >= int(sizeof(detail::cpp_signature_tag)/sizeof(char)-1) + && str(detail::cpp_signature_tag) == func_doc.slice( 1-int(sizeof(detail::cpp_signature_tag)/sizeof(char)), _); + + if(show_cpp_signature) + { + func_doc = str(func_doc.slice(_, 1-int(sizeof(detail::cpp_signature_tag)/sizeof(char)))); + doc_len = len(func_doc); + } + + str res="\n"; + str pad = "\n"; + + if(show_py_signature) + { + str sig = pretty_signature(*fi, n_overloads,false); + res+=sig; + if(doc_len || show_cpp_signature )res+=" :"; + pad+= str(" "); + } + + if(doc_len) + { + if(show_py_signature) + res+=pad; + res+= pad.join(func_doc.split("\n")); + } + + if( show_cpp_signature) + { + if(len(res)>1) + res+="\n"+pad; + res+=detail::cpp_signature_tag+pad+" "+pretty_signature(*fi, n_overloads,true); + } + + signatures.append(res); + } + ++sfi; + n_overloads = 0; + }else + ++n_overloads ; + } + + return signatures; + } + + +}}} + |