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