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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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