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 292*6145b11cSTobias 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) 380*6145b11cSTobias Grosser print_method_group_decl(os, clazz, it->second); 381d169d70bSTobias Grosser } 382d169d70bSTobias Grosser 383*6145b11cSTobias 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, 386*6145b11cSTobias 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); 392*6145b11cSTobias 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, 401*6145b11cSTobias Grosser FunctionDecl *method, function_kind kind) 402d169d70bSTobias Grosser { 403*6145b11cSTobias 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 451d169d70bSTobias Grosser /* Print implementation of global factory functions to "os". 452d169d70bSTobias Grosser * 453d169d70bSTobias Grosser * Each class has two global factory functions: 454d169d70bSTobias Grosser * 455d169d70bSTobias Grosser * set manage(__isl_take isl_set *ptr); 456d169d70bSTobias Grosser * set manage_copy(__isl_keep isl_set *ptr); 457d169d70bSTobias Grosser * 458d169d70bSTobias Grosser * Unless checked C++ bindings are being generated, 459d169d70bSTobias Grosser * both functions require the argument to be non-NULL. 460d169d70bSTobias Grosser * An exception is thrown if anything went wrong during the copying 461d169d70bSTobias Grosser * in manage_copy. 462d169d70bSTobias Grosser * During the copying, isl is made not to print any error message 463d169d70bSTobias Grosser * because the error message is included in the exception. 464d169d70bSTobias Grosser */ 465d169d70bSTobias Grosser void cpp_generator::print_class_factory_impl(ostream &os, 466d169d70bSTobias Grosser const isl_class &clazz) 467d169d70bSTobias Grosser { 468d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 469d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 470d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 471d169d70bSTobias Grosser 472d169d70bSTobias Grosser osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name); 473d169d70bSTobias Grosser if (!checked) { 474d169d70bSTobias Grosser osprintf(os, " if (!ptr)\n"); 475d169d70bSTobias Grosser print_throw_NULL_input(os); 476d169d70bSTobias Grosser } 477d169d70bSTobias Grosser osprintf(os, " return %s(ptr);\n", cppname); 478d169d70bSTobias Grosser osprintf(os, "}\n"); 479d169d70bSTobias Grosser 480d169d70bSTobias Grosser osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname, 481d169d70bSTobias Grosser name); 482d169d70bSTobias Grosser if (!checked) { 483d169d70bSTobias Grosser osprintf(os, " if (!ptr)\n"); 484d169d70bSTobias Grosser print_throw_NULL_input(os); 485d169d70bSTobias Grosser osprintf(os, " auto ctx = %s_get_ctx(ptr);\n", name); 486d169d70bSTobias Grosser print_on_error_continue(os); 487d169d70bSTobias Grosser } 488d169d70bSTobias Grosser osprintf(os, " ptr = %s_copy(ptr);\n", name); 489d169d70bSTobias Grosser if (!checked) { 490d169d70bSTobias Grosser osprintf(os, " if (!ptr)\n"); 491d169d70bSTobias Grosser print_throw_last_error(os); 492d169d70bSTobias Grosser } 493d169d70bSTobias Grosser osprintf(os, " return %s(ptr);\n", cppname); 494d169d70bSTobias Grosser osprintf(os, "}\n"); 495d169d70bSTobias Grosser } 496d169d70bSTobias Grosser 497d169d70bSTobias Grosser /* Print implementations of private constructors for class "clazz" to "os". 498d169d70bSTobias Grosser */ 499d169d70bSTobias Grosser void cpp_generator::print_private_constructors_impl(ostream &os, 500d169d70bSTobias Grosser const isl_class &clazz) 501d169d70bSTobias Grosser { 502d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 503d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 504d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 505d169d70bSTobias Grosser 506d169d70bSTobias Grosser osprintf(os, "%s::%s(__isl_take %s *ptr)\n : ptr(ptr) {}\n", 507d169d70bSTobias Grosser cppname, cppname, name); 508d169d70bSTobias Grosser } 509d169d70bSTobias Grosser 510d169d70bSTobias Grosser /* Print implementations of public constructors for class "clazz" to "os". 511d169d70bSTobias Grosser * 512d169d70bSTobias Grosser * Throw an exception from the copy constructor if anything went wrong 513d169d70bSTobias Grosser * during the copying or if the input is NULL. 514d169d70bSTobias Grosser * During the copying, isl is made not to print any error message 515d169d70bSTobias Grosser * because the error message is included in the exception. 516d169d70bSTobias Grosser * No exceptions are thrown if checked C++ bindings 517d169d70bSTobias Grosser * are being generated, 518d169d70bSTobias Grosser */ 519d169d70bSTobias Grosser void cpp_generator::print_public_constructors_impl(ostream &os, 520d169d70bSTobias Grosser const isl_class &clazz) 521d169d70bSTobias Grosser { 522d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 523d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 524d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 525d169d70bSTobias Grosser 526d169d70bSTobias Grosser osprintf(os, "%s::%s()\n : ptr(nullptr) {}\n\n", cppname, cppname); 527d169d70bSTobias Grosser osprintf(os, "%s::%s(const %s &obj)\n : ptr(nullptr)\n", 528d169d70bSTobias Grosser cppname, cppname, cppname); 529d169d70bSTobias Grosser osprintf(os, "{\n"); 530d169d70bSTobias Grosser if (!checked) { 531d169d70bSTobias Grosser osprintf(os, " if (!obj.ptr)\n"); 532d169d70bSTobias Grosser print_throw_NULL_input(os); 533d169d70bSTobias Grosser osprintf(os, " auto ctx = %s_get_ctx(obj.ptr);\n", name); 534d169d70bSTobias Grosser print_on_error_continue(os); 535d169d70bSTobias Grosser } 536d169d70bSTobias Grosser osprintf(os, " ptr = obj.copy();\n"); 537d169d70bSTobias Grosser if (!checked) { 538d169d70bSTobias Grosser osprintf(os, " if (obj.ptr && !ptr)\n"); 539d169d70bSTobias Grosser print_throw_last_error(os); 540d169d70bSTobias Grosser } 541d169d70bSTobias Grosser osprintf(os, "}\n"); 542d169d70bSTobias Grosser } 543d169d70bSTobias Grosser 544d169d70bSTobias Grosser /* Print implementations of constructors for class "clazz" to "os". 545d169d70bSTobias Grosser */ 546d169d70bSTobias Grosser void cpp_generator::print_constructors_impl(ostream &os, 547d169d70bSTobias Grosser const isl_class &clazz) 548d169d70bSTobias Grosser { 549d169d70bSTobias Grosser set<FunctionDecl *>::const_iterator in; 550d169d70bSTobias Grosser const set<FunctionDecl *> constructors = clazz.constructors; 551d169d70bSTobias Grosser 552d169d70bSTobias Grosser for (in = constructors.begin(); in != constructors.end(); ++in) { 553d169d70bSTobias Grosser FunctionDecl *cons = *in; 554d169d70bSTobias Grosser 555*6145b11cSTobias Grosser print_method_impl(os, clazz, cons, function_kind_constructor); 556d169d70bSTobias Grosser } 557d169d70bSTobias Grosser } 558d169d70bSTobias Grosser 559d169d70bSTobias Grosser /* Print implementation of copy assignment operator for class "clazz" to "os". 560d169d70bSTobias Grosser */ 561d169d70bSTobias Grosser void cpp_generator::print_copy_assignment_impl(ostream &os, 562d169d70bSTobias Grosser const isl_class &clazz) 563d169d70bSTobias Grosser { 564d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 565d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 566d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 567d169d70bSTobias Grosser 568d169d70bSTobias Grosser osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname, 569d169d70bSTobias Grosser cppname, cppname); 570d169d70bSTobias Grosser osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name); 571d169d70bSTobias Grosser osprintf(os, " return *this;\n"); 572d169d70bSTobias Grosser osprintf(os, "}\n"); 573d169d70bSTobias Grosser } 574d169d70bSTobias Grosser 575d169d70bSTobias Grosser /* Print implementation of destructor for class "clazz" to "os". 576d169d70bSTobias Grosser */ 577d169d70bSTobias Grosser void cpp_generator::print_destructor_impl(ostream &os, 578d169d70bSTobias Grosser const isl_class &clazz) 579d169d70bSTobias Grosser { 580d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 581d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 582d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 583d169d70bSTobias Grosser 584d169d70bSTobias Grosser osprintf(os, "%s::~%s() {\n", cppname, cppname); 585d169d70bSTobias Grosser osprintf(os, " if (ptr)\n"); 586d169d70bSTobias Grosser osprintf(os, " %s_free(ptr);\n", name); 587d169d70bSTobias Grosser osprintf(os, "}\n"); 588d169d70bSTobias Grosser } 589d169d70bSTobias Grosser 590d169d70bSTobias Grosser /* Print implementation of ptr() functions for class "clazz" to "os". 591d169d70bSTobias Grosser */ 592d169d70bSTobias Grosser void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz) 593d169d70bSTobias Grosser { 594d169d70bSTobias Grosser const char *name = clazz.name.c_str(); 595d169d70bSTobias Grosser std::string cppstring = type2cpp(clazz); 596d169d70bSTobias Grosser const char *cppname = cppstring.c_str(); 597d169d70bSTobias Grosser 598d169d70bSTobias Grosser osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname); 599d169d70bSTobias Grosser osprintf(os, " return %s_copy(ptr);\n", name); 600d169d70bSTobias Grosser osprintf(os, "}\n\n"); 601d169d70bSTobias Grosser osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname); 602d169d70bSTobias Grosser osprintf(os, " return ptr;\n"); 603d169d70bSTobias Grosser osprintf(os, "}\n\n"); 604d169d70bSTobias Grosser osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname); 605d169d70bSTobias Grosser osprintf(os, " %s *tmp = ptr;\n", name); 606d169d70bSTobias Grosser osprintf(os, " ptr = nullptr;\n"); 607d169d70bSTobias Grosser osprintf(os, " return tmp;\n"); 608d169d70bSTobias Grosser osprintf(os, "}\n\n"); 609d169d70bSTobias Grosser osprintf(os, "bool %s::is_null() const {\n", cppname); 610d169d70bSTobias Grosser osprintf(os, " return ptr == nullptr;\n"); 611d169d70bSTobias Grosser osprintf(os, "}\n"); 612d169d70bSTobias Grosser } 613d169d70bSTobias Grosser 614d169d70bSTobias Grosser /* Print the implementation of the get_ctx method. 615d169d70bSTobias Grosser */ 616d169d70bSTobias Grosser void cpp_generator::print_get_ctx_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, "ctx %s::get_ctx() const {\n", cppname); 623d169d70bSTobias Grosser osprintf(os, " return ctx(%s_get_ctx(ptr));\n", name); 624d169d70bSTobias Grosser osprintf(os, "}\n"); 625d169d70bSTobias Grosser } 626d169d70bSTobias Grosser 627d169d70bSTobias Grosser /* Print definitions for methods of class "clazz" to "os". 628d169d70bSTobias Grosser */ 629d169d70bSTobias Grosser void cpp_generator::print_methods_impl(ostream &os, const isl_class &clazz) 630d169d70bSTobias Grosser { 631d169d70bSTobias Grosser map<string, set<FunctionDecl *> >::const_iterator it; 632d169d70bSTobias Grosser bool first = true; 633d169d70bSTobias Grosser 634d169d70bSTobias Grosser for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it) { 635d169d70bSTobias Grosser if (first) 636d169d70bSTobias Grosser first = false; 637d169d70bSTobias Grosser else 638d169d70bSTobias Grosser osprintf(os, "\n"); 639*6145b11cSTobias Grosser print_method_group_impl(os, clazz, it->second); 640d169d70bSTobias Grosser } 641d169d70bSTobias Grosser } 642d169d70bSTobias Grosser 643*6145b11cSTobias Grosser /* Print definitions for methods "methods" in class "clazz" to "os". 644d169d70bSTobias Grosser * 645d169d70bSTobias Grosser * "kind" specifies the kind of method that should be generated. 646d169d70bSTobias Grosser */ 647d169d70bSTobias Grosser void cpp_generator::print_method_group_impl(ostream &os, const isl_class &clazz, 648*6145b11cSTobias Grosser const set<FunctionDecl *> &methods) 649d169d70bSTobias Grosser { 650d169d70bSTobias Grosser set<FunctionDecl *>::const_iterator it; 651d169d70bSTobias Grosser bool first = true; 652d169d70bSTobias Grosser 653d169d70bSTobias Grosser for (it = methods.begin(); it != methods.end(); ++it) { 654d169d70bSTobias Grosser function_kind kind; 655d169d70bSTobias Grosser if (first) 656d169d70bSTobias Grosser first = false; 657d169d70bSTobias Grosser else 658d169d70bSTobias Grosser osprintf(os, "\n"); 659d169d70bSTobias Grosser kind = get_method_kind(clazz, *it); 660*6145b11cSTobias Grosser print_method_impl(os, clazz, *it, kind); 661d169d70bSTobias Grosser } 662d169d70bSTobias Grosser } 663d169d70bSTobias Grosser 664d169d70bSTobias Grosser /* Print the use of "param" to "os". 665d169d70bSTobias Grosser * 666d169d70bSTobias Grosser * "load_from_this_ptr" specifies whether the parameter should be loaded from 667d169d70bSTobias Grosser * the this-ptr. In case a value is loaded from a this pointer, the original 668d169d70bSTobias Grosser * value must be preserved and must consequently be copied. Values that are 669d169d70bSTobias Grosser * loaded from parameters do not need to be preserved, as such values will 670d169d70bSTobias Grosser * already be copies of the actual parameters. It is consequently possible 671d169d70bSTobias Grosser * to directly take the pointer from these values, which saves 672d169d70bSTobias Grosser * an unnecessary copy. 673d169d70bSTobias Grosser * 674d169d70bSTobias Grosser * In case the parameter is a callback function, two parameters get printed, 675d169d70bSTobias Grosser * a wrapper for the callback function and a pointer to the actual 676d169d70bSTobias Grosser * callback function. The wrapper is expected to be available 677d169d70bSTobias Grosser * in a previously declared variable <name>_lambda, while 678d169d70bSTobias Grosser * the actual callback function is expected to be stored 679d169d70bSTobias Grosser * in a structure called <name>_data. 680d169d70bSTobias Grosser * The caller of this function must ensure that these variables exist. 681d169d70bSTobias Grosser */ 682d169d70bSTobias Grosser void cpp_generator::print_method_param_use(ostream &os, ParmVarDecl *param, 683d169d70bSTobias Grosser bool load_from_this_ptr) 684d169d70bSTobias Grosser { 685d169d70bSTobias Grosser string name = param->getName().str(); 686d169d70bSTobias Grosser const char *name_str = name.c_str(); 687d169d70bSTobias Grosser QualType type = param->getOriginalType(); 688d169d70bSTobias Grosser 689d169d70bSTobias Grosser if (type->isIntegerType()) { 690d169d70bSTobias Grosser osprintf(os, "%s", name_str); 691d169d70bSTobias Grosser return; 692d169d70bSTobias Grosser } 693d169d70bSTobias Grosser 694d169d70bSTobias Grosser if (is_string(type)) { 695d169d70bSTobias Grosser osprintf(os, "%s.c_str()", name_str); 696d169d70bSTobias Grosser return; 697d169d70bSTobias Grosser } 698d169d70bSTobias Grosser 699d169d70bSTobias Grosser if (is_callback(type)) { 700d169d70bSTobias Grosser osprintf(os, "%s_lambda, ", name_str); 701d169d70bSTobias Grosser osprintf(os, "&%s_data", name_str); 702d169d70bSTobias Grosser return; 703d169d70bSTobias Grosser } 704d169d70bSTobias Grosser 705d169d70bSTobias Grosser if (!load_from_this_ptr && !is_callback(type)) 706d169d70bSTobias Grosser osprintf(os, "%s.", name_str); 707d169d70bSTobias Grosser 708d169d70bSTobias Grosser if (keeps(param)) { 709d169d70bSTobias Grosser osprintf(os, "get()"); 710d169d70bSTobias Grosser } else { 711d169d70bSTobias Grosser if (load_from_this_ptr) 712d169d70bSTobias Grosser osprintf(os, "copy()"); 713d169d70bSTobias Grosser else 714d169d70bSTobias Grosser osprintf(os, "release()"); 715d169d70bSTobias Grosser } 716d169d70bSTobias Grosser } 717d169d70bSTobias Grosser 718d169d70bSTobias Grosser /* Print code that checks that all isl object arguments to "method" are valid 719d169d70bSTobias Grosser * (not NULL) and throws an exception if they are not. 720d169d70bSTobias Grosser * "kind" specifies the kind of method that is being generated. 721d169d70bSTobias Grosser * 722d169d70bSTobias Grosser * If checked bindings are being generated, 723d169d70bSTobias Grosser * then no such check is performed. 724d169d70bSTobias Grosser */ 725d169d70bSTobias Grosser void cpp_generator::print_argument_validity_check(ostream &os, 726d169d70bSTobias Grosser FunctionDecl *method, function_kind kind) 727d169d70bSTobias Grosser { 728d169d70bSTobias Grosser int n; 729d169d70bSTobias Grosser bool first = true; 730d169d70bSTobias Grosser 731d169d70bSTobias Grosser if (checked) 732d169d70bSTobias Grosser return; 733d169d70bSTobias Grosser 734d169d70bSTobias Grosser n = method->getNumParams(); 735d169d70bSTobias Grosser for (int i = 0; i < n; ++i) { 736d169d70bSTobias Grosser bool is_this; 737d169d70bSTobias Grosser ParmVarDecl *param = method->getParamDecl(i); 738d169d70bSTobias Grosser string name = param->getName().str(); 739d169d70bSTobias Grosser const char *name_str = name.c_str(); 740d169d70bSTobias Grosser QualType type = param->getOriginalType(); 741d169d70bSTobias Grosser 742d169d70bSTobias Grosser is_this = i == 0 && kind == function_kind_member_method; 743d169d70bSTobias Grosser if (!is_this && (is_isl_ctx(type) || !is_isl_type(type))) 744d169d70bSTobias Grosser continue; 745d169d70bSTobias Grosser 746d169d70bSTobias Grosser if (first) 747d169d70bSTobias Grosser osprintf(os, " if ("); 748d169d70bSTobias Grosser else 749d169d70bSTobias Grosser osprintf(os, " || "); 750d169d70bSTobias Grosser 751d169d70bSTobias Grosser if (is_this) 752d169d70bSTobias Grosser osprintf(os, "!ptr"); 753d169d70bSTobias Grosser else 754d169d70bSTobias Grosser osprintf(os, "%s.is_null()", name_str); 755d169d70bSTobias Grosser 756d169d70bSTobias Grosser first = false; 757d169d70bSTobias Grosser } 758d169d70bSTobias Grosser if (first) 759d169d70bSTobias Grosser return; 760d169d70bSTobias Grosser osprintf(os, ")\n"); 761d169d70bSTobias Grosser print_throw_NULL_input(os); 762d169d70bSTobias Grosser } 763d169d70bSTobias Grosser 764d169d70bSTobias Grosser /* Print code for saving a copy of the isl::ctx available at the start 765d169d70bSTobias Grosser * of the method "method" in a "ctx" variable, for use in exception handling. 766d169d70bSTobias Grosser * "kind" specifies what kind of method "method" is. 767d169d70bSTobias Grosser * 768d169d70bSTobias Grosser * If checked bindings are being generated, 769d169d70bSTobias Grosser * then the "ctx" variable is not needed. 770d169d70bSTobias Grosser * If "method" is a member function, then obtain the isl_ctx from 771d169d70bSTobias Grosser * the "this" object. 772d169d70bSTobias Grosser * If the first argument of the method is an isl::ctx, then use that one, 773d169d70bSTobias Grosser * assuming it is not already called "ctx". 774d169d70bSTobias Grosser * Otherwise, save a copy of the isl::ctx associated to the first argument 775d169d70bSTobias Grosser * of isl object type. 776d169d70bSTobias Grosser */ 777d169d70bSTobias Grosser void cpp_generator::print_save_ctx(ostream &os, FunctionDecl *method, 778d169d70bSTobias Grosser function_kind kind) 779d169d70bSTobias Grosser { 780d169d70bSTobias Grosser int n; 781d169d70bSTobias Grosser ParmVarDecl *param = method->getParamDecl(0); 782d169d70bSTobias Grosser QualType type = param->getOriginalType(); 783d169d70bSTobias Grosser 784d169d70bSTobias Grosser if (checked) 785d169d70bSTobias Grosser return; 786d169d70bSTobias Grosser if (kind == function_kind_member_method) { 787d169d70bSTobias Grosser osprintf(os, " auto ctx = get_ctx();\n"); 788d169d70bSTobias Grosser return; 789d169d70bSTobias Grosser } 790d169d70bSTobias Grosser if (is_isl_ctx(type)) { 791d169d70bSTobias Grosser const char *name; 792d169d70bSTobias Grosser 793d169d70bSTobias Grosser name = param->getName().str().c_str(); 794d169d70bSTobias Grosser if (strcmp(name, "ctx") != 0) 795d169d70bSTobias Grosser osprintf(os, " auto ctx = %s;\n", name); 796d169d70bSTobias Grosser return; 797d169d70bSTobias Grosser } 798d169d70bSTobias Grosser n = method->getNumParams(); 799d169d70bSTobias Grosser for (int i = 0; i < n; ++i) { 800d169d70bSTobias Grosser ParmVarDecl *param = method->getParamDecl(i); 801d169d70bSTobias Grosser QualType type = param->getOriginalType(); 802d169d70bSTobias Grosser 803d169d70bSTobias Grosser if (!is_isl_type(type)) 804d169d70bSTobias Grosser continue; 805d169d70bSTobias Grosser osprintf(os, " auto ctx = %s.get_ctx();\n", 806d169d70bSTobias Grosser param->getName().str().c_str()); 807d169d70bSTobias Grosser return; 808d169d70bSTobias Grosser } 809d169d70bSTobias Grosser } 810d169d70bSTobias Grosser 811d169d70bSTobias Grosser /* Print code to make isl not print an error message when an error occurs 812d169d70bSTobias Grosser * within the current scope (if exceptions are available), 813d169d70bSTobias Grosser * since the error message will be included in the exception. 814d169d70bSTobias Grosser * If exceptions are not available, then exception::on_error 815d169d70bSTobias Grosser * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead. 816d169d70bSTobias Grosser * 817d169d70bSTobias Grosser * If checked bindings are being generated, 818d169d70bSTobias Grosser * then leave it to the user to decide what isl should do on error. 819d169d70bSTobias Grosser * Otherwise, assume that a valid isl::ctx is available in the "ctx" variable, 820d169d70bSTobias Grosser * e.g., through a prior call to print_save_ctx. 821d169d70bSTobias Grosser */ 822d169d70bSTobias Grosser void cpp_generator::print_on_error_continue(ostream &os) 823d169d70bSTobias Grosser { 824d169d70bSTobias Grosser if (checked) 825d169d70bSTobias Grosser return; 826d169d70bSTobias Grosser osprintf(os, " options_scoped_set_on_error saved_on_error(ctx, " 827d169d70bSTobias Grosser "exception::on_error);\n"); 828d169d70bSTobias Grosser } 829d169d70bSTobias Grosser 830d169d70bSTobias Grosser /* Print code that checks whether the execution of the core of "method" 831d169d70bSTobias Grosser * was successful. 832d169d70bSTobias Grosser * 833d169d70bSTobias Grosser * If checked bindings are being generated, 834d169d70bSTobias Grosser * then no checks are performed. 835d169d70bSTobias Grosser * 836d169d70bSTobias Grosser * Otherwise, first check if any of the callbacks failed with 837d169d70bSTobias Grosser * an exception. If so, the "eptr" in the corresponding data structure 838d169d70bSTobias Grosser * contains the exception that was caught and that needs to be rethrown. 839d169d70bSTobias Grosser * Then check if the function call failed in any other way and throw 840d169d70bSTobias Grosser * the appropriate exception. 841d169d70bSTobias Grosser * In particular, if the return type is isl_stat or isl_bool, 842d169d70bSTobias Grosser * then a negative value indicates a failure. If the return type 843d169d70bSTobias Grosser * is an isl type, then a NULL value indicates a failure. 844d169d70bSTobias Grosser * Assume print_save_ctx has made sure that a valid isl::ctx 845d169d70bSTobias Grosser * is available in the "ctx" variable. 846d169d70bSTobias Grosser */ 847d169d70bSTobias Grosser void cpp_generator::print_exceptional_execution_check(ostream &os, 848d169d70bSTobias Grosser FunctionDecl *method) 849d169d70bSTobias Grosser { 850d169d70bSTobias Grosser int n; 851d169d70bSTobias Grosser bool check_null, check_neg; 852d169d70bSTobias Grosser QualType return_type = method->getReturnType(); 853d169d70bSTobias Grosser 854d169d70bSTobias Grosser if (checked) 855d169d70bSTobias Grosser return; 856d169d70bSTobias Grosser 857d169d70bSTobias Grosser n = method->getNumParams(); 858d169d70bSTobias Grosser for (int i = 0; i < n; ++i) { 859d169d70bSTobias Grosser ParmVarDecl *param = method->getParamDecl(i); 860d169d70bSTobias Grosser const char *name; 861d169d70bSTobias Grosser 862d169d70bSTobias Grosser if (!is_callback(param->getOriginalType())) 863d169d70bSTobias Grosser continue; 864d169d70bSTobias Grosser name = param->getName().str().c_str(); 865d169d70bSTobias Grosser osprintf(os, " if (%s_data.eptr)\n", name); 866d169d70bSTobias Grosser osprintf(os, " std::rethrow_exception(%s_data.eptr);\n", 867d169d70bSTobias Grosser name); 868d169d70bSTobias Grosser } 869d169d70bSTobias Grosser 870d169d70bSTobias Grosser check_neg = is_isl_stat(return_type) || is_isl_bool(return_type); 871d169d70bSTobias Grosser check_null = is_isl_type(return_type); 872d169d70bSTobias Grosser if (!check_null && !check_neg) 873d169d70bSTobias Grosser return; 874d169d70bSTobias Grosser 875d169d70bSTobias Grosser if (check_neg) 876d169d70bSTobias Grosser osprintf(os, " if (res < 0)\n"); 877d169d70bSTobias Grosser else 878d169d70bSTobias Grosser osprintf(os, " if (!res)\n"); 879d169d70bSTobias Grosser print_throw_last_error(os); 880d169d70bSTobias Grosser } 881d169d70bSTobias Grosser 882d169d70bSTobias Grosser /* Print definition for "method" in class "clazz" to "os". 883d169d70bSTobias Grosser * 884d169d70bSTobias Grosser * "kind" specifies the kind of method that should be generated. 885d169d70bSTobias Grosser * 886d169d70bSTobias Grosser * This method distinguishes three kinds of methods: member methods, static 887d169d70bSTobias Grosser * methods, and constructors. 888d169d70bSTobias Grosser * 889d169d70bSTobias Grosser * Member methods call "method" by passing to the underlying isl function the 890d169d70bSTobias Grosser * isl object belonging to "this" as first argument and the remaining arguments 891d169d70bSTobias Grosser * as subsequent arguments. The result of the isl function is returned as a new 892d169d70bSTobias Grosser * object if the underlying isl function returns an isl_* ptr, as a bool 893d169d70bSTobias Grosser * if the isl function returns an isl_bool, as void if the isl functions 894d169d70bSTobias Grosser * returns an isl_stat, 895d169d70bSTobias Grosser * as std::string if the isl function returns 'const char *', and as 896d169d70bSTobias Grosser * unmodified return value otherwise. 897d169d70bSTobias Grosser * If checked C++ bindings are being generated, 898d169d70bSTobias Grosser * then an isl_bool return type is transformed into a boolean and 899d169d70bSTobias Grosser * an isl_stat into a stat since no exceptions can be generated 900d169d70bSTobias Grosser * on negative results from the isl function. 901d169d70bSTobias Grosser * 902d169d70bSTobias Grosser * Static methods call "method" by passing all arguments to the underlying isl 903d169d70bSTobias Grosser * function, as no this-pointer is available. The result is a newly managed 904d169d70bSTobias Grosser * isl C++ object. 905d169d70bSTobias Grosser * 906d169d70bSTobias Grosser * Constructors create a new object from a given set of input parameters. They 907d169d70bSTobias Grosser * do not return a value, but instead update the pointer stored inside the 908d169d70bSTobias Grosser * newly created object. 909d169d70bSTobias Grosser * 910d169d70bSTobias Grosser * If the method has a callback argument, we reduce the number of parameters 911d169d70bSTobias Grosser * that are exposed by one to hide the user pointer from the interface. On 912d169d70bSTobias Grosser * the C++ side no user pointer is needed, as arguments can be forwarded 913d169d70bSTobias Grosser * as part of the std::function argument which specifies the callback function. 914d169d70bSTobias Grosser * 915d169d70bSTobias Grosser * Unless checked C++ bindings are being generated, 916d169d70bSTobias Grosser * the inputs of the method are first checked for being valid isl objects and 917d169d70bSTobias Grosser * a copy of the associated isl::ctx is saved (if needed). 918d169d70bSTobias Grosser * If any failure occurs, either during the check for the inputs or 919d169d70bSTobias Grosser * during the isl function call, an exception is thrown. 920d169d70bSTobias Grosser * During the function call, isl is made not to print any error message 921d169d70bSTobias Grosser * because the error message is included in the exception. 922d169d70bSTobias Grosser */ 923d169d70bSTobias Grosser void cpp_generator::print_method_impl(ostream &os, const isl_class &clazz, 924*6145b11cSTobias Grosser FunctionDecl *method, function_kind kind) 925d169d70bSTobias Grosser { 926d169d70bSTobias Grosser string methodname = method->getName(); 927d169d70bSTobias Grosser int num_params = method->getNumParams(); 928d169d70bSTobias Grosser QualType return_type = method->getReturnType(); 929d169d70bSTobias Grosser string rettype_str = type2cpp(return_type); 930d169d70bSTobias Grosser bool has_callback = false; 931d169d70bSTobias Grosser 932*6145b11cSTobias Grosser print_method_header(os, clazz, method, false, kind); 933d169d70bSTobias Grosser osprintf(os, "{\n"); 934d169d70bSTobias Grosser print_argument_validity_check(os, method, kind); 935d169d70bSTobias Grosser print_save_ctx(os, method, kind); 936d169d70bSTobias Grosser print_on_error_continue(os); 937d169d70bSTobias Grosser 938d169d70bSTobias Grosser for (int i = 0; i < num_params; ++i) { 939d169d70bSTobias Grosser ParmVarDecl *param = method->getParamDecl(i); 940d169d70bSTobias Grosser if (is_callback(param->getType())) { 941d169d70bSTobias Grosser has_callback = true; 942d169d70bSTobias Grosser num_params -= 1; 943d169d70bSTobias Grosser print_callback_local(os, param); 944d169d70bSTobias Grosser } 945d169d70bSTobias Grosser } 946d169d70bSTobias Grosser 947d169d70bSTobias Grosser osprintf(os, " auto res = %s(", methodname.c_str()); 948d169d70bSTobias Grosser 949d169d70bSTobias Grosser for (int i = 0; i < num_params; ++i) { 950d169d70bSTobias Grosser ParmVarDecl *param = method->getParamDecl(i); 951d169d70bSTobias Grosser bool load_from_this_ptr = false; 952d169d70bSTobias Grosser 953d169d70bSTobias Grosser if (i == 0 && kind == function_kind_member_method) 954d169d70bSTobias Grosser load_from_this_ptr = true; 955d169d70bSTobias Grosser 956d169d70bSTobias Grosser print_method_param_use(os, param, load_from_this_ptr); 957d169d70bSTobias Grosser 958d169d70bSTobias Grosser if (i != num_params - 1) 959d169d70bSTobias Grosser osprintf(os, ", "); 960d169d70bSTobias Grosser } 961d169d70bSTobias Grosser osprintf(os, ");\n"); 962d169d70bSTobias Grosser 963d169d70bSTobias Grosser print_exceptional_execution_check(os, method); 964d169d70bSTobias Grosser if (kind == function_kind_constructor) { 965d169d70bSTobias Grosser osprintf(os, " ptr = res;\n"); 966d169d70bSTobias Grosser } else if (is_isl_type(return_type) || 967d169d70bSTobias Grosser (checked && 968d169d70bSTobias Grosser (is_isl_bool(return_type) || is_isl_stat(return_type)))) { 969d169d70bSTobias Grosser osprintf(os, " return manage(res);\n"); 970d169d70bSTobias Grosser } else if (has_callback) { 971d169d70bSTobias Grosser osprintf(os, " return %s(res);\n", rettype_str.c_str()); 972d169d70bSTobias Grosser } else if (is_string(return_type)) { 973d169d70bSTobias Grosser osprintf(os, " std::string tmp(res);\n"); 974d169d70bSTobias Grosser if (gives(method)) 975d169d70bSTobias Grosser osprintf(os, " free(res);\n"); 976d169d70bSTobias Grosser osprintf(os, " return tmp;\n"); 977d169d70bSTobias Grosser } else { 978d169d70bSTobias Grosser osprintf(os, " return res;\n"); 979d169d70bSTobias Grosser } 980d169d70bSTobias Grosser 981d169d70bSTobias Grosser osprintf(os, "}\n"); 982d169d70bSTobias Grosser } 983d169d70bSTobias Grosser 984d169d70bSTobias Grosser /* Print the header for "method" in class "clazz" to "os". 985d169d70bSTobias Grosser * 986d169d70bSTobias Grosser * Print the header of a declaration if "is_declaration" is set, otherwise print 987d169d70bSTobias Grosser * the header of a method definition. 988d169d70bSTobias Grosser * 989d169d70bSTobias Grosser * "kind" specifies the kind of method that should be generated. 990d169d70bSTobias Grosser * 991d169d70bSTobias Grosser * This function prints headers for member methods, static methods, and 992d169d70bSTobias Grosser * constructors, either for their declaration or definition. 993d169d70bSTobias Grosser * 994d169d70bSTobias Grosser * Member functions are declared as "const", as they do not change the current 995d169d70bSTobias Grosser * object, but instead create a new object. They always retrieve the first 996d169d70bSTobias Grosser * parameter of the original isl function from the this-pointer of the object, 997d169d70bSTobias Grosser * such that only starting at the second parameter the parameters of the 998d169d70bSTobias Grosser * original function become part of the method's interface. 999d169d70bSTobias Grosser * 1000d169d70bSTobias Grosser * A function 1001d169d70bSTobias Grosser * 1002d169d70bSTobias Grosser * __isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1, 1003d169d70bSTobias Grosser * __isl_take isl_set *s2); 1004d169d70bSTobias Grosser * 1005d169d70bSTobias Grosser * is translated into: 1006d169d70bSTobias Grosser * 1007d169d70bSTobias Grosser * inline set intersect(set set2) const; 1008d169d70bSTobias Grosser * 1009d169d70bSTobias Grosser * For static functions and constructors all parameters of the original isl 1010d169d70bSTobias Grosser * function are exposed. 1011d169d70bSTobias Grosser * 1012d169d70bSTobias Grosser * Parameters that are defined as __isl_keep or are of type string, are passed 1013d169d70bSTobias Grosser * as const reference, which allows the compiler to optimize the parameter 1014d169d70bSTobias Grosser * transfer. 1015d169d70bSTobias Grosser * 1016d169d70bSTobias Grosser * Constructors are marked as explicit using the C++ keyword 'explicit' or as 1017d169d70bSTobias Grosser * implicit using a comment in place of the explicit keyword. By annotating 1018d169d70bSTobias Grosser * implicit constructors with a comment, users of the interface are made 1019d169d70bSTobias Grosser * aware of the potential danger that implicit construction is possible 1020d169d70bSTobias Grosser * for these constructors, whereas without a comment not every user would 1021d169d70bSTobias Grosser * know that implicit construction is allowed in absence of an explicit keyword. 1022d169d70bSTobias Grosser */ 1023d169d70bSTobias Grosser void cpp_generator::print_method_header(ostream &os, const isl_class &clazz, 1024*6145b11cSTobias Grosser FunctionDecl *method, bool is_declaration, function_kind kind) 1025d169d70bSTobias Grosser { 1026*6145b11cSTobias Grosser string cname = clazz.method_name(method); 1027d169d70bSTobias Grosser string rettype_str = type2cpp(method->getReturnType()); 1028d169d70bSTobias Grosser string classname = type2cpp(clazz); 1029d169d70bSTobias Grosser int num_params = method->getNumParams(); 1030d169d70bSTobias Grosser int first_param = 0; 1031d169d70bSTobias Grosser 1032d169d70bSTobias Grosser cname = rename_method(cname); 1033d169d70bSTobias Grosser if (kind == function_kind_member_method) 1034d169d70bSTobias Grosser first_param = 1; 1035d169d70bSTobias Grosser 1036d169d70bSTobias Grosser if (is_declaration) { 1037d169d70bSTobias Grosser osprintf(os, " "); 1038d169d70bSTobias Grosser 1039d169d70bSTobias Grosser if (kind == function_kind_static_method) 1040d169d70bSTobias Grosser osprintf(os, "static "); 1041d169d70bSTobias Grosser 1042d169d70bSTobias Grosser osprintf(os, "inline "); 1043d169d70bSTobias Grosser 1044d169d70bSTobias Grosser if (kind == function_kind_constructor) { 1045d169d70bSTobias Grosser if (is_implicit_conversion(clazz, method)) 1046d169d70bSTobias Grosser osprintf(os, "/* implicit */ "); 1047d169d70bSTobias Grosser else 1048d169d70bSTobias Grosser osprintf(os, "explicit "); 1049d169d70bSTobias Grosser } 1050d169d70bSTobias Grosser } 1051d169d70bSTobias Grosser 1052d169d70bSTobias Grosser if (kind != function_kind_constructor) 1053d169d70bSTobias Grosser osprintf(os, "%s ", rettype_str.c_str()); 1054d169d70bSTobias Grosser 1055d169d70bSTobias Grosser if (!is_declaration) 1056d169d70bSTobias Grosser osprintf(os, "%s::", classname.c_str()); 1057d169d70bSTobias Grosser 1058d169d70bSTobias Grosser if (kind != function_kind_constructor) 1059d169d70bSTobias Grosser osprintf(os, "%s", cname.c_str()); 1060d169d70bSTobias Grosser else 1061d169d70bSTobias Grosser osprintf(os, "%s", classname.c_str()); 1062d169d70bSTobias Grosser 1063d169d70bSTobias Grosser osprintf(os, "("); 1064d169d70bSTobias Grosser 1065d169d70bSTobias Grosser for (int i = first_param; i < num_params; ++i) { 1066d169d70bSTobias Grosser ParmVarDecl *param = method->getParamDecl(i); 1067d169d70bSTobias Grosser QualType type = param->getOriginalType(); 1068d169d70bSTobias Grosser string cpptype = type2cpp(type); 1069d169d70bSTobias Grosser 1070d169d70bSTobias Grosser if (is_callback(type)) 1071d169d70bSTobias Grosser num_params--; 1072d169d70bSTobias Grosser 1073d169d70bSTobias Grosser if (keeps(param) || is_string(type) || is_callback(type)) 1074d169d70bSTobias Grosser osprintf(os, "const %s &%s", cpptype.c_str(), 1075d169d70bSTobias Grosser param->getName().str().c_str()); 1076d169d70bSTobias Grosser else 1077d169d70bSTobias Grosser osprintf(os, "%s %s", cpptype.c_str(), 1078d169d70bSTobias Grosser param->getName().str().c_str()); 1079d169d70bSTobias Grosser 1080d169d70bSTobias Grosser if (i != num_params - 1) 1081d169d70bSTobias Grosser osprintf(os, ", "); 1082d169d70bSTobias Grosser } 1083d169d70bSTobias Grosser 1084d169d70bSTobias Grosser osprintf(os, ")"); 1085d169d70bSTobias Grosser 1086d169d70bSTobias Grosser if (kind == function_kind_member_method) 1087d169d70bSTobias Grosser osprintf(os, " const"); 1088d169d70bSTobias Grosser 1089d169d70bSTobias Grosser if (is_declaration) 1090d169d70bSTobias Grosser osprintf(os, ";"); 1091d169d70bSTobias Grosser osprintf(os, "\n"); 1092d169d70bSTobias Grosser } 1093d169d70bSTobias Grosser 1094d169d70bSTobias Grosser /* Generate the list of argument types for a callback function of 1095d169d70bSTobias Grosser * type "type". If "cpp" is set, then generate the C++ type list, otherwise 1096d169d70bSTobias Grosser * the C type list. 1097d169d70bSTobias Grosser * 1098d169d70bSTobias Grosser * For a callback of type 1099d169d70bSTobias Grosser * 1100d169d70bSTobias Grosser * isl_stat (*)(__isl_take isl_map *map, void *user) 1101d169d70bSTobias Grosser * 1102d169d70bSTobias Grosser * the following C++ argument list is generated: 1103d169d70bSTobias Grosser * 1104d169d70bSTobias Grosser * map 1105d169d70bSTobias Grosser */ 1106d169d70bSTobias Grosser string cpp_generator::generate_callback_args(QualType type, bool cpp) 1107d169d70bSTobias Grosser { 1108d169d70bSTobias Grosser std::string type_str; 1109d169d70bSTobias Grosser const FunctionProtoType *callback; 1110d169d70bSTobias Grosser int num_params; 1111d169d70bSTobias Grosser 1112d169d70bSTobias Grosser callback = type->getPointeeType()->getAs<FunctionProtoType>(); 1113d169d70bSTobias Grosser num_params = callback->getNumArgs(); 1114d169d70bSTobias Grosser if (cpp) 1115d169d70bSTobias Grosser num_params--; 1116d169d70bSTobias Grosser 1117d169d70bSTobias Grosser for (long i = 0; i < num_params; i++) { 1118d169d70bSTobias Grosser QualType type = callback->getArgType(i); 1119d169d70bSTobias Grosser 1120d169d70bSTobias Grosser if (cpp) 1121d169d70bSTobias Grosser type_str += type2cpp(type); 1122d169d70bSTobias Grosser else 1123d169d70bSTobias Grosser type_str += type.getAsString(); 1124d169d70bSTobias Grosser 1125d169d70bSTobias Grosser if (!cpp) 1126d169d70bSTobias Grosser type_str += "arg_" + ::to_string(i); 1127d169d70bSTobias Grosser 1128d169d70bSTobias Grosser if (i != num_params - 1) 1129d169d70bSTobias Grosser type_str += ", "; 1130d169d70bSTobias Grosser } 1131d169d70bSTobias Grosser 1132d169d70bSTobias Grosser return type_str; 1133d169d70bSTobias Grosser } 1134d169d70bSTobias Grosser 1135d169d70bSTobias Grosser /* Generate the full cpp type of a callback function of type "type". 1136d169d70bSTobias Grosser * 1137d169d70bSTobias Grosser * For a callback of type 1138d169d70bSTobias Grosser * 1139d169d70bSTobias Grosser * isl_stat (*)(__isl_take isl_map *map, void *user) 1140d169d70bSTobias Grosser * 1141d169d70bSTobias Grosser * the following type is generated: 1142d169d70bSTobias Grosser * 1143d169d70bSTobias Grosser * std::function<stat(map)> 1144d169d70bSTobias Grosser */ 1145d169d70bSTobias Grosser string cpp_generator::generate_callback_type(QualType type) 1146d169d70bSTobias Grosser { 1147d169d70bSTobias Grosser std::string type_str; 1148d169d70bSTobias Grosser const FunctionProtoType *callback = type->getPointeeType()->getAs<FunctionProtoType>(); 1149d169d70bSTobias Grosser QualType return_type = callback->getReturnType(); 1150d169d70bSTobias Grosser string rettype_str = type2cpp(return_type); 1151d169d70bSTobias Grosser 1152d169d70bSTobias Grosser type_str = "std::function<"; 1153d169d70bSTobias Grosser type_str += rettype_str; 1154d169d70bSTobias Grosser type_str += "("; 1155d169d70bSTobias Grosser type_str += generate_callback_args(type, true); 1156d169d70bSTobias Grosser type_str += ")>"; 1157d169d70bSTobias Grosser 1158d169d70bSTobias Grosser return type_str; 1159d169d70bSTobias Grosser } 1160d169d70bSTobias Grosser 1161d169d70bSTobias Grosser /* Print the call to the C++ callback function "call", wrapped 1162d169d70bSTobias Grosser * for use inside the lambda function that is used as the C callback function, 1163d169d70bSTobias Grosser * in the case where checked C++ bindings are being generated. 1164d169d70bSTobias Grosser * 1165d169d70bSTobias Grosser * In particular, print 1166d169d70bSTobias Grosser * 1167d169d70bSTobias Grosser * stat ret = @call@; 1168d169d70bSTobias Grosser * return ret.release(); 1169d169d70bSTobias Grosser */ 1170d169d70bSTobias Grosser void cpp_generator::print_wrapped_call_checked(ostream &os, 1171d169d70bSTobias Grosser const string &call) 1172d169d70bSTobias Grosser { 1173d169d70bSTobias Grosser osprintf(os, " stat ret = %s;\n", call.c_str()); 1174d169d70bSTobias Grosser osprintf(os, " return ret.release();\n"); 1175d169d70bSTobias Grosser } 1176d169d70bSTobias Grosser 1177d169d70bSTobias Grosser /* Print the call to the C++ callback function "call", wrapped 1178d169d70bSTobias Grosser * for use inside the lambda function that is used as the C callback function. 1179d169d70bSTobias Grosser * 1180d169d70bSTobias Grosser * In particular, print 1181d169d70bSTobias Grosser * 1182d169d70bSTobias Grosser * ISL_CPP_TRY { 1183d169d70bSTobias Grosser * @call@; 1184d169d70bSTobias Grosser * return isl_stat_ok; 1185d169d70bSTobias Grosser * } ISL_CPP_CATCH_ALL { 1186d169d70bSTobias Grosser * data->eptr = std::current_exception(); 1187d169d70bSTobias Grosser * return isl_stat_error; 1188d169d70bSTobias Grosser * } 1189d169d70bSTobias Grosser * 1190d169d70bSTobias Grosser * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)" 1191d169d70bSTobias Grosser * (if exceptions are available). 1192d169d70bSTobias Grosser * 1193d169d70bSTobias Grosser * If checked C++ bindings are being generated, then 1194d169d70bSTobias Grosser * the call is wrapped differently. 1195d169d70bSTobias Grosser */ 1196d169d70bSTobias Grosser void cpp_generator::print_wrapped_call(ostream &os, const string &call) 1197d169d70bSTobias Grosser { 1198d169d70bSTobias Grosser if (checked) 1199d169d70bSTobias Grosser return print_wrapped_call_checked(os, call); 1200d169d70bSTobias Grosser 1201d169d70bSTobias Grosser osprintf(os, " ISL_CPP_TRY {\n"); 1202d169d70bSTobias Grosser osprintf(os, " %s;\n", call.c_str()); 1203d169d70bSTobias Grosser osprintf(os, " return isl_stat_ok;\n"); 1204d169d70bSTobias Grosser osprintf(os, " } ISL_CPP_CATCH_ALL {\n" 1205d169d70bSTobias Grosser " data->eptr = std::current_exception();\n"); 1206d169d70bSTobias Grosser osprintf(os, " return isl_stat_error;\n"); 1207d169d70bSTobias Grosser osprintf(os, " }\n"); 1208d169d70bSTobias Grosser } 1209d169d70bSTobias Grosser 1210d169d70bSTobias Grosser /* Print the local variables that are needed for a callback argument, 1211d169d70bSTobias Grosser * in particular, print a lambda function that wraps the callback and 1212d169d70bSTobias Grosser * a pointer to the actual C++ callback function. 1213d169d70bSTobias Grosser * 1214d169d70bSTobias Grosser * For a callback of the form 1215d169d70bSTobias Grosser * 1216d169d70bSTobias Grosser * isl_stat (*fn)(__isl_take isl_map *map, void *user) 1217d169d70bSTobias Grosser * 1218d169d70bSTobias Grosser * the following lambda function is generated: 1219d169d70bSTobias Grosser * 1220d169d70bSTobias Grosser * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat { 1221d169d70bSTobias Grosser * auto *data = static_cast<struct fn_data *>(arg_1); 1222d169d70bSTobias Grosser * try { 1223d169d70bSTobias Grosser * stat ret = (*data->func)(manage(arg_0)); 1224d169d70bSTobias Grosser * return isl_stat_ok; 1225d169d70bSTobias Grosser * } catch (...) { 1226d169d70bSTobias Grosser * data->eptr = std::current_exception(); 1227d169d70bSTobias Grosser * return isl_stat_error; 1228d169d70bSTobias Grosser * } 1229d169d70bSTobias Grosser * }; 1230d169d70bSTobias Grosser * 1231d169d70bSTobias Grosser * The pointer to the std::function C++ callback function is stored in 1232d169d70bSTobias Grosser * a fn_data data structure for passing to the C callback function, 1233d169d70bSTobias Grosser * along with an std::exception_ptr that is used to store any 1234d169d70bSTobias Grosser * exceptions thrown in the C++ callback. 1235d169d70bSTobias Grosser * 1236d169d70bSTobias Grosser * struct fn_data { 1237d169d70bSTobias Grosser * const std::function<stat(map)> *func; 1238d169d70bSTobias Grosser * std::exception_ptr eptr; 1239d169d70bSTobias Grosser * } fn_data = { &fn }; 1240d169d70bSTobias Grosser * 1241d169d70bSTobias Grosser * This std::function object represents the actual user 1242d169d70bSTobias Grosser * callback function together with the locally captured state at the caller. 1243d169d70bSTobias Grosser * 1244d169d70bSTobias Grosser * The lambda function is expected to be used as a C callback function 1245d169d70bSTobias Grosser * where the lambda itself is provided as the function pointer and 1246d169d70bSTobias Grosser * where the user void pointer is a pointer to fn_data. 1247d169d70bSTobias Grosser * The std::function object is extracted from the pointer to fn_data 1248d169d70bSTobias Grosser * inside the lambda function. 1249d169d70bSTobias Grosser * 1250d169d70bSTobias Grosser * The std::exception_ptr object is not added to fn_data 1251d169d70bSTobias Grosser * if checked C++ bindings are being generated. 1252d169d70bSTobias Grosser * The body of the generated lambda function then is as follows: 1253d169d70bSTobias Grosser * 1254d169d70bSTobias Grosser * stat ret = (*data->func)(manage(arg_0)); 1255d169d70bSTobias Grosser * return isl_stat(ret); 1256*6145b11cSTobias Grosser * 1257*6145b11cSTobias Grosser * If the C callback does not take its arguments, then 1258*6145b11cSTobias Grosser * manage_copy is used instead of manage. 1259d169d70bSTobias Grosser */ 1260d169d70bSTobias Grosser void cpp_generator::print_callback_local(ostream &os, ParmVarDecl *param) 1261d169d70bSTobias Grosser { 1262d169d70bSTobias Grosser string pname; 1263d169d70bSTobias Grosser QualType ptype; 1264d169d70bSTobias Grosser string call, c_args, cpp_args, rettype, last_idx; 1265d169d70bSTobias Grosser const FunctionProtoType *callback; 1266d169d70bSTobias Grosser int num_params; 1267d169d70bSTobias Grosser 1268d169d70bSTobias Grosser pname = param->getName().str(); 1269d169d70bSTobias Grosser ptype = param->getType(); 1270d169d70bSTobias Grosser 1271d169d70bSTobias Grosser c_args = generate_callback_args(ptype, false); 1272d169d70bSTobias Grosser cpp_args = generate_callback_type(ptype); 1273d169d70bSTobias Grosser 1274d169d70bSTobias Grosser callback = ptype->getPointeeType()->getAs<FunctionProtoType>(); 1275d169d70bSTobias Grosser rettype = callback->getReturnType().getAsString(); 1276d169d70bSTobias Grosser num_params = callback->getNumArgs(); 1277d169d70bSTobias Grosser 1278d169d70bSTobias Grosser last_idx = ::to_string(num_params - 1); 1279d169d70bSTobias Grosser 1280d169d70bSTobias Grosser call = "(*data->func)("; 1281d169d70bSTobias Grosser for (long i = 0; i < num_params - 1; i++) { 1282*6145b11cSTobias Grosser if (!callback_takes_argument(param, i)) 1283*6145b11cSTobias Grosser call += "manage_copy"; 1284*6145b11cSTobias Grosser else 1285*6145b11cSTobias Grosser call += "manage"; 1286*6145b11cSTobias Grosser call += "(arg_" + ::to_string(i) + ")"; 1287d169d70bSTobias Grosser if (i != num_params - 2) 1288d169d70bSTobias Grosser call += ", "; 1289d169d70bSTobias Grosser } 1290d169d70bSTobias Grosser call += ")"; 1291d169d70bSTobias Grosser 1292d169d70bSTobias Grosser osprintf(os, " struct %s_data {\n", pname.c_str()); 1293d169d70bSTobias Grosser osprintf(os, " const %s *func;\n", cpp_args.c_str()); 1294d169d70bSTobias Grosser if (!checked) 1295d169d70bSTobias Grosser osprintf(os, " std::exception_ptr eptr;\n"); 1296d169d70bSTobias Grosser osprintf(os, " } %s_data = { &%s };\n", pname.c_str(), pname.c_str()); 1297d169d70bSTobias Grosser osprintf(os, " auto %s_lambda = [](%s) -> %s {\n", 1298d169d70bSTobias Grosser pname.c_str(), c_args.c_str(), rettype.c_str()); 1299d169d70bSTobias Grosser osprintf(os, 1300d169d70bSTobias Grosser " auto *data = static_cast<struct %s_data *>(arg_%s);\n", 1301d169d70bSTobias Grosser pname.c_str(), last_idx.c_str()); 1302d169d70bSTobias Grosser print_wrapped_call(os, call); 1303d169d70bSTobias Grosser osprintf(os, " };\n"); 1304d169d70bSTobias Grosser } 1305d169d70bSTobias Grosser 1306d169d70bSTobias Grosser /* An array listing functions that must be renamed and the function name they 1307d169d70bSTobias Grosser * should be renamed to. We currently rename functions in case their name would 1308d169d70bSTobias Grosser * match a reserved C++ keyword, which is not allowed in C++. 1309d169d70bSTobias Grosser */ 1310d169d70bSTobias Grosser static const char *rename_map[][2] = { 1311d169d70bSTobias Grosser { "union", "unite" }, 1312d169d70bSTobias Grosser }; 1313d169d70bSTobias Grosser 1314d169d70bSTobias Grosser /* Rename method "name" in case the method name in the C++ bindings should not 1315d169d70bSTobias Grosser * match the name in the C bindings. We do this for example to avoid 1316d169d70bSTobias Grosser * C++ keywords. 1317d169d70bSTobias Grosser */ 1318d169d70bSTobias Grosser std::string cpp_generator::rename_method(std::string name) 1319d169d70bSTobias Grosser { 1320d169d70bSTobias Grosser for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++) 1321d169d70bSTobias Grosser if (name.compare(rename_map[i][0]) == 0) 1322d169d70bSTobias Grosser return rename_map[i][1]; 1323d169d70bSTobias Grosser 1324d169d70bSTobias Grosser return name; 1325d169d70bSTobias Grosser } 1326d169d70bSTobias Grosser 1327d169d70bSTobias Grosser /* Translate isl class "clazz" to its corresponding C++ type. 1328d169d70bSTobias Grosser */ 1329d169d70bSTobias Grosser string cpp_generator::type2cpp(const isl_class &clazz) 1330d169d70bSTobias Grosser { 1331d169d70bSTobias Grosser return type2cpp(clazz.name); 1332d169d70bSTobias Grosser } 1333d169d70bSTobias Grosser 1334d169d70bSTobias Grosser /* Translate type string "type_str" to its C++ name counterpart. 1335d169d70bSTobias Grosser */ 1336d169d70bSTobias Grosser string cpp_generator::type2cpp(string type_str) 1337d169d70bSTobias Grosser { 1338d169d70bSTobias Grosser return type_str.substr(4); 1339d169d70bSTobias Grosser } 1340d169d70bSTobias Grosser 1341d169d70bSTobias Grosser /* Translate QualType "type" to its C++ name counterpart. 1342d169d70bSTobias Grosser * 1343d169d70bSTobias Grosser * An isl_bool return type is translated into "bool", 1344d169d70bSTobias Grosser * while an isl_stat is translated into "void". 1345d169d70bSTobias Grosser * The exceptional cases are handled through exceptions. 1346d169d70bSTobias Grosser * If checked C++ bindings are being generated, then 1347d169d70bSTobias Grosser * C++ counterparts of isl_bool and isl_stat need to be used instead. 1348d169d70bSTobias Grosser */ 1349d169d70bSTobias Grosser string cpp_generator::type2cpp(QualType type) 1350d169d70bSTobias Grosser { 1351d169d70bSTobias Grosser if (is_isl_type(type)) 1352d169d70bSTobias Grosser return type2cpp(type->getPointeeType().getAsString()); 1353d169d70bSTobias Grosser 1354d169d70bSTobias Grosser if (is_isl_bool(type)) 1355d169d70bSTobias Grosser return checked ? "boolean" : "bool"; 1356d169d70bSTobias Grosser 1357d169d70bSTobias Grosser if (is_isl_stat(type)) 1358d169d70bSTobias Grosser return checked ? "stat" : "void"; 1359d169d70bSTobias Grosser 1360d169d70bSTobias Grosser if (type->isIntegerType()) 1361d169d70bSTobias Grosser return type.getAsString(); 1362d169d70bSTobias Grosser 1363d169d70bSTobias Grosser if (is_string(type)) 1364d169d70bSTobias Grosser return "std::string"; 1365d169d70bSTobias Grosser 1366d169d70bSTobias Grosser if (is_callback(type)) 1367d169d70bSTobias Grosser return generate_callback_type(type); 1368d169d70bSTobias Grosser 1369d169d70bSTobias Grosser die("Cannot convert type to C++ type"); 1370d169d70bSTobias Grosser } 1371d169d70bSTobias Grosser 1372d169d70bSTobias Grosser /* Check if "subclass_type" is a subclass of "class_type". 1373d169d70bSTobias Grosser */ 1374d169d70bSTobias Grosser bool cpp_generator::is_subclass(QualType subclass_type, 1375d169d70bSTobias Grosser const isl_class &class_type) 1376d169d70bSTobias Grosser { 1377d169d70bSTobias Grosser std::string type_str = subclass_type->getPointeeType().getAsString(); 1378d169d70bSTobias Grosser std::vector<std::string> superclasses; 1379d169d70bSTobias Grosser std::vector<const isl_class *> parents; 1380d169d70bSTobias Grosser std::vector<std::string>::iterator ci; 1381d169d70bSTobias Grosser 1382d169d70bSTobias Grosser superclasses = generator::find_superclasses(classes[type_str].type); 1383d169d70bSTobias Grosser 1384d169d70bSTobias Grosser for (ci = superclasses.begin(); ci < superclasses.end(); ci++) 1385d169d70bSTobias Grosser parents.push_back(&classes[*ci]); 1386d169d70bSTobias Grosser 1387d169d70bSTobias Grosser while (!parents.empty()) { 1388d169d70bSTobias Grosser const isl_class *candidate = parents.back(); 1389d169d70bSTobias Grosser 1390d169d70bSTobias Grosser parents.pop_back(); 1391d169d70bSTobias Grosser 1392d169d70bSTobias Grosser if (&class_type == candidate) 1393d169d70bSTobias Grosser return true; 1394d169d70bSTobias Grosser 1395d169d70bSTobias Grosser superclasses = generator::find_superclasses(candidate->type); 1396d169d70bSTobias Grosser 1397d169d70bSTobias Grosser for (ci = superclasses.begin(); ci < superclasses.end(); ci++) 1398d169d70bSTobias Grosser parents.push_back(&classes[*ci]); 1399d169d70bSTobias Grosser } 1400d169d70bSTobias Grosser 1401d169d70bSTobias Grosser return false; 1402d169d70bSTobias Grosser } 1403d169d70bSTobias Grosser 1404d169d70bSTobias Grosser /* Check if "cons" is an implicit conversion constructor of class "clazz". 1405d169d70bSTobias Grosser * 1406d169d70bSTobias Grosser * An implicit conversion constructor is generated in case "cons" has a single 1407d169d70bSTobias Grosser * parameter, where the parameter type is a subclass of the class that is 1408d169d70bSTobias Grosser * currently being generated. 1409d169d70bSTobias Grosser */ 1410d169d70bSTobias Grosser bool cpp_generator::is_implicit_conversion(const isl_class &clazz, 1411d169d70bSTobias Grosser FunctionDecl *cons) 1412d169d70bSTobias Grosser { 1413d169d70bSTobias Grosser ParmVarDecl *param = cons->getParamDecl(0); 1414d169d70bSTobias Grosser QualType type = param->getOriginalType(); 1415d169d70bSTobias Grosser 1416d169d70bSTobias Grosser int num_params = cons->getNumParams(); 1417d169d70bSTobias Grosser if (num_params != 1) 1418d169d70bSTobias Grosser return false; 1419d169d70bSTobias Grosser 1420d169d70bSTobias Grosser if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz)) 1421d169d70bSTobias Grosser return true; 1422d169d70bSTobias Grosser 1423d169d70bSTobias Grosser return false; 1424d169d70bSTobias Grosser } 1425d169d70bSTobias Grosser 1426d169d70bSTobias Grosser /* Get kind of "method" in "clazz". 1427d169d70bSTobias Grosser * 1428d169d70bSTobias Grosser * Given the declaration of a static or member method, returns its kind. 1429d169d70bSTobias Grosser */ 1430d169d70bSTobias Grosser cpp_generator::function_kind cpp_generator::get_method_kind( 1431d169d70bSTobias Grosser const isl_class &clazz, FunctionDecl *method) 1432d169d70bSTobias Grosser { 1433d169d70bSTobias Grosser if (is_static(clazz, method)) 1434d169d70bSTobias Grosser return function_kind_static_method; 1435d169d70bSTobias Grosser else 1436d169d70bSTobias Grosser return function_kind_member_method; 1437d169d70bSTobias Grosser } 1438