1 /*
2 * Copyright 2011,2015 Sven Verdoolaege. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY SVEN VERDOOLAEGE ''AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * The views and conclusions contained in the software and documentation
29 * are those of the authors and should not be interpreted as
30 * representing official policies, either expressed or implied, of
31 * Sven Verdoolaege.
32 */
33
34 #include "isl_config.h"
35
36 #include <stdarg.h>
37 #include <stdio.h>
38
39 #include <algorithm>
40 #include <iostream>
41 #include <map>
42 #include <vector>
43
44 #include "python.h"
45 #include "generator.h"
46
47 /* Argument format for Python methods with a fixed number of arguments.
48 */
49 static const char *fixed_arg_fmt = "arg%d";
50 /* Argument format for Python methods with a variable number of arguments.
51 */
52 static const char *var_arg_fmt = "args[%d]";
53
54 /* Drop the "isl_" initial part of the type name "name".
55 */
type2python(string name)56 static string type2python(string name)
57 {
58 return name.substr(4);
59 }
60
61 /* Print the arguments of a method with "n_arg" arguments, starting at "first".
62 */
print_method_arguments(int first,int n_arg)63 void python_generator::print_method_arguments(int first, int n_arg)
64 {
65 for (int i = first; i < n_arg; ++i) {
66 if (i > first)
67 printf(", ");
68 printf("arg%d", i);
69 }
70 }
71
72 /* Print the start of a definition for method "name"
73 * (without specifying the arguments).
74 * If "is_static" is set, then mark the python method as static.
75 *
76 * If the method is called "from", then rename it to "convert_from"
77 * because "from" is a python keyword.
78 */
print_method_def(bool is_static,const string & name)79 static void print_method_def(bool is_static, const string &name)
80 {
81 const char *s;
82
83 if (is_static)
84 printf(" @staticmethod\n");
85
86 s = name.c_str();
87 if (name == "from")
88 s = "convert_from";
89
90 printf(" def %s", s);
91 }
92
93 /* Print the header of the method "name" with "n_arg" arguments.
94 * If "is_static" is set, then mark the python method as static.
95 */
print_method_header(bool is_static,const string & name,int n_arg)96 void python_generator::print_method_header(bool is_static, const string &name,
97 int n_arg)
98 {
99 print_method_def(is_static, name);
100 printf("(");
101 print_method_arguments(0, n_arg);
102 printf("):\n");
103 }
104
105 /* Print formatted output with the given indentation.
106 */
print_indent(int indent,const char * format,...)107 static void print_indent(int indent, const char *format, ...)
108 {
109 va_list args;
110
111 printf("%*s", indent, " ");
112 va_start(args, format);
113 vprintf(format, args);
114 va_end(args);
115 }
116
117 /* Print a check that the argument in position "pos" is of type "type"
118 * with the given indentation.
119 * If this fails and if "upcast" is set, then convert the first
120 * argument to "super" and call the method "name" on it, passing
121 * the remaining of the "n" arguments.
122 * If the check fails and "upcast" is not set, then simply raise
123 * an exception.
124 * If "upcast" is not set, then the "super", "name" and "n" arguments
125 * to this function are ignored.
126 * "fmt" is the format for printing Python method arguments.
127 */
print_type_check(int indent,const string & type,const char * fmt,int pos,bool upcast,const string & super,const string & name,int n)128 void python_generator::print_type_check(int indent, const string &type,
129 const char *fmt, int pos, bool upcast, const string &super,
130 const string &name, int n)
131 {
132 print_indent(indent, "try:\n");
133 print_indent(indent, " if not ");
134 printf(fmt, pos);
135 printf(".__class__ is %s:\n", type.c_str());
136 print_indent(indent, " ");
137 printf(fmt, pos);
138 printf(" = %s(", type.c_str());
139 printf(fmt, pos);
140 printf(")\n");
141 print_indent(indent, "except:\n");
142 if (upcast) {
143 print_indent(indent, " return %s(",
144 type2python(super).c_str());
145 printf(fmt, 0);
146 printf(").%s(", name.c_str());
147 for (int i = 1; i < n; ++i) {
148 if (i != 1)
149 printf(", ");
150 printf(fmt, i);
151 }
152 printf(")\n");
153 } else
154 print_indent(indent, " raise\n");
155 }
156
157 /* For each of the "n" initial arguments of the function "method"
158 * that refer to an isl structure,
159 * including the object on which the method is called,
160 * check if the corresponding actual argument is of the right type.
161 * If not, try and convert it to the right type.
162 * If that doesn't work and if "super" contains at least one element,
163 * try and convert self to the type of the first superclass in "super" and
164 * call the corresponding method.
165 * If "first_is_ctx" is set, then the first argument is skipped.
166 */
print_type_checks(const string & cname,FunctionDecl * method,bool first_is_ctx,int n,const vector<string> & super)167 void python_generator::print_type_checks(const string &cname,
168 FunctionDecl *method, bool first_is_ctx, int n,
169 const vector<string> &super)
170 {
171 for (int i = first_is_ctx; i < n; ++i) {
172 ParmVarDecl *param = method->getParamDecl(i);
173 string type;
174
175 if (!is_isl_type(param->getOriginalType()))
176 continue;
177 type = type2python(extract_type(param->getOriginalType()));
178 if (!first_is_ctx && i > 0 && super.size() > 0)
179 print_type_check(8, type, fixed_arg_fmt,
180 i - first_is_ctx, true,
181 super[0], cname, n);
182 else
183 print_type_check(8, type, fixed_arg_fmt,
184 i - first_is_ctx, false, "", cname, -1);
185 }
186 }
187
188 /* Print a call to the *_copy function corresponding to "type".
189 */
print_copy(QualType type)190 void python_generator::print_copy(QualType type)
191 {
192 string type_s = extract_type(type);
193
194 printf("isl.%s_copy", type_s.c_str());
195 }
196
197 /* Construct a wrapper for callback argument "param" (at position "arg").
198 * Assign the wrapper to "cb". We assume here that a function call
199 * has at most one callback argument.
200 *
201 * The wrapper converts the arguments of the callback to python types,
202 * taking a copy if the C callback does not take its arguments.
203 * If any exception is thrown, the wrapper keeps track of it in exc_info[0]
204 * and returns a value indicating an error. Otherwise the wrapper
205 * returns a value indicating success.
206 * In case the C callback is expected to return an isl_stat,
207 * the error value is -1 and the success value is 0.
208 * In case the C callback is expected to return an isl_bool,
209 * the error value is -1 and the success value is 1 or 0 depending
210 * on the result of the Python callback.
211 * Otherwise, None is returned to indicate an error and
212 * a copy of the object in case of success.
213 */
print_callback(ParmVarDecl * param,int arg)214 void python_generator::print_callback(ParmVarDecl *param, int arg)
215 {
216 QualType type = param->getOriginalType();
217 const FunctionProtoType *fn = extract_prototype(type);
218 QualType return_type = fn->getReturnType();
219 unsigned n_arg = fn->getNumArgs();
220
221 printf(" exc_info = [None]\n");
222 printf(" fn = CFUNCTYPE(");
223 if (is_isl_stat(return_type) || is_isl_bool(return_type))
224 printf("c_int");
225 else
226 printf("c_void_p");
227 for (unsigned i = 0; i < n_arg - 1; ++i) {
228 if (!is_isl_type(fn->getArgType(i)))
229 die("Argument has non-isl type");
230 printf(", c_void_p");
231 }
232 printf(", c_void_p)\n");
233 printf(" def cb_func(");
234 for (unsigned i = 0; i < n_arg; ++i) {
235 if (i)
236 printf(", ");
237 printf("cb_arg%d", i);
238 }
239 printf("):\n");
240 for (unsigned i = 0; i < n_arg - 1; ++i) {
241 string arg_type;
242 arg_type = type2python(extract_type(fn->getArgType(i)));
243 printf(" cb_arg%d = %s(ctx=arg0.ctx, ptr=",
244 i, arg_type.c_str());
245 if (!callback_takes_argument(param, i))
246 print_copy(fn->getArgType(i));
247 printf("(cb_arg%d))\n", i);
248 }
249 printf(" try:\n");
250 if (is_isl_stat(return_type))
251 printf(" arg%d(", arg);
252 else
253 printf(" res = arg%d(", arg);
254 for (unsigned i = 0; i < n_arg - 1; ++i) {
255 if (i)
256 printf(", ");
257 printf("cb_arg%d", i);
258 }
259 printf(")\n");
260 printf(" except:\n");
261 printf(" import sys\n");
262 printf(" exc_info[0] = sys.exc_info()\n");
263 if (is_isl_stat(return_type) || is_isl_bool(return_type))
264 printf(" return -1\n");
265 else
266 printf(" return None\n");
267 if (is_isl_stat(return_type)) {
268 printf(" return 0\n");
269 } else if (is_isl_bool(return_type)) {
270 printf(" return 1 if res else 0\n");
271 } else {
272 printf(" return ");
273 print_copy(return_type);
274 printf("(res.ptr)\n");
275 }
276 printf(" cb = fn(cb_func)\n");
277 }
278
279 /* Print the argument at position "arg" in call to "fd".
280 * "fmt" is the format for printing Python method arguments.
281 * "skip" is the number of initial arguments of "fd" that are
282 * skipped in the Python method.
283 *
284 * If the (first) argument is an isl_ctx, then print "ctx",
285 * assuming that the caller has made the context available
286 * in a "ctx" variable.
287 * Otherwise, if the argument is a callback, then print a reference to
288 * the callback wrapper "cb".
289 * Otherwise, if the argument is marked as consuming a reference,
290 * then pass a copy of the pointer stored in the corresponding
291 * argument passed to the Python method.
292 * Otherwise, if the argument is a string, then the python string is first
293 * encoded as a byte sequence, using 'ascii' as encoding. This assumes
294 * that all strings passed to isl can be converted to 'ascii'.
295 * Otherwise, if the argument is a pointer, then pass this pointer itself.
296 * Otherwise, pass the argument directly.
297 */
print_arg_in_call(FunctionDecl * fd,const char * fmt,int arg,int skip)298 void python_generator::print_arg_in_call(FunctionDecl *fd, const char *fmt,
299 int arg, int skip)
300 {
301 ParmVarDecl *param = fd->getParamDecl(arg);
302 QualType type = param->getOriginalType();
303 if (is_isl_ctx(type)) {
304 printf("ctx");
305 } else if (is_callback(type)) {
306 printf("cb");
307 } else if (takes(param)) {
308 print_copy(type);
309 printf("(");
310 printf(fmt, arg - skip);
311 printf(".ptr)");
312 } else if (is_string(type)) {
313 printf(fmt, arg - skip);
314 printf(".encode('ascii')");
315 } else if (type->isPointerType()) {
316 printf(fmt, arg - skip);
317 printf(".ptr");
318 } else {
319 printf(fmt, arg - skip);
320 }
321 }
322
323 /* Generate code that raises the exception captured in "exc_info", if any,
324 * with the given indentation.
325 */
print_rethrow(int indent,const char * exc_info)326 static void print_rethrow(int indent, const char *exc_info)
327 {
328 print_indent(indent, "if %s != None:\n", exc_info);
329 print_indent(indent, " raise (%s[0], %s[1], %s[2])\n",
330 exc_info, exc_info, exc_info);
331 }
332
333 /* Print code with the given indentation that checks
334 * whether any of the persistent callbacks of "clazz"
335 * is set and if it failed with an exception. If so, the 'exc_info'
336 * field contains the exception and is raised again.
337 * The field is cleared because the callback and its data may get reused.
338 * "fmt" is the format for printing Python method arguments.
339 */
print_persistent_callback_failure_check(int indent,const isl_class & clazz,const char * fmt)340 static void print_persistent_callback_failure_check(int indent,
341 const isl_class &clazz, const char *fmt)
342 {
343 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
344 set<FunctionDecl *>::const_iterator in;
345
346 for (in = callbacks.begin(); in != callbacks.end(); ++in) {
347 string callback_name = clazz.persistent_callback_name(*in);
348
349 print_indent(indent, "if hasattr(");
350 printf(fmt, 0);
351 printf(", '%s') and ", callback_name.c_str());
352 printf(fmt, 0);
353 printf(".%s['exc_info'] != None:\n", callback_name.c_str());
354 print_indent(indent, " exc_info = ");
355 printf(fmt, 0);
356 printf(".%s['exc_info'][0]\n", callback_name.c_str());
357 print_indent(indent, " ");
358 printf(fmt, 0);
359 printf(".%s['exc_info'][0] = None\n", callback_name.c_str());
360 print_rethrow(indent + 4, "exc_info");
361 }
362 }
363
364 /* Print the return statement of the python method corresponding
365 * to the C function "method" with the given indentation.
366 * If the object on which the method was called
367 * may have a persistent callback, then first check if any of those failed.
368 * "fmt" is the format for printing Python method arguments.
369 *
370 * If the method returns a new instance of the same object type and
371 * if the class has any persistent callbacks, then the data
372 * for these callbacks are copied from the original to the new object.
373 * If the method it itself setting a persistent callback,
374 * then keep track of the constructed C callback (such that it doesn't
375 * get destroyed) and the data structure that holds the captured exception
376 * (such that it can be raised again).
377 *
378 * If the return type is a (const) char *, then convert the result
379 * to a Python string, raising an error on NULL and freeing
380 * the C string if needed. For python 3 compatibility, the string returned
381 * by isl is explicitly decoded as an 'ascii' string. This is correct
382 * as all strings returned by isl are expected to be 'ascii'.
383 *
384 * If the return type is isl_stat, isl_bool or isl_size, then
385 * raise an error on isl_stat_error, isl_bool_error or isl_size_error.
386 * In case of isl_bool, the result is converted to
387 * a Python boolean.
388 * In case of isl_size, the result is converted to a Python int.
389 */
print_method_return(int indent,const isl_class & clazz,FunctionDecl * method,const char * fmt)390 void python_generator::print_method_return(int indent, const isl_class &clazz,
391 FunctionDecl *method, const char *fmt)
392 {
393 QualType return_type = method->getReturnType();
394
395 if (!is_static(clazz, method))
396 print_persistent_callback_failure_check(indent, clazz, fmt);
397
398 if (is_isl_type(return_type)) {
399 string type;
400
401 type = type2python(extract_type(return_type));
402 print_indent(indent,
403 "obj = %s(ctx=ctx, ptr=res)\n", type.c_str());
404 if (is_mutator(clazz, method) &&
405 clazz.has_persistent_callbacks())
406 print_indent(indent, "obj.copy_callbacks(arg0)\n");
407 if (clazz.persistent_callbacks.count(method)) {
408 string callback_name;
409
410 callback_name = clazz.persistent_callback_name(method);
411 print_indent(indent, "obj.%s = { 'func': cb, "
412 "'exc_info': exc_info }\n",
413 callback_name.c_str());
414 }
415 print_indent(indent, "return obj\n");
416 } else if (is_string(return_type)) {
417 print_indent(indent, "if res == 0:\n");
418 print_indent(indent, " raise\n");
419 print_indent(indent, "string = "
420 "cast(res, c_char_p).value.decode('ascii')\n");
421
422 if (gives(method))
423 print_indent(indent, "libc.free(res)\n");
424
425 print_indent(indent, "return string\n");
426 } else if (is_isl_neg_error(return_type)) {
427 print_indent(indent, "if res < 0:\n");
428 print_indent(indent, " raise\n");
429 if (is_isl_bool(return_type))
430 print_indent(indent, "return bool(res)\n");
431 else if (is_isl_size(return_type))
432 print_indent(indent, "return int(res)\n");
433 } else {
434 print_indent(indent, "return res\n");
435 }
436 }
437
438 /* Print a python "get" method corresponding to the C function "fd"
439 * in class "clazz" using a name that includes the "get_" prefix.
440 *
441 * This method simply calls the variant without the "get_" prefix and
442 * returns its result.
443 * Note that static methods are not considered to be "get" methods.
444 */
print_get_method(const isl_class & clazz,FunctionDecl * fd)445 void python_generator::print_get_method(const isl_class &clazz,
446 FunctionDecl *fd)
447 {
448 string get_name = clazz.base_method_name(fd);
449 string name = clazz.method_name(fd);
450 int num_params = fd->getNumParams();
451
452 print_method_header(false, get_name, num_params);
453 printf(" return arg0.%s(", name.c_str());
454 print_method_arguments(1, num_params);
455 printf(")\n");
456 }
457
458 /* Print a call to "method", along with the corresponding
459 * return statement, with the given indentation.
460 * "drop_ctx" is set if the first argument is an isl_ctx.
461 * "drop_user" is set if the last argument is a "user" argument
462 * corresponding to a callback argument.
463 *
464 * A "ctx" variable is first initialized as it may be needed
465 * in the first call to print_arg_in_call and in print_method_return.
466 *
467 * If the method has a callback function, then any exception
468 * thrown in the callback also need to be rethrown.
469 */
print_method_call(int indent,const isl_class & clazz,FunctionDecl * method,const char * fmt,int drop_ctx,int drop_user)470 void python_generator::print_method_call(int indent, const isl_class &clazz,
471 FunctionDecl *method, const char *fmt, int drop_ctx, int drop_user)
472 {
473 string fullname = method->getName().str();
474 int num_params = method->getNumParams();
475
476 if (drop_ctx) {
477 print_indent(indent, "ctx = Context.getDefaultInstance()\n");
478 } else {
479 print_indent(indent, "ctx = ");
480 printf(fmt, 0);
481 printf(".ctx\n");
482 }
483 print_indent(indent, "res = isl.%s(", fullname.c_str());
484 for (int i = 0; i < num_params - drop_user; ++i) {
485 if (i > 0)
486 printf(", ");
487 print_arg_in_call(method, fmt, i, drop_ctx);
488 }
489 if (drop_user)
490 printf(", None");
491 printf(")\n");
492
493 if (drop_user)
494 print_rethrow(indent, "exc_info[0]");
495
496 print_method_return(indent, clazz, method, fmt);
497 }
498
499 /* Print a python method corresponding to the C function "method".
500 * "super" contains the superclasses of the class to which the method belongs,
501 * with the first element corresponding to the annotation that appears
502 * closest to the annotated type. This superclass is the least
503 * general extension of the annotated type in the linearization
504 * of the class hierarchy.
505 *
506 * If the first argument of "method" is something other than an instance
507 * of the class, then mark the python method as static.
508 * If, moreover, this first argument is an isl_ctx, then remove
509 * it from the arguments of the Python method.
510 *
511 * If the function has a callback argument, then it also has a "user"
512 * argument. Since Python has closures, there is no need for such
513 * a user argument in the Python interface, so we simply drop it.
514 * We also create a wrapper ("cb") for the callback.
515 *
516 * If the function consumes a reference, then we pass it a copy of
517 * the actual argument.
518 *
519 * For methods that are identified as "get" methods, also
520 * print a variant of the method using a name that includes
521 * the "get_" prefix.
522 */
print_method(const isl_class & clazz,FunctionDecl * method,vector<string> super)523 void python_generator::print_method(const isl_class &clazz,
524 FunctionDecl *method, vector<string> super)
525 {
526 string cname = clazz.method_name(method);
527 int num_params = method->getNumParams();
528 int drop_user = 0;
529 int drop_ctx = first_arg_is_isl_ctx(method);
530
531 for (int i = 1; i < num_params; ++i) {
532 ParmVarDecl *param = method->getParamDecl(i);
533 QualType type = param->getOriginalType();
534 if (is_callback(type))
535 drop_user = 1;
536 }
537
538 print_method_header(is_static(clazz, method), cname,
539 num_params - drop_ctx - drop_user);
540
541 print_type_checks(cname, method, drop_ctx,
542 num_params - drop_user, super);
543 for (int i = 1; i < num_params; ++i) {
544 ParmVarDecl *param = method->getParamDecl(i);
545 QualType type = param->getOriginalType();
546 if (!is_callback(type))
547 continue;
548 print_callback(param, i - drop_ctx);
549 }
550 print_method_call(8, clazz, method, fixed_arg_fmt, drop_ctx, drop_user);
551
552 if (clazz.is_get_method(method))
553 print_get_method(clazz, method);
554 }
555
556 /* Print a condition that checks whether Python method argument "i"
557 * corresponds to the C function argument type "type".
558 */
print_argument_check(QualType type,int i)559 static void print_argument_check(QualType type, int i)
560 {
561 if (generator::is_isl_type(type)) {
562 string type_str;
563 type_str = generator::extract_type(type);
564 type_str = type2python(type_str);
565 printf("args[%d].__class__ is %s", i, type_str.c_str());
566 } else if (type->isPointerType()) {
567 printf("type(args[%d]) == str", i);
568 } else {
569 printf("type(args[%d]) == int", i);
570 }
571 }
572
573 /* Print a test that checks whether the arguments passed
574 * to the Python method correspond to the arguments
575 * expected by "fd".
576 * "drop_ctx" is set if the first argument of "fd" is an isl_ctx,
577 * which does not appear as an argument to the Python method.
578 *
579 * If an automatic conversion function is available for any
580 * of the argument types, then also allow the argument
581 * to be of the type as prescribed by the second input argument
582 * of the conversion function.
583 * The corresponding arguments are then converted to the expected types
584 * if needed. The argument tuple first needs to be converted to a list
585 * in order to be able to modify the entries.
586 */
print_argument_checks(const isl_class & clazz,FunctionDecl * fd,int drop_ctx)587 void python_generator::print_argument_checks(const isl_class &clazz,
588 FunctionDecl *fd, int drop_ctx)
589 {
590 int num_params = fd->getNumParams();
591 int first = generator::is_static(clazz, fd) ? drop_ctx : 1;
592 std::vector<bool> convert(num_params);
593
594 printf(" if len(args) == %d", num_params - drop_ctx);
595 for (int i = first; i < num_params; ++i) {
596 ParmVarDecl *param = fd->getParamDecl(i);
597 QualType type = param->getOriginalType();
598 const Type *ptr = type.getTypePtr();
599
600 printf(" and ");
601 if (conversions.count(ptr) == 0) {
602 print_argument_check(type, i - drop_ctx);
603 } else {
604 QualType type2 = conversions.at(ptr)->getOriginalType();
605 convert[i] = true;
606 printf("(");
607 print_argument_check(type, i - drop_ctx);
608 printf(" or ");
609 print_argument_check(type2, i - drop_ctx);
610 printf(")");
611 }
612 }
613 printf(":\n");
614
615 if (std::find(convert.begin(), convert.end(), true) == convert.end())
616 return;
617 print_indent(12, "args = list(args)\n");
618 for (int i = first; i < num_params; ++i) {
619 ParmVarDecl *param = fd->getParamDecl(i);
620 string type;
621
622 if (!convert[i])
623 continue;
624 type = type2python(extract_type(param->getOriginalType()));
625 print_type_check(12, type, var_arg_fmt,
626 i - drop_ctx, false, "", "", -1);
627 }
628 }
629
630 /* Print part of an overloaded python method corresponding to the C function
631 * "method".
632 * "drop_ctx" is set if the first argument of "method" is an isl_ctx.
633 *
634 * In particular, print code to test whether the arguments passed to
635 * the python method correspond to the arguments expected by "method"
636 * and to call "method" if they do.
637 */
print_method_overload(const isl_class & clazz,FunctionDecl * method)638 void python_generator::print_method_overload(const isl_class &clazz,
639 FunctionDecl *method)
640 {
641 int drop_ctx = first_arg_is_isl_ctx(method);
642
643 print_argument_checks(clazz, method, drop_ctx);
644 print_method_call(12, clazz, method, var_arg_fmt, drop_ctx, 0);
645 }
646
647 /* Print a python method with a name derived from "fullname"
648 * corresponding to the C functions "methods".
649 * "super" contains the superclasses of the class to which the method belongs.
650 *
651 * If "methods" consists of a single element that is not marked overloaded,
652 * the use print_method to print the method.
653 * Otherwise, print an overloaded method with pieces corresponding
654 * to each function in "methods".
655 */
print_method(const isl_class & clazz,const string & fullname,const function_set & methods,vector<string> super)656 void python_generator::print_method(const isl_class &clazz,
657 const string &fullname, const function_set &methods,
658 vector<string> super)
659 {
660 string cname;
661 function_set::const_iterator it;
662 FunctionDecl *any_method;
663
664 any_method = *methods.begin();
665 if (methods.size() == 1 && !is_overload(any_method)) {
666 print_method(clazz, any_method, super);
667 return;
668 }
669
670 cname = clazz.method_name(any_method);
671
672 print_method_def(is_static(clazz, any_method), cname);
673 printf("(*args):\n");
674
675 for (it = methods.begin(); it != methods.end(); ++it)
676 print_method_overload(clazz, *it);
677 printf(" raise Error\n");
678 }
679
680 /* Print a python method "name" corresponding to "fd" setting
681 * the enum value "value".
682 * "super" contains the superclasses of the class to which the method belongs,
683 * with the first element corresponding to the annotation that appears
684 * closest to the annotated type.
685 *
686 * The last argument of the C function does not appear in the method call,
687 * but is fixed to "value" instead.
688 * Other than that, the method printed here is similar to one
689 * printed by python_generator::print_method, except that
690 * some of the special cases do not occur.
691 */
print_set_enum(const isl_class & clazz,FunctionDecl * fd,int value,const string & name,const vector<string> & super)692 void python_generator::print_set_enum(const isl_class &clazz,
693 FunctionDecl *fd, int value, const string &name,
694 const vector<string> &super)
695 {
696 string fullname = fd->getName().str();
697 int num_params = fd->getNumParams();
698
699 print_method_header(is_static(clazz, fd), name, num_params - 1);
700
701 print_type_checks(name, fd, false, num_params - 1, super);
702 printf(" ctx = arg0.ctx\n");
703 printf(" res = isl.%s(", fullname.c_str());
704 for (int i = 0; i < num_params - 1; ++i) {
705 if (i)
706 printf(", ");
707 print_arg_in_call(fd, fixed_arg_fmt, i, 0);
708 }
709 printf(", %d", value);
710 printf(")\n");
711 print_method_return(8, clazz, fd, fixed_arg_fmt);
712 }
713
714 /* Print python methods corresponding to "fd", which sets an enum.
715 * "super" contains the superclasses of the class to which the method belongs,
716 * with the first element corresponding to the annotation that appears
717 * closest to the annotated type.
718 *
719 * A method is generated for each value in the enum, setting
720 * the enum to that value.
721 */
print_set_enum(const isl_class & clazz,FunctionDecl * fd,const vector<string> & super)722 void python_generator::print_set_enum(const isl_class &clazz,
723 FunctionDecl *fd, const vector<string> &super)
724 {
725 vector<set_enum>::const_iterator it;
726 const vector<set_enum> &set_enums = clazz.set_enums.at(fd);
727
728 for (it = set_enums.begin(); it != set_enums.end(); ++it)
729 print_set_enum(clazz, fd, it->value, it->method_name, super);
730 }
731
732 /* Print part of the constructor for this isl_class.
733 *
734 * In particular, check if the actual arguments correspond to the
735 * formal arguments of "cons" and if so call "cons" and put the
736 * result in self.ptr and a reference to the default context in self.ctx.
737 */
print_constructor(const isl_class & clazz,FunctionDecl * cons)738 void python_generator::print_constructor(const isl_class &clazz,
739 FunctionDecl *cons)
740 {
741 string fullname = cons->getName().str();
742 string cname = clazz.method_name(cons);
743 int num_params = cons->getNumParams();
744 int drop_ctx = first_arg_is_isl_ctx(cons);
745
746 print_argument_checks(clazz, cons, drop_ctx);
747 printf(" self.ctx = Context.getDefaultInstance()\n");
748 printf(" self.ptr = isl.%s(", fullname.c_str());
749 if (drop_ctx)
750 printf("self.ctx");
751 for (int i = drop_ctx; i < num_params; ++i) {
752 if (i)
753 printf(", ");
754 print_arg_in_call(cons, var_arg_fmt, i, drop_ctx);
755 }
756 printf(")\n");
757 printf(" return\n");
758 }
759
760 /* If "clazz" has a type function describing subclasses,
761 * then add constructors that allow each of these subclasses
762 * to be treated as an object to the superclass.
763 */
print_upcast_constructors(const isl_class & clazz)764 void python_generator::print_upcast_constructors(const isl_class &clazz)
765 {
766 map<int, string>::const_iterator i;
767
768 if (!clazz.fn_type)
769 return;
770
771 for (i = clazz.type_subclasses.begin();
772 i != clazz.type_subclasses.end(); ++i) {
773 printf(" if len(args) == 1 and "
774 "isinstance(args[0], %s):\n",
775 type2python(i->second).c_str());
776 printf(" self.ctx = args[0].ctx\n");
777 printf(" self.ptr = isl.%s_copy(args[0].ptr)\n",
778 clazz.name.c_str());
779 printf(" return\n");
780 }
781 }
782
783 /* Print the header of the class "name" with superclasses "super".
784 * The order of the superclasses is the opposite of the order
785 * in which the corresponding annotations appear in the source code.
786 * If "clazz" is a subclass derived from a type function,
787 * then the immediate superclass is recorded in "clazz" itself.
788 */
print_class_header(const isl_class & clazz,const string & name,const vector<string> & super)789 void python_generator::print_class_header(const isl_class &clazz,
790 const string &name, const vector<string> &super)
791 {
792 printf("class %s", name.c_str());
793 if (super.size() > 0) {
794 printf("(");
795 for (unsigned i = 0; i < super.size(); ++i) {
796 if (i > 0)
797 printf(", ");
798 printf("%s", type2python(super[i]).c_str());
799 }
800 printf(")");
801 } else if (clazz.is_type_subclass()) {
802 printf("(%s)", type2python(clazz.superclass_name).c_str());
803 } else {
804 printf("(object)");
805 }
806 printf(":\n");
807 }
808
809 /* Tell ctypes about the return type of "fd".
810 * In particular, if "fd" returns a pointer to an isl object,
811 * then tell ctypes it returns a "c_void_p".
812 * If "fd" returns a char *, then simply tell ctypes.
813 *
814 * Nothing needs to be done for functions returning
815 * isl_bool, isl_stat or isl_size since they are represented by an int and
816 * ctypes assumes that a function returns int by default.
817 */
print_restype(FunctionDecl * fd)818 void python_generator::print_restype(FunctionDecl *fd)
819 {
820 string fullname = fd->getName().str();
821 QualType type = fd->getReturnType();
822 if (is_isl_type(type))
823 printf("isl.%s.restype = c_void_p\n", fullname.c_str());
824 else if (is_string(type))
825 printf("isl.%s.restype = POINTER(c_char)\n", fullname.c_str());
826 }
827
828 /* Tell ctypes about the types of the arguments of the function "fd".
829 */
print_argtypes(FunctionDecl * fd)830 void python_generator::print_argtypes(FunctionDecl *fd)
831 {
832 string fullname = fd->getName().str();
833 int n = fd->getNumParams();
834 int drop_user = 0;
835
836 printf("isl.%s.argtypes = [", fullname.c_str());
837 for (int i = 0; i < n - drop_user; ++i) {
838 ParmVarDecl *param = fd->getParamDecl(i);
839 QualType type = param->getOriginalType();
840 if (is_callback(type))
841 drop_user = 1;
842 if (i)
843 printf(", ");
844 if (is_isl_ctx(type))
845 printf("Context");
846 else if (is_isl_type(type) || is_callback(type))
847 printf("c_void_p");
848 else if (is_string(type))
849 printf("c_char_p");
850 else if (is_long(type))
851 printf("c_long");
852 else
853 printf("c_int");
854 }
855 if (drop_user)
856 printf(", c_void_p");
857 printf("]\n");
858 }
859
860 /* Print type definitions for the method 'fd'.
861 */
print_method_type(FunctionDecl * fd)862 void python_generator::print_method_type(FunctionDecl *fd)
863 {
864 print_restype(fd);
865 print_argtypes(fd);
866 }
867
868 /* If "clazz" has a type function describing subclasses or
869 * if it is one of those type subclasses, then print a __new__ method.
870 *
871 * In the superclass, the __new__ method constructs an object
872 * of the subclass type specified by the type function.
873 * In the subclass, the __new__ method reverts to the original behavior.
874 */
print_new(const isl_class & clazz,const string & python_name)875 void python_generator::print_new(const isl_class &clazz,
876 const string &python_name)
877 {
878 if (!clazz.fn_type && !clazz.is_type_subclass())
879 return;
880
881 printf(" def __new__(cls, *args, **keywords):\n");
882
883 if (clazz.fn_type) {
884 map<int, string>::const_iterator i;
885
886 printf(" if \"ptr\" in keywords:\n");
887 printf(" type = isl.%s(keywords[\"ptr\"])\n",
888 clazz.fn_type->getNameAsString().c_str());
889
890 for (i = clazz.type_subclasses.begin();
891 i != clazz.type_subclasses.end(); ++i) {
892 printf(" if type == %d:\n", i->first);
893 printf(" return %s(**keywords)\n",
894 type2python(i->second).c_str());
895 }
896 printf(" raise\n");
897 }
898
899 printf(" return super(%s, cls).__new__(cls)\n",
900 python_name.c_str());
901 }
902
903 /* Print declarations for methods printing the class representation,
904 * provided there is a corresponding *_to_str function.
905 *
906 * In particular, provide an implementation of __str__ and __repr__ methods to
907 * override the default representation used by python. Python uses __str__ to
908 * pretty print the class (e.g., when calling print(obj)) and uses __repr__
909 * when printing a precise representation of an object (e.g., when dumping it
910 * in the REPL console).
911 *
912 * Check the type of the argument before calling the *_to_str function
913 * on it in case the method was called on an object from a subclass.
914 *
915 * The return value of the *_to_str function is decoded to a python string
916 * assuming an 'ascii' encoding. This is necessary for python 3 compatibility.
917 */
print_representation(const isl_class & clazz,const string & python_name)918 void python_generator::print_representation(const isl_class &clazz,
919 const string &python_name)
920 {
921 if (!clazz.fn_to_str)
922 return;
923
924 printf(" def __str__(arg0):\n");
925 print_type_check(8, python_name, fixed_arg_fmt, 0, false, "", "", -1);
926 printf(" ptr = isl.%s(arg0.ptr)\n",
927 string(clazz.fn_to_str->getName()).c_str());
928 printf(" res = cast(ptr, c_char_p).value.decode('ascii')\n");
929 printf(" libc.free(ptr)\n");
930 printf(" return res\n");
931 printf(" def __repr__(self):\n");
932 printf(" s = str(self)\n");
933 printf(" if '\"' in s:\n");
934 printf(" return 'isl.%s(\"\"\"%%s\"\"\")' %% s\n",
935 python_name.c_str());
936 printf(" else:\n");
937 printf(" return 'isl.%s(\"%%s\")' %% s\n",
938 python_name.c_str());
939 }
940
941 /* If "clazz" has any persistent callbacks, then print the definition
942 * of a "copy_callbacks" function that copies the persistent callbacks
943 * from one object to another.
944 */
print_copy_callbacks(const isl_class & clazz)945 void python_generator::print_copy_callbacks(const isl_class &clazz)
946 {
947 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
948 set<FunctionDecl *>::const_iterator in;
949
950 if (!clazz.has_persistent_callbacks())
951 return;
952
953 printf(" def copy_callbacks(self, obj):\n");
954 for (in = callbacks.begin(); in != callbacks.end(); ++in) {
955 string callback_name = clazz.persistent_callback_name(*in);
956
957 printf(" if hasattr(obj, '%s'):\n",
958 callback_name.c_str());
959 printf(" self.%s = obj.%s\n",
960 callback_name.c_str(), callback_name.c_str());
961 }
962 }
963
964 /* Print code to set method type signatures.
965 *
966 * To be able to call C functions it is necessary to explicitly set their
967 * argument and result types. Do this for all exported constructors and
968 * methods (including those that set a persistent callback and
969 * those that set an enum value),
970 * as well as for the *_to_str and the type function, if they exist.
971 * Assuming each exported class has a *_copy and a *_free method,
972 * also unconditionally set the type of such methods.
973 */
print_method_types(const isl_class & clazz)974 void python_generator::print_method_types(const isl_class &clazz)
975 {
976 function_set::const_iterator in;
977 map<string, function_set>::const_iterator it;
978 map<FunctionDecl *, vector<set_enum> >::const_iterator ie;
979 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
980
981 for (in = clazz.constructors.begin(); in != clazz.constructors.end();
982 ++in)
983 print_method_type(*in);
984
985 for (in = callbacks.begin(); in != callbacks.end(); ++in)
986 print_method_type(*in);
987 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
988 for (in = it->second.begin(); in != it->second.end(); ++in)
989 print_method_type(*in);
990 for (ie = clazz.set_enums.begin(); ie != clazz.set_enums.end(); ++ie)
991 print_method_type(ie->first);
992
993 print_method_type(clazz.fn_copy);
994 print_method_type(clazz.fn_free);
995 if (clazz.fn_to_str)
996 print_method_type(clazz.fn_to_str);
997 if (clazz.fn_type)
998 print_method_type(clazz.fn_type);
999 }
1000
1001 /* Print out the definition of this isl_class.
1002 *
1003 * We first check if this isl_class is a subclass of one or more other classes.
1004 * If it is, we make sure those superclasses are printed out first.
1005 *
1006 * Then we print a constructor with several cases, one for constructing
1007 * a Python object from a return value, one for each function that
1008 * was marked as a constructor and for each type based subclass.
1009 *
1010 * Next, we print out some common methods and the methods corresponding
1011 * to functions that are not marked as constructors, including those
1012 * that set a persistent callback and those that set an enum value.
1013 *
1014 * Finally, we tell ctypes about the types of the arguments of the
1015 * constructor functions and the return types of those function returning
1016 * an isl object.
1017 */
print(const isl_class & clazz)1018 void python_generator::print(const isl_class &clazz)
1019 {
1020 string p_name = type2python(clazz.subclass_name);
1021 function_set::const_iterator in;
1022 map<string, function_set>::const_iterator it;
1023 map<FunctionDecl *, vector<set_enum> >::const_iterator ie;
1024 vector<string> super = find_superclasses(clazz.type);
1025 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
1026
1027 for (unsigned i = 0; i < super.size(); ++i)
1028 if (done.find(super[i]) == done.end())
1029 print(classes[super[i]]);
1030 if (clazz.is_type_subclass() && done.find(clazz.name) == done.end())
1031 print(classes[clazz.name]);
1032 done.insert(clazz.subclass_name);
1033
1034 printf("\n");
1035 print_class_header(clazz, p_name, super);
1036 printf(" def __init__(self, *args, **keywords):\n");
1037
1038 printf(" if \"ptr\" in keywords:\n");
1039 printf(" self.ctx = keywords[\"ctx\"]\n");
1040 printf(" self.ptr = keywords[\"ptr\"]\n");
1041 printf(" return\n");
1042
1043 for (in = clazz.constructors.begin(); in != clazz.constructors.end();
1044 ++in)
1045 print_constructor(clazz, *in);
1046 print_upcast_constructors(clazz);
1047 printf(" raise Error\n");
1048 printf(" def __del__(self):\n");
1049 printf(" if hasattr(self, 'ptr'):\n");
1050 printf(" isl.%s_free(self.ptr)\n", clazz.name.c_str());
1051
1052 print_new(clazz, p_name);
1053 print_representation(clazz, p_name);
1054 print_copy_callbacks(clazz);
1055
1056 for (in = callbacks.begin(); in != callbacks.end(); ++in)
1057 print_method(clazz, *in, super);
1058 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
1059 print_method(clazz, it->first, it->second, super);
1060 for (ie = clazz.set_enums.begin(); ie != clazz.set_enums.end(); ++ie)
1061 print_set_enum(clazz, ie->first, super);
1062
1063 printf("\n");
1064
1065 print_method_types(clazz);
1066 }
1067
1068 /* Generate a python interface based on the extracted types and
1069 * functions.
1070 *
1071 * Print out each class in turn. If one of these is a subclass of some
1072 * other class, make sure the superclass is printed out first.
1073 * functions.
1074 */
generate()1075 void python_generator::generate()
1076 {
1077 map<string, isl_class>::iterator ci;
1078
1079 for (ci = classes.begin(); ci != classes.end(); ++ci) {
1080 if (done.find(ci->first) == done.end())
1081 print(ci->second);
1082 }
1083 }
1084