]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/python/src/object/function_doc_signature.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / python / src / object / function_doc_signature.cpp
1 // Copyright Nikolay Mladenov 2007.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5
6 // boost::python::make_tuple below are for gcc 4.4 -std=c++0x compatibility
7 // (Intel C++ 10 and 11 with -std=c++0x don't need the full qualification).
8
9 #include <boost/python/converter/registrations.hpp>
10 #include <boost/python/object/function_doc_signature.hpp>
11 #include <boost/python/errors.hpp>
12 #include <boost/python/str.hpp>
13 #include <boost/python/args.hpp>
14 #include <boost/python/tuple.hpp>
15
16 #include <boost/python/detail/signature.hpp>
17
18 #include <vector>
19
20 namespace boost { namespace python { namespace objects {
21
22 bool function_doc_signature_generator::arity_cmp( function const *f1, function const *f2 )
23 {
24 return f1->m_fn.max_arity() < f2->m_fn.max_arity();
25 }
26
27 bool function_doc_signature_generator::are_seq_overloads( function const *f1, function const *f2 , bool check_docs)
28 {
29 py_function const & impl1 = f1->m_fn;
30 py_function const & impl2 = f2->m_fn;
31
32 //the number of parameters differs by 1
33 if (impl2.max_arity()-impl1.max_arity() != 1)
34 return false;
35
36 // if check docs then f1 shold not have docstring or have the same docstring as f2
37 if (check_docs && f2->doc() != f1->doc() && f1->doc())
38 return false;
39
40 python::detail::signature_element const* s1 = impl1.signature();
41 python::detail::signature_element const* s2 = impl2.signature();
42
43 unsigned size = impl1.max_arity()+1;
44
45 for (unsigned i = 0; i != size; ++i)
46 {
47 //check if the argument types are the same
48 if (s1[i].basename != s2[i].basename)
49 return false;
50
51 //return type
52 if (!i) continue;
53
54 //check if the argument default values are the same
55 bool f1_has_names = bool(f1->m_arg_names);
56 bool f2_has_names = bool(f2->m_arg_names);
57 if ( (f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=f1->m_arg_names[i-1])
58 || (f1_has_names && !f2_has_names)
59 || (!f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=python::object())
60 )
61 return false;
62 }
63 return true;
64 }
65
66 std::vector<function const*> function_doc_signature_generator::flatten(function const *f)
67 {
68 object name = f->name();
69
70 std::vector<function const*> res;
71
72 while (f) {
73
74 //this if takes out the not_implemented_function
75 if (f->name() == name)
76 res.push_back(f);
77
78 f=f->m_overloads.get();
79 }
80
81 //std::sort(res.begin(),res.end(), &arity_cmp);
82
83 return res;
84 }
85 std::vector<function const*> function_doc_signature_generator::split_seq_overloads( const std::vector<function const *> &funcs, bool split_on_doc_change)
86 {
87 std::vector<function const*> res;
88
89 std::vector<function const*>::const_iterator fi = funcs.begin();
90
91 function const * last = *fi;
92
93 while (++fi != funcs.end()){
94
95 //check if fi starts a new chain of overloads
96 if (!are_seq_overloads( last, *fi, split_on_doc_change ))
97 res.push_back(last);
98
99 last = *fi;
100 }
101
102 if (last)
103 res.push_back(last);
104
105 return res;
106 }
107
108 str function_doc_signature_generator::raw_function_pretty_signature(function const *f, size_t n_overloads, bool cpp_types )
109 {
110 str res("object");
111
112 res = str("%s %s(%s)" % make_tuple( res, f->m_name, str("tuple args, dict kwds")) );
113
114 return res;
115 }
116
117 const char * function_doc_signature_generator::py_type_str(const python::detail::signature_element &s)
118 {
119 if (s.basename==std::string("void")){
120 static const char * none = "None";
121 return none;
122 }
123
124 PyTypeObject const * py_type = s.pytype_f?s.pytype_f():0;
125 if ( py_type )
126 return py_type->tp_name;
127 else{
128 static const char * object = "object";
129 return object;
130 }
131 }
132
133 str function_doc_signature_generator::parameter_string(py_function const &f, size_t n, object arg_names, bool cpp_types)
134 {
135 str param;
136
137 python::detail::signature_element const * s = f.signature();
138 if (cpp_types)
139 {
140 if(!n)
141 s = &f.get_return_type();
142 if (s[n].basename == 0)
143 {
144 return str("...");
145 }
146
147 param = str(s[n].basename);
148
149 if (s[n].lvalue)
150 param += " {lvalue}";
151
152 }
153 else
154 {
155 if (n) //we are processing an argument and trying to come up with a name for it
156 {
157 object kv;
158 if ( arg_names && (kv = arg_names[n-1]) )
159 param = str( " (%s)%s" % make_tuple(py_type_str(s[n]),kv[0]) );
160 else
161 param = str(" (%s)%s%d" % make_tuple(py_type_str(s[n]),"arg", n) );
162 }
163 else //we are processing the return type
164 param = py_type_str(f.get_return_type());
165 }
166
167 //an argument - check for default value and append it
168 if(n && arg_names)
169 {
170 object kv(arg_names[n-1]);
171 if (kv && len(kv) == 2)
172 {
173 param = str("%s=%r" % make_tuple(param, kv[1]));
174 }
175 }
176 return param;
177 }
178
179 str function_doc_signature_generator::pretty_signature(function const *f, size_t n_overloads, bool cpp_types )
180 {
181 py_function
182 const& impl = f->m_fn;
183 ;
184
185
186 unsigned arity = impl.max_arity();
187
188 if(arity == unsigned(-1))// is this the proper raw function test?
189 {
190 return raw_function_pretty_signature(f,n_overloads,cpp_types);
191 }
192
193 list formal_params;
194
195 size_t n_extra_default_args=0;
196
197 for (unsigned n = 0; n <= arity; ++n)
198 {
199 str param;
200
201 formal_params.append(
202 parameter_string(impl, n, f->m_arg_names, cpp_types)
203 );
204
205 // find all the arguments with default values preceeding the arity-n_overloads
206 if (n && f->m_arg_names)
207 {
208 object kv(f->m_arg_names[n-1]);
209
210 if (kv && len(kv) == 2)
211 {
212 //default argument preceeding the arity-n_overloads
213 if( n <= arity-n_overloads)
214 ++n_extra_default_args;
215 }
216 else
217 //argument without default, preceeding the arity-n_overloads
218 if( n <= arity-n_overloads)
219 n_extra_default_args = 0;
220 }
221 }
222
223 n_overloads+=n_extra_default_args;
224
225 if (!arity && cpp_types)
226 formal_params.append("void");
227
228 str ret_type (formal_params.pop(0));
229 if (cpp_types )
230 {
231 return str(
232 "%s %s(%s%s%s%s)"
233 % boost::python::make_tuple // workaround, see top
234 ( ret_type
235 , f->m_name
236 , str(",").join(formal_params.slice(0,arity-n_overloads))
237 , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str()
238 , str(" [,").join(formal_params.slice(arity-n_overloads,arity))
239 , std::string(n_overloads,']')
240 ));
241 }else{
242 return str(
243 "%s(%s%s%s%s) -> %s"
244 % boost::python::make_tuple // workaround, see top
245 ( f->m_name
246 , str(",").join(formal_params.slice(0,arity-n_overloads))
247 , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str()
248 , str(" [,").join(formal_params.slice(arity-n_overloads,arity))
249 , std::string(n_overloads,']')
250 , ret_type
251 ));
252 }
253
254 return str(
255 "%s %s(%s%s%s%s) %s"
256 % boost::python::make_tuple // workaround, see top
257 ( cpp_types?ret_type:str("")
258 , f->m_name
259 , str(",").join(formal_params.slice(0,arity-n_overloads))
260 , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str()
261 , str(" [,").join(formal_params.slice(arity-n_overloads,arity))
262 , std::string(n_overloads,']')
263 , cpp_types?str(""):ret_type
264 ));
265
266 }
267
268 namespace detail {
269 char py_signature_tag[] = "PY signature :";
270 char cpp_signature_tag[] = "C++ signature :";
271 }
272
273 list function_doc_signature_generator::function_doc_signatures( function const * f)
274 {
275 list signatures;
276 std::vector<function const*> funcs = flatten( f);
277 std::vector<function const*> split_funcs = split_seq_overloads( funcs, true);
278 std::vector<function const*>::const_iterator sfi=split_funcs.begin(), fi;
279 size_t n_overloads=0;
280 for (fi=funcs.begin(); fi!=funcs.end(); ++fi)
281 {
282 if(*sfi == *fi){
283 if((*fi)->doc())
284 {
285 str func_doc = str((*fi)->doc());
286
287 int doc_len = len(func_doc);
288
289 bool show_py_signature = doc_len >= int(sizeof(detail::py_signature_tag)/sizeof(char)-1)
290 && str(detail::py_signature_tag) == func_doc.slice(0, int(sizeof(detail::py_signature_tag)/sizeof(char))-1);
291 if(show_py_signature)
292 {
293 func_doc = str(func_doc.slice(int(sizeof(detail::py_signature_tag)/sizeof(char))-1, _));
294 doc_len = len(func_doc);
295 }
296
297 bool show_cpp_signature = doc_len >= int(sizeof(detail::cpp_signature_tag)/sizeof(char)-1)
298 && str(detail::cpp_signature_tag) == func_doc.slice( 1-int(sizeof(detail::cpp_signature_tag)/sizeof(char)), _);
299
300 if(show_cpp_signature)
301 {
302 func_doc = str(func_doc.slice(_, 1-int(sizeof(detail::cpp_signature_tag)/sizeof(char))));
303 doc_len = len(func_doc);
304 }
305
306 str res="\n";
307 str pad = "\n";
308
309 if(show_py_signature)
310 {
311 str sig = pretty_signature(*fi, n_overloads,false);
312 res+=sig;
313 if(doc_len || show_cpp_signature )res+=" :";
314 pad+= str(" ");
315 }
316
317 if(doc_len)
318 {
319 if(show_py_signature)
320 res+=pad;
321 res+= pad.join(func_doc.split("\n"));
322 }
323
324 if( show_cpp_signature)
325 {
326 if(len(res)>1)
327 res+="\n"+pad;
328 res+=detail::cpp_signature_tag+pad+" "+pretty_signature(*fi, n_overloads,true);
329 }
330
331 signatures.append(res);
332 }
333 ++sfi;
334 n_overloads = 0;
335 }else
336 ++n_overloads ;
337 }
338
339 return signatures;
340 }
341
342
343 }}}
344