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