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 BaseException as e:\n"); 261 printf(" exc_info[0] = e\n"); 262 if (is_isl_stat(return_type) || is_isl_bool(return_type)) 263 printf(" return -1\n"); 264 else 265 printf(" return None\n"); 266 if (is_isl_stat(return_type)) { 267 printf(" return 0\n"); 268 } else if (is_isl_bool(return_type)) { 269 printf(" return 1 if res else 0\n"); 270 } else { 271 printf(" return "); 272 print_copy(return_type); 273 printf("(res.ptr)\n"); 274 } 275 printf(" cb = fn(cb_func)\n"); 276 } 277 278 /* Print the argument at position "arg" in call to "fd". 279 * "fmt" is the format for printing Python method arguments. 280 * "skip" is the number of initial arguments of "fd" that are 281 * skipped in the Python method. 282 * 283 * If the (first) argument is an isl_ctx, then print "ctx", 284 * assuming that the caller has made the context available 285 * in a "ctx" variable. 286 * Otherwise, if the argument is a callback, then print a reference to 287 * the callback wrapper "cb". 288 * Otherwise, if the argument is marked as consuming a reference, 289 * then pass a copy of the pointer stored in the corresponding 290 * argument passed to the Python method. 291 * Otherwise, if the argument is a string, then the python string is first 292 * encoded as a byte sequence, using 'ascii' as encoding. This assumes 293 * that all strings passed to isl can be converted to 'ascii'. 294 * Otherwise, if the argument is a pointer, then pass this pointer itself. 295 * Otherwise, pass the argument directly. 296 */ 297 void python_generator::print_arg_in_call(FunctionDecl *fd, const char *fmt, 298 int arg, int skip) 299 { 300 ParmVarDecl *param = fd->getParamDecl(arg); 301 QualType type = param->getOriginalType(); 302 if (is_isl_ctx(type)) { 303 printf("ctx"); 304 } else if (is_callback(type)) { 305 printf("cb"); 306 } else if (takes(param)) { 307 print_copy(type); 308 printf("("); 309 printf(fmt, arg - skip); 310 printf(".ptr)"); 311 } else if (is_string(type)) { 312 printf(fmt, arg - skip); 313 printf(".encode('ascii')"); 314 } else if (type->isPointerType()) { 315 printf(fmt, arg - skip); 316 printf(".ptr"); 317 } else { 318 printf(fmt, arg - skip); 319 } 320 } 321 322 /* Generate code that raises the exception captured in "exc_info", if any, 323 * with the given indentation. 324 */ 325 static void print_rethrow(int indent, const char *exc_info) 326 { 327 print_indent(indent, "if %s is not None:\n", exc_info); 328 print_indent(indent, " raise %s\n", exc_info); 329 } 330 331 /* Print code with the given indentation that checks 332 * whether any of the persistent callbacks of "clazz" 333 * is set and if it failed with an exception. If so, the 'exc_info' 334 * field contains the exception and is raised again. 335 * The field is cleared because the callback and its data may get reused. 336 * "fmt" is the format for printing Python method arguments. 337 */ 338 static void print_persistent_callback_failure_check(int indent, 339 const isl_class &clazz, const char *fmt) 340 { 341 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks; 342 set<FunctionDecl *>::const_iterator in; 343 344 for (in = callbacks.begin(); in != callbacks.end(); ++in) { 345 string callback_name = clazz.persistent_callback_name(*in); 346 347 print_indent(indent, "if hasattr("); 348 printf(fmt, 0); 349 printf(", '%s') and ", callback_name.c_str()); 350 printf(fmt, 0); 351 printf(".%s['exc_info'] != None:\n", callback_name.c_str()); 352 print_indent(indent, " exc_info = "); 353 printf(fmt, 0); 354 printf(".%s['exc_info'][0]\n", callback_name.c_str()); 355 print_indent(indent, " "); 356 printf(fmt, 0); 357 printf(".%s['exc_info'][0] = None\n", callback_name.c_str()); 358 print_rethrow(indent + 4, "exc_info"); 359 } 360 } 361 362 /* Print the return statement of the python method corresponding 363 * to the C function "method" with the given indentation. 364 * If the object on which the method was called 365 * may have a persistent callback, then first check if any of those failed. 366 * "fmt" is the format for printing Python method arguments. 367 * 368 * If the method returns a new instance of the same object type and 369 * if the class has any persistent callbacks, then the data 370 * for these callbacks are copied from the original to the new object. 371 * If the method it itself setting a persistent callback, 372 * then keep track of the constructed C callback (such that it doesn't 373 * get destroyed) and the data structure that holds the captured exception 374 * (such that it can be raised again). 375 * 376 * If the return type is a (const) char *, then convert the result 377 * to a Python string, raising an error on NULL and freeing 378 * the C string if needed. For python 3 compatibility, the string returned 379 * by isl is explicitly decoded as an 'ascii' string. This is correct 380 * as all strings returned by isl are expected to be 'ascii'. 381 * 382 * If the return type is isl_stat, isl_bool or isl_size, then 383 * raise an error on isl_stat_error, isl_bool_error or isl_size_error. 384 * In case of isl_bool, the result is converted to 385 * a Python boolean. 386 * In case of isl_size, the result is converted to a Python int. 387 */ 388 void python_generator::print_method_return(int indent, const isl_class &clazz, 389 FunctionDecl *method, const char *fmt) 390 { 391 QualType return_type = method->getReturnType(); 392 393 if (!is_static(clazz, method)) 394 print_persistent_callback_failure_check(indent, clazz, fmt); 395 396 if (is_isl_type(return_type)) { 397 string type; 398 399 type = type2python(extract_type(return_type)); 400 print_indent(indent, 401 "obj = %s(ctx=ctx, ptr=res)\n", type.c_str()); 402 if (is_mutator(clazz, method) && 403 clazz.has_persistent_callbacks()) 404 print_indent(indent, "obj.copy_callbacks(arg0)\n"); 405 if (clazz.persistent_callbacks.count(method)) { 406 string callback_name; 407 408 callback_name = clazz.persistent_callback_name(method); 409 print_indent(indent, "obj.%s = { 'func': cb, " 410 "'exc_info': exc_info }\n", 411 callback_name.c_str()); 412 } 413 print_indent(indent, "return obj\n"); 414 } else if (is_string(return_type)) { 415 print_indent(indent, "if res == 0:\n"); 416 print_indent(indent, " raise\n"); 417 print_indent(indent, "string = " 418 "cast(res, c_char_p).value.decode('ascii')\n"); 419 420 if (gives(method)) 421 print_indent(indent, "libc.free(res)\n"); 422 423 print_indent(indent, "return string\n"); 424 } else if (is_isl_neg_error(return_type)) { 425 print_indent(indent, "if res < 0:\n"); 426 print_indent(indent, " raise\n"); 427 if (is_isl_bool(return_type)) 428 print_indent(indent, "return bool(res)\n"); 429 else if (is_isl_size(return_type)) 430 print_indent(indent, "return int(res)\n"); 431 } else { 432 print_indent(indent, "return res\n"); 433 } 434 } 435 436 /* Print a python "get" method corresponding to the C function "fd" 437 * in class "clazz" using a name that includes the "get_" prefix. 438 * 439 * This method simply calls the variant without the "get_" prefix and 440 * returns its result. 441 * Note that static methods are not considered to be "get" methods. 442 */ 443 void python_generator::print_get_method(const isl_class &clazz, 444 FunctionDecl *fd) 445 { 446 string get_name = clazz.base_method_name(fd); 447 string name = clazz.method_name(fd); 448 int num_params = fd->getNumParams(); 449 450 print_method_header(false, get_name, num_params); 451 printf(" return arg0.%s(", name.c_str()); 452 print_method_arguments(1, num_params); 453 printf(")\n"); 454 } 455 456 /* Print a call to "method", along with the corresponding 457 * return statement, with the given indentation. 458 * "drop_ctx" is set if the first argument is an isl_ctx. 459 * "drop_user" is set if the last argument is a "user" argument 460 * corresponding to a callback argument. 461 * 462 * A "ctx" variable is first initialized as it may be needed 463 * in the first call to print_arg_in_call and in print_method_return. 464 * 465 * If the method has a callback function, then any exception 466 * thrown in the callback also need to be rethrown. 467 */ 468 void python_generator::print_method_call(int indent, const isl_class &clazz, 469 FunctionDecl *method, const char *fmt, int drop_ctx, int drop_user) 470 { 471 string fullname = method->getName().str(); 472 int num_params = method->getNumParams(); 473 474 if (drop_ctx) { 475 print_indent(indent, "ctx = Context.getDefaultInstance()\n"); 476 } else { 477 print_indent(indent, "ctx = "); 478 printf(fmt, 0); 479 printf(".ctx\n"); 480 } 481 print_indent(indent, "res = isl.%s(", fullname.c_str()); 482 for (int i = 0; i < num_params - drop_user; ++i) { 483 if (i > 0) 484 printf(", "); 485 print_arg_in_call(method, fmt, i, drop_ctx); 486 } 487 if (drop_user) 488 printf(", None"); 489 printf(")\n"); 490 491 if (drop_user) 492 print_rethrow(indent, "exc_info[0]"); 493 494 print_method_return(indent, clazz, method, fmt); 495 } 496 497 /* Print a python method corresponding to the C function "method". 498 * "super" contains the superclasses of the class to which the method belongs, 499 * with the first element corresponding to the annotation that appears 500 * closest to the annotated type. This superclass is the least 501 * general extension of the annotated type in the linearization 502 * of the class hierarchy. 503 * 504 * If the first argument of "method" is something other than an instance 505 * of the class, then mark the python method as static. 506 * If, moreover, this first argument is an isl_ctx, then remove 507 * it from the arguments of the Python method. 508 * 509 * If the function has a callback argument, then it also has a "user" 510 * argument. Since Python has closures, there is no need for such 511 * a user argument in the Python interface, so we simply drop it. 512 * We also create a wrapper ("cb") for the callback. 513 * 514 * If the function consumes a reference, then we pass it a copy of 515 * the actual argument. 516 * 517 * For methods that are identified as "get" methods, also 518 * print a variant of the method using a name that includes 519 * the "get_" prefix. 520 */ 521 void python_generator::print_method(const isl_class &clazz, 522 FunctionDecl *method, vector<string> super) 523 { 524 string cname = clazz.method_name(method); 525 int num_params = method->getNumParams(); 526 int drop_user = 0; 527 int drop_ctx = first_arg_is_isl_ctx(method); 528 529 for (int i = 1; i < num_params; ++i) { 530 ParmVarDecl *param = method->getParamDecl(i); 531 QualType type = param->getOriginalType(); 532 if (is_callback(type)) 533 drop_user = 1; 534 } 535 536 print_method_header(is_static(clazz, method), cname, 537 num_params - drop_ctx - drop_user); 538 539 print_type_checks(cname, method, drop_ctx, 540 num_params - drop_user, super); 541 for (int i = 1; i < num_params; ++i) { 542 ParmVarDecl *param = method->getParamDecl(i); 543 QualType type = param->getOriginalType(); 544 if (!is_callback(type)) 545 continue; 546 print_callback(param, i - drop_ctx); 547 } 548 print_method_call(8, clazz, method, fixed_arg_fmt, drop_ctx, drop_user); 549 550 if (clazz.is_get_method(method)) 551 print_get_method(clazz, method); 552 } 553 554 /* Print a condition that checks whether Python method argument "i" 555 * corresponds to the C function argument type "type". 556 */ 557 static void print_argument_check(QualType type, int i) 558 { 559 if (generator::is_isl_type(type)) { 560 string type_str; 561 type_str = generator::extract_type(type); 562 type_str = type2python(type_str); 563 printf("args[%d].__class__ is %s", i, type_str.c_str()); 564 } else if (type->isPointerType()) { 565 printf("type(args[%d]) == str", i); 566 } else { 567 printf("type(args[%d]) == int", i); 568 } 569 } 570 571 /* Print a test that checks whether the arguments passed 572 * to the Python method correspond to the arguments 573 * expected by "fd". 574 * "drop_ctx" is set if the first argument of "fd" is an isl_ctx, 575 * which does not appear as an argument to the Python method. 576 * 577 * If an automatic conversion function is available for any 578 * of the argument types, then also allow the argument 579 * to be of the type as prescribed by the second input argument 580 * of the conversion function. 581 * The corresponding arguments are then converted to the expected types 582 * if needed. The argument tuple first needs to be converted to a list 583 * in order to be able to modify the entries. 584 */ 585 void python_generator::print_argument_checks(const isl_class &clazz, 586 FunctionDecl *fd, int drop_ctx) 587 { 588 int num_params = fd->getNumParams(); 589 int first = generator::is_static(clazz, fd) ? drop_ctx : 1; 590 std::vector<bool> convert(num_params); 591 592 printf(" if len(args) == %d", num_params - drop_ctx); 593 for (int i = first; i < num_params; ++i) { 594 ParmVarDecl *param = fd->getParamDecl(i); 595 QualType type = param->getOriginalType(); 596 const Type *ptr = type.getTypePtr(); 597 598 printf(" and "); 599 if (conversions.count(ptr) == 0) { 600 print_argument_check(type, i - drop_ctx); 601 } else { 602 QualType type2 = conversions.at(ptr)->getOriginalType(); 603 convert[i] = true; 604 printf("("); 605 print_argument_check(type, i - drop_ctx); 606 printf(" or "); 607 print_argument_check(type2, i - drop_ctx); 608 printf(")"); 609 } 610 } 611 printf(":\n"); 612 613 if (std::find(convert.begin(), convert.end(), true) == convert.end()) 614 return; 615 print_indent(12, "args = list(args)\n"); 616 for (int i = first; i < num_params; ++i) { 617 ParmVarDecl *param = fd->getParamDecl(i); 618 string type; 619 620 if (!convert[i]) 621 continue; 622 type = type2python(extract_type(param->getOriginalType())); 623 print_type_check(12, type, var_arg_fmt, 624 i - drop_ctx, false, "", "", -1); 625 } 626 } 627 628 /* Print part of an overloaded python method corresponding to the C function 629 * "method". 630 * "drop_ctx" is set if the first argument of "method" is an isl_ctx. 631 * 632 * In particular, print code to test whether the arguments passed to 633 * the python method correspond to the arguments expected by "method" 634 * and to call "method" if they do. 635 */ 636 void python_generator::print_method_overload(const isl_class &clazz, 637 FunctionDecl *method) 638 { 639 int drop_ctx = first_arg_is_isl_ctx(method); 640 641 print_argument_checks(clazz, method, drop_ctx); 642 print_method_call(12, clazz, method, var_arg_fmt, drop_ctx, 0); 643 } 644 645 /* Print a python method with a name derived from "fullname" 646 * corresponding to the C functions "methods". 647 * "super" contains the superclasses of the class to which the method belongs. 648 * 649 * If "methods" consists of a single element that is not marked overloaded, 650 * the use print_method to print the method. 651 * Otherwise, print an overloaded method with pieces corresponding 652 * to each function in "methods". 653 */ 654 void python_generator::print_method(const isl_class &clazz, 655 const string &fullname, const function_set &methods, 656 vector<string> super) 657 { 658 string cname; 659 function_set::const_iterator it; 660 FunctionDecl *any_method; 661 662 any_method = *methods.begin(); 663 if (methods.size() == 1 && !is_overload(any_method)) { 664 print_method(clazz, any_method, super); 665 return; 666 } 667 668 cname = clazz.method_name(any_method); 669 670 print_method_def(is_static(clazz, any_method), cname); 671 printf("(*args):\n"); 672 673 for (it = methods.begin(); it != methods.end(); ++it) 674 print_method_overload(clazz, *it); 675 printf(" raise Error\n"); 676 } 677 678 /* Print a python method "name" corresponding to "fd" setting 679 * the enum value "value". 680 * "super" contains the superclasses of the class to which the method belongs, 681 * with the first element corresponding to the annotation that appears 682 * closest to the annotated type. 683 * 684 * The last argument of the C function does not appear in the method call, 685 * but is fixed to "value" instead. 686 * Other than that, the method printed here is similar to one 687 * printed by python_generator::print_method, except that 688 * some of the special cases do not occur. 689 */ 690 void python_generator::print_set_enum(const isl_class &clazz, 691 FunctionDecl *fd, int value, const string &name, 692 const vector<string> &super) 693 { 694 string fullname = fd->getName().str(); 695 int num_params = fd->getNumParams(); 696 697 print_method_header(is_static(clazz, fd), name, num_params - 1); 698 699 print_type_checks(name, fd, false, num_params - 1, super); 700 printf(" ctx = arg0.ctx\n"); 701 printf(" res = isl.%s(", fullname.c_str()); 702 for (int i = 0; i < num_params - 1; ++i) { 703 if (i) 704 printf(", "); 705 print_arg_in_call(fd, fixed_arg_fmt, i, 0); 706 } 707 printf(", %d", value); 708 printf(")\n"); 709 print_method_return(8, clazz, fd, fixed_arg_fmt); 710 } 711 712 /* Print python methods corresponding to "fd", which sets an enum. 713 * "super" contains the superclasses of the class to which the method belongs, 714 * with the first element corresponding to the annotation that appears 715 * closest to the annotated type. 716 * 717 * A method is generated for each value in the enum, setting 718 * the enum to that value. 719 */ 720 void python_generator::print_set_enum(const isl_class &clazz, 721 FunctionDecl *fd, const vector<string> &super) 722 { 723 vector<set_enum>::const_iterator it; 724 const vector<set_enum> &set_enums = clazz.set_enums.at(fd); 725 726 for (it = set_enums.begin(); it != set_enums.end(); ++it) 727 print_set_enum(clazz, fd, it->value, it->method_name, super); 728 } 729 730 /* Print part of the constructor for this isl_class. 731 * 732 * In particular, check if the actual arguments correspond to the 733 * formal arguments of "cons" and if so call "cons" and put the 734 * result in self.ptr and a reference to the default context in self.ctx. 735 */ 736 void python_generator::print_constructor(const isl_class &clazz, 737 FunctionDecl *cons) 738 { 739 string fullname = cons->getName().str(); 740 string cname = clazz.method_name(cons); 741 int num_params = cons->getNumParams(); 742 int drop_ctx = first_arg_is_isl_ctx(cons); 743 744 print_argument_checks(clazz, cons, drop_ctx); 745 printf(" self.ctx = Context.getDefaultInstance()\n"); 746 printf(" self.ptr = isl.%s(", fullname.c_str()); 747 if (drop_ctx) 748 printf("self.ctx"); 749 for (int i = drop_ctx; i < num_params; ++i) { 750 if (i) 751 printf(", "); 752 print_arg_in_call(cons, var_arg_fmt, i, drop_ctx); 753 } 754 printf(")\n"); 755 printf(" return\n"); 756 } 757 758 /* If "clazz" has a type function describing subclasses, 759 * then add constructors that allow each of these subclasses 760 * to be treated as an object to the superclass. 761 */ 762 void python_generator::print_upcast_constructors(const isl_class &clazz) 763 { 764 map<int, string>::const_iterator i; 765 766 if (!clazz.fn_type) 767 return; 768 769 for (i = clazz.type_subclasses.begin(); 770 i != clazz.type_subclasses.end(); ++i) { 771 printf(" if len(args) == 1 and " 772 "isinstance(args[0], %s):\n", 773 type2python(i->second).c_str()); 774 printf(" self.ctx = args[0].ctx\n"); 775 printf(" self.ptr = isl.%s_copy(args[0].ptr)\n", 776 clazz.name.c_str()); 777 printf(" return\n"); 778 } 779 } 780 781 /* Print the header of the class "name" with superclasses "super". 782 * The order of the superclasses is the opposite of the order 783 * in which the corresponding annotations appear in the source code. 784 * If "clazz" is a subclass derived from a type function, 785 * then the immediate superclass is recorded in "clazz" itself. 786 */ 787 void python_generator::print_class_header(const isl_class &clazz, 788 const string &name, const vector<string> &super) 789 { 790 printf("class %s", name.c_str()); 791 if (super.size() > 0) { 792 printf("("); 793 for (unsigned i = 0; i < super.size(); ++i) { 794 if (i > 0) 795 printf(", "); 796 printf("%s", type2python(super[i]).c_str()); 797 } 798 printf(")"); 799 } else if (clazz.is_type_subclass()) { 800 printf("(%s)", type2python(clazz.superclass_name).c_str()); 801 } else { 802 printf("(object)"); 803 } 804 printf(":\n"); 805 } 806 807 /* Tell ctypes about the return type of "fd". 808 * In particular, if "fd" returns a pointer to an isl object, 809 * then tell ctypes it returns a "c_void_p". 810 * If "fd" returns a char *, then simply tell ctypes. 811 * 812 * Nothing needs to be done for functions returning 813 * isl_bool, isl_stat or isl_size since they are represented by an int and 814 * ctypes assumes that a function returns int by default. 815 */ 816 void python_generator::print_restype(FunctionDecl *fd) 817 { 818 string fullname = fd->getName().str(); 819 QualType type = fd->getReturnType(); 820 if (is_isl_type(type)) 821 printf("isl.%s.restype = c_void_p\n", fullname.c_str()); 822 else if (is_string(type)) 823 printf("isl.%s.restype = POINTER(c_char)\n", fullname.c_str()); 824 } 825 826 /* Tell ctypes about the types of the arguments of the function "fd". 827 */ 828 void python_generator::print_argtypes(FunctionDecl *fd) 829 { 830 string fullname = fd->getName().str(); 831 int n = fd->getNumParams(); 832 int drop_user = 0; 833 834 printf("isl.%s.argtypes = [", fullname.c_str()); 835 for (int i = 0; i < n - drop_user; ++i) { 836 ParmVarDecl *param = fd->getParamDecl(i); 837 QualType type = param->getOriginalType(); 838 if (is_callback(type)) 839 drop_user = 1; 840 if (i) 841 printf(", "); 842 if (is_isl_ctx(type)) 843 printf("Context"); 844 else if (is_isl_type(type) || is_callback(type)) 845 printf("c_void_p"); 846 else if (is_string(type)) 847 printf("c_char_p"); 848 else if (is_long(type)) 849 printf("c_long"); 850 else 851 printf("c_int"); 852 } 853 if (drop_user) 854 printf(", c_void_p"); 855 printf("]\n"); 856 } 857 858 /* Print type definitions for the method 'fd'. 859 */ 860 void python_generator::print_method_type(FunctionDecl *fd) 861 { 862 print_restype(fd); 863 print_argtypes(fd); 864 } 865 866 /* If "clazz" has a type function describing subclasses or 867 * if it is one of those type subclasses, then print a __new__ method. 868 * 869 * In the superclass, the __new__ method constructs an object 870 * of the subclass type specified by the type function. 871 * In the subclass, the __new__ method reverts to the original behavior. 872 */ 873 void python_generator::print_new(const isl_class &clazz, 874 const string &python_name) 875 { 876 if (!clazz.fn_type && !clazz.is_type_subclass()) 877 return; 878 879 printf(" def __new__(cls, *args, **keywords):\n"); 880 881 if (clazz.fn_type) { 882 map<int, string>::const_iterator i; 883 884 printf(" if \"ptr\" in keywords:\n"); 885 printf(" type = isl.%s(keywords[\"ptr\"])\n", 886 clazz.fn_type->getNameAsString().c_str()); 887 888 for (i = clazz.type_subclasses.begin(); 889 i != clazz.type_subclasses.end(); ++i) { 890 printf(" if type == %d:\n", i->first); 891 printf(" return %s(**keywords)\n", 892 type2python(i->second).c_str()); 893 } 894 printf(" raise\n"); 895 } 896 897 printf(" return super(%s, cls).__new__(cls)\n", 898 python_name.c_str()); 899 } 900 901 /* Print declarations for methods printing the class representation, 902 * provided there is a corresponding *_to_str function. 903 * 904 * In particular, provide an implementation of __str__ and __repr__ methods to 905 * override the default representation used by python. Python uses __str__ to 906 * pretty print the class (e.g., when calling print(obj)) and uses __repr__ 907 * when printing a precise representation of an object (e.g., when dumping it 908 * in the REPL console). 909 * 910 * Check the type of the argument before calling the *_to_str function 911 * on it in case the method was called on an object from a subclass. 912 * 913 * The return value of the *_to_str function is decoded to a python string 914 * assuming an 'ascii' encoding. This is necessary for python 3 compatibility. 915 */ 916 void python_generator::print_representation(const isl_class &clazz, 917 const string &python_name) 918 { 919 if (!clazz.fn_to_str) 920 return; 921 922 printf(" def __str__(arg0):\n"); 923 print_type_check(8, python_name, fixed_arg_fmt, 0, false, "", "", -1); 924 printf(" ptr = isl.%s(arg0.ptr)\n", 925 string(clazz.fn_to_str->getName()).c_str()); 926 printf(" res = cast(ptr, c_char_p).value.decode('ascii')\n"); 927 printf(" libc.free(ptr)\n"); 928 printf(" return res\n"); 929 printf(" def __repr__(self):\n"); 930 printf(" s = str(self)\n"); 931 printf(" if '\"' in s:\n"); 932 printf(" return 'isl.%s(\"\"\"%%s\"\"\")' %% s\n", 933 python_name.c_str()); 934 printf(" else:\n"); 935 printf(" return 'isl.%s(\"%%s\")' %% s\n", 936 python_name.c_str()); 937 } 938 939 /* If "clazz" has any persistent callbacks, then print the definition 940 * of a "copy_callbacks" function that copies the persistent callbacks 941 * from one object to another. 942 */ 943 void python_generator::print_copy_callbacks(const isl_class &clazz) 944 { 945 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks; 946 set<FunctionDecl *>::const_iterator in; 947 948 if (!clazz.has_persistent_callbacks()) 949 return; 950 951 printf(" def copy_callbacks(self, obj):\n"); 952 for (in = callbacks.begin(); in != callbacks.end(); ++in) { 953 string callback_name = clazz.persistent_callback_name(*in); 954 955 printf(" if hasattr(obj, '%s'):\n", 956 callback_name.c_str()); 957 printf(" self.%s = obj.%s\n", 958 callback_name.c_str(), callback_name.c_str()); 959 } 960 } 961 962 /* Print code to set method type signatures. 963 * 964 * To be able to call C functions it is necessary to explicitly set their 965 * argument and result types. Do this for all exported constructors and 966 * methods (including those that set a persistent callback and 967 * those that set an enum value), 968 * as well as for the *_to_str and the type function, if they exist. 969 * Assuming each exported class has a *_copy and a *_free method, 970 * also unconditionally set the type of such methods. 971 */ 972 void python_generator::print_method_types(const isl_class &clazz) 973 { 974 function_set::const_iterator in; 975 map<string, function_set>::const_iterator it; 976 map<FunctionDecl *, vector<set_enum> >::const_iterator ie; 977 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks; 978 979 for (in = clazz.constructors.begin(); in != clazz.constructors.end(); 980 ++in) 981 print_method_type(*in); 982 983 for (in = callbacks.begin(); in != callbacks.end(); ++in) 984 print_method_type(*in); 985 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) 986 for (in = it->second.begin(); in != it->second.end(); ++in) 987 print_method_type(*in); 988 for (ie = clazz.set_enums.begin(); ie != clazz.set_enums.end(); ++ie) 989 print_method_type(ie->first); 990 991 print_method_type(clazz.fn_copy); 992 print_method_type(clazz.fn_free); 993 if (clazz.fn_to_str) 994 print_method_type(clazz.fn_to_str); 995 if (clazz.fn_type) 996 print_method_type(clazz.fn_type); 997 } 998 999 /* Print out the definition of this isl_class. 1000 * 1001 * We first check if this isl_class is a subclass of one or more other classes. 1002 * If it is, we make sure those superclasses are printed out first. 1003 * 1004 * Then we print a constructor with several cases, one for constructing 1005 * a Python object from a return value, one for each function that 1006 * was marked as a constructor and for each type based subclass. 1007 * 1008 * Next, we print out some common methods and the methods corresponding 1009 * to functions that are not marked as constructors, including those 1010 * that set a persistent callback and those that set an enum value. 1011 * 1012 * Finally, we tell ctypes about the types of the arguments of the 1013 * constructor functions and the return types of those function returning 1014 * an isl object. 1015 */ 1016 void python_generator::print(const isl_class &clazz) 1017 { 1018 string p_name = type2python(clazz.subclass_name); 1019 function_set::const_iterator in; 1020 map<string, function_set>::const_iterator it; 1021 map<FunctionDecl *, vector<set_enum> >::const_iterator ie; 1022 vector<string> super = find_superclasses(clazz.type); 1023 const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks; 1024 1025 for (unsigned i = 0; i < super.size(); ++i) 1026 if (done.find(super[i]) == done.end()) 1027 print(classes[super[i]]); 1028 if (clazz.is_type_subclass() && done.find(clazz.name) == done.end()) 1029 print(classes[clazz.name]); 1030 done.insert(clazz.subclass_name); 1031 1032 printf("\n"); 1033 print_class_header(clazz, p_name, super); 1034 printf(" def __init__(self, *args, **keywords):\n"); 1035 1036 printf(" if \"ptr\" in keywords:\n"); 1037 printf(" self.ctx = keywords[\"ctx\"]\n"); 1038 printf(" self.ptr = keywords[\"ptr\"]\n"); 1039 printf(" return\n"); 1040 1041 for (in = clazz.constructors.begin(); in != clazz.constructors.end(); 1042 ++in) 1043 print_constructor(clazz, *in); 1044 print_upcast_constructors(clazz); 1045 printf(" raise Error\n"); 1046 printf(" def __del__(self):\n"); 1047 printf(" if hasattr(self, 'ptr'):\n"); 1048 printf(" isl.%s_free(self.ptr)\n", clazz.name.c_str()); 1049 1050 print_new(clazz, p_name); 1051 print_representation(clazz, p_name); 1052 print_copy_callbacks(clazz); 1053 1054 for (in = callbacks.begin(); in != callbacks.end(); ++in) 1055 print_method(clazz, *in, super); 1056 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) 1057 print_method(clazz, it->first, it->second, super); 1058 for (ie = clazz.set_enums.begin(); ie != clazz.set_enums.end(); ++ie) 1059 print_set_enum(clazz, ie->first, super); 1060 1061 printf("\n"); 1062 1063 print_method_types(clazz); 1064 } 1065 1066 /* Generate a python interface based on the extracted types and 1067 * functions. 1068 * 1069 * Print out each class in turn. If one of these is a subclass of some 1070 * other class, make sure the superclass is printed out first. 1071 * functions. 1072 */ 1073 void python_generator::generate() 1074 { 1075 map<string, isl_class>::iterator ci; 1076 1077 for (ci = classes.begin(); ci != classes.end(); ++ci) { 1078 if (done.find(ci->first) == done.end()) 1079 print(ci->second); 1080 } 1081 } 1082