1 1.1 mrg /* 2 1.1 mrg * Copyright 2016, 2017 Tobias Grosser. All rights reserved. 3 1.1 mrg * 4 1.1 mrg * Redistribution and use in source and binary forms, with or without 5 1.1 mrg * modification, are permitted provided that the following conditions 6 1.1 mrg * are met: 7 1.1 mrg * 8 1.1 mrg * 1. Redistributions of source code must retain the above copyright 9 1.1 mrg * notice, this list of conditions and the following disclaimer. 10 1.1 mrg * 11 1.1 mrg * 2. Redistributions in binary form must reproduce the above 12 1.1 mrg * copyright notice, this list of conditions and the following 13 1.1 mrg * disclaimer in the documentation and/or other materials provided 14 1.1 mrg * with the distribution. 15 1.1 mrg * 16 1.1 mrg * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY 17 1.1 mrg * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 mrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 mrg * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOBIAS GROSSER OR 20 1.1 mrg * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 1.1 mrg * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 1.1 mrg * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 23 1.1 mrg * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 1.1 mrg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 1.1 mrg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 1.1 mrg * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 1.1 mrg * 28 1.1 mrg * The views and conclusions contained in the software and documentation 29 1.1 mrg * are those of the authors and should not be interpreted as 30 1.1 mrg * representing official policies, either expressed or implied, of 31 1.1 mrg * Tobias Grosser. 32 1.1 mrg */ 33 1.1 mrg 34 1.1 mrg #include <cstdarg> 35 1.1 mrg #include <cstdio> 36 1.1 mrg #include <iostream> 37 1.1 mrg #include <map> 38 1.1 mrg #include <memory> 39 1.1 mrg #include <sstream> 40 1.1 mrg #include <string> 41 1.1 mrg #include <vector> 42 1.1 mrg 43 1.1 mrg #include "plain_cpp.h" 44 1.1 mrg #include "isl_config.h" 45 1.1 mrg 46 1.1 mrg /* Print string formatted according to "fmt" to ostream "os". 47 1.1 mrg * 48 1.1 mrg * This osprintf method allows us to use printf style formatting constructs when 49 1.1 mrg * writing to an ostream. 50 1.1 mrg */ 51 1.1 mrg static void osprintf(ostream &os, const char *format, va_list arguments) 52 1.1 mrg { 53 1.1 mrg va_list copy; 54 1.1 mrg char *string_pointer; 55 1.1 mrg size_t size; 56 1.1 mrg 57 1.1 mrg va_copy(copy, arguments); 58 1.1 mrg size = vsnprintf(NULL, 0, format, copy); 59 1.1 mrg string_pointer = new char[size + 1]; 60 1.1 mrg va_end(copy); 61 1.1 mrg vsnprintf(string_pointer, size + 1, format, arguments); 62 1.1 mrg os << string_pointer; 63 1.1 mrg delete[] string_pointer; 64 1.1 mrg } 65 1.1 mrg 66 1.1 mrg /* Print string formatted according to "fmt" to ostream "os". 67 1.1 mrg * 68 1.1 mrg * This osprintf method allows us to use printf style formatting constructs when 69 1.1 mrg * writing to an ostream. 70 1.1 mrg */ 71 1.1 mrg static void osprintf(ostream &os, const char *format, ...) 72 1.1 mrg { 73 1.1 mrg va_list arguments; 74 1.1 mrg 75 1.1 mrg va_start(arguments, format); 76 1.1 mrg osprintf(os, format, arguments); 77 1.1 mrg va_end(arguments); 78 1.1 mrg } 79 1.1 mrg 80 1.1 mrg /* Print string formatted according to "fmt" to ostream "os" 81 1.1 mrg * with the given indentation. 82 1.1 mrg * 83 1.1 mrg * This osprintf method allows us to use printf style formatting constructs when 84 1.1 mrg * writing to an ostream. 85 1.1 mrg */ 86 1.1 mrg static void osprintf(ostream &os, int indent, const char *format, ...) 87 1.1 mrg { 88 1.1 mrg va_list arguments; 89 1.1 mrg 90 1.1 mrg osprintf(os, "%*s", indent, " "); 91 1.1 mrg va_start(arguments, format); 92 1.1 mrg osprintf(os, format, arguments); 93 1.1 mrg va_end(arguments); 94 1.1 mrg } 95 1.1 mrg 96 1.1 mrg /* Convert "l" to a string. 97 1.1 mrg */ 98 1.1 mrg static std::string to_string(long l) 99 1.1 mrg { 100 1.1 mrg std::ostringstream strm; 101 1.1 mrg strm << l; 102 1.1 mrg return strm.str(); 103 1.1 mrg } 104 1.1 mrg 105 1.1 mrg /* Construct a generator for plain C++ bindings. 106 1.1 mrg * 107 1.1 mrg * "checked" is set if C++ bindings should be generated 108 1.1 mrg * that rely on the user to check for error conditions. 109 1.1 mrg */ 110 1.1 mrg plain_cpp_generator::plain_cpp_generator(SourceManager &SM, 111 1.1 mrg set<RecordDecl *> &exported_types, 112 1.1 mrg set<FunctionDecl *> exported_functions, set<FunctionDecl *> functions, 113 1.1 mrg bool checked) : 114 1.1 mrg cpp_generator(SM, exported_types, exported_functions, 115 1.1 mrg functions), 116 1.1 mrg checked(checked) 117 1.1 mrg { 118 1.1 mrg } 119 1.1 mrg 120 1.1 mrg /* Generate a cpp interface based on the extracted types and functions. 121 1.1 mrg * 122 1.1 mrg * Print first a set of forward declarations for all isl wrapper 123 1.1 mrg * classes, then the declarations of the classes, and at the end all 124 1.1 mrg * implementations. 125 1.1 mrg * 126 1.1 mrg * If checked C++ bindings are being generated, 127 1.1 mrg * then wrap them in a namespace to avoid conflicts 128 1.1 mrg * with the default C++ bindings (with automatic checks using exceptions). 129 1.1 mrg */ 130 1.1 mrg void plain_cpp_generator::generate() 131 1.1 mrg { 132 1.1 mrg ostream &os = cout; 133 1.1 mrg 134 1.1 mrg osprintf(os, "\n"); 135 1.1 mrg osprintf(os, "namespace isl {\n\n"); 136 1.1 mrg if (checked) 137 1.1 mrg osprintf(os, "namespace checked {\n\n"); 138 1.1 mrg 139 1.1 mrg print_forward_declarations(os); 140 1.1 mrg osprintf(os, "\n"); 141 1.1 mrg print_declarations(os); 142 1.1 mrg osprintf(os, "\n"); 143 1.1 mrg print_implementations(os); 144 1.1 mrg 145 1.1 mrg if (checked) 146 1.1 mrg osprintf(os, "} // namespace checked\n"); 147 1.1 mrg osprintf(os, "} // namespace isl\n"); 148 1.1 mrg } 149 1.1 mrg 150 1.1 mrg /* Print forward declarations for all classes to "os". 151 1.1 mrg */ 152 1.1 mrg void plain_cpp_generator::print_forward_declarations(ostream &os) 153 1.1 mrg { 154 1.1 mrg map<string, isl_class>::iterator ci; 155 1.1 mrg 156 1.1 mrg osprintf(os, "// forward declarations\n"); 157 1.1 mrg 158 1.1 mrg for (ci = classes.begin(); ci != classes.end(); ++ci) 159 1.1 mrg print_class_forward_decl(os, ci->second); 160 1.1 mrg } 161 1.1 mrg 162 1.1 mrg /* Print all declarations to "os". 163 1.1 mrg */ 164 1.1 mrg void plain_cpp_generator::print_declarations(ostream &os) 165 1.1 mrg { 166 1.1 mrg map<string, isl_class>::iterator ci; 167 1.1 mrg bool first = true; 168 1.1 mrg 169 1.1 mrg for (ci = classes.begin(); ci != classes.end(); ++ci) { 170 1.1 mrg if (first) 171 1.1 mrg first = false; 172 1.1 mrg else 173 1.1 mrg osprintf(os, "\n"); 174 1.1 mrg 175 1.1 mrg print_class(os, ci->second); 176 1.1 mrg } 177 1.1 mrg } 178 1.1 mrg 179 1.1 mrg /* Print all implementations to "os". 180 1.1 mrg */ 181 1.1 mrg void plain_cpp_generator::print_implementations(ostream &os) 182 1.1 mrg { 183 1.1 mrg map<string, isl_class>::iterator ci; 184 1.1 mrg bool first = true; 185 1.1 mrg 186 1.1 mrg for (ci = classes.begin(); ci != classes.end(); ++ci) { 187 1.1 mrg if (first) 188 1.1 mrg first = false; 189 1.1 mrg else 190 1.1 mrg osprintf(os, "\n"); 191 1.1 mrg 192 1.1 mrg print_class_impl(os, ci->second); 193 1.1 mrg } 194 1.1 mrg } 195 1.1 mrg 196 1.1 mrg /* If the printed class is a subclass that is based on a type function, 197 1.1 mrg * then introduce a "type" field that holds the value of the type 198 1.1 mrg * corresponding to the subclass and make the fields of the class 199 1.1 mrg * accessible to the "isa" and "as" methods of the (immediate) superclass. 200 1.1 mrg * In particular, "isa" needs access to the type field itself, 201 1.1 mrg * while "as" needs access to the private constructor. 202 1.1 mrg * In case of the "isa" method, all instances are made friends 203 1.1 mrg * to avoid access right confusion. 204 1.1 mrg */ 205 1.1 mrg void plain_cpp_generator::decl_printer::print_subclass_type() 206 1.1 mrg { 207 1.1 mrg std::string super; 208 1.1 mrg const char *cppname = cppstring.c_str(); 209 1.1 mrg const char *supername; 210 1.1 mrg 211 1.1 mrg if (!clazz.is_type_subclass()) 212 1.1 mrg return; 213 1.1 mrg 214 1.1 mrg super = type2cpp(clazz.superclass_name); 215 1.1 mrg supername = super.c_str(); 216 1.1 mrg osprintf(os, " template <class T>\n"); 217 1.1 mrg osprintf(os, " friend %s %s::isa() const;\n", 218 1.1 mrg generator.isl_bool2cpp().c_str(), supername); 219 1.1 mrg osprintf(os, " friend %s %s::as<%s>() const;\n", 220 1.1 mrg cppname, supername, cppname); 221 1.1 mrg osprintf(os, " static const auto type = %s;\n", 222 1.1 mrg clazz.subclass_name.c_str()); 223 1.1 mrg } 224 1.1 mrg 225 1.1 mrg /* Print declarations for class "clazz" to "os". 226 1.1 mrg * 227 1.1 mrg * If "clazz" is a subclass based on a type function, 228 1.1 mrg * then it is made to inherit from the (immediate) superclass and 229 1.1 mrg * a "type" attribute is added for use in the "as" and "isa" 230 1.1 mrg * methods of the superclass. 231 1.1 mrg * 232 1.1 mrg * Conversely, if "clazz" is a superclass with a type function, 233 1.1 mrg * then declare those "as" and "isa" methods. 234 1.1 mrg * 235 1.1 mrg * The pointer to the isl object is only added for classes that 236 1.1 mrg * are not subclasses, since subclasses refer to the same isl object. 237 1.1 mrg */ 238 1.1 mrg void plain_cpp_generator::print_class(ostream &os, const isl_class &clazz) 239 1.1 mrg { 240 1.1 mrg decl_printer printer(os, clazz, *this); 241 1.1 mrg const char *name = clazz.name.c_str(); 242 1.1 mrg const char *cppname = printer.cppstring.c_str(); 243 1.1 mrg 244 1.1 mrg osprintf(os, "// declarations for isl::%s\n", cppname); 245 1.1 mrg 246 1.1 mrg printer.print_class_factory(); 247 1.1 mrg osprintf(os, "\n"); 248 1.1 mrg osprintf(os, "class %s ", cppname); 249 1.1 mrg if (clazz.is_type_subclass()) 250 1.1 mrg osprintf(os, ": public %s ", 251 1.1 mrg type2cpp(clazz.superclass_name).c_str()); 252 1.1 mrg osprintf(os, "{\n"); 253 1.1 mrg printer.print_subclass_type(); 254 1.1 mrg printer.print_class_factory(" friend "); 255 1.1 mrg osprintf(os, "\n"); 256 1.1 mrg osprintf(os, "protected:\n"); 257 1.1 mrg if (!clazz.is_type_subclass()) { 258 1.1 mrg osprintf(os, " %s *ptr = nullptr;\n", name); 259 1.1 mrg osprintf(os, "\n"); 260 1.1 mrg } 261 1.1 mrg printer.print_protected_constructors(); 262 1.1 mrg osprintf(os, "\n"); 263 1.1 mrg osprintf(os, "public:\n"); 264 1.1 mrg printer.print_public_methods(); 265 1.1 mrg 266 1.1 mrg osprintf(os, "};\n"); 267 1.1 mrg } 268 1.1 mrg 269 1.1 mrg /* Print forward declaration of class "clazz" to "os". 270 1.1 mrg */ 271 1.1 mrg void plain_cpp_generator::print_class_forward_decl(ostream &os, 272 1.1 mrg const isl_class &clazz) 273 1.1 mrg { 274 1.1 mrg std::string cppstring = type2cpp(clazz); 275 1.1 mrg const char *cppname = cppstring.c_str(); 276 1.1 mrg 277 1.1 mrg osprintf(os, "class %s;\n", cppname); 278 1.1 mrg } 279 1.1 mrg 280 1.1 mrg /* Print global factory functions. 281 1.1 mrg * 282 1.1 mrg * Each class has two global factory functions: 283 1.1 mrg * 284 1.1 mrg * set manage(__isl_take isl_set *ptr); 285 1.1 mrg * set manage_copy(__isl_keep isl_set *ptr); 286 1.1 mrg * 287 1.1 mrg * A user can construct isl C++ objects from a raw pointer and indicate whether 288 1.1 mrg * they intend to take the ownership of the object or not through these global 289 1.1 mrg * factory functions. This ensures isl object creation is very explicit and 290 1.1 mrg * pointers are not converted by accident. Thanks to overloading, manage() and 291 1.1 mrg * manage_copy() can be called on any isl raw pointer and the corresponding 292 1.1 mrg * object is automatically created, without the user having to choose the right 293 1.1 mrg * isl object type. 294 1.1 mrg * 295 1.1 mrg * For a subclass based on a type function, no factory functions 296 1.1 mrg * are introduced because they share the C object type with 297 1.1 mrg * the superclass. 298 1.1 mrg */ 299 1.1 mrg void plain_cpp_generator::decl_printer::print_class_factory( 300 1.1 mrg const std::string &prefix) 301 1.1 mrg { 302 1.1 mrg const char *name = clazz.name.c_str(); 303 1.1 mrg const char *cppname = cppstring.c_str(); 304 1.1 mrg 305 1.1 mrg if (clazz.is_type_subclass()) 306 1.1 mrg return; 307 1.1 mrg 308 1.1 mrg os << prefix; 309 1.1 mrg osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name); 310 1.1 mrg os << prefix; 311 1.1 mrg osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n", 312 1.1 mrg cppname, name); 313 1.1 mrg } 314 1.1 mrg 315 1.1 mrg /* Print declarations of protected constructors. 316 1.1 mrg * 317 1.1 mrg * Each class has currently one protected constructor: 318 1.1 mrg * 319 1.1 mrg * 1) Constructor from a plain isl_* C pointer 320 1.1 mrg * 321 1.1 mrg * Example: 322 1.1 mrg * 323 1.1 mrg * set(__isl_take isl_set *ptr); 324 1.1 mrg * 325 1.1 mrg * The raw pointer constructor is kept protected. Object creation is only 326 1.1 mrg * possible through manage() or manage_copy(). 327 1.1 mrg */ 328 1.1 mrg void plain_cpp_generator::decl_printer::print_protected_constructors() 329 1.1 mrg { 330 1.1 mrg const char *name = clazz.name.c_str(); 331 1.1 mrg const char *cppname = cppstring.c_str(); 332 1.1 mrg 333 1.1 mrg osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname, 334 1.1 mrg name); 335 1.1 mrg } 336 1.1 mrg 337 1.1 mrg /* Print declarations of public constructors. 338 1.1 mrg * 339 1.1 mrg * Each class currently has two public constructors: 340 1.1 mrg * 341 1.1 mrg * 1) A default constructor 342 1.1 mrg * 2) A copy constructor 343 1.1 mrg * 344 1.1 mrg * Example: 345 1.1 mrg * 346 1.1 mrg * set(); 347 1.1 mrg * set(const set &set); 348 1.1 mrg */ 349 1.1 mrg void plain_cpp_generator::decl_printer::print_public_constructors() 350 1.1 mrg { 351 1.1 mrg const char *cppname = cppstring.c_str(); 352 1.1 mrg osprintf(os, " inline /* implicit */ %s();\n", cppname); 353 1.1 mrg 354 1.1 mrg osprintf(os, " inline /* implicit */ %s(const %s &obj);\n", 355 1.1 mrg cppname, cppname); 356 1.1 mrg } 357 1.1 mrg 358 1.1 mrg /* Print declarations for "method". 359 1.1 mrg */ 360 1.1 mrg void plain_cpp_generator::decl_printer::print_method( 361 1.1 mrg const ConversionMethod &method) 362 1.1 mrg { 363 1.1 mrg print_full_method_header(method); 364 1.1 mrg } 365 1.1 mrg 366 1.1 mrg /* Print declarations for "method". 367 1.1 mrg */ 368 1.1 mrg void plain_cpp_generator::decl_printer::print_method(const Method &method) 369 1.1 mrg { 370 1.1 mrg print_full_method_header(method); 371 1.1 mrg } 372 1.1 mrg 373 1.1 mrg /* Print a declaration for a constructor for the "id" class 374 1.1 mrg * that takes a user object. 375 1.1 mrg */ 376 1.1 mrg void plain_cpp_generator::decl_printer::print_id_constructor_user() 377 1.1 mrg { 378 1.1 mrg print_id_constructor_user_header(); 379 1.1 mrg } 380 1.1 mrg 381 1.1 mrg /* Print a declaration for an "id" method 382 1.1 mrg * for retrieving the user object associated to the identifier. 383 1.1 mrg * If "optional" is set, the method returns a std::optional user object. 384 1.1 mrg */ 385 1.1 mrg void plain_cpp_generator::decl_printer::print_id_user(bool optional) 386 1.1 mrg { 387 1.1 mrg print_id_user_header(optional); 388 1.1 mrg } 389 1.1 mrg 390 1.1 mrg /* Print declarations of copy assignment operator. 391 1.1 mrg * 392 1.1 mrg * Each class has one assignment operator. 393 1.1 mrg * 394 1.1 mrg * isl:set &set::operator=(set obj) 395 1.1 mrg * 396 1.1 mrg */ 397 1.1 mrg void plain_cpp_generator::decl_printer::print_copy_assignment() 398 1.1 mrg { 399 1.1 mrg const char *cppname = cppstring.c_str(); 400 1.1 mrg 401 1.1 mrg osprintf(os, " inline %s &operator=(%s obj);\n", cppname, cppname); 402 1.1 mrg } 403 1.1 mrg 404 1.1 mrg /* Print declaration of destructor. 405 1.1 mrg * 406 1.1 mrg * No explicit destructor is needed for type based subclasses. 407 1.1 mrg */ 408 1.1 mrg void plain_cpp_generator::decl_printer::print_destructor() 409 1.1 mrg { 410 1.1 mrg const char *cppname = cppstring.c_str(); 411 1.1 mrg 412 1.1 mrg if (clazz.is_type_subclass()) 413 1.1 mrg return; 414 1.1 mrg 415 1.1 mrg osprintf(os, " inline ~%s();\n", cppname); 416 1.1 mrg } 417 1.1 mrg 418 1.1 mrg /* Print declaration of pointer functions. 419 1.1 mrg * Since type based subclasses share the pointer with their superclass, 420 1.1 mrg * they can also reuse these functions from the superclass. 421 1.1 mrg * 422 1.1 mrg * To obtain a raw pointer three functions are provided: 423 1.1 mrg * 424 1.1 mrg * 1) __isl_give isl_set *copy() 425 1.1 mrg * 426 1.1 mrg * Returns a pointer to a _copy_ of the internal object 427 1.1 mrg * 428 1.1 mrg * 2) __isl_keep isl_set *get() 429 1.1 mrg * 430 1.1 mrg * Returns a pointer to the internal object 431 1.1 mrg * 432 1.1 mrg * 3) __isl_give isl_set *release() 433 1.1 mrg * 434 1.1 mrg * Returns a pointer to the internal object and resets the 435 1.1 mrg * internal pointer to nullptr. 436 1.1 mrg * 437 1.1 mrg * We also provide functionality to explicitly check if a pointer is 438 1.1 mrg * currently managed by this object. 439 1.1 mrg * 440 1.1 mrg * 4) bool is_null() 441 1.1 mrg * 442 1.1 mrg * Check if the current object is a null pointer. 443 1.1 mrg * 444 1.1 mrg * The functions get() and release() model the value_ptr proposed in 445 1.1 mrg * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf. 446 1.1 mrg * The copy() function is an extension to allow the user to explicitly 447 1.1 mrg * copy the underlying object. 448 1.1 mrg * 449 1.1 mrg * Also generate a declaration to delete copy() for r-values, for 450 1.1 mrg * r-values release() should be used to avoid unnecessary copies. 451 1.1 mrg */ 452 1.1 mrg void plain_cpp_generator::decl_printer::print_ptr() 453 1.1 mrg { 454 1.1 mrg const char *name = clazz.name.c_str(); 455 1.1 mrg 456 1.1 mrg if (clazz.is_type_subclass()) 457 1.1 mrg return; 458 1.1 mrg 459 1.1 mrg osprintf(os, " inline __isl_give %s *copy() const &;\n", name); 460 1.1 mrg osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name); 461 1.1 mrg osprintf(os, " inline __isl_keep %s *get() const;\n", name); 462 1.1 mrg osprintf(os, " inline __isl_give %s *release();\n", name); 463 1.1 mrg osprintf(os, " inline bool is_null() const;\n"); 464 1.1 mrg } 465 1.1 mrg 466 1.1 mrg /* Print a template declaration with given indentation 467 1.1 mrg * for the "isa_type" method that ensures it is only enabled 468 1.1 mrg * when called with a template argument 469 1.1 mrg * that represents a type that is equal to that 470 1.1 mrg * of the return type of the type function of "super". 471 1.1 mrg * In particular, "isa_type" gets called from "isa" 472 1.1 mrg * with as template argument the type of the "type" field 473 1.1 mrg * of the subclass. 474 1.1 mrg * The check ensures that this subclass is in fact a direct subclass 475 1.1 mrg * of "super". 476 1.1 mrg */ 477 1.1 mrg void plain_cpp_generator::decl_printer::print_isa_type_template(int indent, 478 1.1 mrg const isl_class &super) 479 1.1 mrg { 480 1.1 mrg osprintf(os, indent, 481 1.1 mrg "template <typename T,\n"); 482 1.1 mrg osprintf(os, indent, 483 1.1 mrg " typename = typename std::enable_if<std::is_same<\n"); 484 1.1 mrg osprintf(os, indent, 485 1.1 mrg " const decltype(%s(NULL)),\n", 486 1.1 mrg super.fn_type->getNameAsString().c_str()); 487 1.1 mrg osprintf(os, indent, 488 1.1 mrg " const T>::value>::type>\n"); 489 1.1 mrg } 490 1.1 mrg 491 1.1 mrg /* Print declarations for the "as" and "isa" methods, if the printed class 492 1.1 mrg * is a superclass with a type function. 493 1.1 mrg * 494 1.1 mrg * "isa" checks whether an object is of a given subclass type. 495 1.1 mrg * "isa_type" does the same, but gets passed the value of the type field 496 1.1 mrg * of the subclass as a function argument and the type of this field 497 1.1 mrg * as a template argument. 498 1.1 mrg * "as" tries to cast an object to a given subclass type, returning 499 1.1 mrg * an invalid object if the object is not of the given type. 500 1.1 mrg */ 501 1.1 mrg void plain_cpp_generator::decl_printer::print_downcast() 502 1.1 mrg { 503 1.1 mrg if (!clazz.fn_type) 504 1.1 mrg return; 505 1.1 mrg 506 1.1 mrg osprintf(os, "private:\n"); 507 1.1 mrg print_isa_type_template(2, clazz); 508 1.1 mrg osprintf(os, " inline %s isa_type(T subtype) const;\n", 509 1.1 mrg generator.isl_bool2cpp().c_str()); 510 1.1 mrg osprintf(os, "public:\n"); 511 1.1 mrg osprintf(os, " template <class T> inline %s isa() const;\n", 512 1.1 mrg generator.isl_bool2cpp().c_str()); 513 1.1 mrg osprintf(os, " template <class T> inline T as() const;\n"); 514 1.1 mrg } 515 1.1 mrg 516 1.1 mrg /* Print the declaration of the ctx method. 517 1.1 mrg */ 518 1.1 mrg void plain_cpp_generator::decl_printer::print_ctx() 519 1.1 mrg { 520 1.1 mrg std::string ns = generator.isl_namespace(); 521 1.1 mrg 522 1.1 mrg osprintf(os, " inline %sctx ctx() const;\n", ns.c_str()); 523 1.1 mrg } 524 1.1 mrg 525 1.1 mrg /* Print a separator between groups of method declarations. 526 1.1 mrg */ 527 1.1 mrg void plain_cpp_generator::decl_printer::print_method_separator() 528 1.1 mrg { 529 1.1 mrg os << "\n"; 530 1.1 mrg } 531 1.1 mrg 532 1.1 mrg /* Add a space to the return type "type" if needed, 533 1.1 mrg * i.e., if it is not the type of a pointer. 534 1.1 mrg */ 535 1.1 mrg static string add_space_to_return_type(const string &type) 536 1.1 mrg { 537 1.1 mrg if (type[type.size() - 1] == '*') 538 1.1 mrg return type; 539 1.1 mrg return type + " "; 540 1.1 mrg } 541 1.1 mrg 542 1.1 mrg /* Print the prototype of the static inline method that is used 543 1.1 mrg * as the C callback set by "method". 544 1.1 mrg */ 545 1.1 mrg void plain_cpp_generator::plain_printer::print_persistent_callback_prototype( 546 1.1 mrg FunctionDecl *method) 547 1.1 mrg { 548 1.1 mrg string callback_name, rettype, c_args; 549 1.1 mrg ParmVarDecl *param = persistent_callback_arg(method); 550 1.1 mrg const FunctionProtoType *callback; 551 1.1 mrg QualType ptype; 552 1.1 mrg string classname; 553 1.1 mrg 554 1.1 mrg ptype = param->getType(); 555 1.1 mrg callback = extract_prototype(ptype); 556 1.1 mrg 557 1.1 mrg rettype = callback->getReturnType().getAsString(); 558 1.1 mrg rettype = add_space_to_return_type(rettype); 559 1.1 mrg callback_name = clazz.persistent_callback_name(method); 560 1.1 mrg c_args = generator.generate_callback_args(ptype, false); 561 1.1 mrg 562 1.1 mrg if (!declarations) 563 1.1 mrg classname = type2cpp(clazz) + "::"; 564 1.1 mrg 565 1.1 mrg osprintf(os, "%s%s%s(%s)", 566 1.1 mrg rettype.c_str(), classname.c_str(), 567 1.1 mrg callback_name.c_str(), c_args.c_str()); 568 1.1 mrg } 569 1.1 mrg 570 1.1 mrg /* Print the prototype of the method for setting the callback function 571 1.1 mrg * set by "method". 572 1.1 mrg */ 573 1.1 mrg void 574 1.1 mrg plain_cpp_generator::plain_printer::print_persistent_callback_setter_prototype( 575 1.1 mrg FunctionDecl *method) 576 1.1 mrg { 577 1.1 mrg string classname, callback_name, cpptype; 578 1.1 mrg ParmVarDecl *param = persistent_callback_arg(method); 579 1.1 mrg 580 1.1 mrg if (!declarations) 581 1.1 mrg classname = type2cpp(clazz) + "::"; 582 1.1 mrg 583 1.1 mrg cpptype = generator.param2cpp(param->getOriginalType()); 584 1.1 mrg callback_name = clazz.persistent_callback_name(method); 585 1.1 mrg osprintf(os, "void %sset_%s_data(const %s &%s)", 586 1.1 mrg classname.c_str(), callback_name.c_str(), cpptype.c_str(), 587 1.1 mrg param->getName().str().c_str()); 588 1.1 mrg } 589 1.1 mrg 590 1.1 mrg /* Given a method "method" for setting a persistent callback, 591 1.1 mrg * print the fields that are needed for marshalling the callback. 592 1.1 mrg * 593 1.1 mrg * In particular, print 594 1.1 mrg * - the declaration of a data structure for storing the C++ callback function 595 1.1 mrg * - a shared pointer to such a data structure 596 1.1 mrg * - the declaration of a static inline method 597 1.1 mrg * for use as the C callback function 598 1.1 mrg * - the declaration of a private method for setting the callback function 599 1.1 mrg */ 600 1.1 mrg void plain_cpp_generator::decl_printer::print_persistent_callback_data( 601 1.1 mrg FunctionDecl *method) 602 1.1 mrg { 603 1.1 mrg string callback_name; 604 1.1 mrg ParmVarDecl *param = generator.persistent_callback_arg(method); 605 1.1 mrg 606 1.1 mrg callback_name = clazz.persistent_callback_name(method); 607 1.1 mrg print_callback_data_decl(param, callback_name); 608 1.1 mrg osprintf(os, ";\n"); 609 1.1 mrg osprintf(os, " std::shared_ptr<%s_data> %s_data;\n", 610 1.1 mrg callback_name.c_str(), callback_name.c_str()); 611 1.1 mrg osprintf(os, " static inline "); 612 1.1 mrg print_persistent_callback_prototype(method); 613 1.1 mrg osprintf(os, ";\n"); 614 1.1 mrg osprintf(os, " inline "); 615 1.1 mrg print_persistent_callback_setter_prototype(method); 616 1.1 mrg osprintf(os, ";\n"); 617 1.1 mrg } 618 1.1 mrg 619 1.1 mrg /* Print declarations needed for the persistent callbacks of the class. 620 1.1 mrg * 621 1.1 mrg * In particular, if there are any persistent callbacks, then 622 1.1 mrg * print a private method for copying callback data from 623 1.1 mrg * one object to another, 624 1.1 mrg * private data for keeping track of the persistent callbacks and 625 1.1 mrg * public methods for setting the persistent callbacks. 626 1.1 mrg */ 627 1.1 mrg void plain_cpp_generator::decl_printer::print_persistent_callbacks() 628 1.1 mrg { 629 1.1 mrg const char *cppname = cppstring.c_str(); 630 1.1 mrg 631 1.1 mrg if (!clazz.has_persistent_callbacks()) 632 1.1 mrg return; 633 1.1 mrg 634 1.1 mrg osprintf(os, "private:\n"); 635 1.1 mrg osprintf(os, " inline %s ©_callbacks(const %s &obj);\n", 636 1.1 mrg cppname, cppname); 637 1.1 mrg for (const auto &callback : clazz.persistent_callbacks) 638 1.1 mrg print_persistent_callback_data(callback); 639 1.1 mrg 640 1.1 mrg osprintf(os, "public:\n"); 641 1.1 mrg for (const auto &callback : clazz.persistent_callbacks) 642 1.1 mrg print_method(Method(clazz, callback)); 643 1.1 mrg } 644 1.1 mrg 645 1.1 mrg /* Print a declaration for the "get" method "fd", 646 1.1 mrg * using a name that includes the "get_" prefix. 647 1.1 mrg */ 648 1.1 mrg void plain_cpp_generator::decl_printer::print_get_method(FunctionDecl *fd) 649 1.1 mrg { 650 1.1 mrg string base = clazz.base_method_name(fd); 651 1.1 mrg 652 1.1 mrg print_method(Method(clazz, fd, base)); 653 1.1 mrg } 654 1.1 mrg 655 1.1 mrg /* Print implementations for class "clazz" to "os". 656 1.1 mrg */ 657 1.1 mrg void plain_cpp_generator::print_class_impl(ostream &os, const isl_class &clazz) 658 1.1 mrg { 659 1.1 mrg impl_printer printer(os, clazz, *this); 660 1.1 mrg const char *cppname = printer.cppstring.c_str(); 661 1.1 mrg 662 1.1 mrg osprintf(os, "// implementations for isl::%s", cppname); 663 1.1 mrg 664 1.1 mrg printer.print_class_factory(); 665 1.1 mrg printer.print_protected_constructors(); 666 1.1 mrg printer.print_public_methods(); 667 1.1 mrg printer.print_stream_insertion(); 668 1.1 mrg } 669 1.1 mrg 670 1.1 mrg /* Print code for throwing an exception corresponding to the last error 671 1.1 mrg * that occurred on "saved_ctx". 672 1.1 mrg * This assumes that a valid isl::ctx is available in the "saved_ctx" variable, 673 1.1 mrg * e.g., through a prior call to print_save_ctx. 674 1.1 mrg */ 675 1.1 mrg static void print_throw_last_error(ostream &os) 676 1.1 mrg { 677 1.1 mrg osprintf(os, " exception::throw_last_error(saved_ctx);\n"); 678 1.1 mrg } 679 1.1 mrg 680 1.1 mrg /* Print code with the given indentation 681 1.1 mrg * for throwing an exception_invalid with the given message. 682 1.1 mrg */ 683 1.1 mrg static void print_throw_invalid(ostream &os, int indent, const char *msg) 684 1.1 mrg { 685 1.1 mrg osprintf(os, indent, 686 1.1 mrg "exception::throw_invalid(\"%s\", __FILE__, __LINE__);\n", msg); 687 1.1 mrg } 688 1.1 mrg 689 1.1 mrg /* Print code for throwing an exception on NULL input. 690 1.1 mrg */ 691 1.1 mrg static void print_throw_NULL_input(ostream &os) 692 1.1 mrg { 693 1.1 mrg print_throw_invalid(os, 4, "NULL input"); 694 1.1 mrg } 695 1.1 mrg 696 1.1 mrg /* Print code with the given indentation 697 1.1 mrg * for acting on an invalid error with message "msg". 698 1.1 mrg * In particular, throw an exception_invalid. 699 1.1 mrg * In the checked C++ bindings, isl_die is called instead with the code 700 1.1 mrg * in "checked_code". 701 1.1 mrg */ 702 1.1 mrg void plain_cpp_generator::print_invalid(ostream &os, int indent, 703 1.1 mrg const char *msg, const char *checked_code) 704 1.1 mrg { 705 1.1 mrg if (checked) 706 1.1 mrg osprintf(os, indent, 707 1.1 mrg "isl_die(ctx().get(), isl_error_invalid, " 708 1.1 mrg "\"%s\", %s);\n", msg, checked_code); 709 1.1 mrg else 710 1.1 mrg print_throw_invalid(os, indent, msg); 711 1.1 mrg } 712 1.1 mrg 713 1.1 mrg /* Print an operator for inserting objects of the class 714 1.1 mrg * into an output stream. 715 1.1 mrg * 716 1.1 mrg * Unless checked C++ bindings are being generated, 717 1.1 mrg * the operator requires its argument to be non-NULL. 718 1.1 mrg * An exception is thrown if anything went wrong during the printing. 719 1.1 mrg * During this printing, isl is made not to print any error message 720 1.1 mrg * because the error message is included in the exception. 721 1.1 mrg * 722 1.1 mrg * If checked C++ bindings are being generated and anything went wrong, 723 1.1 mrg * then record this failure in the output stream. 724 1.1 mrg */ 725 1.1 mrg void plain_cpp_generator::impl_printer::print_stream_insertion() 726 1.1 mrg { 727 1.1 mrg const char *name = clazz.name.c_str(); 728 1.1 mrg const char *cppname = cppstring.c_str(); 729 1.1 mrg 730 1.1 mrg if (!clazz.fn_to_str) 731 1.1 mrg return; 732 1.1 mrg 733 1.1 mrg osprintf(os, "\n"); 734 1.1 mrg osprintf(os, "inline std::ostream &operator<<(std::ostream &os, "); 735 1.1 mrg osprintf(os, "const %s &obj)\n", cppname); 736 1.1 mrg osprintf(os, "{\n"); 737 1.1 mrg print_check_ptr_start("obj.get()"); 738 1.1 mrg osprintf(os, " char *str = %s_to_str(obj.get());\n", name); 739 1.1 mrg print_check_ptr_end("str"); 740 1.1 mrg if (generator.checked) { 741 1.1 mrg osprintf(os, " if (!str) {\n"); 742 1.1 mrg osprintf(os, " os.setstate(std::ios_base::badbit);\n"); 743 1.1 mrg osprintf(os, " return os;\n"); 744 1.1 mrg osprintf(os, " }\n"); 745 1.1 mrg } 746 1.1 mrg osprintf(os, " os << str;\n"); 747 1.1 mrg osprintf(os, " free(str);\n"); 748 1.1 mrg osprintf(os, " return os;\n"); 749 1.1 mrg osprintf(os, "}\n"); 750 1.1 mrg } 751 1.1 mrg 752 1.1 mrg /* Print code that checks that "ptr" is not NULL at input. 753 1.1 mrg * 754 1.1 mrg * Omit the check if checked C++ bindings are being generated. 755 1.1 mrg */ 756 1.1 mrg void plain_cpp_generator::impl_printer::print_check_ptr(const char *ptr) 757 1.1 mrg { 758 1.1 mrg if (generator.checked) 759 1.1 mrg return; 760 1.1 mrg 761 1.1 mrg osprintf(os, " if (!%s)\n", ptr); 762 1.1 mrg print_throw_NULL_input(os); 763 1.1 mrg } 764 1.1 mrg 765 1.1 mrg /* Print code that checks that "ptr" is not NULL at input and 766 1.1 mrg * that saves a copy of the isl_ctx of "ptr" for a later check. 767 1.1 mrg * 768 1.1 mrg * Omit the check if checked C++ bindings are being generated. 769 1.1 mrg */ 770 1.1 mrg void plain_cpp_generator::impl_printer::print_check_ptr_start(const char *ptr) 771 1.1 mrg { 772 1.1 mrg if (generator.checked) 773 1.1 mrg return; 774 1.1 mrg 775 1.1 mrg print_check_ptr(ptr); 776 1.1 mrg print_save_ctx(clazz.name + "_get_ctx(" + ptr + ")"); 777 1.1 mrg print_on_error_continue(); 778 1.1 mrg } 779 1.1 mrg 780 1.1 mrg /* Print code that checks that "ptr" is not NULL at the end. 781 1.1 mrg * A copy of the isl_ctx is expected to have been saved by 782 1.1 mrg * code generated by print_check_ptr_start. 783 1.1 mrg * 784 1.1 mrg * Omit the check if checked C++ bindings are being generated. 785 1.1 mrg */ 786 1.1 mrg void plain_cpp_generator::impl_printer::print_check_ptr_end(const char *ptr) 787 1.1 mrg { 788 1.1 mrg if (generator.checked) 789 1.1 mrg return; 790 1.1 mrg 791 1.1 mrg osprintf(os, " if (!%s)\n", ptr); 792 1.1 mrg print_throw_last_error(os); 793 1.1 mrg } 794 1.1 mrg 795 1.1 mrg /* Print implementation of global factory functions. 796 1.1 mrg * 797 1.1 mrg * Each class has two global factory functions: 798 1.1 mrg * 799 1.1 mrg * set manage(__isl_take isl_set *ptr); 800 1.1 mrg * set manage_copy(__isl_keep isl_set *ptr); 801 1.1 mrg * 802 1.1 mrg * Unless checked C++ bindings are being generated, 803 1.1 mrg * both functions require the argument to be non-NULL. 804 1.1 mrg * An exception is thrown if anything went wrong during the copying 805 1.1 mrg * in manage_copy. 806 1.1 mrg * During the copying, isl is made not to print any error message 807 1.1 mrg * because the error message is included in the exception. 808 1.1 mrg * 809 1.1 mrg * For a subclass based on a type function, no factory functions 810 1.1 mrg * are introduced because they share the C object type with 811 1.1 mrg * the superclass. 812 1.1 mrg */ 813 1.1 mrg void plain_cpp_generator::impl_printer::print_class_factory() 814 1.1 mrg { 815 1.1 mrg const char *name = clazz.name.c_str(); 816 1.1 mrg const char *cppname = cppstring.c_str(); 817 1.1 mrg 818 1.1 mrg if (clazz.is_type_subclass()) 819 1.1 mrg return; 820 1.1 mrg 821 1.1 mrg osprintf(os, "\n"); 822 1.1 mrg osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name); 823 1.1 mrg print_check_ptr("ptr"); 824 1.1 mrg osprintf(os, " return %s(ptr);\n", cppname); 825 1.1 mrg osprintf(os, "}\n"); 826 1.1 mrg 827 1.1 mrg osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname, 828 1.1 mrg name); 829 1.1 mrg print_check_ptr_start("ptr"); 830 1.1 mrg osprintf(os, " ptr = %s_copy(ptr);\n", name); 831 1.1 mrg print_check_ptr_end("ptr"); 832 1.1 mrg osprintf(os, " return %s(ptr);\n", cppname); 833 1.1 mrg osprintf(os, "}\n"); 834 1.1 mrg } 835 1.1 mrg 836 1.1 mrg /* Print implementations of protected constructors. 837 1.1 mrg * 838 1.1 mrg * The pointer to the isl object is either initialized directly or 839 1.1 mrg * through the (immediate) superclass. 840 1.1 mrg */ 841 1.1 mrg void plain_cpp_generator::impl_printer::print_protected_constructors() 842 1.1 mrg { 843 1.1 mrg const char *name = clazz.name.c_str(); 844 1.1 mrg const char *cppname = cppstring.c_str(); 845 1.1 mrg bool subclass = clazz.is_type_subclass(); 846 1.1 mrg 847 1.1 mrg osprintf(os, "\n"); 848 1.1 mrg osprintf(os, "%s::%s(__isl_take %s *ptr)\n", cppname, cppname, name); 849 1.1 mrg if (subclass) 850 1.1 mrg osprintf(os, " : %s(ptr) {}\n", 851 1.1 mrg type2cpp(clazz.superclass_name).c_str()); 852 1.1 mrg else 853 1.1 mrg osprintf(os, " : ptr(ptr) {}\n"); 854 1.1 mrg } 855 1.1 mrg 856 1.1 mrg /* Print implementations of public constructors. 857 1.1 mrg * 858 1.1 mrg * The pointer to the isl object is either initialized directly or 859 1.1 mrg * through the (immediate) superclass. 860 1.1 mrg * 861 1.1 mrg * If the class has any persistent callbacks, then copy them 862 1.1 mrg * from the original object in the copy constructor. 863 1.1 mrg * If the class is a subclass, then the persistent callbacks 864 1.1 mrg * are assumed to be copied by the copy constructor of the superclass. 865 1.1 mrg * 866 1.1 mrg * Throw an exception from the copy constructor if anything went wrong 867 1.1 mrg * during the copying or if the input is NULL, if any copying is performed. 868 1.1 mrg * During the copying, isl is made not to print any error message 869 1.1 mrg * because the error message is included in the exception. 870 1.1 mrg * No exceptions are thrown if checked C++ bindings 871 1.1 mrg * are being generated, 872 1.1 mrg */ 873 1.1 mrg void plain_cpp_generator::impl_printer::print_public_constructors() 874 1.1 mrg { 875 1.1 mrg std::string super; 876 1.1 mrg const char *cppname = cppstring.c_str(); 877 1.1 mrg bool subclass = clazz.is_type_subclass(); 878 1.1 mrg 879 1.1 mrg osprintf(os, "\n"); 880 1.1 mrg if (subclass) 881 1.1 mrg super = type2cpp(clazz.superclass_name); 882 1.1 mrg osprintf(os, "%s::%s()\n", cppname, cppname); 883 1.1 mrg if (subclass) 884 1.1 mrg osprintf(os, " : %s() {}\n\n", super.c_str()); 885 1.1 mrg else 886 1.1 mrg osprintf(os, " : ptr(nullptr) {}\n\n"); 887 1.1 mrg osprintf(os, "%s::%s(const %s &obj)\n", cppname, cppname, cppname); 888 1.1 mrg if (subclass) 889 1.1 mrg osprintf(os, " : %s(obj)\n", super.c_str()); 890 1.1 mrg else 891 1.1 mrg osprintf(os, " : ptr(nullptr)\n"); 892 1.1 mrg osprintf(os, "{\n"); 893 1.1 mrg if (!subclass) { 894 1.1 mrg print_check_ptr_start("obj.ptr"); 895 1.1 mrg osprintf(os, " ptr = obj.copy();\n"); 896 1.1 mrg if (clazz.has_persistent_callbacks()) 897 1.1 mrg osprintf(os, " copy_callbacks(obj);\n"); 898 1.1 mrg print_check_ptr_end("ptr"); 899 1.1 mrg } 900 1.1 mrg osprintf(os, "}\n"); 901 1.1 mrg } 902 1.1 mrg 903 1.1 mrg /* Print definition for "method", 904 1.1 mrg * without any automatic type conversions. 905 1.1 mrg * 906 1.1 mrg * This method distinguishes three kinds of methods: member methods, static 907 1.1 mrg * methods, and constructors. 908 1.1 mrg * 909 1.1 mrg * Member methods and static methods return a newly managed 910 1.1 mrg * isl C++ object. 911 1.1 mrg * 912 1.1 mrg * Constructors create a new object from a given set of input parameters. They 913 1.1 mrg * do not return a value, but instead update the pointer stored inside the 914 1.1 mrg * newly created object. 915 1.1 mrg * 916 1.1 mrg * Unless checked C++ bindings are being generated, 917 1.1 mrg * the inputs of the method are first checked for being valid isl objects and 918 1.1 mrg * a copy of the associated isl::ctx is saved (if needed). 919 1.1 mrg * If any failure occurs, either during the check for the inputs or 920 1.1 mrg * during the isl function call, an exception is thrown. 921 1.1 mrg * During the function call, isl is made not to print any error message 922 1.1 mrg * because the error message is included in the exception. 923 1.1 mrg */ 924 1.1 mrg void plain_cpp_generator::impl_printer::print_method(const Method &method) 925 1.1 mrg { 926 1.1 mrg string methodname = method.fd->getName().str(); 927 1.1 mrg int num_params = method.c_num_params(); 928 1.1 mrg 929 1.1 mrg osprintf(os, "\n"); 930 1.1 mrg print_full_method_header(method); 931 1.1 mrg osprintf(os, "{\n"); 932 1.1 mrg print_argument_validity_check(method); 933 1.1 mrg print_save_ctx(method); 934 1.1 mrg print_on_error_continue(); 935 1.1 mrg 936 1.1 mrg for (const auto &callback : method.callbacks) 937 1.1 mrg print_callback_local(callback); 938 1.1 mrg 939 1.1 mrg osprintf(os, " auto res = %s", methodname.c_str()); 940 1.1 mrg 941 1.1 mrg method.print_fd_arg_list(os, 0, num_params, [&] (int i, int arg) { 942 1.1 mrg method.print_param_use(os, i); 943 1.1 mrg }); 944 1.1 mrg osprintf(os, ";\n"); 945 1.1 mrg 946 1.1 mrg print_exceptional_execution_check(method); 947 1.1 mrg if (method.kind == Method::Kind::constructor) { 948 1.1 mrg osprintf(os, " ptr = res;\n"); 949 1.1 mrg } else { 950 1.1 mrg print_method_return(method); 951 1.1 mrg } 952 1.1 mrg 953 1.1 mrg osprintf(os, "}\n"); 954 1.1 mrg } 955 1.1 mrg 956 1.1 mrg /* Convert argument of type "src" to "dst", with a name specified by "dst". 957 1.1 mrg * 958 1.1 mrg * If "src" is the same as "dst", then no argument conversion is needed. 959 1.1 mrg * 960 1.1 mrg * Otherwise, call the conversion function 961 1.1 mrg * with as arguments the isl_ctx of the object and the argument name, 962 1.1 mrg * or simply the argument name if the source type is an isl type. 963 1.1 mrg * This means this isl_ctx should be available. 964 1.1 mrg */ 965 1.1 mrg void plain_cpp_generator::impl_printer::print_arg_conversion(ParmVarDecl *dst, 966 1.1 mrg ParmVarDecl *src) 967 1.1 mrg { 968 1.1 mrg std::string name = dst->getName().str(); 969 1.1 mrg QualType type = dst->getOriginalType(); 970 1.1 mrg string cpptype = generator.param2cpp(type); 971 1.1 mrg 972 1.1 mrg if (dst == src) 973 1.1 mrg os << name; 974 1.1 mrg else if (is_isl_type(src->getOriginalType())) 975 1.1 mrg os << cpptype << "(" << name << ")"; 976 1.1 mrg else 977 1.1 mrg os << cpptype << "(ctx(), " << name << ")"; 978 1.1 mrg } 979 1.1 mrg 980 1.1 mrg /* Print a definition for "method", 981 1.1 mrg * where "this" or at least one of the argument types needs to be converted. 982 1.1 mrg * 983 1.1 mrg * "method" is assumed to be a member method. 984 1.1 mrg * 985 1.1 mrg * The generated method performs the required conversion(s) and 986 1.1 mrg * calls the method generated without conversions. 987 1.1 mrg * 988 1.1 mrg * Perform a conversion from the argument in the method declaration 989 1.1 mrg * (as specified by Method::get_param) to the argument of the C function, 990 1.1 mrg * if needed. 991 1.1 mrg * Such a conversion may require the isl_ctx to be available. 992 1.1 mrg * In order to be able to use this isl_ctx, the current object needs 993 1.1 mrg * to valid. The validity of other arguments is checked 994 1.1 mrg * by the called method. 995 1.1 mrg */ 996 1.1 mrg void plain_cpp_generator::impl_printer::print_method( 997 1.1 mrg const ConversionMethod &method) 998 1.1 mrg { 999 1.1 mrg if (method.kind != Method::Kind::member_method) 1000 1.1 mrg die("Automatic conversion currently only supported " 1001 1.1 mrg "for object methods"); 1002 1.1 mrg 1003 1.1 mrg osprintf(os, "\n"); 1004 1.1 mrg print_full_method_header(method); 1005 1.1 mrg osprintf(os, "{\n"); 1006 1.1 mrg print_check_ptr("ptr"); 1007 1.1 mrg osprintf(os, " return "); 1008 1.1 mrg method.print_call(os, generator.isl_namespace()); 1009 1.1 mrg method.print_cpp_arg_list(os, [&] (int i, int arg) { 1010 1.1 mrg ParmVarDecl *param = method.fd->getParamDecl(i); 1011 1.1 mrg 1012 1.1 mrg print_arg_conversion(param, method.get_param(i)); 1013 1.1 mrg }); 1014 1.1 mrg osprintf(os, ";\n"); 1015 1.1 mrg osprintf(os, "}\n"); 1016 1.1 mrg } 1017 1.1 mrg 1018 1.1 mrg /* Print a definition for a constructor for the "id" class 1019 1.1 mrg * that takes a user object. 1020 1.1 mrg * 1021 1.1 mrg * The user object is taken as a std::any and copied into 1022 1.1 mrg * a new std::any object on the heap. 1023 1.1 mrg * A pointer to this heap object is stored in the isl_id and 1024 1.1 mrg * is scheduled to be freed when the reference count of the isl_id 1025 1.1 mrg * drops to zero. 1026 1.1 mrg * If the allocation of the isl_id fails, then the heap object 1027 1.1 mrg * will not be freed automatically, so it needs to be freed manually. 1028 1.1 mrg * 1029 1.1 mrg * Unless checked C++ bindings are being generated, 1030 1.1 mrg * the ctx argument is copied into the save_ctx variable 1031 1.1 mrg * for use by print_throw_last_error, which throws an exception 1032 1.1 mrg * if the construction fails. 1033 1.1 mrg * During the function call, isl is made not to print any error message 1034 1.1 mrg * because the error message is included in the exception. 1035 1.1 mrg */ 1036 1.1 mrg void plain_cpp_generator::impl_printer::print_id_constructor_user() 1037 1.1 mrg { 1038 1.1 mrg print_id_constructor_user_header(); 1039 1.1 mrg os << "{\n"; 1040 1.1 mrg if (!generator.checked) { 1041 1.1 mrg print_save_ctx("ctx"); 1042 1.1 mrg print_on_error_continue(); 1043 1.1 mrg } 1044 1.1 mrg os << " std::any *p = new std::any(any);\n"; 1045 1.1 mrg os << " auto res = isl_id_alloc(ctx.get(), str.c_str(), p);\n"; 1046 1.1 mrg os << " res = isl_id_set_free_user(res, &ctx::free_user);\n"; 1047 1.1 mrg os << " if (!res) {\n"; 1048 1.1 mrg os << " delete p;\n"; 1049 1.1 mrg if (!generator.checked) 1050 1.1 mrg print_throw_last_error(os); 1051 1.1 mrg os << " }\n"; 1052 1.1 mrg os << " ptr = res;\n"; 1053 1.1 mrg os << "}\n"; 1054 1.1 mrg } 1055 1.1 mrg 1056 1.1 mrg /* Print a definition for an "id" method 1057 1.1 mrg * for retrieving the user object associated to the identifier. 1058 1.1 mrg * If "optional" is set, the method returns a std::optional user object. 1059 1.1 mrg * The returned object is of a type specified by template parameter T. 1060 1.1 mrg * 1061 1.1 mrg * The isl_id needs to have been created by the constructor generated 1062 1.1 mrg * by print_id_constructor_user. That is, it needs to have a user pointer and 1063 1.1 mrg * it needs to have its free_user callback set to &ctx::free_user. 1064 1.1 mrg * The object stored in the std::any also needs to be of the required type. 1065 1.1 mrg * 1066 1.1 mrg * If "optional" is set, return a std::nullopt if any of the checks fail. 1067 1.1 mrg * Otherwise, throw an exception_invalid (or call isl_die and 1068 1.1 mrg * return a default T in the checked C++ bindings). 1069 1.1 mrg */ 1070 1.1 mrg void plain_cpp_generator::impl_printer::print_id_user(bool optional) 1071 1.1 mrg { 1072 1.1 mrg auto fail = [&] (const char *msg) { 1073 1.1 mrg if (optional) 1074 1.1 mrg os << " return std::nullopt;\n"; 1075 1.1 mrg else 1076 1.1 mrg generator.print_invalid(os, 4, msg, "return T()"); 1077 1.1 mrg }; 1078 1.1 mrg os << "\n"; 1079 1.1 mrg print_id_user_header(optional); 1080 1.1 mrg os << "{\n"; 1081 1.1 mrg print_check_ptr("ptr"); 1082 1.1 mrg os << " std::any *p = (std::any *) isl_id_get_user(ptr);\n"; 1083 1.1 mrg os << " if (!p)\n"; 1084 1.1 mrg fail("no user pointer"); 1085 1.1 mrg os << " if (isl_id_get_free_user(ptr) != &ctx::free_user)\n"; 1086 1.1 mrg fail("user pointer not attached by C++ interface"); 1087 1.1 mrg os << " T *res = std::any_cast<T>(p);\n"; 1088 1.1 mrg os << " if (!res)\n"; 1089 1.1 mrg fail("user pointer not of given type"); 1090 1.1 mrg os << " return *res;\n"; 1091 1.1 mrg os << "}\n"; 1092 1.1 mrg } 1093 1.1 mrg 1094 1.1 mrg /* Print implementation of copy assignment operator. 1095 1.1 mrg * 1096 1.1 mrg * If the class has any persistent callbacks, then copy them 1097 1.1 mrg * from the original object. 1098 1.1 mrg */ 1099 1.1 mrg void plain_cpp_generator::impl_printer::print_copy_assignment() 1100 1.1 mrg { 1101 1.1 mrg const char *name = clazz.name.c_str(); 1102 1.1 mrg const char *cppname = cppstring.c_str(); 1103 1.1 mrg 1104 1.1 mrg osprintf(os, "\n"); 1105 1.1 mrg osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname, 1106 1.1 mrg cppname, cppname); 1107 1.1 mrg osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name); 1108 1.1 mrg if (clazz.has_persistent_callbacks()) 1109 1.1 mrg osprintf(os, " copy_callbacks(obj);\n"); 1110 1.1 mrg osprintf(os, " return *this;\n"); 1111 1.1 mrg osprintf(os, "}\n"); 1112 1.1 mrg } 1113 1.1 mrg 1114 1.1 mrg /* Print implementation of destructor. 1115 1.1 mrg * 1116 1.1 mrg * No explicit destructor is needed for type based subclasses. 1117 1.1 mrg */ 1118 1.1 mrg void plain_cpp_generator::impl_printer::print_destructor() 1119 1.1 mrg { 1120 1.1 mrg const char *name = clazz.name.c_str(); 1121 1.1 mrg const char *cppname = cppstring.c_str(); 1122 1.1 mrg 1123 1.1 mrg if (clazz.is_type_subclass()) 1124 1.1 mrg return; 1125 1.1 mrg 1126 1.1 mrg osprintf(os, "\n"); 1127 1.1 mrg osprintf(os, "%s::~%s() {\n", cppname, cppname); 1128 1.1 mrg osprintf(os, " if (ptr)\n"); 1129 1.1 mrg osprintf(os, " %s_free(ptr);\n", name); 1130 1.1 mrg osprintf(os, "}\n"); 1131 1.1 mrg } 1132 1.1 mrg 1133 1.1 mrg /* Print a check that the persistent callback corresponding to "fd" 1134 1.1 mrg * is not set, throwing an exception (or printing an error message 1135 1.1 mrg * and returning nullptr) if it is set. 1136 1.1 mrg */ 1137 1.1 mrg void plain_cpp_generator::print_check_no_persistent_callback(ostream &os, 1138 1.1 mrg const isl_class &clazz, FunctionDecl *fd) 1139 1.1 mrg { 1140 1.1 mrg string callback_name = clazz.persistent_callback_name(fd); 1141 1.1 mrg 1142 1.1 mrg osprintf(os, " if (%s_data)\n", callback_name.c_str()); 1143 1.1 mrg print_invalid(os, 4, "cannot release object with persistent callbacks", 1144 1.1 mrg "return nullptr"); 1145 1.1 mrg } 1146 1.1 mrg 1147 1.1 mrg /* Print implementation of ptr() functions. 1148 1.1 mrg * Since type based subclasses share the pointer with their superclass, 1149 1.1 mrg * they can also reuse these functions from the superclass. 1150 1.1 mrg * 1151 1.1 mrg * If an object has persistent callbacks set, then the underlying 1152 1.1 mrg * C object pointer cannot be released because it references data 1153 1.1 mrg * in the C++ object. 1154 1.1 mrg */ 1155 1.1 mrg void plain_cpp_generator::impl_printer::print_ptr() 1156 1.1 mrg { 1157 1.1 mrg const char *name = clazz.name.c_str(); 1158 1.1 mrg const char *cppname = cppstring.c_str(); 1159 1.1 mrg set<FunctionDecl *>::const_iterator in; 1160 1.1 mrg const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks; 1161 1.1 mrg 1162 1.1 mrg if (clazz.is_type_subclass()) 1163 1.1 mrg return; 1164 1.1 mrg 1165 1.1 mrg osprintf(os, "\n"); 1166 1.1 mrg osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname); 1167 1.1 mrg osprintf(os, " return %s_copy(ptr);\n", name); 1168 1.1 mrg osprintf(os, "}\n\n"); 1169 1.1 mrg osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname); 1170 1.1 mrg osprintf(os, " return ptr;\n"); 1171 1.1 mrg osprintf(os, "}\n\n"); 1172 1.1 mrg osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname); 1173 1.1 mrg for (in = callbacks.begin(); in != callbacks.end(); ++in) 1174 1.1 mrg generator.print_check_no_persistent_callback(os, clazz, *in); 1175 1.1 mrg osprintf(os, " %s *tmp = ptr;\n", name); 1176 1.1 mrg osprintf(os, " ptr = nullptr;\n"); 1177 1.1 mrg osprintf(os, " return tmp;\n"); 1178 1.1 mrg osprintf(os, "}\n\n"); 1179 1.1 mrg osprintf(os, "bool %s::is_null() const {\n", cppname); 1180 1.1 mrg osprintf(os, " return ptr == nullptr;\n"); 1181 1.1 mrg osprintf(os, "}\n"); 1182 1.1 mrg } 1183 1.1 mrg 1184 1.1 mrg /* Print implementations for the "as" and "isa" methods, if the printed class 1185 1.1 mrg * is a superclass with a type function. 1186 1.1 mrg * 1187 1.1 mrg * "isa" checks whether an object is of a given subclass type. 1188 1.1 mrg * "isa_type" does the same, but gets passed the value of the type field 1189 1.1 mrg * of the subclass as a function argument and the type of this field 1190 1.1 mrg * as a template argument. 1191 1.1 mrg * "as" casts an object to a given subclass type, erroring out 1192 1.1 mrg * if the object is not of the given type. 1193 1.1 mrg * 1194 1.1 mrg * If the input is an invalid object, then these methods raise 1195 1.1 mrg * an exception. 1196 1.1 mrg * If checked bindings are being generated, 1197 1.1 mrg * then an invalid boolean or object is returned instead. 1198 1.1 mrg */ 1199 1.1 mrg void plain_cpp_generator::impl_printer::print_downcast() 1200 1.1 mrg { 1201 1.1 mrg const char *cppname = cppstring.c_str(); 1202 1.1 mrg 1203 1.1 mrg if (!clazz.fn_type) 1204 1.1 mrg return; 1205 1.1 mrg 1206 1.1 mrg osprintf(os, "\n"); 1207 1.1 mrg osprintf(os, "template <typename T, typename>\n"); 1208 1.1 mrg osprintf(os, "%s %s::isa_type(T subtype) const\n", 1209 1.1 mrg generator.isl_bool2cpp().c_str(), cppname); 1210 1.1 mrg osprintf(os, "{\n"); 1211 1.1 mrg osprintf(os, " if (is_null())\n"); 1212 1.1 mrg if (generator.checked) 1213 1.1 mrg osprintf(os, " return boolean();\n"); 1214 1.1 mrg else 1215 1.1 mrg print_throw_NULL_input(os); 1216 1.1 mrg osprintf(os, " return %s(get()) == subtype;\n", 1217 1.1 mrg clazz.fn_type->getNameAsString().c_str()); 1218 1.1 mrg osprintf(os, "}\n"); 1219 1.1 mrg 1220 1.1 mrg osprintf(os, "template <class T>\n"); 1221 1.1 mrg osprintf(os, "%s %s::isa() const\n", 1222 1.1 mrg generator.isl_bool2cpp().c_str(), cppname); 1223 1.1 mrg osprintf(os, "{\n"); 1224 1.1 mrg osprintf(os, " return isa_type<decltype(T::type)>(T::type);\n"); 1225 1.1 mrg osprintf(os, "}\n"); 1226 1.1 mrg 1227 1.1 mrg osprintf(os, "template <class T>\n"); 1228 1.1 mrg osprintf(os, "T %s::as() const\n", cppname); 1229 1.1 mrg osprintf(os, "{\n"); 1230 1.1 mrg if (generator.checked) 1231 1.1 mrg osprintf(os, " if (isa<T>().is_false())\n"); 1232 1.1 mrg else 1233 1.1 mrg osprintf(os, " if (!isa<T>())\n"); 1234 1.1 mrg generator.print_invalid(os, 4, "not an object of the requested subtype", 1235 1.1 mrg "return T()"); 1236 1.1 mrg osprintf(os, " return T(copy());\n"); 1237 1.1 mrg osprintf(os, "}\n"); 1238 1.1 mrg } 1239 1.1 mrg 1240 1.1 mrg /* Print the implementation of the ctx method. 1241 1.1 mrg */ 1242 1.1 mrg void plain_cpp_generator::impl_printer::print_ctx() 1243 1.1 mrg { 1244 1.1 mrg const char *name = clazz.name.c_str(); 1245 1.1 mrg const char *cppname = cppstring.c_str(); 1246 1.1 mrg std::string ns = generator.isl_namespace(); 1247 1.1 mrg 1248 1.1 mrg osprintf(os, "\n"); 1249 1.1 mrg osprintf(os, "%sctx %s::ctx() const {\n", ns.c_str(), cppname); 1250 1.1 mrg osprintf(os, " return %sctx(%s_get_ctx(ptr));\n", ns.c_str(), name); 1251 1.1 mrg osprintf(os, "}\n"); 1252 1.1 mrg } 1253 1.1 mrg 1254 1.1 mrg /* Print a separator between groups of method definitions. 1255 1.1 mrg * 1256 1.1 mrg * No additional separator is required between method definitions. 1257 1.1 mrg */ 1258 1.1 mrg void plain_cpp_generator::impl_printer::print_method_separator() 1259 1.1 mrg { 1260 1.1 mrg } 1261 1.1 mrg 1262 1.1 mrg /* Print the implementations of the methods needed for the persistent callbacks 1263 1.1 mrg * of the class. 1264 1.1 mrg */ 1265 1.1 mrg void plain_cpp_generator::impl_printer::print_persistent_callbacks() 1266 1.1 mrg { 1267 1.1 mrg const char *cppname = cppstring.c_str(); 1268 1.1 mrg string classname = type2cpp(clazz); 1269 1.1 mrg 1270 1.1 mrg if (!clazz.has_persistent_callbacks()) 1271 1.1 mrg return; 1272 1.1 mrg 1273 1.1 mrg osprintf(os, "\n"); 1274 1.1 mrg osprintf(os, "%s &%s::copy_callbacks(const %s &obj)\n", 1275 1.1 mrg cppname, classname.c_str(), cppname); 1276 1.1 mrg osprintf(os, "{\n"); 1277 1.1 mrg for (const auto &callback : clazz.persistent_callbacks) { 1278 1.1 mrg string callback_name = clazz.persistent_callback_name(callback); 1279 1.1 mrg 1280 1.1 mrg osprintf(os, " %s_data = obj.%s_data;\n", 1281 1.1 mrg callback_name.c_str(), callback_name.c_str()); 1282 1.1 mrg } 1283 1.1 mrg osprintf(os, " return *this;\n"); 1284 1.1 mrg osprintf(os, "}\n"); 1285 1.1 mrg 1286 1.1 mrg for (const auto &callback : clazz.persistent_callbacks) 1287 1.1 mrg print_set_persistent_callback(Method(clazz, callback)); 1288 1.1 mrg } 1289 1.1 mrg 1290 1.1 mrg /* Print a definition for the "get" method "fd" in class "clazz", 1291 1.1 mrg * using a name that includes the "get_" prefix, to "os". 1292 1.1 mrg * 1293 1.1 mrg * This definition simply calls the variant without the "get_" prefix and 1294 1.1 mrg * returns its result. 1295 1.1 mrg * Note that static methods are not considered to be "get" methods. 1296 1.1 mrg */ 1297 1.1 mrg void plain_cpp_generator::impl_printer::print_get_method(FunctionDecl *fd) 1298 1.1 mrg { 1299 1.1 mrg string get_name = clazz.base_method_name(fd); 1300 1.1 mrg string name = clazz.method_name(fd); 1301 1.1 mrg int num_params = fd->getNumParams(); 1302 1.1 mrg 1303 1.1 mrg osprintf(os, "\n"); 1304 1.1 mrg print_full_method_header(Method(clazz, fd, get_name)); 1305 1.1 mrg osprintf(os, "{\n"); 1306 1.1 mrg osprintf(os, " return %s(", name.c_str()); 1307 1.1 mrg for (int i = 1; i < num_params; ++i) { 1308 1.1 mrg ParmVarDecl *param = fd->getParamDecl(i); 1309 1.1 mrg 1310 1.1 mrg if (i != 1) 1311 1.1 mrg osprintf(os, ", "); 1312 1.1 mrg osprintf(os, "%s", param->getName().str().c_str()); 1313 1.1 mrg } 1314 1.1 mrg osprintf(os, ");\n"); 1315 1.1 mrg osprintf(os, "}\n"); 1316 1.1 mrg } 1317 1.1 mrg 1318 1.1 mrg /* Print code that checks that all isl object arguments to "method" are valid 1319 1.1 mrg * (not NULL) and throws an exception if they are not. 1320 1.1 mrg * 1321 1.1 mrg * If checked bindings are being generated, 1322 1.1 mrg * then no such check is performed. 1323 1.1 mrg */ 1324 1.1 mrg void plain_cpp_generator::impl_printer::print_argument_validity_check( 1325 1.1 mrg const Method &method) 1326 1.1 mrg { 1327 1.1 mrg int n; 1328 1.1 mrg bool first = true; 1329 1.1 mrg 1330 1.1 mrg if (generator.checked) 1331 1.1 mrg return; 1332 1.1 mrg 1333 1.1 mrg n = method.num_params(); 1334 1.1 mrg for (int i = 0; i < n; ++i) { 1335 1.1 mrg bool is_this; 1336 1.1 mrg ParmVarDecl *param = method.fd->getParamDecl(i); 1337 1.1 mrg string name = param->getName().str(); 1338 1.1 mrg const char *name_str = name.c_str(); 1339 1.1 mrg QualType type = param->getOriginalType(); 1340 1.1 mrg 1341 1.1 mrg is_this = i == 0 && method.kind == Method::Kind::member_method; 1342 1.1 mrg if (!is_this && (is_isl_ctx(type) || !is_isl_type(type))) 1343 1.1 mrg continue; 1344 1.1 mrg 1345 1.1 mrg if (first) 1346 1.1 mrg osprintf(os, " if ("); 1347 1.1 mrg else 1348 1.1 mrg osprintf(os, " || "); 1349 1.1 mrg 1350 1.1 mrg if (is_this) 1351 1.1 mrg osprintf(os, "!ptr"); 1352 1.1 mrg else 1353 1.1 mrg osprintf(os, "%s.is_null()", name_str); 1354 1.1 mrg 1355 1.1 mrg first = false; 1356 1.1 mrg } 1357 1.1 mrg if (first) 1358 1.1 mrg return; 1359 1.1 mrg osprintf(os, ")\n"); 1360 1.1 mrg print_throw_NULL_input(os); 1361 1.1 mrg } 1362 1.1 mrg 1363 1.1 mrg /* Print code for saving a copy of "ctx" in a "saved_ctx" variable. 1364 1.1 mrg */ 1365 1.1 mrg void plain_cpp_generator::impl_printer::print_save_ctx(const std::string &ctx) 1366 1.1 mrg { 1367 1.1 mrg os << " auto saved_ctx = " << ctx << ";\n"; 1368 1.1 mrg } 1369 1.1 mrg 1370 1.1 mrg /* Print code for saving a copy of the isl::ctx available at the start 1371 1.1 mrg * of the method "method" in a "saved_ctx" variable, 1372 1.1 mrg * for use in exception handling. 1373 1.1 mrg * 1374 1.1 mrg * If checked bindings are being generated, 1375 1.1 mrg * then the "saved_ctx" variable is not needed. 1376 1.1 mrg * If "method" is a member function, then obtain the isl_ctx from 1377 1.1 mrg * the "this" object. 1378 1.1 mrg * If the first argument of the method is an isl::ctx, then use that one. 1379 1.1 mrg * Otherwise, save a copy of the isl::ctx associated to the first argument 1380 1.1 mrg * of isl object type. 1381 1.1 mrg */ 1382 1.1 mrg void plain_cpp_generator::impl_printer::print_save_ctx(const Method &method) 1383 1.1 mrg { 1384 1.1 mrg int n; 1385 1.1 mrg ParmVarDecl *param = method.fd->getParamDecl(0); 1386 1.1 mrg QualType type = param->getOriginalType(); 1387 1.1 mrg 1388 1.1 mrg if (generator.checked) 1389 1.1 mrg return; 1390 1.1 mrg if (method.kind == Method::Kind::member_method) 1391 1.1 mrg return print_save_ctx("ctx()"); 1392 1.1 mrg if (is_isl_ctx(type)) 1393 1.1 mrg return print_save_ctx(param->getName().str()); 1394 1.1 mrg n = method.num_params(); 1395 1.1 mrg for (int i = 0; i < n; ++i) { 1396 1.1 mrg ParmVarDecl *param = method.fd->getParamDecl(i); 1397 1.1 mrg QualType type = param->getOriginalType(); 1398 1.1 mrg 1399 1.1 mrg if (!is_isl_type(type)) 1400 1.1 mrg continue; 1401 1.1 mrg print_save_ctx(param->getName().str() + ".ctx()"); 1402 1.1 mrg return; 1403 1.1 mrg } 1404 1.1 mrg } 1405 1.1 mrg 1406 1.1 mrg /* Print code to make isl not print an error message when an error occurs 1407 1.1 mrg * within the current scope (if exceptions are available), 1408 1.1 mrg * since the error message will be included in the exception. 1409 1.1 mrg * If exceptions are not available, then exception::on_error 1410 1.1 mrg * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead. 1411 1.1 mrg * 1412 1.1 mrg * If checked bindings are being generated, 1413 1.1 mrg * then leave it to the user to decide what isl should do on error. 1414 1.1 mrg * Otherwise, assume that a valid isl::ctx is available 1415 1.1 mrg * in the "saved_ctx" variable, 1416 1.1 mrg * e.g., through a prior call to print_save_ctx. 1417 1.1 mrg */ 1418 1.1 mrg void plain_cpp_generator::impl_printer::print_on_error_continue() 1419 1.1 mrg { 1420 1.1 mrg if (generator.checked) 1421 1.1 mrg return; 1422 1.1 mrg osprintf(os, " options_scoped_set_on_error saved_on_error(saved_ctx, " 1423 1.1 mrg "exception::on_error);\n"); 1424 1.1 mrg } 1425 1.1 mrg 1426 1.1 mrg /* Print code to "os" that checks whether any of the persistent callbacks 1427 1.1 mrg * of the class of "method" is set and if it failed with an exception. 1428 1.1 mrg * If so, the "eptr" in the corresponding data structure contains the exception 1429 1.1 mrg * that was caught and that needs to be rethrown. 1430 1.1 mrg * This field is cleared because the callback and its data may get reused. 1431 1.1 mrg * 1432 1.1 mrg * The check only needs to be generated for member methods since 1433 1.1 mrg * an object is needed for any of the persistent callbacks to be set. 1434 1.1 mrg */ 1435 1.1 mrg static void print_persistent_callback_exceptional_execution_check(ostream &os, 1436 1.1 mrg const Method &method) 1437 1.1 mrg { 1438 1.1 mrg if (method.kind != Method::Kind::member_method) 1439 1.1 mrg return; 1440 1.1 mrg 1441 1.1 mrg for (const auto &pcb : method.clazz.persistent_callbacks) { 1442 1.1 mrg auto callback_name = method.clazz.persistent_callback_name(pcb); 1443 1.1 mrg 1444 1.1 mrg osprintf(os, " if (%s_data && %s_data->eptr) {\n", 1445 1.1 mrg callback_name.c_str(), callback_name.c_str()); 1446 1.1 mrg osprintf(os, " std::exception_ptr eptr = %s_data->eptr;\n", 1447 1.1 mrg callback_name.c_str()); 1448 1.1 mrg osprintf(os, " %s_data->eptr = nullptr;\n", 1449 1.1 mrg callback_name.c_str()); 1450 1.1 mrg osprintf(os, " std::rethrow_exception(eptr);\n"); 1451 1.1 mrg osprintf(os, " }\n"); 1452 1.1 mrg } 1453 1.1 mrg } 1454 1.1 mrg 1455 1.1 mrg /* Print code that checks whether the execution of the core of "method" 1456 1.1 mrg * was successful. 1457 1.1 mrg * 1458 1.1 mrg * If checked bindings are being generated, 1459 1.1 mrg * then no checks are performed. 1460 1.1 mrg * 1461 1.1 mrg * Otherwise, first check if any of the callbacks failed with 1462 1.1 mrg * an exception. If so, the "eptr" in the corresponding data structure 1463 1.1 mrg * contains the exception that was caught and that needs to be rethrown. 1464 1.1 mrg * Then check if the function call failed in any other way and throw 1465 1.1 mrg * the appropriate exception. 1466 1.1 mrg * In particular, if the return type is isl_stat, isl_bool or isl_size, 1467 1.1 mrg * then a negative value indicates a failure. If the return type 1468 1.1 mrg * is an isl type, then a NULL value indicates a failure. 1469 1.1 mrg * Assume print_save_ctx has made sure that a valid isl::ctx 1470 1.1 mrg * is available in the "ctx" variable. 1471 1.1 mrg */ 1472 1.1 mrg void plain_cpp_generator::impl_printer::print_exceptional_execution_check( 1473 1.1 mrg const Method &method) 1474 1.1 mrg { 1475 1.1 mrg bool check_null, check_neg; 1476 1.1 mrg QualType return_type = method.fd->getReturnType(); 1477 1.1 mrg 1478 1.1 mrg if (generator.checked) 1479 1.1 mrg return; 1480 1.1 mrg 1481 1.1 mrg print_persistent_callback_exceptional_execution_check(os, method); 1482 1.1 mrg 1483 1.1 mrg for (const auto &callback : method.callbacks) { 1484 1.1 mrg std::string name; 1485 1.1 mrg 1486 1.1 mrg name = callback->getName().str(); 1487 1.1 mrg osprintf(os, " if (%s_data.eptr)\n", name.c_str()); 1488 1.1 mrg osprintf(os, " std::rethrow_exception(%s_data.eptr);\n", 1489 1.1 mrg name.c_str()); 1490 1.1 mrg } 1491 1.1 mrg 1492 1.1 mrg check_neg = is_isl_neg_error(return_type); 1493 1.1 mrg check_null = is_isl_type(return_type); 1494 1.1 mrg if (!check_null && !check_neg) 1495 1.1 mrg return; 1496 1.1 mrg 1497 1.1 mrg if (check_neg) 1498 1.1 mrg osprintf(os, " if (res < 0)\n"); 1499 1.1 mrg else 1500 1.1 mrg osprintf(os, " if (!res)\n"); 1501 1.1 mrg print_throw_last_error(os); 1502 1.1 mrg } 1503 1.1 mrg 1504 1.1 mrg /* Return a pointer to the appropriate type printer, 1505 1.1 mrg * i.e., the regular type printer or the checked type printer 1506 1.1 mrg * depending on the setting of this->checked. 1507 1.1 mrg */ 1508 1.1 mrg std::unique_ptr<cpp_type_printer> plain_cpp_generator::type_printer() 1509 1.1 mrg { 1510 1.1 mrg cpp_type_printer *printer; 1511 1.1 mrg 1512 1.1 mrg if (checked) 1513 1.1 mrg printer = new checked_cpp_type_printer(); 1514 1.1 mrg else 1515 1.1 mrg printer = new cpp_type_printer(); 1516 1.1 mrg 1517 1.1 mrg return std::unique_ptr<cpp_type_printer>(printer); 1518 1.1 mrg } 1519 1.1 mrg 1520 1.1 mrg /* Return the C++ return type of the method "method". 1521 1.1 mrg * 1522 1.1 mrg * Use the appropriate type printer. 1523 1.1 mrg */ 1524 1.1 mrg std::string plain_cpp_generator::get_return_type(const Method &method) 1525 1.1 mrg { 1526 1.1 mrg return type_printer()->return_type(method); 1527 1.1 mrg } 1528 1.1 mrg 1529 1.1 mrg /* Given a method "method" for setting a persistent callback of its class, 1530 1.1 mrg * print the implementations of the methods needed for that callback. 1531 1.1 mrg * 1532 1.1 mrg * In particular, print 1533 1.1 mrg * - the implementation of a static inline method 1534 1.1 mrg * for use as the C callback function 1535 1.1 mrg * - the definition of a private method for setting the callback function 1536 1.1 mrg * - the public method for constructing a new object with the callback set. 1537 1.1 mrg */ 1538 1.1 mrg void plain_cpp_generator::impl_printer::print_set_persistent_callback( 1539 1.1 mrg const Method &method) 1540 1.1 mrg { 1541 1.1 mrg string fullname = method.fd->getName().str(); 1542 1.1 mrg ParmVarDecl *param = persistent_callback_arg(method.fd); 1543 1.1 mrg string pname; 1544 1.1 mrg string callback_name = clazz.persistent_callback_name(method.fd); 1545 1.1 mrg 1546 1.1 mrg osprintf(os, "\n"); 1547 1.1 mrg print_persistent_callback_prototype(method.fd); 1548 1.1 mrg osprintf(os, "\n"); 1549 1.1 mrg osprintf(os, "{\n"); 1550 1.1 mrg print_callback_body(2, param, callback_name); 1551 1.1 mrg osprintf(os, "}\n\n"); 1552 1.1 mrg 1553 1.1 mrg pname = param->getName().str(); 1554 1.1 mrg print_persistent_callback_setter_prototype(method.fd); 1555 1.1 mrg osprintf(os, "\n"); 1556 1.1 mrg osprintf(os, "{\n"); 1557 1.1 mrg print_check_ptr_start("ptr"); 1558 1.1 mrg osprintf(os, " %s_data = std::make_shared<struct %s_data>();\n", 1559 1.1 mrg callback_name.c_str(), callback_name.c_str()); 1560 1.1 mrg osprintf(os, " %s_data->func = %s;\n", 1561 1.1 mrg callback_name.c_str(), pname.c_str()); 1562 1.1 mrg osprintf(os, " ptr = %s(ptr, &%s, %s_data.get());\n", 1563 1.1 mrg fullname.c_str(), callback_name.c_str(), callback_name.c_str()); 1564 1.1 mrg print_check_ptr_end("ptr"); 1565 1.1 mrg osprintf(os, "}\n\n"); 1566 1.1 mrg 1567 1.1 mrg print_full_method_header(method); 1568 1.1 mrg osprintf(os, "{\n"); 1569 1.1 mrg osprintf(os, " auto copy = *this;\n"); 1570 1.1 mrg osprintf(os, " copy.set_%s_data(%s);\n", 1571 1.1 mrg callback_name.c_str(), pname.c_str()); 1572 1.1 mrg osprintf(os, " return copy;\n"); 1573 1.1 mrg osprintf(os, "}\n"); 1574 1.1 mrg } 1575 1.1 mrg 1576 1.1 mrg /* Print the return statement of the C++ method "method". 1577 1.1 mrg * 1578 1.1 mrg * The result of the corresponding isl function is returned as a new 1579 1.1 mrg * object if the underlying isl function returns an isl_* ptr, as a bool 1580 1.1 mrg * if the isl function returns an isl_bool, as void if the isl functions 1581 1.1 mrg * returns an isl_stat, 1582 1.1 mrg * as std::string if the isl function returns 'const char *', and as 1583 1.1 mrg * unmodified return value otherwise. 1584 1.1 mrg * If checked C++ bindings are being generated, 1585 1.1 mrg * then an isl_bool return type is transformed into a boolean and 1586 1.1 mrg * an isl_stat into a stat since no exceptions can be generated 1587 1.1 mrg * on negative results from the isl function. 1588 1.1 mrg * If the method returns a new instance of the same object type and 1589 1.1 mrg * if the class has any persistent callbacks, then the data 1590 1.1 mrg * for these callbacks are copied from the original to the new object. 1591 1.1 mrg * If "clazz" is a subclass that is based on a type function and 1592 1.1 mrg * if the return type corresponds to the superclass data type, 1593 1.1 mrg * then it is replaced by the subclass data type. 1594 1.1 mrg */ 1595 1.1 mrg void plain_cpp_generator::impl_printer::print_method_return( 1596 1.1 mrg const Method &method) 1597 1.1 mrg { 1598 1.1 mrg QualType return_type = method.fd->getReturnType(); 1599 1.1 mrg string rettype_str = generator.get_return_type(method); 1600 1.1 mrg bool returns_super = method.is_subclass_mutator(); 1601 1.1 mrg 1602 1.1 mrg if (is_isl_type(return_type) || 1603 1.1 mrg (generator.checked && is_isl_neg_error(return_type))) { 1604 1.1 mrg osprintf(os, " return manage(res)"); 1605 1.1 mrg if (is_mutator(clazz, method.fd) && 1606 1.1 mrg clazz.has_persistent_callbacks()) 1607 1.1 mrg osprintf(os, ".copy_callbacks(*this)"); 1608 1.1 mrg if (returns_super) 1609 1.1 mrg osprintf(os, ".as<%s>()", rettype_str.c_str()); 1610 1.1 mrg osprintf(os, ";\n"); 1611 1.1 mrg } else if (is_isl_stat(return_type)) { 1612 1.1 mrg osprintf(os, " return;\n"); 1613 1.1 mrg } else if (is_string(return_type)) { 1614 1.1 mrg osprintf(os, " std::string tmp(res);\n"); 1615 1.1 mrg if (gives(method.fd)) 1616 1.1 mrg osprintf(os, " free(res);\n"); 1617 1.1 mrg osprintf(os, " return tmp;\n"); 1618 1.1 mrg } else { 1619 1.1 mrg osprintf(os, " return res;\n"); 1620 1.1 mrg } 1621 1.1 mrg } 1622 1.1 mrg 1623 1.1 mrg /* Print the header for "method", including the terminating semicolon 1624 1.1 mrg * in case of a declaration and a newline. 1625 1.1 mrg * 1626 1.1 mrg * Use the appropriate type printer to print argument and return types. 1627 1.1 mrg */ 1628 1.1 mrg void plain_cpp_generator::plain_printer::print_full_method_header( 1629 1.1 mrg const Method &method) 1630 1.1 mrg { 1631 1.1 mrg auto type_printer = generator.type_printer(); 1632 1.1 mrg 1633 1.1 mrg print_method_header(method, *type_printer); 1634 1.1 mrg 1635 1.1 mrg if (declarations) 1636 1.1 mrg osprintf(os, ";"); 1637 1.1 mrg osprintf(os, "\n"); 1638 1.1 mrg } 1639 1.1 mrg 1640 1.1 mrg /* Generate the list of argument types for a callback function of 1641 1.1 mrg * type "type". If "cpp" is set, then generate the C++ type list, otherwise 1642 1.1 mrg * the C type list. 1643 1.1 mrg * 1644 1.1 mrg * Use the appropriate type printer. 1645 1.1 mrg * For the plain C++ interface, the argument position is irrelevant, 1646 1.1 mrg * so simply pass in -1. 1647 1.1 mrg */ 1648 1.1 mrg string plain_cpp_generator::generate_callback_args(QualType type, bool cpp) 1649 1.1 mrg { 1650 1.1 mrg return type_printer()->generate_callback_args(-1, type, cpp); 1651 1.1 mrg } 1652 1.1 mrg 1653 1.1 mrg /* Generate the full cpp type of a callback function of type "type". 1654 1.1 mrg * 1655 1.1 mrg * Use the appropriate type printer. 1656 1.1 mrg * For the plain C++ interface, the argument position is irrelevant, 1657 1.1 mrg * so simply pass in -1. 1658 1.1 mrg */ 1659 1.1 mrg string plain_cpp_generator::generate_callback_type(QualType type) 1660 1.1 mrg { 1661 1.1 mrg return type_printer()->generate_callback_type(-1, type); 1662 1.1 mrg } 1663 1.1 mrg 1664 1.1 mrg /* Print the call to the C++ callback function "call", 1665 1.1 mrg * with the given indentation, wrapped 1666 1.1 mrg * for use inside the lambda function that is used as the C callback function, 1667 1.1 mrg * in the case where checked C++ bindings are being generated. 1668 1.1 mrg * 1669 1.1 mrg * In particular, print 1670 1.1 mrg * 1671 1.1 mrg * auto ret = @call@; 1672 1.1 mrg * return ret.release(); 1673 1.1 mrg */ 1674 1.1 mrg void plain_cpp_generator::impl_printer::print_wrapped_call_checked(int indent, 1675 1.1 mrg const string &call) 1676 1.1 mrg { 1677 1.1 mrg osprintf(os, indent, "auto ret = %s;\n", call.c_str()); 1678 1.1 mrg osprintf(os, indent, "return ret.release();\n"); 1679 1.1 mrg } 1680 1.1 mrg 1681 1.1 mrg /* Print the call to the C++ callback function "call", 1682 1.1 mrg * with the given indentation and with return type "rtype", wrapped 1683 1.1 mrg * for use inside the lambda function that is used as the C callback function. 1684 1.1 mrg * 1685 1.1 mrg * In particular, print 1686 1.1 mrg * 1687 1.1 mrg * ISL_CPP_TRY { 1688 1.1 mrg * @call@; 1689 1.1 mrg * return isl_stat_ok; 1690 1.1 mrg * } ISL_CPP_CATCH_ALL { 1691 1.1 mrg * data->eptr = std::current_exception(); 1692 1.1 mrg * return isl_stat_error; 1693 1.1 mrg * } 1694 1.1 mrg * or 1695 1.1 mrg * ISL_CPP_TRY { 1696 1.1 mrg * auto ret = @call@; 1697 1.1 mrg * return ret ? isl_bool_true : isl_bool_false; 1698 1.1 mrg * } ISL_CPP_CATCH_ALL { 1699 1.1 mrg * data->eptr = std::current_exception(); 1700 1.1 mrg * return isl_bool_error; 1701 1.1 mrg * } 1702 1.1 mrg * or 1703 1.1 mrg * ISL_CPP_TRY { 1704 1.1 mrg * auto ret = @call@; 1705 1.1 mrg * return ret.release(); 1706 1.1 mrg * } ISL_CPP_CATCH_ALL { 1707 1.1 mrg * data->eptr = std::current_exception(); 1708 1.1 mrg * return NULL; 1709 1.1 mrg * } 1710 1.1 mrg * 1711 1.1 mrg * depending on the return type. 1712 1.1 mrg * 1713 1.1 mrg * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)" 1714 1.1 mrg * (if exceptions are available). 1715 1.1 mrg * 1716 1.1 mrg * If checked C++ bindings are being generated, then 1717 1.1 mrg * the call is wrapped differently. 1718 1.1 mrg */ 1719 1.1 mrg void plain_cpp_generator::impl_printer::print_wrapped_call(int indent, 1720 1.1 mrg const string &call, QualType rtype) 1721 1.1 mrg { 1722 1.1 mrg if (generator.checked) 1723 1.1 mrg return print_wrapped_call_checked(indent, call); 1724 1.1 mrg 1725 1.1 mrg osprintf(os, indent, "ISL_CPP_TRY {\n"); 1726 1.1 mrg if (is_isl_stat(rtype)) 1727 1.1 mrg osprintf(os, indent, " %s;\n", call.c_str()); 1728 1.1 mrg else 1729 1.1 mrg osprintf(os, indent, " auto ret = %s;\n", call.c_str()); 1730 1.1 mrg if (is_isl_stat(rtype)) 1731 1.1 mrg osprintf(os, indent, " return isl_stat_ok;\n"); 1732 1.1 mrg else if (is_isl_bool(rtype)) 1733 1.1 mrg osprintf(os, indent, 1734 1.1 mrg " return ret ? isl_bool_true : isl_bool_false;\n"); 1735 1.1 mrg else 1736 1.1 mrg osprintf(os, indent, " return ret.release();\n"); 1737 1.1 mrg osprintf(os, indent, "} ISL_CPP_CATCH_ALL {\n"); 1738 1.1 mrg osprintf(os, indent, " data->eptr = std::current_exception();\n"); 1739 1.1 mrg if (is_isl_stat(rtype)) 1740 1.1 mrg osprintf(os, indent, " return isl_stat_error;\n"); 1741 1.1 mrg else if (is_isl_bool(rtype)) 1742 1.1 mrg osprintf(os, indent, " return isl_bool_error;\n"); 1743 1.1 mrg else 1744 1.1 mrg osprintf(os, indent, " return NULL;\n"); 1745 1.1 mrg osprintf(os, indent, "}\n"); 1746 1.1 mrg } 1747 1.1 mrg 1748 1.1 mrg /* Print the declaration for a "prefix"_data data structure 1749 1.1 mrg * that can be used for passing to a C callback function 1750 1.1 mrg * containing a copy of the C++ callback function "param", 1751 1.1 mrg * along with an std::exception_ptr that is used to store any 1752 1.1 mrg * exceptions thrown in the C++ callback. 1753 1.1 mrg * 1754 1.1 mrg * If the C callback is of the form 1755 1.1 mrg * 1756 1.1 mrg * isl_stat (*fn)(__isl_take isl_map *map, void *user) 1757 1.1 mrg * 1758 1.1 mrg * then the following declaration is printed: 1759 1.1 mrg * 1760 1.1 mrg * struct <prefix>_data { 1761 1.1 mrg * std::function<stat(map)> func; 1762 1.1 mrg * std::exception_ptr eptr; 1763 1.1 mrg * } 1764 1.1 mrg * 1765 1.1 mrg * (without a newline or a semicolon). 1766 1.1 mrg * 1767 1.1 mrg * The std::exception_ptr object is not added to "prefix"_data 1768 1.1 mrg * if checked C++ bindings are being generated. 1769 1.1 mrg */ 1770 1.1 mrg void plain_cpp_generator::plain_printer::print_callback_data_decl( 1771 1.1 mrg ParmVarDecl *param, 1772 1.1 mrg const string &prefix) 1773 1.1 mrg { 1774 1.1 mrg string cpp_args; 1775 1.1 mrg 1776 1.1 mrg cpp_args = generator.generate_callback_type(param->getType()); 1777 1.1 mrg 1778 1.1 mrg osprintf(os, " struct %s_data {\n", prefix.c_str()); 1779 1.1 mrg osprintf(os, " %s func;\n", cpp_args.c_str()); 1780 1.1 mrg if (!generator.checked) 1781 1.1 mrg osprintf(os, " std::exception_ptr eptr;\n"); 1782 1.1 mrg osprintf(os, " }"); 1783 1.1 mrg } 1784 1.1 mrg 1785 1.1 mrg /* Given a group of methods with the same name, 1786 1.1 mrg * should extra methods be added that take as arguments 1787 1.1 mrg * those types that can be converted to the original argument type 1788 1.1 mrg * through a unary constructor? 1789 1.1 mrg * 1790 1.1 mrg * Note that even if this method returns true, 1791 1.1 mrg * the extra methods are only printed by the caller 1792 1.1 mrg * if exactly one of the methods in the group was originally defined 1793 1.1 mrg * in the printed class. 1794 1.1 mrg * Signal that they should be printed if the group contains 1795 1.1 mrg * both methods originally defined in the printed class and 1796 1.1 mrg * methods that have been copied from an ancestor 1797 1.1 mrg * by checking whether there are at least two methods in the group. 1798 1.1 mrg */ 1799 1.1 mrg bool plain_cpp_generator::plain_printer::want_descendent_overloads( 1800 1.1 mrg const function_set &methods) 1801 1.1 mrg { 1802 1.1 mrg return methods.size() > 1; 1803 1.1 mrg } 1804 1.1 mrg 1805 1.1 mrg /* Print the header of the constructor for the "id" class 1806 1.1 mrg * that takes a user object. 1807 1.1 mrg * 1808 1.1 mrg * The user object is taken as a std::any. 1809 1.1 mrg */ 1810 1.1 mrg void plain_cpp_generator::plain_printer::print_id_constructor_user_header() 1811 1.1 mrg { 1812 1.1 mrg if (declarations) 1813 1.1 mrg os << " inline explicit "; 1814 1.1 mrg else 1815 1.1 mrg os << "id::"; 1816 1.1 mrg os << "id(" << generator.isl_namespace() << "ctx ctx, " 1817 1.1 mrg << "const std::string &str, const std::any &any)"; 1818 1.1 mrg if (declarations) 1819 1.1 mrg os << ";"; 1820 1.1 mrg os << "\n"; 1821 1.1 mrg } 1822 1.1 mrg 1823 1.1 mrg /* Print the header of the "id" method 1824 1.1 mrg * for retrieving the user object associated to the identifier. 1825 1.1 mrg * If "optional" is set, the method returns a std::optional user object. 1826 1.1 mrg * The returned object is of a type specified by template parameter T. 1827 1.1 mrg */ 1828 1.1 mrg void plain_cpp_generator::plain_printer::print_id_user_header(bool optional) 1829 1.1 mrg { 1830 1.1 mrg auto indent = declarations ? " " : ""; 1831 1.1 mrg os << indent << "template <class T>\n"; 1832 1.1 mrg os << indent << (optional ? "std::optional<T> " : "T "); 1833 1.1 mrg if (!declarations) 1834 1.1 mrg os << "id::"; 1835 1.1 mrg os << (optional ? "try_" : ""); 1836 1.1 mrg os << "user() const"; 1837 1.1 mrg if (declarations) 1838 1.1 mrg os << ";"; 1839 1.1 mrg os << "\n"; 1840 1.1 mrg } 1841 1.1 mrg 1842 1.1 mrg /* Perform printing by "fn" in a context that only gets compiled 1843 1.1 mrg * by C++17 compilers. 1844 1.1 mrg */ 1845 1.1 mrg static void on_cplusplus17(ostream &os, const std::function<void(void)> &fn) 1846 1.1 mrg { 1847 1.1 mrg os << "#if __cplusplus >= 201703L\n"; 1848 1.1 mrg fn(); 1849 1.1 mrg os << "#endif\n"; 1850 1.1 mrg } 1851 1.1 mrg 1852 1.1 mrg /* Print declarations or definitions of the special methods of the "id" class 1853 1.1 mrg * that are not automatically derived from the C interface. 1854 1.1 mrg * 1855 1.1 mrg * In particular, print a constructor that takes a user pointer 1856 1.1 mrg * as well as methods for retrieving this user pointer. 1857 1.1 mrg * 1858 1.1 mrg * These methods require C++17 features. 1859 1.1 mrg */ 1860 1.1 mrg void plain_cpp_generator::plain_printer::print_special_id() 1861 1.1 mrg { 1862 1.1 mrg os << "\n"; 1863 1.1 mrg on_cplusplus17(os, [this] () { 1864 1.1 mrg print_id_constructor_user(); 1865 1.1 mrg print_id_user(true); 1866 1.1 mrg print_id_user(false); 1867 1.1 mrg }); 1868 1.1 mrg } 1869 1.1 mrg 1870 1.1 mrg /* Print declarations or definitions of any special methods of this class 1871 1.1 mrg * not automatically derived from the C interface. 1872 1.1 mrg * 1873 1.1 mrg * In particular, print special methods for the "id" class. 1874 1.1 mrg */ 1875 1.1 mrg void plain_cpp_generator::plain_printer::print_special() 1876 1.1 mrg { 1877 1.1 mrg if (clazz.name == "isl_id") 1878 1.1 mrg print_special_id(); 1879 1.1 mrg } 1880 1.1 mrg 1881 1.1 mrg /* Print declarations or definitions of the public methods. 1882 1.1 mrg */ 1883 1.1 mrg void plain_cpp_generator::plain_printer::print_public_methods() 1884 1.1 mrg { 1885 1.1 mrg print_public_constructors(); 1886 1.1 mrg print_constructors(); 1887 1.1 mrg print_copy_assignment(); 1888 1.1 mrg print_destructor(); 1889 1.1 mrg print_ptr(); 1890 1.1 mrg print_downcast(); 1891 1.1 mrg print_ctx(); 1892 1.1 mrg print_method_separator(); 1893 1.1 mrg print_persistent_callbacks(); 1894 1.1 mrg print_methods(); 1895 1.1 mrg print_set_enums(); 1896 1.1 mrg print_special(); 1897 1.1 mrg } 1898 1.1 mrg 1899 1.1 mrg /* Print the body of C function callback with the given indentation 1900 1.1 mrg * that can be use as an argument to "param" for marshalling 1901 1.1 mrg * the corresponding C++ callback. 1902 1.1 mrg * The data structure that contains the C++ callback is of type 1903 1.1 mrg * "prefix"_data. 1904 1.1 mrg * 1905 1.1 mrg * For a callback of the form 1906 1.1 mrg * 1907 1.1 mrg * isl_stat (*fn)(__isl_take isl_map *map, void *user) 1908 1.1 mrg * 1909 1.1 mrg * the following code is generated: 1910 1.1 mrg * 1911 1.1 mrg * auto *data = static_cast<struct <prefix>_data *>(arg_1); 1912 1.1 mrg * ISL_CPP_TRY { 1913 1.1 mrg * stat ret = (data->func)(manage(arg_0)); 1914 1.1 mrg * return isl_stat_ok; 1915 1.1 mrg * } ISL_CPP_CATCH_ALL { 1916 1.1 mrg * data->eptr = std::current_exception(); 1917 1.1 mrg * return isl_stat_error; 1918 1.1 mrg * } 1919 1.1 mrg * 1920 1.1 mrg * If checked C++ bindings are being generated, then 1921 1.1 mrg * generate the following code: 1922 1.1 mrg * 1923 1.1 mrg * auto *data = static_cast<struct <prefix>_data *>(arg_1); 1924 1.1 mrg * stat ret = (data->func)(manage(arg_0)); 1925 1.1 mrg * return isl_stat(ret); 1926 1.1 mrg */ 1927 1.1 mrg void plain_cpp_generator::impl_printer::print_callback_body(int indent, 1928 1.1 mrg ParmVarDecl *param, const string &prefix) 1929 1.1 mrg { 1930 1.1 mrg QualType ptype, rtype; 1931 1.1 mrg string call, last_idx; 1932 1.1 mrg const FunctionProtoType *callback; 1933 1.1 mrg int num_params; 1934 1.1 mrg 1935 1.1 mrg ptype = param->getType(); 1936 1.1 mrg 1937 1.1 mrg callback = extract_prototype(ptype); 1938 1.1 mrg rtype = callback->getReturnType(); 1939 1.1 mrg num_params = callback->getNumArgs(); 1940 1.1 mrg 1941 1.1 mrg last_idx = ::to_string(num_params - 1); 1942 1.1 mrg 1943 1.1 mrg call = "(data->func)("; 1944 1.1 mrg for (long i = 0; i < num_params - 1; i++) { 1945 1.1 mrg if (!generator.callback_takes_argument(param, i)) 1946 1.1 mrg call += "manage_copy"; 1947 1.1 mrg else 1948 1.1 mrg call += "manage"; 1949 1.1 mrg call += "(arg_" + ::to_string(i) + ")"; 1950 1.1 mrg if (i != num_params - 2) 1951 1.1 mrg call += ", "; 1952 1.1 mrg } 1953 1.1 mrg call += ")"; 1954 1.1 mrg 1955 1.1 mrg osprintf(os, indent, 1956 1.1 mrg "auto *data = static_cast<struct %s_data *>(arg_%s);\n", 1957 1.1 mrg prefix.c_str(), last_idx.c_str()); 1958 1.1 mrg print_wrapped_call(indent, call, rtype); 1959 1.1 mrg } 1960 1.1 mrg 1961 1.1 mrg /* Print the local variables that are needed for a callback argument, 1962 1.1 mrg * in particular, print a lambda function that wraps the callback and 1963 1.1 mrg * a pointer to the actual C++ callback function. 1964 1.1 mrg * 1965 1.1 mrg * For a callback of the form 1966 1.1 mrg * 1967 1.1 mrg * isl_stat (*fn)(__isl_take isl_map *map, void *user) 1968 1.1 mrg * 1969 1.1 mrg * the following lambda function is generated: 1970 1.1 mrg * 1971 1.1 mrg * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat { 1972 1.1 mrg * auto *data = static_cast<struct fn_data *>(arg_1); 1973 1.1 mrg * try { 1974 1.1 mrg * stat ret = (data->func)(manage(arg_0)); 1975 1.1 mrg * return isl_stat_ok; 1976 1.1 mrg * } catch (...) { 1977 1.1 mrg * data->eptr = std::current_exception(); 1978 1.1 mrg * return isl_stat_error; 1979 1.1 mrg * } 1980 1.1 mrg * }; 1981 1.1 mrg * 1982 1.1 mrg * A copy of the std::function C++ callback function is stored in 1983 1.1 mrg * a fn_data data structure for passing to the C callback function, 1984 1.1 mrg * along with an std::exception_ptr that is used to store any 1985 1.1 mrg * exceptions thrown in the C++ callback. 1986 1.1 mrg * 1987 1.1 mrg * struct fn_data { 1988 1.1 mrg * std::function<stat(map)> func; 1989 1.1 mrg * std::exception_ptr eptr; 1990 1.1 mrg * } fn_data = { fn }; 1991 1.1 mrg * 1992 1.1 mrg * This std::function object represents the actual user 1993 1.1 mrg * callback function together with the locally captured state at the caller. 1994 1.1 mrg * 1995 1.1 mrg * The lambda function is expected to be used as a C callback function 1996 1.1 mrg * where the lambda itself is provided as the function pointer and 1997 1.1 mrg * where the user void pointer is a pointer to fn_data. 1998 1.1 mrg * The std::function object is extracted from the pointer to fn_data 1999 1.1 mrg * inside the lambda function. 2000 1.1 mrg * 2001 1.1 mrg * The std::exception_ptr object is not added to fn_data 2002 1.1 mrg * if checked C++ bindings are being generated. 2003 1.1 mrg * The body of the generated lambda function then is as follows: 2004 1.1 mrg * 2005 1.1 mrg * stat ret = (data->func)(manage(arg_0)); 2006 1.1 mrg * return isl_stat(ret); 2007 1.1 mrg * 2008 1.1 mrg * If the C callback does not take its arguments, then 2009 1.1 mrg * manage_copy is used instead of manage. 2010 1.1 mrg */ 2011 1.1 mrg void plain_cpp_generator::impl_printer::print_callback_local(ParmVarDecl *param) 2012 1.1 mrg { 2013 1.1 mrg string pname; 2014 1.1 mrg QualType ptype, rtype; 2015 1.1 mrg string c_args, cpp_args, rettype; 2016 1.1 mrg const FunctionProtoType *callback; 2017 1.1 mrg 2018 1.1 mrg pname = param->getName().str(); 2019 1.1 mrg ptype = param->getType(); 2020 1.1 mrg 2021 1.1 mrg c_args = generator.generate_callback_args(ptype, false); 2022 1.1 mrg 2023 1.1 mrg callback = extract_prototype(ptype); 2024 1.1 mrg rtype = callback->getReturnType(); 2025 1.1 mrg rettype = rtype.getAsString(); 2026 1.1 mrg 2027 1.1 mrg print_callback_data_decl(param, pname); 2028 1.1 mrg osprintf(os, " %s_data = { %s };\n", pname.c_str(), pname.c_str()); 2029 1.1 mrg osprintf(os, " auto %s_lambda = [](%s) -> %s {\n", 2030 1.1 mrg pname.c_str(), c_args.c_str(), rettype.c_str()); 2031 1.1 mrg print_callback_body(4, param, pname); 2032 1.1 mrg osprintf(os, " };\n"); 2033 1.1 mrg } 2034 1.1 mrg 2035 1.1 mrg /* Return the C++ counterpart to the isl_bool type. 2036 1.1 mrg * 2037 1.1 mrg * For the checked C++ bindings this is "boolean". 2038 1.1 mrg */ 2039 1.1 mrg std::string checked_cpp_type_printer::isl_bool() const 2040 1.1 mrg { 2041 1.1 mrg return "boolean"; 2042 1.1 mrg } 2043 1.1 mrg 2044 1.1 mrg /* Return the C++ counterpart to the isl_bool type. 2045 1.1 mrg * 2046 1.1 mrg * Use the appropriate type printer. 2047 1.1 mrg */ 2048 1.1 mrg string plain_cpp_generator::isl_bool2cpp() 2049 1.1 mrg { 2050 1.1 mrg return type_printer()->isl_bool(); 2051 1.1 mrg } 2052 1.1 mrg 2053 1.1 mrg /* Return the C++ counterpart to the isl_stat type. 2054 1.1 mrg * 2055 1.1 mrg * For the checked C++ bindings this is "stat". 2056 1.1 mrg */ 2057 1.1 mrg string checked_cpp_type_printer::isl_stat() const 2058 1.1 mrg { 2059 1.1 mrg return "stat"; 2060 1.1 mrg } 2061 1.1 mrg 2062 1.1 mrg /* Return the C++ counterpart to the isl_size type. 2063 1.1 mrg * 2064 1.1 mrg * For the checked C++ bindings this is "class size". 2065 1.1 mrg */ 2066 1.1 mrg string checked_cpp_type_printer::isl_size() const 2067 1.1 mrg { 2068 1.1 mrg return "class size"; 2069 1.1 mrg } 2070 1.1 mrg 2071 1.1 mrg /* Return the namespace of the generated C++ bindings. 2072 1.1 mrg * 2073 1.1 mrg * For the checked C++ bindings this is "isl::checked::". 2074 1.1 mrg */ 2075 1.1 mrg std::string checked_cpp_type_printer::isl_namespace() const 2076 1.1 mrg { 2077 1.1 mrg return "isl::checked::"; 2078 1.1 mrg } 2079 1.1 mrg 2080 1.1 mrg /* Return the namespace of the generated C++ bindings. 2081 1.1 mrg * 2082 1.1 mrg * Use the appropriate type printer. 2083 1.1 mrg */ 2084 1.1 mrg string plain_cpp_generator::isl_namespace() 2085 1.1 mrg { 2086 1.1 mrg return type_printer()->isl_namespace(); 2087 1.1 mrg } 2088 1.1 mrg 2089 1.1 mrg /* Translate parameter or return type "type" to its C++ name counterpart. 2090 1.1 mrg * 2091 1.1 mrg * Use the appropriate type printer. 2092 1.1 mrg * For the plain C++ interface, the argument position is irrelevant, 2093 1.1 mrg * so simply pass in -1. 2094 1.1 mrg */ 2095 1.1 mrg string plain_cpp_generator::param2cpp(QualType type) 2096 1.1 mrg { 2097 1.1 mrg return type_printer()->param(-1, type); 2098 1.1 mrg } 2099