1 /* 2 * Copyright 2016, 2017 Tobias Grosser. 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 TOBIAS GROSSER ''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 * Tobias Grosser. 32 */ 33 34 #include <cstdarg> 35 #include <cstdio> 36 #include <iostream> 37 #include <map> 38 #include <sstream> 39 #include <string> 40 #include <vector> 41 42 #include "cpp.h" 43 #include "isl_config.h" 44 45 /* Print string formatted according to "fmt" to ostream "os". 46 * 47 * This osprintf method allows us to use printf style formatting constructs when 48 * writing to an ostream. 49 */ 50 static void osprintf(ostream &os, const char *format, ...) 51 { 52 va_list arguments; 53 char *string_pointer; 54 size_t size; 55 56 va_start(arguments, format); 57 size = vsnprintf(NULL, 0, format, arguments); 58 string_pointer = new char[size + 1]; 59 va_end(arguments); 60 va_start(arguments, format); 61 vsnprintf(string_pointer, size + 1, format, arguments); 62 va_end(arguments); 63 os << string_pointer; 64 delete[] string_pointer; 65 } 66 67 /* Convert "l" to a string. 68 */ 69 static std::string to_string(long l) 70 { 71 std::ostringstream strm; 72 strm << l; 73 return strm.str(); 74 } 75 76 /* Generate a cpp interface based on the extracted types and functions. 77 * 78 * Print first a set of forward declarations for all isl wrapper 79 * classes, then the declarations of the classes, and at the end all 80 * implementations. 81 * 82 * If checked C++ bindings are being generated, 83 * then wrap them in a namespace to avoid conflicts 84 * with the default C++ bindings (with automatic checks using exceptions). 85 */ 86 void cpp_generator::generate() 87 { 88 ostream &os = cout; 89 90 osprintf(os, "\n"); 91 osprintf(os, "namespace isl {\n\n"); 92 if (checked) 93 osprintf(os, "namespace checked {\n\n"); 94 95 print_forward_declarations(os); 96 osprintf(os, "\n"); 97 print_declarations(os); 98 osprintf(os, "\n"); 99 print_implementations(os); 100 101 if (checked) 102 osprintf(os, "} // namespace checked\n"); 103 osprintf(os, "} // namespace isl\n"); 104 } 105 106 /* Print forward declarations for all classes to "os". 107 */ 108 void cpp_generator::print_forward_declarations(ostream &os) 109 { 110 map<string, isl_class>::iterator ci; 111 112 osprintf(os, "// forward declarations\n"); 113 114 for (ci = classes.begin(); ci != classes.end(); ++ci) 115 print_class_forward_decl(os, ci->second); 116 } 117 118 /* Print all declarations to "os". 119 */ 120 void cpp_generator::print_declarations(ostream &os) 121 { 122 map<string, isl_class>::iterator ci; 123 bool first = true; 124 125 for (ci = classes.begin(); ci != classes.end(); ++ci) { 126 if (first) 127 first = false; 128 else 129 osprintf(os, "\n"); 130 131 print_class(os, ci->second); 132 } 133 } 134 135 /* Print all implementations to "os". 136 */ 137 void cpp_generator::print_implementations(ostream &os) 138 { 139 map<string, isl_class>::iterator ci; 140 bool first = true; 141 142 for (ci = classes.begin(); ci != classes.end(); ++ci) { 143 if (first) 144 first = false; 145 else 146 osprintf(os, "\n"); 147 148 print_class_impl(os, ci->second); 149 } 150 } 151 152 /* Print declarations for class "clazz" to "os". 153 */ 154 void cpp_generator::print_class(ostream &os, const isl_class &clazz) 155 { 156 const char *name = clazz.name.c_str(); 157 std::string cppstring = type2cpp(clazz); 158 const char *cppname = cppstring.c_str(); 159 160 osprintf(os, "// declarations for isl::%s\n", cppname); 161 162 print_class_factory_decl(os, clazz); 163 osprintf(os, "\n"); 164 osprintf(os, "class %s {\n", cppname); 165 print_class_factory_decl(os, clazz, " friend "); 166 osprintf(os, "\n"); 167 osprintf(os, " %s *ptr = nullptr;\n", name); 168 osprintf(os, "\n"); 169 print_private_constructors_decl(os, clazz); 170 osprintf(os, "\n"); 171 osprintf(os, "public:\n"); 172 print_public_constructors_decl(os, clazz); 173 print_constructors_decl(os, clazz); 174 print_copy_assignment_decl(os, clazz); 175 print_destructor_decl(os, clazz); 176 print_ptr_decl(os, clazz); 177 print_get_ctx_decl(os); 178 osprintf(os, "\n"); 179 print_methods_decl(os, clazz); 180 181 osprintf(os, "};\n"); 182 } 183 184 /* Print forward declaration of class "clazz" to "os". 185 */ 186 void cpp_generator::print_class_forward_decl(ostream &os, 187 const isl_class &clazz) 188 { 189 std::string cppstring = type2cpp(clazz); 190 const char *cppname = cppstring.c_str(); 191 192 osprintf(os, "class %s;\n", cppname); 193 } 194 195 /* Print global factory functions to "os". 196 * 197 * Each class has two global factory functions: 198 * 199 * set manage(__isl_take isl_set *ptr); 200 * set manage_copy(__isl_keep isl_set *ptr); 201 * 202 * A user can construct isl C++ objects from a raw pointer and indicate whether 203 * they intend to take the ownership of the object or not through these global 204 * factory functions. This ensures isl object creation is very explicit and 205 * pointers are not converted by accident. Thanks to overloading, manage() and 206 * manage_copy() can be called on any isl raw pointer and the corresponding 207 * object is automatically created, without the user having to choose the right 208 * isl object type. 209 */ 210 void cpp_generator::print_class_factory_decl(ostream &os, 211 const isl_class &clazz, const std::string &prefix) 212 { 213 const char *name = clazz.name.c_str(); 214 std::string cppstring = type2cpp(clazz); 215 const char *cppname = cppstring.c_str(); 216 217 os << prefix; 218 osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name); 219 os << prefix; 220 osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n", 221 cppname, name); 222 } 223 224 /* Print declarations of private constructors for class "clazz" to "os". 225 * 226 * Each class has currently one private constructor: 227 * 228 * 1) Constructor from a plain isl_* C pointer 229 * 230 * Example: 231 * 232 * set(__isl_take isl_set *ptr); 233 * 234 * The raw pointer constructor is kept private. Object creation is only 235 * possible through manage() or manage_copy(). 236 */ 237 void cpp_generator::print_private_constructors_decl(ostream &os, 238 const isl_class &clazz) 239 { 240 const char *name = clazz.name.c_str(); 241 std::string cppstring = type2cpp(clazz); 242 const char *cppname = cppstring.c_str(); 243 244 osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname, 245 name); 246 } 247 248 /* Print declarations of public constructors for class "clazz" to "os". 249 * 250 * Each class currently has two public constructors: 251 * 252 * 1) A default constructor 253 * 2) A copy constructor 254 * 255 * Example: 256 * 257 * set(); 258 * set(const set &set); 259 */ 260 void cpp_generator::print_public_constructors_decl(ostream &os, 261 const isl_class &clazz) 262 { 263 std::string cppstring = type2cpp(clazz); 264 const char *cppname = cppstring.c_str(); 265 osprintf(os, " inline /* implicit */ %s();\n", cppname); 266 267 osprintf(os, " inline /* implicit */ %s(const %s &obj);\n", 268 cppname, cppname); 269 } 270 271 /* Print declarations for constructors for class "class" to "os". 272 * 273 * For each isl function that is marked as __isl_constructor, 274 * add a corresponding C++ constructor. 275 * 276 * Example: 277 * 278 * inline /\* implicit *\/ union_set(basic_set bset); 279 * inline /\* implicit *\/ union_set(set set); 280 * inline explicit val(ctx ctx, long i); 281 * inline explicit val(ctx ctx, const std::string &str); 282 */ 283 void cpp_generator::print_constructors_decl(ostream &os, 284 const isl_class &clazz) 285 { 286 set<FunctionDecl *>::const_iterator in; 287 const set<FunctionDecl *> &constructors = clazz.constructors; 288 289 for (in = constructors.begin(); in != constructors.end(); ++in) { 290 FunctionDecl *cons = *in; 291 292 print_method_decl(os, clazz, cons, function_kind_constructor); 293 } 294 } 295 296 /* Print declarations of copy assignment operator for class "clazz" 297 * to "os". 298 * 299 * Each class has one assignment operator. 300 * 301 * isl:set &set::operator=(set obj) 302 * 303 */ 304 void cpp_generator::print_copy_assignment_decl(ostream &os, 305 const isl_class &clazz) 306 { 307 std::string cppstring = type2cpp(clazz); 308 const char *cppname = cppstring.c_str(); 309 310 osprintf(os, " inline %s &operator=(%s obj);\n", cppname, cppname); 311 } 312 313 /* Print declaration of destructor for class "clazz" to "os". 314 */ 315 void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz) 316 { 317 std::string cppstring = type2cpp(clazz); 318 const char *cppname = cppstring.c_str(); 319 320 osprintf(os, " inline ~%s();\n", cppname); 321 } 322 323 /* Print declaration of pointer functions for class "clazz" to "os". 324 * 325 * To obtain a raw pointer three functions are provided: 326 * 327 * 1) __isl_give isl_set *copy() 328 * 329 * Returns a pointer to a _copy_ of the internal object 330 * 331 * 2) __isl_keep isl_set *get() 332 * 333 * Returns a pointer to the internal object 334 * 335 * 3) __isl_give isl_set *release() 336 * 337 * Returns a pointer to the internal object and resets the 338 * internal pointer to nullptr. 339 * 340 * We also provide functionality to explicitly check if a pointer is 341 * currently managed by this object. 342 * 343 * 4) bool is_null() 344 * 345 * Check if the current object is a null pointer. 346 * 347 * The functions get() and release() model the value_ptr proposed in 348 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf. 349 * The copy() function is an extension to allow the user to explicitly 350 * copy the underlying object. 351 * 352 * Also generate a declaration to delete copy() for r-values, for 353 * r-values release() should be used to avoid unnecessary copies. 354 */ 355 void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz) 356 { 357 const char *name = clazz.name.c_str(); 358 359 osprintf(os, " inline __isl_give %s *copy() const &;\n", name); 360 osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name); 361 osprintf(os, " inline __isl_keep %s *get() const;\n", name); 362 osprintf(os, " inline __isl_give %s *release();\n", name); 363 osprintf(os, " inline bool is_null() const;\n"); 364 } 365 366 /* Print the declaration of the get_ctx method. 367 */ 368 void cpp_generator::print_get_ctx_decl(ostream &os) 369 { 370 osprintf(os, " inline ctx get_ctx() const;\n"); 371 } 372 373 /* Print declarations for methods in class "clazz" to "os". 374 */ 375 void cpp_generator::print_methods_decl(ostream &os, const isl_class &clazz) 376 { 377 map<string, set<FunctionDecl *> >::const_iterator it; 378 379 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) 380 print_method_group_decl(os, clazz, it->second); 381 } 382 383 /* Print declarations for methods "methods" in class "clazz" to "os". 384 */ 385 void cpp_generator::print_method_group_decl(ostream &os, const isl_class &clazz, 386 const set<FunctionDecl *> &methods) 387 { 388 set<FunctionDecl *>::const_iterator it; 389 390 for (it = methods.begin(); it != methods.end(); ++it) { 391 function_kind kind = get_method_kind(clazz, *it); 392 print_method_decl(os, clazz, *it, kind); 393 } 394 } 395 396 /* Print declarations for "method" in class "clazz" to "os". 397 * 398 * "kind" specifies the kind of method that should be generated. 399 */ 400 void cpp_generator::print_method_decl(ostream &os, const isl_class &clazz, 401 FunctionDecl *method, function_kind kind) 402 { 403 print_method_header(os, clazz, method, true, kind); 404 } 405 406 /* Print implementations for class "clazz" to "os". 407 */ 408 void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz) 409 { 410 std::string cppstring = type2cpp(clazz); 411 const char *cppname = cppstring.c_str(); 412 413 osprintf(os, "// implementations for isl::%s\n", cppname); 414 415 print_class_factory_impl(os, clazz); 416 osprintf(os, "\n"); 417 print_public_constructors_impl(os, clazz); 418 osprintf(os, "\n"); 419 print_private_constructors_impl(os, clazz); 420 osprintf(os, "\n"); 421 print_constructors_impl(os, clazz); 422 osprintf(os, "\n"); 423 print_copy_assignment_impl(os, clazz); 424 osprintf(os, "\n"); 425 print_destructor_impl(os, clazz); 426 osprintf(os, "\n"); 427 print_ptr_impl(os, clazz); 428 osprintf(os, "\n"); 429 print_get_ctx_impl(os, clazz); 430 osprintf(os, "\n"); 431 print_methods_impl(os, clazz); 432 } 433 434 /* Print code for throwing an exception corresponding to the last error 435 * that occurred on "ctx". 436 * This assumes that a valid isl::ctx is available in the "ctx" variable, 437 * e.g., through a prior call to print_save_ctx. 438 */ 439 static void print_throw_last_error(ostream &os) 440 { 441 osprintf(os, " exception::throw_last_error(ctx);\n"); 442 } 443 444 /* Print code for throwing an exception on NULL input. 445 */ 446 static void print_throw_NULL_input(ostream &os) 447 { 448 osprintf(os, " exception::throw_NULL_input(__FILE__, __LINE__);\n"); 449 } 450 451 /* Print code that checks that "ptr" is not NULL at input. 452 * 453 * Omit the check if checked C++ bindings are being generated. 454 */ 455 void cpp_generator::print_check_ptr(ostream &os, const char *ptr) 456 { 457 if (checked) 458 return; 459 460 osprintf(os, " if (!%s)\n", ptr); 461 print_throw_NULL_input(os); 462 } 463 464 /* Print code that checks that "ptr" is not NULL at input and 465 * that saves a copy of the isl_ctx of "ptr" for a later check. 466 * 467 * Omit the check if checked C++ bindings are being generated. 468 */ 469 void cpp_generator::print_check_ptr_start(ostream &os, const isl_class &clazz, 470 const char *ptr) 471 { 472 if (checked) 473 return; 474 475 print_check_ptr(os, ptr); 476 osprintf(os, " auto ctx = %s_get_ctx(%s);\n", clazz.name.c_str(), ptr); 477 print_on_error_continue(os); 478 } 479 480 /* Print code that checks that "ptr" is not NULL at the end. 481 * A copy of the isl_ctx is expected to have been saved by 482 * code generated by print_check_ptr_start. 483 * 484 * Omit the check if checked C++ bindings are being generated. 485 */ 486 void cpp_generator::print_check_ptr_end(ostream &os, const char *ptr) 487 { 488 if (checked) 489 return; 490 491 osprintf(os, " if (!%s)\n", ptr); 492 print_throw_last_error(os); 493 } 494 495 /* Print implementation of global factory functions to "os". 496 * 497 * Each class has two global factory functions: 498 * 499 * set manage(__isl_take isl_set *ptr); 500 * set manage_copy(__isl_keep isl_set *ptr); 501 * 502 * Unless checked C++ bindings are being generated, 503 * both functions require the argument to be non-NULL. 504 * An exception is thrown if anything went wrong during the copying 505 * in manage_copy. 506 * During the copying, isl is made not to print any error message 507 * because the error message is included in the exception. 508 */ 509 void cpp_generator::print_class_factory_impl(ostream &os, 510 const isl_class &clazz) 511 { 512 const char *name = clazz.name.c_str(); 513 std::string cppstring = type2cpp(clazz); 514 const char *cppname = cppstring.c_str(); 515 516 osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name); 517 print_check_ptr(os, "ptr"); 518 osprintf(os, " return %s(ptr);\n", cppname); 519 osprintf(os, "}\n"); 520 521 osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname, 522 name); 523 print_check_ptr_start(os, clazz, "ptr"); 524 osprintf(os, " ptr = %s_copy(ptr);\n", name); 525 print_check_ptr_end(os, "ptr"); 526 osprintf(os, " return %s(ptr);\n", cppname); 527 osprintf(os, "}\n"); 528 } 529 530 /* Print implementations of private constructors for class "clazz" to "os". 531 */ 532 void cpp_generator::print_private_constructors_impl(ostream &os, 533 const isl_class &clazz) 534 { 535 const char *name = clazz.name.c_str(); 536 std::string cppstring = type2cpp(clazz); 537 const char *cppname = cppstring.c_str(); 538 539 osprintf(os, "%s::%s(__isl_take %s *ptr)\n : ptr(ptr) {}\n", 540 cppname, cppname, name); 541 } 542 543 /* Print implementations of public constructors for class "clazz" to "os". 544 * 545 * Throw an exception from the copy constructor if anything went wrong 546 * during the copying or if the input is NULL. 547 * During the copying, isl is made not to print any error message 548 * because the error message is included in the exception. 549 * No exceptions are thrown if checked C++ bindings 550 * are being generated, 551 */ 552 void cpp_generator::print_public_constructors_impl(ostream &os, 553 const isl_class &clazz) 554 { 555 std::string cppstring = type2cpp(clazz); 556 const char *cppname = cppstring.c_str(); 557 558 osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, cppname); 559 osprintf(os, "%s::%s(const %s &obj)\n : ptr(nullptr)\n", 560 cppname, cppname, cppname); 561 osprintf(os, "{\n"); 562 print_check_ptr_start(os, clazz, "obj.ptr"); 563 osprintf(os, " ptr = obj.copy();\n"); 564 print_check_ptr_end(os, "ptr"); 565 osprintf(os, "}\n"); 566 } 567 568 /* Print implementations of constructors for class "clazz" to "os". 569 */ 570 void cpp_generator::print_constructors_impl(ostream &os, 571 const isl_class &clazz) 572 { 573 set<FunctionDecl *>::const_iterator in; 574 const set<FunctionDecl *> constructors = clazz.constructors; 575 576 for (in = constructors.begin(); in != constructors.end(); ++in) { 577 FunctionDecl *cons = *in; 578 579 print_method_impl(os, clazz, cons, function_kind_constructor); 580 } 581 } 582 583 /* Print implementation of copy assignment operator for class "clazz" to "os". 584 */ 585 void cpp_generator::print_copy_assignment_impl(ostream &os, 586 const isl_class &clazz) 587 { 588 const char *name = clazz.name.c_str(); 589 std::string cppstring = type2cpp(clazz); 590 const char *cppname = cppstring.c_str(); 591 592 osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname, 593 cppname, cppname); 594 osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name); 595 osprintf(os, " return *this;\n"); 596 osprintf(os, "}\n"); 597 } 598 599 /* Print implementation of destructor for class "clazz" to "os". 600 */ 601 void cpp_generator::print_destructor_impl(ostream &os, 602 const isl_class &clazz) 603 { 604 const char *name = clazz.name.c_str(); 605 std::string cppstring = type2cpp(clazz); 606 const char *cppname = cppstring.c_str(); 607 608 osprintf(os, "%s::~%s() {\n", cppname, cppname); 609 osprintf(os, " if (ptr)\n"); 610 osprintf(os, " %s_free(ptr);\n", name); 611 osprintf(os, "}\n"); 612 } 613 614 /* Print implementation of ptr() functions for class "clazz" to "os". 615 */ 616 void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz) 617 { 618 const char *name = clazz.name.c_str(); 619 std::string cppstring = type2cpp(clazz); 620 const char *cppname = cppstring.c_str(); 621 622 osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname); 623 osprintf(os, " return %s_copy(ptr);\n", name); 624 osprintf(os, "}\n\n"); 625 osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname); 626 osprintf(os, " return ptr;\n"); 627 osprintf(os, "}\n\n"); 628 osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname); 629 osprintf(os, " %s *tmp = ptr;\n", name); 630 osprintf(os, " ptr = nullptr;\n"); 631 osprintf(os, " return tmp;\n"); 632 osprintf(os, "}\n\n"); 633 osprintf(os, "bool %s::is_null() const {\n", cppname); 634 osprintf(os, " return ptr == nullptr;\n"); 635 osprintf(os, "}\n"); 636 } 637 638 /* Print the implementation of the get_ctx method. 639 */ 640 void cpp_generator::print_get_ctx_impl(ostream &os, const isl_class &clazz) 641 { 642 const char *name = clazz.name.c_str(); 643 std::string cppstring = type2cpp(clazz); 644 const char *cppname = cppstring.c_str(); 645 646 osprintf(os, "ctx %s::get_ctx() const {\n", cppname); 647 osprintf(os, " return ctx(%s_get_ctx(ptr));\n", name); 648 osprintf(os, "}\n"); 649 } 650 651 /* Print definitions for methods of class "clazz" to "os". 652 */ 653 void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz) 654 { 655 map<string, set<FunctionDecl *> >::const_iterator it; 656 bool first = true; 657 658 for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) { 659 if (first) 660 first = false; 661 else 662 osprintf(os, "\n"); 663 print_method_group_impl(os, clazz, it->second); 664 } 665 } 666 667 /* Print definitions for methods "methods" in class "clazz" to "os". 668 * 669 * "kind" specifies the kind of method that should be generated. 670 */ 671 void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz, 672 const set<FunctionDecl *> &methods) 673 { 674 set<FunctionDecl *>::const_iterator it; 675 bool first = true; 676 677 for (it = methods.begin(); it != methods.end(); ++it) { 678 function_kind kind; 679 if (first) 680 first = false; 681 else 682 osprintf(os, "\n"); 683 kind = get_method_kind(clazz, *it); 684 print_method_impl(os, clazz, *it, kind); 685 } 686 } 687 688 /* Print the use of "param" to "os". 689 * 690 * "load_from_this_ptr" specifies whether the parameter should be loaded from 691 * the this-ptr. In case a value is loaded from a this pointer, the original 692 * value must be preserved and must consequently be copied. Values that are 693 * loaded from parameters do not need to be preserved, as such values will 694 * already be copies of the actual parameters. It is consequently possible 695 * to directly take the pointer from these values, which saves 696 * an unnecessary copy. 697 * 698 * In case the parameter is a callback function, two parameters get printed, 699 * a wrapper for the callback function and a pointer to the actual 700 * callback function. The wrapper is expected to be available 701 * in a previously declared variable <name>_lambda, while 702 * the actual callback function is expected to be stored 703 * in a structure called <name>_data. 704 * The caller of this function must ensure that these variables exist. 705 */ 706 void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param, 707 bool load_from_this_ptr) 708 { 709 string name = param->getName().str(); 710 const char *name_str = name.c_str(); 711 QualType type = param->getOriginalType(); 712 713 if (type->isIntegerType()) { 714 osprintf(os, "%s", name_str); 715 return; 716 } 717 718 if (is_string(type)) { 719 osprintf(os, "%s.c_str()", name_str); 720 return; 721 } 722 723 if (is_callback(type)) { 724 osprintf(os, "%s_lambda, ", name_str); 725 osprintf(os, "&%s_data", name_str); 726 return; 727 } 728 729 if (!load_from_this_ptr && !is_callback(type)) 730 osprintf(os, "%s.", name_str); 731 732 if (keeps(param)) { 733 osprintf(os, "get()"); 734 } else { 735 if (load_from_this_ptr) 736 osprintf(os, "copy()"); 737 else 738 osprintf(os, "release()"); 739 } 740 } 741 742 /* Print code that checks that all isl object arguments to "method" are valid 743 * (not NULL) and throws an exception if they are not. 744 * "kind" specifies the kind of method that is being generated. 745 * 746 * If checked bindings are being generated, 747 * then no such check is performed. 748 */ 749 void cpp_generator::print_argument_validity_check(ostream &os, 750 FunctionDecl *method, function_kind kind) 751 { 752 int n; 753 bool first = true; 754 755 if (checked) 756 return; 757 758 n = method->getNumParams(); 759 for (int i = 0; i < n; ++i) { 760 bool is_this; 761 ParmVarDecl *param = method->getParamDecl(i); 762 string name = param->getName().str(); 763 const char *name_str = name.c_str(); 764 QualType type = param->getOriginalType(); 765 766 is_this = i == 0 && kind == function_kind_member_method; 767 if (!is_this && (is_isl_ctx(type) || !is_isl_type(type))) 768 continue; 769 770 if (first) 771 osprintf(os, " if ("); 772 else 773 osprintf(os, " || "); 774 775 if (is_this) 776 osprintf(os, "!ptr"); 777 else 778 osprintf(os, "%s.is_null()", name_str); 779 780 first = false; 781 } 782 if (first) 783 return; 784 osprintf(os, ")\n"); 785 print_throw_NULL_input(os); 786 } 787 788 /* Print code for saving a copy of the isl::ctx available at the start 789 * of the method "method" in a "ctx" variable, for use in exception handling. 790 * "kind" specifies what kind of method "method" is. 791 * 792 * If checked bindings are being generated, 793 * then the "ctx" variable is not needed. 794 * If "method" is a member function, then obtain the isl_ctx from 795 * the "this" object. 796 * If the first argument of the method is an isl::ctx, then use that one, 797 * assuming it is not already called "ctx". 798 * Otherwise, save a copy of the isl::ctx associated to the first argument 799 * of isl object type. 800 */ 801 void cpp_generator::print_save_ctx(ostream &os, FunctionDecl *method, 802 function_kind kind) 803 { 804 int n; 805 ParmVarDecl *param = method->getParamDecl(0); 806 QualType type = param->getOriginalType(); 807 808 if (checked) 809 return; 810 if (kind == function_kind_member_method) { 811 osprintf(os, " auto ctx = get_ctx();\n"); 812 return; 813 } 814 if (is_isl_ctx(type)) { 815 const char *name; 816 817 name = param->getName().str().c_str(); 818 if (strcmp(name, "ctx") != 0) 819 osprintf(os, " auto ctx = %s;\n", name); 820 return; 821 } 822 n = method->getNumParams(); 823 for (int i = 0; i < n; ++i) { 824 ParmVarDecl *param = method->getParamDecl(i); 825 QualType type = param->getOriginalType(); 826 827 if (!is_isl_type(type)) 828 continue; 829 osprintf(os, " auto ctx = %s.get_ctx();\n", 830 param->getName().str().c_str()); 831 return; 832 } 833 } 834 835 /* Print code to make isl not print an error message when an error occurs 836 * within the current scope (if exceptions are available), 837 * since the error message will be included in the exception. 838 * If exceptions are not available, then exception::on_error 839 * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead. 840 * 841 * If checked bindings are being generated, 842 * then leave it to the user to decide what isl should do on error. 843 * Otherwise, assume that a valid isl::ctx is available in the "ctx" variable, 844 * e.g., through a prior call to print_save_ctx. 845 */ 846 void cpp_generator::print_on_error_continue(ostream &os) 847 { 848 if (checked) 849 return; 850 osprintf(os, " options_scoped_set_on_error saved_on_error(ctx, " 851 "exception::on_error);\n"); 852 } 853 854 /* Print code that checks whether the execution of the core of "method" 855 * was successful. 856 * 857 * If checked bindings are being generated, 858 * then no checks are performed. 859 * 860 * Otherwise, first check if any of the callbacks failed with 861 * an exception. If so, the "eptr" in the corresponding data structure 862 * contains the exception that was caught and that needs to be rethrown. 863 * Then check if the function call failed in any other way and throw 864 * the appropriate exception. 865 * In particular, if the return type is isl_stat or isl_bool, 866 * then a negative value indicates a failure. If the return type 867 * is an isl type, then a NULL value indicates a failure. 868 * Assume print_save_ctx has made sure that a valid isl::ctx 869 * is available in the "ctx" variable. 870 */ 871 void cpp_generator::print_exceptional_execution_check(ostream &os, 872 FunctionDecl *method) 873 { 874 int n; 875 bool check_null, check_neg; 876 QualType return_type = method->getReturnType(); 877 878 if (checked) 879 return; 880 881 n = method->getNumParams(); 882 for (int i = 0; i < n; ++i) { 883 ParmVarDecl *param = method->getParamDecl(i); 884 const char *name; 885 886 if (!is_callback(param->getOriginalType())) 887 continue; 888 name = param->getName().str().c_str(); 889 osprintf(os, " if (%s_data.eptr)\n", name); 890 osprintf(os, " std::rethrow_exception(%s_data.eptr);\n", 891 name); 892 } 893 894 check_neg = is_isl_stat(return_type) || is_isl_bool(return_type); 895 check_null = is_isl_type(return_type); 896 if (!check_null && !check_neg) 897 return; 898 899 if (check_neg) 900 osprintf(os, " if (res < 0)\n"); 901 else 902 osprintf(os, " if (!res)\n"); 903 print_throw_last_error(os); 904 } 905 906 /* Print the return statement of the C++ method corresponding 907 * to the C function "method" in class "clazz" to "os". 908 * 909 * The result of the isl function is returned as a new 910 * object if the underlying isl function returns an isl_* ptr, as a bool 911 * if the isl function returns an isl_bool, as void if the isl functions 912 * returns an isl_stat, 913 * as std::string if the isl function returns 'const char *', and as 914 * unmodified return value otherwise. 915 * If checked C++ bindings are being generated, 916 * then an isl_bool return type is transformed into a boolean and 917 * an isl_stat into a stat since no exceptions can be generated 918 * on negative results from the isl function. 919 */ 920 void cpp_generator::print_method_return(ostream &os, const isl_class &clazz, 921 FunctionDecl *method) 922 { 923 QualType return_type = method->getReturnType(); 924 925 if (is_isl_type(return_type) || 926 (checked && 927 (is_isl_bool(return_type) || is_isl_stat(return_type)))) { 928 osprintf(os, " return manage(res);\n"); 929 } else if (is_isl_stat(return_type)) { 930 osprintf(os, " return;\n"); 931 } else if (is_string(return_type)) { 932 osprintf(os, " std::string tmp(res);\n"); 933 if (gives(method)) 934 osprintf(os, " free(res);\n"); 935 osprintf(os, " return tmp;\n"); 936 } else { 937 osprintf(os, " return res;\n"); 938 } 939 } 940 941 /* Print definition for "method" in class "clazz" to "os". 942 * 943 * "kind" specifies the kind of method that should be generated. 944 * 945 * This method distinguishes three kinds of methods: member methods, static 946 * methods, and constructors. 947 * 948 * Member methods call "method" by passing to the underlying isl function the 949 * isl object belonging to "this" as first argument and the remaining arguments 950 * as subsequent arguments. 951 * 952 * Static methods call "method" by passing all arguments to the underlying isl 953 * function, as no this-pointer is available. The result is a newly managed 954 * isl C++ object. 955 * 956 * Constructors create a new object from a given set of input parameters. They 957 * do not return a value, but instead update the pointer stored inside the 958 * newly created object. 959 * 960 * If the method has a callback argument, we reduce the number of parameters 961 * that are exposed by one to hide the user pointer from the interface. On 962 * the C++ side no user pointer is needed, as arguments can be forwarded 963 * as part of the std::function argument which specifies the callback function. 964 * 965 * Unless checked C++ bindings are being generated, 966 * the inputs of the method are first checked for being valid isl objects and 967 * a copy of the associated isl::ctx is saved (if needed). 968 * If any failure occurs, either during the check for the inputs or 969 * during the isl function call, an exception is thrown. 970 * During the function call, isl is made not to print any error message 971 * because the error message is included in the exception. 972 */ 973 void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz, 974 FunctionDecl *method, function_kind kind) 975 { 976 string methodname = method->getName(); 977 int num_params = method->getNumParams(); 978 979 print_method_header(os, clazz, method, false, kind); 980 osprintf(os, "{\n"); 981 print_argument_validity_check(os, method, kind); 982 print_save_ctx(os, method, kind); 983 print_on_error_continue(os); 984 985 for (int i = 0; i < num_params; ++i) { 986 ParmVarDecl *param = method->getParamDecl(i); 987 if (is_callback(param->getType())) { 988 num_params -= 1; 989 print_callback_local(os, param); 990 } 991 } 992 993 osprintf(os, " auto res = %s(", methodname.c_str()); 994 995 for (int i = 0; i < num_params; ++i) { 996 ParmVarDecl *param = method->getParamDecl(i); 997 bool load_from_this_ptr = false; 998 999 if (i == 0 && kind == function_kind_member_method) 1000 load_from_this_ptr = true; 1001 1002 print_method_param_use(os, param, load_from_this_ptr); 1003 1004 if (i != num_params - 1) 1005 osprintf(os, ", "); 1006 } 1007 osprintf(os, ");\n"); 1008 1009 print_exceptional_execution_check(os, method); 1010 if (kind == function_kind_constructor) { 1011 osprintf(os, " ptr = res;\n"); 1012 } else { 1013 print_method_return(os, clazz, method); 1014 } 1015 1016 osprintf(os, "}\n"); 1017 } 1018 1019 /* Print the header for "method" in class "clazz" to "os". 1020 * 1021 * Print the header of a declaration if "is_declaration" is set, otherwise print 1022 * the header of a method definition. 1023 * 1024 * "kind" specifies the kind of method that should be generated. 1025 * 1026 * This function prints headers for member methods, static methods, and 1027 * constructors, either for their declaration or definition. 1028 * 1029 * Member functions are declared as "const", as they do not change the current 1030 * object, but instead create a new object. They always retrieve the first 1031 * parameter of the original isl function from the this-pointer of the object, 1032 * such that only starting at the second parameter the parameters of the 1033 * original function become part of the method's interface. 1034 * 1035 * A function 1036 * 1037 * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1, 1038 * __isl_take isl_set *s2); 1039 * 1040 * is translated into: 1041 * 1042 * inline set intersect(set set2) const; 1043 * 1044 * For static functions and constructors all parameters of the original isl 1045 * function are exposed. 1046 * 1047 * Parameters that are defined as __isl_keep or are of type string, are passed 1048 * as const reference, which allows the compiler to optimize the parameter 1049 * transfer. 1050 * 1051 * Constructors are marked as explicit using the C++ keyword 'explicit' or as 1052 * implicit using a comment in place of the explicit keyword. By annotating 1053 * implicit constructors with a comment, users of the interface are made 1054 * aware of the potential danger that implicit construction is possible 1055 * for these constructors, whereas without a comment not every user would 1056 * know that implicit construction is allowed in absence of an explicit keyword. 1057 */ 1058 void cpp_generator::print_method_header(ostream &os, const isl_class &clazz, 1059 FunctionDecl *method, bool is_declaration, function_kind kind) 1060 { 1061 string cname = clazz.method_name(method); 1062 string rettype_str = type2cpp(method->getReturnType()); 1063 string classname = type2cpp(clazz); 1064 int num_params = method->getNumParams(); 1065 int first_param = 0; 1066 1067 cname = rename_method(cname); 1068 if (kind == function_kind_member_method) 1069 first_param = 1; 1070 1071 if (is_declaration) { 1072 osprintf(os, " "); 1073 1074 if (kind == function_kind_static_method) 1075 osprintf(os, "static "); 1076 1077 osprintf(os, "inline "); 1078 1079 if (kind == function_kind_constructor) { 1080 if (is_implicit_conversion(clazz, method)) 1081 osprintf(os, "/* implicit */ "); 1082 else 1083 osprintf(os, "explicit "); 1084 } 1085 } 1086 1087 if (kind != function_kind_constructor) 1088 osprintf(os, "%s ", rettype_str.c_str()); 1089 1090 if (!is_declaration) 1091 osprintf(os, "%s::", classname.c_str()); 1092 1093 if (kind != function_kind_constructor) 1094 osprintf(os, "%s", cname.c_str()); 1095 else 1096 osprintf(os, "%s", classname.c_str()); 1097 1098 osprintf(os, "("); 1099 1100 for (int i = first_param; i < num_params; ++i) { 1101 ParmVarDecl *param = method->getParamDecl(i); 1102 QualType type = param->getOriginalType(); 1103 string cpptype = type2cpp(type); 1104 1105 if (is_callback(type)) 1106 num_params--; 1107 1108 if (keeps(param) || is_string(type) || is_callback(type)) 1109 osprintf(os, "const %s &%s", cpptype.c_str(), 1110 param->getName().str().c_str()); 1111 else 1112 osprintf(os, "%s %s", cpptype.c_str(), 1113 param->getName().str().c_str()); 1114 1115 if (i != num_params - 1) 1116 osprintf(os, ", "); 1117 } 1118 1119 osprintf(os, ")"); 1120 1121 if (kind == function_kind_member_method) 1122 osprintf(os, " const"); 1123 1124 if (is_declaration) 1125 osprintf(os, ";"); 1126 osprintf(os, "\n"); 1127 } 1128 1129 /* Generate the list of argument types for a callback function of 1130 * type "type". If "cpp" is set, then generate the C++ type list, otherwise 1131 * the C type list. 1132 * 1133 * For a callback of type 1134 * 1135 * isl_stat (*)(__isl_take isl_map *map, void *user) 1136 * 1137 * the following C++ argument list is generated: 1138 * 1139 * map 1140 */ 1141 string cpp_generator::generate_callback_args(QualType type, bool cpp) 1142 { 1143 std::string type_str; 1144 const FunctionProtoType *callback; 1145 int num_params; 1146 1147 callback = extract_prototype(type); 1148 num_params = callback->getNumArgs(); 1149 if (cpp) 1150 num_params--; 1151 1152 for (long i = 0; i < num_params; i++) { 1153 QualType type = callback->getArgType(i); 1154 1155 if (cpp) 1156 type_str += type2cpp(type); 1157 else 1158 type_str += type.getAsString(); 1159 1160 if (!cpp) 1161 type_str += "arg_" + ::to_string(i); 1162 1163 if (i != num_params - 1) 1164 type_str += ", "; 1165 } 1166 1167 return type_str; 1168 } 1169 1170 /* Generate the full cpp type of a callback function of type "type". 1171 * 1172 * For a callback of type 1173 * 1174 * isl_stat (*)(__isl_take isl_map *map, void *user) 1175 * 1176 * the following type is generated: 1177 * 1178 * std::function<stat(map)> 1179 */ 1180 string cpp_generator::generate_callback_type(QualType type) 1181 { 1182 std::string type_str; 1183 const FunctionProtoType *callback = extract_prototype(type); 1184 QualType return_type = callback->getReturnType(); 1185 string rettype_str = type2cpp(return_type); 1186 1187 type_str = "std::function<"; 1188 type_str += rettype_str; 1189 type_str += "("; 1190 type_str += generate_callback_args(type, true); 1191 type_str += ")>"; 1192 1193 return type_str; 1194 } 1195 1196 /* Print the call to the C++ callback function "call", wrapped 1197 * for use inside the lambda function that is used as the C callback function, 1198 * in the case where checked C++ bindings are being generated. 1199 * 1200 * In particular, print 1201 * 1202 * stat ret = @call@; 1203 * return ret.release(); 1204 */ 1205 void cpp_generator::print_wrapped_call_checked(ostream &os, 1206 const string &call) 1207 { 1208 osprintf(os, " stat ret = %s;\n", call.c_str()); 1209 osprintf(os, " return ret.release();\n"); 1210 } 1211 1212 /* Print the call to the C++ callback function "call", wrapped 1213 * for use inside the lambda function that is used as the C callback function. 1214 * 1215 * In particular, print 1216 * 1217 * ISL_CPP_TRY { 1218 * @call@; 1219 * return isl_stat_ok; 1220 * } ISL_CPP_CATCH_ALL { 1221 * data->eptr = std::current_exception(); 1222 * return isl_stat_error; 1223 * } 1224 * 1225 * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)" 1226 * (if exceptions are available). 1227 * 1228 * If checked C++ bindings are being generated, then 1229 * the call is wrapped differently. 1230 */ 1231 void cpp_generator::print_wrapped_call(ostream &os, const string &call) 1232 { 1233 if (checked) 1234 return print_wrapped_call_checked(os, call); 1235 1236 osprintf(os, " ISL_CPP_TRY {\n"); 1237 osprintf(os, " %s;\n", call.c_str()); 1238 osprintf(os, " return isl_stat_ok;\n"); 1239 osprintf(os, " } ISL_CPP_CATCH_ALL {\n" 1240 " data->eptr = std::current_exception();\n"); 1241 osprintf(os, " return isl_stat_error;\n"); 1242 osprintf(os, " }\n"); 1243 } 1244 1245 /* Print the local variables that are needed for a callback argument, 1246 * in particular, print a lambda function that wraps the callback and 1247 * a pointer to the actual C++ callback function. 1248 * 1249 * For a callback of the form 1250 * 1251 * isl_stat (*fn)(__isl_take isl_map *map, void *user) 1252 * 1253 * the following lambda function is generated: 1254 * 1255 * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat { 1256 * auto *data = static_cast<struct fn_data *>(arg_1); 1257 * try { 1258 * stat ret = (*data->func)(manage(arg_0)); 1259 * return isl_stat_ok; 1260 * } catch (...) { 1261 * data->eptr = std::current_exception(); 1262 * return isl_stat_error; 1263 * } 1264 * }; 1265 * 1266 * The pointer to the std::function C++ callback function is stored in 1267 * a fn_data data structure for passing to the C callback function, 1268 * along with an std::exception_ptr that is used to store any 1269 * exceptions thrown in the C++ callback. 1270 * 1271 * struct fn_data { 1272 * const std::function<stat(map)> *func; 1273 * std::exception_ptr eptr; 1274 * } fn_data = { &fn }; 1275 * 1276 * This std::function object represents the actual user 1277 * callback function together with the locally captured state at the caller. 1278 * 1279 * The lambda function is expected to be used as a C callback function 1280 * where the lambda itself is provided as the function pointer and 1281 * where the user void pointer is a pointer to fn_data. 1282 * The std::function object is extracted from the pointer to fn_data 1283 * inside the lambda function. 1284 * 1285 * The std::exception_ptr object is not added to fn_data 1286 * if checked C++ bindings are being generated. 1287 * The body of the generated lambda function then is as follows: 1288 * 1289 * stat ret = (*data->func)(manage(arg_0)); 1290 * return isl_stat(ret); 1291 * 1292 * If the C callback does not take its arguments, then 1293 * manage_copy is used instead of manage. 1294 */ 1295 void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param) 1296 { 1297 string pname; 1298 QualType ptype; 1299 string call, c_args, cpp_args, rettype, last_idx; 1300 const FunctionProtoType *callback; 1301 int num_params; 1302 1303 pname = param->getName().str(); 1304 ptype = param->getType(); 1305 1306 c_args = generate_callback_args(ptype, false); 1307 cpp_args = generate_callback_type(ptype); 1308 1309 callback = extract_prototype(ptype); 1310 rettype = callback->getReturnType().getAsString(); 1311 num_params = callback->getNumArgs(); 1312 1313 last_idx = ::to_string(num_params - 1); 1314 1315 call = "(*data->func)("; 1316 for (long i = 0; i < num_params - 1; i++) { 1317 if (!callback_takes_argument(param, i)) 1318 call += "manage_copy"; 1319 else 1320 call += "manage"; 1321 call += "(arg_" + ::to_string(i) + ")"; 1322 if (i != num_params - 2) 1323 call += ", "; 1324 } 1325 call += ")"; 1326 1327 osprintf(os, " struct %s_data {\n", pname.c_str()); 1328 osprintf(os, " const %s *func;\n", cpp_args.c_str()); 1329 if (!checked) 1330 osprintf(os, " std::exception_ptr eptr;\n"); 1331 osprintf(os, " } %s_data = { &%s };\n", pname.c_str(), pname.c_str()); 1332 osprintf(os, " auto %s_lambda = [](%s) -> %s {\n", 1333 pname.c_str(), c_args.c_str(), rettype.c_str()); 1334 osprintf(os, 1335 " auto *data = static_cast<struct %s_data *>(arg_%s);\n", 1336 pname.c_str(), last_idx.c_str()); 1337 print_wrapped_call(os, call); 1338 osprintf(os, " };\n"); 1339 } 1340 1341 /* An array listing functions that must be renamed and the function name they 1342 * should be renamed to. We currently rename functions in case their name would 1343 * match a reserved C++ keyword, which is not allowed in C++. 1344 */ 1345 static const char *rename_map[][2] = { 1346 { "union", "unite" }, 1347 }; 1348 1349 /* Rename method "name" in case the method name in the C++ bindings should not 1350 * match the name in the C bindings. We do this for example to avoid 1351 * C++ keywords. 1352 */ 1353 std::string cpp_generator::rename_method(std::string name) 1354 { 1355 for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++) 1356 if (name.compare(rename_map[i][0]) == 0) 1357 return rename_map[i][1]; 1358 1359 return name; 1360 } 1361 1362 /* Translate isl class "clazz" to its corresponding C++ type. 1363 */ 1364 string cpp_generator::type2cpp(const isl_class &clazz) 1365 { 1366 return type2cpp(clazz.name); 1367 } 1368 1369 /* Translate type string "type_str" to its C++ name counterpart. 1370 */ 1371 string cpp_generator::type2cpp(string type_str) 1372 { 1373 return type_str.substr(4); 1374 } 1375 1376 /* Translate QualType "type" to its C++ name counterpart. 1377 * 1378 * An isl_bool return type is translated into "bool", 1379 * while an isl_stat is translated into "void". 1380 * The exceptional cases are handled through exceptions. 1381 * If checked C++ bindings are being generated, then 1382 * C++ counterparts of isl_bool and isl_stat need to be used instead. 1383 */ 1384 string cpp_generator::type2cpp(QualType type) 1385 { 1386 if (is_isl_type(type)) 1387 return type2cpp(type->getPointeeType().getAsString()); 1388 1389 if (is_isl_bool(type)) 1390 return checked ? "boolean" : "bool"; 1391 1392 if (is_isl_stat(type)) 1393 return checked ? "stat" : "void"; 1394 1395 if (type->isIntegerType()) 1396 return type.getAsString(); 1397 1398 if (is_string(type)) 1399 return "std::string"; 1400 1401 if (is_callback(type)) 1402 return generate_callback_type(type); 1403 1404 die("Cannot convert type to C++ type"); 1405 } 1406 1407 /* Check if "subclass_type" is a subclass of "class_type". 1408 */ 1409 bool cpp_generator::is_subclass(QualType subclass_type, 1410 const isl_class &class_type) 1411 { 1412 std::string type_str = subclass_type->getPointeeType().getAsString(); 1413 std::vector<std::string> superclasses; 1414 std::vector<const isl_class *> parents; 1415 std::vector<std::string>::iterator ci; 1416 1417 superclasses = generator::find_superclasses(classes[type_str].type); 1418 1419 for (ci = superclasses.begin(); ci < superclasses.end(); ci++) 1420 parents.push_back(&classes[*ci]); 1421 1422 while (!parents.empty()) { 1423 const isl_class *candidate = parents.back(); 1424 1425 parents.pop_back(); 1426 1427 if (&class_type == candidate) 1428 return true; 1429 1430 superclasses = generator::find_superclasses(candidate->type); 1431 1432 for (ci = superclasses.begin(); ci < superclasses.end(); ci++) 1433 parents.push_back(&classes[*ci]); 1434 } 1435 1436 return false; 1437 } 1438 1439 /* Check if "cons" is an implicit conversion constructor of class "clazz". 1440 * 1441 * An implicit conversion constructor is generated in case "cons" has a single 1442 * parameter, where the parameter type is a subclass of the class that is 1443 * currently being generated. 1444 */ 1445 bool cpp_generator::is_implicit_conversion(const isl_class &clazz, 1446 FunctionDecl *cons) 1447 { 1448 ParmVarDecl *param = cons->getParamDecl(0); 1449 QualType type = param->getOriginalType(); 1450 1451 int num_params = cons->getNumParams(); 1452 if (num_params != 1) 1453 return false; 1454 1455 if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz)) 1456 return true; 1457 1458 return false; 1459 } 1460 1461 /* Get kind of "method" in "clazz". 1462 * 1463 * Given the declaration of a static or member method, returns its kind. 1464 */ 1465 cpp_generator::function_kind cpp_generator::get_method_kind( 1466 const isl_class &clazz, FunctionDecl *method) 1467 { 1468 if (is_static(clazz, method)) 1469 return function_kind_static_method; 1470 else 1471 return function_kind_member_method; 1472 } 1473