interface: do not assume every callback returns isl_stat
[isl.git] / interface / python.cc
blob17fd86e00fa1fccf3b3dac515b738b30b91e9945
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.
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.
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.
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 */
34 #include "isl_config.h"
36 #include <stdio.h>
37 #include <iostream>
38 #include <map>
39 #include <vector>
41 #include "python.h"
42 #include "generator.h"
44 /* Drop the "isl_" initial part of the type name "name".
46 static string type2python(string name)
48 return name.substr(4);
51 /* Print the header of the method "name" with "n_arg" arguments.
52 * If "is_static" is set, then mark the python method as static.
54 * If the method is called "from", then rename it to "convert_from"
55 * because "from" is a python keyword.
57 void python_generator::print_method_header(bool is_static, const string &name,
58 int n_arg)
60 const char *s;
62 if (is_static)
63 printf(" @staticmethod\n");
65 s = name.c_str();
66 if (name == "from")
67 s = "convert_from";
69 printf(" def %s(", s);
70 for (int i = 0; i < n_arg; ++i) {
71 if (i)
72 printf(", ");
73 printf("arg%d", i);
75 printf("):\n");
78 /* Print a check that the argument in position "pos" is of type "type".
79 * If this fails and if "upcast" is set, then convert the first
80 * argument to "super" and call the method "name" on it, passing
81 * the remaining of the "n" arguments.
82 * If the check fails and "upcast" is not set, then simply raise
83 * an exception.
84 * If "upcast" is not set, then the "super", "name" and "n" arguments
85 * to this function are ignored.
87 void python_generator::print_type_check(const string &type, int pos,
88 bool upcast, const string &super, const string &name, int n)
90 printf(" try:\n");
91 printf(" if not arg%d.__class__ is %s:\n",
92 pos, type.c_str());
93 printf(" arg%d = %s(arg%d)\n",
94 pos, type.c_str(), pos);
95 printf(" except:\n");
96 if (upcast) {
97 printf(" return %s(arg0).%s(",
98 type2python(super).c_str(), name.c_str());
99 for (int i = 1; i < n; ++i) {
100 if (i != 1)
101 printf(", ");
102 printf("arg%d", i);
104 printf(")\n");
105 } else
106 printf(" raise\n");
109 /* Print a call to the *_copy function corresponding to "type".
111 void python_generator::print_copy(QualType type)
113 string type_s = extract_type(type);
115 printf("isl.%s_copy", type_s.c_str());
118 /* Construct a wrapper for callback argument "param" (at position "arg").
119 * Assign the wrapper to "cb". We assume here that a function call
120 * has at most one callback argument.
122 * The wrapper converts the arguments of the callback to python types,
123 * taking a copy if the C callback does not take its arguments.
124 * If any exception is thrown, the wrapper keeps track of it in exc_info[0]
125 * and returns a value indicating an error. Otherwise the wrapper
126 * returns a value indicating success.
127 * In case the C callback is expected to return an isl_stat,
128 * the error value is -1 and the success value is 0.
129 * Otherwise, None is returned to indicate an error and
130 * a copy of the object in case of success.
132 void python_generator::print_callback(ParmVarDecl *param, int arg)
134 QualType type = param->getOriginalType();
135 const FunctionProtoType *fn = extract_prototype(type);
136 QualType return_type = fn->getReturnType();
137 unsigned n_arg = fn->getNumArgs();
139 printf(" exc_info = [None]\n");
140 printf(" fn = CFUNCTYPE(");
141 if (is_isl_stat(return_type))
142 printf("c_int");
143 else
144 printf("c_void_p");
145 for (unsigned i = 0; i < n_arg - 1; ++i) {
146 if (!is_isl_type(fn->getArgType(i)))
147 die("Argument has non-isl type");
148 printf(", c_void_p");
150 printf(", c_void_p)\n");
151 printf(" def cb_func(");
152 for (unsigned i = 0; i < n_arg; ++i) {
153 if (i)
154 printf(", ");
155 printf("cb_arg%d", i);
157 printf("):\n");
158 for (unsigned i = 0; i < n_arg - 1; ++i) {
159 string arg_type;
160 arg_type = type2python(extract_type(fn->getArgType(i)));
161 printf(" cb_arg%d = %s(ctx=arg0.ctx, ptr=",
162 i, arg_type.c_str());
163 if (!callback_takes_argument(param, i))
164 print_copy(fn->getArgType(i));
165 printf("(cb_arg%d))\n", i);
167 printf(" try:\n");
168 if (is_isl_stat(return_type))
169 printf(" arg%d(", arg);
170 else
171 printf(" res = arg%d(", arg);
172 for (unsigned i = 0; i < n_arg - 1; ++i) {
173 if (i)
174 printf(", ");
175 printf("cb_arg%d", i);
177 printf(")\n");
178 printf(" except:\n");
179 printf(" import sys\n");
180 printf(" exc_info[0] = sys.exc_info()\n");
181 if (is_isl_stat(return_type))
182 printf(" return -1\n");
183 else
184 printf(" return None\n");
185 if (is_isl_stat(return_type)) {
186 printf(" return 0\n");
187 } else {
188 printf(" return ");
189 print_copy(return_type);
190 printf("(res.ptr)\n");
192 printf(" cb = fn(cb_func)\n");
195 /* Print the argument at position "arg" in call to "fd".
196 * "skip" is the number of initial arguments of "fd" that are
197 * skipped in the Python method.
199 * If the argument is a callback, then print a reference to
200 * the callback wrapper "cb".
201 * Otherwise, if the argument is marked as consuming a reference,
202 * then pass a copy of the pointer stored in the corresponding
203 * argument passed to the Python method.
204 * Otherwise, if the argument is a pointer, then pass this pointer itself.
205 * Otherwise, pass the argument directly.
207 void python_generator::print_arg_in_call(FunctionDecl *fd, int arg, int skip)
209 ParmVarDecl *param = fd->getParamDecl(arg);
210 QualType type = param->getOriginalType();
211 if (is_callback(type)) {
212 printf("cb");
213 } else if (takes(param)) {
214 print_copy(type);
215 printf("(arg%d.ptr)", arg - skip);
216 } else if (type->isPointerType()) {
217 printf("arg%d.ptr", arg - skip);
218 } else {
219 printf("arg%d", arg - skip);
223 /* Print the return statement of the python method corresponding
224 * to the C function "method".
226 * If the return type is a (const) char *, then convert the result
227 * to a Python string, raising an error on NULL and freeing
228 * the C string if needed. For python 3 compatibility, the string returned
229 * by isl is explicitly decoded as an 'ascii' string. This is correct
230 * as all strings returned by isl are expected to be 'ascii'.
232 * If the return type is isl_stat, isl_bool or isl_size, then
233 * raise an error on isl_stat_error, isl_bool_error or isl_size_error.
234 * In case of isl_bool, the result is converted to
235 * a Python boolean.
236 * In case of isl_size, the result is converted to a Python int.
238 void python_generator::print_method_return(FunctionDecl *method)
240 QualType return_type = method->getReturnType();
242 if (is_isl_type(return_type)) {
243 string type;
245 type = type2python(extract_type(return_type));
246 printf(" return %s(ctx=ctx, ptr=res)\n", type.c_str());
247 } else if (is_string(return_type)) {
248 printf(" if res == 0:\n");
249 printf(" raise\n");
250 printf(" string = "
251 "cast(res, c_char_p).value.decode('ascii')\n");
253 if (gives(method))
254 printf(" libc.free(res)\n");
256 printf(" return string\n");
257 } else if (is_isl_neg_error(return_type)) {
258 printf(" if res < 0:\n");
259 printf(" raise\n");
260 if (is_isl_bool(return_type))
261 printf(" return bool(res)\n");
262 else if (is_isl_size(return_type))
263 printf(" return int(res)\n");
264 } else {
265 printf(" return res\n");
269 /* Print a python method corresponding to the C function "method".
270 * "super" contains the superclasses of the class to which the method belongs,
271 * with the first element corresponding to the annotation that appears
272 * closest to the annotated type. This superclass is the least
273 * general extension of the annotated type in the linearization
274 * of the class hierarchy.
276 * If the first argument of "method" is something other than an instance
277 * of the class, then mark the python method as static.
278 * If, moreover, this first argument is an isl_ctx, then remove
279 * it from the arguments of the Python method.
281 * If the function has a callback argument, then it also has a "user"
282 * argument. Since Python has closures, there is no need for such
283 * a user argument in the Python interface, so we simply drop it.
284 * We also create a wrapper ("cb") for the callback.
286 * For each argument of the function that refers to an isl structure,
287 * including the object on which the method is called,
288 * we check if the corresponding actual argument is of the right type.
289 * If not, we try to convert it to the right type.
290 * If that doesn't work and if "super" contains at least one element, we try
291 * to convert self to the type of the first superclass in "super" and
292 * call the corresponding method.
294 * If the function consumes a reference, then we pass it a copy of
295 * the actual argument.
297 void python_generator::print_method(const isl_class &clazz,
298 FunctionDecl *method, vector<string> super)
300 string fullname = method->getName();
301 string cname = clazz.method_name(method);
302 int num_params = method->getNumParams();
303 int drop_user = 0;
304 int drop_ctx = first_arg_is_isl_ctx(method);
306 for (int i = 1; i < num_params; ++i) {
307 ParmVarDecl *param = method->getParamDecl(i);
308 QualType type = param->getOriginalType();
309 if (is_callback(type))
310 drop_user = 1;
313 print_method_header(is_static(clazz, method), cname,
314 num_params - drop_ctx - drop_user);
316 for (int i = drop_ctx; i < num_params; ++i) {
317 ParmVarDecl *param = method->getParamDecl(i);
318 string type;
319 if (!is_isl_type(param->getOriginalType()))
320 continue;
321 type = type2python(extract_type(param->getOriginalType()));
322 if (!drop_ctx && i > 0 && super.size() > 0)
323 print_type_check(type, i - drop_ctx, true, super[0],
324 cname, num_params - drop_user);
325 else
326 print_type_check(type, i - drop_ctx, false, "",
327 cname, -1);
329 for (int i = 1; i < num_params; ++i) {
330 ParmVarDecl *param = method->getParamDecl(i);
331 QualType type = param->getOriginalType();
332 if (!is_callback(type))
333 continue;
334 print_callback(param, i - drop_ctx);
336 if (drop_ctx)
337 printf(" ctx = Context.getDefaultInstance()\n");
338 else
339 printf(" ctx = arg0.ctx\n");
340 printf(" res = isl.%s(", fullname.c_str());
341 if (drop_ctx)
342 printf("ctx");
343 else
344 print_arg_in_call(method, 0, 0);
345 for (int i = 1; i < num_params - drop_user; ++i) {
346 printf(", ");
347 print_arg_in_call(method, i, drop_ctx);
349 if (drop_user)
350 printf(", None");
351 printf(")\n");
353 if (drop_user) {
354 printf(" if exc_info[0] != None:\n");
355 printf(" raise (exc_info[0][0], "
356 "exc_info[0][1], exc_info[0][2])\n");
359 print_method_return(method);
362 /* Print part of an overloaded python method corresponding to the C function
363 * "method".
365 * In particular, print code to test whether the arguments passed to
366 * the python method correspond to the arguments expected by "method"
367 * and to call "method" if they do.
369 void python_generator::print_method_overload(const isl_class &clazz,
370 FunctionDecl *method)
372 string fullname = method->getName();
373 int num_params = method->getNumParams();
374 int first;
375 string type;
377 first = is_static(clazz, method) ? 0 : 1;
379 printf(" if ");
380 for (int i = first; i < num_params; ++i) {
381 if (i > first)
382 printf(" and ");
383 ParmVarDecl *param = method->getParamDecl(i);
384 if (is_isl_type(param->getOriginalType())) {
385 string type;
386 type = extract_type(param->getOriginalType());
387 type = type2python(type);
388 printf("arg%d.__class__ is %s", i, type.c_str());
389 } else
390 printf("type(arg%d) == str", i);
392 printf(":\n");
393 printf(" res = isl.%s(", fullname.c_str());
394 print_arg_in_call(method, 0, 0);
395 for (int i = 1; i < num_params; ++i) {
396 printf(", ");
397 print_arg_in_call(method, i, 0);
399 printf(")\n");
400 type = type2python(extract_type(method->getReturnType()));
401 printf(" return %s(ctx=arg0.ctx, ptr=res)\n", type.c_str());
404 /* Print a python method with a name derived from "fullname"
405 * corresponding to the C functions "methods".
406 * "super" contains the superclasses of the class to which the method belongs.
408 * If "methods" consists of a single element that is not marked overloaded,
409 * the use print_method to print the method.
410 * Otherwise, print an overloaded method with pieces corresponding
411 * to each function in "methods".
413 void python_generator::print_method(const isl_class &clazz,
414 const string &fullname, const set<FunctionDecl *> &methods,
415 vector<string> super)
417 string cname;
418 set<FunctionDecl *>::const_iterator it;
419 int num_params;
420 FunctionDecl *any_method;
422 any_method = *methods.begin();
423 if (methods.size() == 1 && !is_overload(any_method)) {
424 print_method(clazz, any_method, super);
425 return;
428 cname = clazz.method_name(any_method);
429 num_params = any_method->getNumParams();
431 print_method_header(is_static(clazz, any_method), cname, num_params);
433 for (it = methods.begin(); it != methods.end(); ++it)
434 print_method_overload(clazz, *it);
437 /* Print part of the constructor for this isl_class.
439 * In particular, check if the actual arguments correspond to the
440 * formal arguments of "cons" and if so call "cons" and put the
441 * result in self.ptr and a reference to the default context in self.ctx.
443 * If the function consumes a reference, then we pass it a copy of
444 * the actual argument.
446 * If the function takes a string argument, the python string is first
447 * encoded as a byte sequence, using 'ascii' as encoding. This assumes
448 * that all strings passed to isl can be converted to 'ascii'.
450 void python_generator::print_constructor(const isl_class &clazz,
451 FunctionDecl *cons)
453 string fullname = cons->getName();
454 string cname = clazz.method_name(cons);
455 int num_params = cons->getNumParams();
456 int drop_ctx = first_arg_is_isl_ctx(cons);
458 printf(" if len(args) == %d", num_params - drop_ctx);
459 for (int i = drop_ctx; i < num_params; ++i) {
460 ParmVarDecl *param = cons->getParamDecl(i);
461 QualType type = param->getOriginalType();
462 if (is_isl_type(type)) {
463 string s;
464 s = type2python(extract_type(type));
465 printf(" and args[%d].__class__ is %s",
466 i - drop_ctx, s.c_str());
467 } else if (type->isPointerType()) {
468 printf(" and type(args[%d]) == str", i - drop_ctx);
469 } else {
470 printf(" and type(args[%d]) == int", i - drop_ctx);
473 printf(":\n");
474 printf(" self.ctx = Context.getDefaultInstance()\n");
475 printf(" self.ptr = isl.%s(", fullname.c_str());
476 if (drop_ctx)
477 printf("self.ctx");
478 for (int i = drop_ctx; i < num_params; ++i) {
479 ParmVarDecl *param = cons->getParamDecl(i);
480 QualType type = param->getOriginalType();
481 if (i)
482 printf(", ");
483 if (is_isl_type(type)) {
484 if (takes(param))
485 print_copy(param->getOriginalType());
486 printf("(args[%d].ptr)", i - drop_ctx);
487 } else if (is_string(type)) {
488 printf("args[%d].encode('ascii')", i - drop_ctx);
489 } else {
490 printf("args[%d]", i - drop_ctx);
493 printf(")\n");
494 printf(" return\n");
497 /* Print the header of the class "name" with superclasses "super".
498 * The order of the superclasses is the opposite of the order
499 * in which the corresponding annotations appear in the source code.
501 void python_generator::print_class_header(const isl_class &clazz,
502 const string &name, const vector<string> &super)
504 printf("class %s", name.c_str());
505 if (super.size() > 0) {
506 printf("(");
507 for (unsigned i = 0; i < super.size(); ++i) {
508 if (i > 0)
509 printf(", ");
510 printf("%s", type2python(super[i]).c_str());
512 printf(")");
513 } else {
514 printf("(object)");
516 printf(":\n");
519 /* Tell ctypes about the return type of "fd".
520 * In particular, if "fd" returns a pointer to an isl object,
521 * then tell ctypes it returns a "c_void_p".
522 * If "fd" returns a char *, then simply tell ctypes.
524 * Nothing needs to be done for functions returning
525 * isl_bool, isl_stat or isl_size since they are represented by an int and
526 * ctypes assumes that a function returns int by default.
528 void python_generator::print_restype(FunctionDecl *fd)
530 string fullname = fd->getName();
531 QualType type = fd->getReturnType();
532 if (is_isl_type(type))
533 printf("isl.%s.restype = c_void_p\n", fullname.c_str());
534 else if (is_string(type))
535 printf("isl.%s.restype = POINTER(c_char)\n", fullname.c_str());
538 /* Tell ctypes about the types of the arguments of the function "fd".
540 void python_generator::print_argtypes(FunctionDecl *fd)
542 string fullname = fd->getName();
543 int n = fd->getNumParams();
544 int drop_user = 0;
546 printf("isl.%s.argtypes = [", fullname.c_str());
547 for (int i = 0; i < n - drop_user; ++i) {
548 ParmVarDecl *param = fd->getParamDecl(i);
549 QualType type = param->getOriginalType();
550 if (is_callback(type))
551 drop_user = 1;
552 if (i)
553 printf(", ");
554 if (is_isl_ctx(type))
555 printf("Context");
556 else if (is_isl_type(type) || is_callback(type))
557 printf("c_void_p");
558 else if (is_string(type))
559 printf("c_char_p");
560 else if (is_long(type))
561 printf("c_long");
562 else
563 printf("c_int");
565 if (drop_user)
566 printf(", c_void_p");
567 printf("]\n");
570 /* Print type definitions for the method 'fd'.
572 void python_generator::print_method_type(FunctionDecl *fd)
574 print_restype(fd);
575 print_argtypes(fd);
578 /* Print declarations for methods printing the class representation,
579 * provided there is a corresponding *_to_str function.
581 * In particular, provide an implementation of __str__ and __repr__ methods to
582 * override the default representation used by python. Python uses __str__ to
583 * pretty print the class (e.g., when calling print(obj)) and uses __repr__
584 * when printing a precise representation of an object (e.g., when dumping it
585 * in the REPL console).
587 * Check the type of the argument before calling the *_to_str function
588 * on it in case the method was called on an object from a subclass.
590 * The return value of the *_to_str function is decoded to a python string
591 * assuming an 'ascii' encoding. This is necessary for python 3 compatibility.
593 void python_generator::print_representation(const isl_class &clazz,
594 const string &python_name)
596 if (!clazz.fn_to_str)
597 return;
599 printf(" def __str__(arg0):\n");
600 print_type_check(python_name, 0, false, "", "", -1);
601 printf(" ptr = isl.%s(arg0.ptr)\n",
602 string(clazz.fn_to_str->getName()).c_str());
603 printf(" res = cast(ptr, c_char_p).value.decode('ascii')\n");
604 printf(" libc.free(ptr)\n");
605 printf(" return res\n");
606 printf(" def __repr__(self):\n");
607 printf(" s = str(self)\n");
608 printf(" if '\"' in s:\n");
609 printf(" return 'isl.%s(\"\"\"%%s\"\"\")' %% s\n",
610 python_name.c_str());
611 printf(" else:\n");
612 printf(" return 'isl.%s(\"%%s\")' %% s\n",
613 python_name.c_str());
616 /* Print code to set method type signatures.
618 * To be able to call C functions it is necessary to explicitly set their
619 * argument and result types. Do this for all exported constructors and
620 * methods, as well as for the *_to_str method, if it exists.
621 * Assuming each exported class has a *_copy and a *_free method,
622 * also unconditionally set the type of such methods.
624 void python_generator::print_method_types(const isl_class &clazz)
626 set<FunctionDecl *>::const_iterator in;
627 map<string, set<FunctionDecl *> >::const_iterator it;
629 for (in = clazz.constructors.begin(); in != clazz.constructors.end();
630 ++in)
631 print_method_type(*in);
633 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
634 for (in = it->second.begin(); in != it->second.end(); ++in)
635 print_method_type(*in);
637 print_method_type(clazz.fn_copy);
638 print_method_type(clazz.fn_free);
639 if (clazz.fn_to_str)
640 print_method_type(clazz.fn_to_str);
643 /* Print out the definition of this isl_class.
645 * We first check if this isl_class is a subclass of one or more other classes.
646 * If it is, we make sure those superclasses are printed out first.
648 * Then we print a constructor with several cases, one for constructing
649 * a Python object from a return value and one for each function that
650 * was marked as a constructor.
652 * Next, we print out some common methods and the methods corresponding
653 * to functions that are not marked as constructors.
655 * Finally, we tell ctypes about the types of the arguments of the
656 * constructor functions and the return types of those function returning
657 * an isl object.
659 void python_generator::print(const isl_class &clazz)
661 string p_name = type2python(clazz.name);
662 set<FunctionDecl *>::const_iterator in;
663 map<string, set<FunctionDecl *> >::const_iterator it;
664 vector<string> super = find_superclasses(clazz.type);
666 for (unsigned i = 0; i < super.size(); ++i)
667 if (done.find(super[i]) == done.end())
668 print(classes[super[i]]);
669 done.insert(clazz.name);
671 printf("\n");
672 print_class_header(clazz, p_name, super);
673 printf(" def __init__(self, *args, **keywords):\n");
675 printf(" if \"ptr\" in keywords:\n");
676 printf(" self.ctx = keywords[\"ctx\"]\n");
677 printf(" self.ptr = keywords[\"ptr\"]\n");
678 printf(" return\n");
680 for (in = clazz.constructors.begin(); in != clazz.constructors.end();
681 ++in)
682 print_constructor(clazz, *in);
683 printf(" raise Error\n");
684 printf(" def __del__(self):\n");
685 printf(" if hasattr(self, 'ptr'):\n");
686 printf(" isl.%s_free(self.ptr)\n", clazz.name.c_str());
688 print_representation(clazz, p_name);
690 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)
691 print_method(clazz, it->first, it->second, super);
693 printf("\n");
695 print_method_types(clazz);
698 /* Generate a python interface based on the extracted types and
699 * functions.
701 * Print out each class in turn. If one of these is a subclass of some
702 * other class, make sure the superclass is printed out first.
703 * functions.
705 void python_generator::generate()
707 map<string, isl_class>::iterator ci;
709 for (ci = classes.begin(); ci != classes.end(); ++ci) {
710 if (done.find(ci->first) == done.end())
711 print(ci->second);