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