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