13f9bf9f4Spatacca /*
23f9bf9f4Spatacca * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
33f9bf9f4Spatacca *
43f9bf9f4Spatacca * Redistribution and use in source and binary forms, with or without
53f9bf9f4Spatacca * modification, are permitted provided that the following conditions
63f9bf9f4Spatacca * are met:
73f9bf9f4Spatacca *
83f9bf9f4Spatacca * 1. Redistributions of source code must retain the above copyright
93f9bf9f4Spatacca * notice, this list of conditions and the following disclaimer.
103f9bf9f4Spatacca *
113f9bf9f4Spatacca * 2. Redistributions in binary form must reproduce the above
123f9bf9f4Spatacca * copyright notice, this list of conditions and the following
133f9bf9f4Spatacca * disclaimer in the documentation and/or other materials provided
143f9bf9f4Spatacca * with the distribution.
153f9bf9f4Spatacca *
163f9bf9f4Spatacca * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY
173f9bf9f4Spatacca * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183f9bf9f4Spatacca * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
193f9bf9f4Spatacca * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOBIAS GROSSER OR
203f9bf9f4Spatacca * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
213f9bf9f4Spatacca * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
223f9bf9f4Spatacca * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
233f9bf9f4Spatacca * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243f9bf9f4Spatacca * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253f9bf9f4Spatacca * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263f9bf9f4Spatacca * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273f9bf9f4Spatacca *
283f9bf9f4Spatacca * The views and conclusions contained in the software and documentation
293f9bf9f4Spatacca * are those of the authors and should not be interpreted as
303f9bf9f4Spatacca * representing official policies, either expressed or implied, of
313f9bf9f4Spatacca * Tobias Grosser.
323f9bf9f4Spatacca */
333f9bf9f4Spatacca
343f9bf9f4Spatacca #include <cstdarg>
353f9bf9f4Spatacca #include <cstdio>
363f9bf9f4Spatacca #include <iostream>
373f9bf9f4Spatacca #include <map>
383f9bf9f4Spatacca #include <memory>
393f9bf9f4Spatacca #include <sstream>
403f9bf9f4Spatacca #include <string>
413f9bf9f4Spatacca #include <vector>
423f9bf9f4Spatacca
433f9bf9f4Spatacca #include "plain_cpp.h"
443f9bf9f4Spatacca #include "isl_config.h"
453f9bf9f4Spatacca
463f9bf9f4Spatacca /* Print string formatted according to "fmt" to ostream "os".
473f9bf9f4Spatacca *
483f9bf9f4Spatacca * This osprintf method allows us to use printf style formatting constructs when
493f9bf9f4Spatacca * writing to an ostream.
503f9bf9f4Spatacca */
osprintf(ostream & os,const char * format,va_list arguments)513f9bf9f4Spatacca static void osprintf(ostream &os, const char *format, va_list arguments)
523f9bf9f4Spatacca {
533f9bf9f4Spatacca va_list copy;
543f9bf9f4Spatacca char *string_pointer;
553f9bf9f4Spatacca size_t size;
563f9bf9f4Spatacca
573f9bf9f4Spatacca va_copy(copy, arguments);
583f9bf9f4Spatacca size = vsnprintf(NULL, 0, format, copy);
593f9bf9f4Spatacca string_pointer = new char[size + 1];
603f9bf9f4Spatacca va_end(copy);
613f9bf9f4Spatacca vsnprintf(string_pointer, size + 1, format, arguments);
623f9bf9f4Spatacca os << string_pointer;
633f9bf9f4Spatacca delete[] string_pointer;
643f9bf9f4Spatacca }
653f9bf9f4Spatacca
663f9bf9f4Spatacca /* Print string formatted according to "fmt" to ostream "os".
673f9bf9f4Spatacca *
683f9bf9f4Spatacca * This osprintf method allows us to use printf style formatting constructs when
693f9bf9f4Spatacca * writing to an ostream.
703f9bf9f4Spatacca */
osprintf(ostream & os,const char * format,...)713f9bf9f4Spatacca static void osprintf(ostream &os, const char *format, ...)
723f9bf9f4Spatacca {
733f9bf9f4Spatacca va_list arguments;
743f9bf9f4Spatacca
753f9bf9f4Spatacca va_start(arguments, format);
763f9bf9f4Spatacca osprintf(os, format, arguments);
773f9bf9f4Spatacca va_end(arguments);
783f9bf9f4Spatacca }
793f9bf9f4Spatacca
803f9bf9f4Spatacca /* Print string formatted according to "fmt" to ostream "os"
813f9bf9f4Spatacca * with the given indentation.
823f9bf9f4Spatacca *
833f9bf9f4Spatacca * This osprintf method allows us to use printf style formatting constructs when
843f9bf9f4Spatacca * writing to an ostream.
853f9bf9f4Spatacca */
osprintf(ostream & os,int indent,const char * format,...)863f9bf9f4Spatacca static void osprintf(ostream &os, int indent, const char *format, ...)
873f9bf9f4Spatacca {
883f9bf9f4Spatacca va_list arguments;
893f9bf9f4Spatacca
903f9bf9f4Spatacca osprintf(os, "%*s", indent, " ");
913f9bf9f4Spatacca va_start(arguments, format);
923f9bf9f4Spatacca osprintf(os, format, arguments);
933f9bf9f4Spatacca va_end(arguments);
943f9bf9f4Spatacca }
953f9bf9f4Spatacca
963f9bf9f4Spatacca /* Convert "l" to a string.
973f9bf9f4Spatacca */
to_string(long l)983f9bf9f4Spatacca static std::string to_string(long l)
993f9bf9f4Spatacca {
1003f9bf9f4Spatacca std::ostringstream strm;
1013f9bf9f4Spatacca strm << l;
1023f9bf9f4Spatacca return strm.str();
1033f9bf9f4Spatacca }
1043f9bf9f4Spatacca
1053f9bf9f4Spatacca /* Construct a generator for plain C++ bindings.
1063f9bf9f4Spatacca *
1073f9bf9f4Spatacca * "checked" is set if C++ bindings should be generated
1083f9bf9f4Spatacca * that rely on the user to check for error conditions.
1093f9bf9f4Spatacca */
plain_cpp_generator(SourceManager & SM,set<RecordDecl * > & exported_types,set<FunctionDecl * > exported_functions,set<FunctionDecl * > functions,bool checked)1103f9bf9f4Spatacca plain_cpp_generator::plain_cpp_generator(SourceManager &SM,
1113f9bf9f4Spatacca set<RecordDecl *> &exported_types,
1123f9bf9f4Spatacca set<FunctionDecl *> exported_functions, set<FunctionDecl *> functions,
1133f9bf9f4Spatacca bool checked) :
1143f9bf9f4Spatacca cpp_generator(SM, exported_types, exported_functions,
1153f9bf9f4Spatacca functions),
1163f9bf9f4Spatacca checked(checked)
1173f9bf9f4Spatacca {
1183f9bf9f4Spatacca }
1193f9bf9f4Spatacca
1203f9bf9f4Spatacca /* Generate a cpp interface based on the extracted types and functions.
1213f9bf9f4Spatacca *
1223f9bf9f4Spatacca * Print first a set of forward declarations for all isl wrapper
1233f9bf9f4Spatacca * classes, then the declarations of the classes, and at the end all
1243f9bf9f4Spatacca * implementations.
1253f9bf9f4Spatacca *
1263f9bf9f4Spatacca * If checked C++ bindings are being generated,
1273f9bf9f4Spatacca * then wrap them in a namespace to avoid conflicts
1283f9bf9f4Spatacca * with the default C++ bindings (with automatic checks using exceptions).
1293f9bf9f4Spatacca */
generate()1303f9bf9f4Spatacca void plain_cpp_generator::generate()
1313f9bf9f4Spatacca {
1323f9bf9f4Spatacca ostream &os = cout;
1333f9bf9f4Spatacca
1343f9bf9f4Spatacca osprintf(os, "\n");
1353f9bf9f4Spatacca osprintf(os, "namespace isl {\n\n");
1363f9bf9f4Spatacca if (checked)
1373f9bf9f4Spatacca osprintf(os, "namespace checked {\n\n");
1383f9bf9f4Spatacca
1393f9bf9f4Spatacca print_forward_declarations(os);
1403f9bf9f4Spatacca osprintf(os, "\n");
1413f9bf9f4Spatacca print_declarations(os);
1423f9bf9f4Spatacca osprintf(os, "\n");
1433f9bf9f4Spatacca print_implementations(os);
1443f9bf9f4Spatacca
1453f9bf9f4Spatacca if (checked)
1463f9bf9f4Spatacca osprintf(os, "} // namespace checked\n");
1473f9bf9f4Spatacca osprintf(os, "} // namespace isl\n");
1483f9bf9f4Spatacca }
1493f9bf9f4Spatacca
1503f9bf9f4Spatacca /* Print forward declarations for all classes to "os".
1513f9bf9f4Spatacca */
print_forward_declarations(ostream & os)1523f9bf9f4Spatacca void plain_cpp_generator::print_forward_declarations(ostream &os)
1533f9bf9f4Spatacca {
1543f9bf9f4Spatacca map<string, isl_class>::iterator ci;
1553f9bf9f4Spatacca
1563f9bf9f4Spatacca osprintf(os, "// forward declarations\n");
1573f9bf9f4Spatacca
1583f9bf9f4Spatacca for (ci = classes.begin(); ci != classes.end(); ++ci)
1593f9bf9f4Spatacca print_class_forward_decl(os, ci->second);
1603f9bf9f4Spatacca }
1613f9bf9f4Spatacca
1623f9bf9f4Spatacca /* Print all declarations to "os".
1633f9bf9f4Spatacca */
print_declarations(ostream & os)1643f9bf9f4Spatacca void plain_cpp_generator::print_declarations(ostream &os)
1653f9bf9f4Spatacca {
1663f9bf9f4Spatacca map<string, isl_class>::iterator ci;
1673f9bf9f4Spatacca bool first = true;
1683f9bf9f4Spatacca
1693f9bf9f4Spatacca for (ci = classes.begin(); ci != classes.end(); ++ci) {
1703f9bf9f4Spatacca if (first)
1713f9bf9f4Spatacca first = false;
1723f9bf9f4Spatacca else
1733f9bf9f4Spatacca osprintf(os, "\n");
1743f9bf9f4Spatacca
1753f9bf9f4Spatacca print_class(os, ci->second);
1763f9bf9f4Spatacca }
1773f9bf9f4Spatacca }
1783f9bf9f4Spatacca
1793f9bf9f4Spatacca /* Print all implementations to "os".
1803f9bf9f4Spatacca */
print_implementations(ostream & os)1813f9bf9f4Spatacca void plain_cpp_generator::print_implementations(ostream &os)
1823f9bf9f4Spatacca {
1833f9bf9f4Spatacca map<string, isl_class>::iterator ci;
1843f9bf9f4Spatacca bool first = true;
1853f9bf9f4Spatacca
1863f9bf9f4Spatacca for (ci = classes.begin(); ci != classes.end(); ++ci) {
1873f9bf9f4Spatacca if (first)
1883f9bf9f4Spatacca first = false;
1893f9bf9f4Spatacca else
1903f9bf9f4Spatacca osprintf(os, "\n");
1913f9bf9f4Spatacca
1923f9bf9f4Spatacca print_class_impl(os, ci->second);
1933f9bf9f4Spatacca }
1943f9bf9f4Spatacca }
1953f9bf9f4Spatacca
1963f9bf9f4Spatacca /* If the printed class is a subclass that is based on a type function,
1973f9bf9f4Spatacca * then introduce a "type" field that holds the value of the type
1983f9bf9f4Spatacca * corresponding to the subclass and make the fields of the class
1993f9bf9f4Spatacca * accessible to the "isa" and "as" methods of the (immediate) superclass.
2003f9bf9f4Spatacca * In particular, "isa" needs access to the type field itself,
2013f9bf9f4Spatacca * while "as" needs access to the private constructor.
2023f9bf9f4Spatacca * In case of the "isa" method, all instances are made friends
2033f9bf9f4Spatacca * to avoid access right confusion.
2043f9bf9f4Spatacca */
print_subclass_type()2053f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_subclass_type()
2063f9bf9f4Spatacca {
2073f9bf9f4Spatacca std::string super;
2083f9bf9f4Spatacca const char *cppname = cppstring.c_str();
2093f9bf9f4Spatacca const char *supername;
2103f9bf9f4Spatacca
2113f9bf9f4Spatacca if (!clazz.is_type_subclass())
2123f9bf9f4Spatacca return;
2133f9bf9f4Spatacca
2143f9bf9f4Spatacca super = type2cpp(clazz.superclass_name);
2153f9bf9f4Spatacca supername = super.c_str();
2163f9bf9f4Spatacca osprintf(os, " template <class T>\n");
2173f9bf9f4Spatacca osprintf(os, " friend %s %s::isa() const;\n",
2183f9bf9f4Spatacca generator.isl_bool2cpp().c_str(), supername);
2193f9bf9f4Spatacca osprintf(os, " friend %s %s::as<%s>() const;\n",
2203f9bf9f4Spatacca cppname, supername, cppname);
2213f9bf9f4Spatacca osprintf(os, " static const auto type = %s;\n",
2223f9bf9f4Spatacca clazz.subclass_name.c_str());
2233f9bf9f4Spatacca }
2243f9bf9f4Spatacca
2253f9bf9f4Spatacca /* Print declarations for class "clazz" to "os".
2263f9bf9f4Spatacca *
2273f9bf9f4Spatacca * If "clazz" is a subclass based on a type function,
2283f9bf9f4Spatacca * then it is made to inherit from the (immediate) superclass and
2293f9bf9f4Spatacca * a "type" attribute is added for use in the "as" and "isa"
2303f9bf9f4Spatacca * methods of the superclass.
2313f9bf9f4Spatacca *
2323f9bf9f4Spatacca * Conversely, if "clazz" is a superclass with a type function,
2333f9bf9f4Spatacca * then declare those "as" and "isa" methods.
2343f9bf9f4Spatacca *
2353f9bf9f4Spatacca * The pointer to the isl object is only added for classes that
2363f9bf9f4Spatacca * are not subclasses, since subclasses refer to the same isl object.
2373f9bf9f4Spatacca */
print_class(ostream & os,const isl_class & clazz)2383f9bf9f4Spatacca void plain_cpp_generator::print_class(ostream &os, const isl_class &clazz)
2393f9bf9f4Spatacca {
2403f9bf9f4Spatacca decl_printer printer(os, clazz, *this);
2413f9bf9f4Spatacca const char *name = clazz.name.c_str();
2423f9bf9f4Spatacca const char *cppname = printer.cppstring.c_str();
2433f9bf9f4Spatacca
2443f9bf9f4Spatacca osprintf(os, "// declarations for isl::%s\n", cppname);
2453f9bf9f4Spatacca
2463f9bf9f4Spatacca printer.print_class_factory();
2473f9bf9f4Spatacca osprintf(os, "\n");
2483f9bf9f4Spatacca osprintf(os, "class %s ", cppname);
2493f9bf9f4Spatacca if (clazz.is_type_subclass())
2503f9bf9f4Spatacca osprintf(os, ": public %s ",
2513f9bf9f4Spatacca type2cpp(clazz.superclass_name).c_str());
2523f9bf9f4Spatacca osprintf(os, "{\n");
2533f9bf9f4Spatacca printer.print_subclass_type();
2543f9bf9f4Spatacca printer.print_class_factory(" friend ");
2553f9bf9f4Spatacca osprintf(os, "\n");
2563f9bf9f4Spatacca osprintf(os, "protected:\n");
2573f9bf9f4Spatacca if (!clazz.is_type_subclass()) {
2583f9bf9f4Spatacca osprintf(os, " %s *ptr = nullptr;\n", name);
2593f9bf9f4Spatacca osprintf(os, "\n");
2603f9bf9f4Spatacca }
2613f9bf9f4Spatacca printer.print_protected_constructors();
2623f9bf9f4Spatacca osprintf(os, "\n");
2633f9bf9f4Spatacca osprintf(os, "public:\n");
264*a749e09eSMichael Kruse printer.print_public_methods();
2653f9bf9f4Spatacca
2663f9bf9f4Spatacca osprintf(os, "};\n");
2673f9bf9f4Spatacca }
2683f9bf9f4Spatacca
2693f9bf9f4Spatacca /* Print forward declaration of class "clazz" to "os".
2703f9bf9f4Spatacca */
print_class_forward_decl(ostream & os,const isl_class & clazz)2713f9bf9f4Spatacca void plain_cpp_generator::print_class_forward_decl(ostream &os,
2723f9bf9f4Spatacca const isl_class &clazz)
2733f9bf9f4Spatacca {
2743f9bf9f4Spatacca std::string cppstring = type2cpp(clazz);
2753f9bf9f4Spatacca const char *cppname = cppstring.c_str();
2763f9bf9f4Spatacca
2773f9bf9f4Spatacca osprintf(os, "class %s;\n", cppname);
2783f9bf9f4Spatacca }
2793f9bf9f4Spatacca
2803f9bf9f4Spatacca /* Print global factory functions.
2813f9bf9f4Spatacca *
2823f9bf9f4Spatacca * Each class has two global factory functions:
2833f9bf9f4Spatacca *
2843f9bf9f4Spatacca * set manage(__isl_take isl_set *ptr);
2853f9bf9f4Spatacca * set manage_copy(__isl_keep isl_set *ptr);
2863f9bf9f4Spatacca *
2873f9bf9f4Spatacca * A user can construct isl C++ objects from a raw pointer and indicate whether
2883f9bf9f4Spatacca * they intend to take the ownership of the object or not through these global
2893f9bf9f4Spatacca * factory functions. This ensures isl object creation is very explicit and
2903f9bf9f4Spatacca * pointers are not converted by accident. Thanks to overloading, manage() and
2913f9bf9f4Spatacca * manage_copy() can be called on any isl raw pointer and the corresponding
2923f9bf9f4Spatacca * object is automatically created, without the user having to choose the right
2933f9bf9f4Spatacca * isl object type.
2943f9bf9f4Spatacca *
2953f9bf9f4Spatacca * For a subclass based on a type function, no factory functions
2963f9bf9f4Spatacca * are introduced because they share the C object type with
2973f9bf9f4Spatacca * the superclass.
2983f9bf9f4Spatacca */
print_class_factory(const std::string & prefix)2993f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_class_factory(
3003f9bf9f4Spatacca const std::string &prefix)
3013f9bf9f4Spatacca {
3023f9bf9f4Spatacca const char *name = clazz.name.c_str();
3033f9bf9f4Spatacca const char *cppname = cppstring.c_str();
3043f9bf9f4Spatacca
3053f9bf9f4Spatacca if (clazz.is_type_subclass())
3063f9bf9f4Spatacca return;
3073f9bf9f4Spatacca
3083f9bf9f4Spatacca os << prefix;
3093f9bf9f4Spatacca osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name);
3103f9bf9f4Spatacca os << prefix;
3113f9bf9f4Spatacca osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n",
3123f9bf9f4Spatacca cppname, name);
3133f9bf9f4Spatacca }
3143f9bf9f4Spatacca
3153f9bf9f4Spatacca /* Print declarations of protected constructors.
3163f9bf9f4Spatacca *
3173f9bf9f4Spatacca * Each class has currently one protected constructor:
3183f9bf9f4Spatacca *
3193f9bf9f4Spatacca * 1) Constructor from a plain isl_* C pointer
3203f9bf9f4Spatacca *
3213f9bf9f4Spatacca * Example:
3223f9bf9f4Spatacca *
3233f9bf9f4Spatacca * set(__isl_take isl_set *ptr);
3243f9bf9f4Spatacca *
3253f9bf9f4Spatacca * The raw pointer constructor is kept protected. Object creation is only
3263f9bf9f4Spatacca * possible through manage() or manage_copy().
3273f9bf9f4Spatacca */
print_protected_constructors()3283f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_protected_constructors()
3293f9bf9f4Spatacca {
3303f9bf9f4Spatacca const char *name = clazz.name.c_str();
3313f9bf9f4Spatacca const char *cppname = cppstring.c_str();
3323f9bf9f4Spatacca
3333f9bf9f4Spatacca osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname,
3343f9bf9f4Spatacca name);
3353f9bf9f4Spatacca }
3363f9bf9f4Spatacca
3373f9bf9f4Spatacca /* Print declarations of public constructors.
3383f9bf9f4Spatacca *
3393f9bf9f4Spatacca * Each class currently has two public constructors:
3403f9bf9f4Spatacca *
3413f9bf9f4Spatacca * 1) A default constructor
3423f9bf9f4Spatacca * 2) A copy constructor
3433f9bf9f4Spatacca *
3443f9bf9f4Spatacca * Example:
3453f9bf9f4Spatacca *
3463f9bf9f4Spatacca * set();
3473f9bf9f4Spatacca * set(const set &set);
3483f9bf9f4Spatacca */
print_public_constructors()3493f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_public_constructors()
3503f9bf9f4Spatacca {
3513f9bf9f4Spatacca const char *cppname = cppstring.c_str();
3523f9bf9f4Spatacca osprintf(os, " inline /* implicit */ %s();\n", cppname);
3533f9bf9f4Spatacca
3543f9bf9f4Spatacca osprintf(os, " inline /* implicit */ %s(const %s &obj);\n",
3553f9bf9f4Spatacca cppname, cppname);
3563f9bf9f4Spatacca }
3573f9bf9f4Spatacca
3583f9bf9f4Spatacca /* Print declarations for "method".
3593f9bf9f4Spatacca */
print_method(const ConversionMethod & method)3603f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_method(
3613f9bf9f4Spatacca const ConversionMethod &method)
3623f9bf9f4Spatacca {
3633f9bf9f4Spatacca print_full_method_header(method);
3643f9bf9f4Spatacca }
3653f9bf9f4Spatacca
3663f9bf9f4Spatacca /* Print declarations for "method".
3673f9bf9f4Spatacca */
print_method(const Method & method)3683f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_method(const Method &method)
3693f9bf9f4Spatacca {
3703f9bf9f4Spatacca print_full_method_header(method);
3713f9bf9f4Spatacca }
3723f9bf9f4Spatacca
373*a749e09eSMichael Kruse /* Print a declaration for a constructor for the "id" class
374*a749e09eSMichael Kruse * that takes a user object.
375*a749e09eSMichael Kruse */
print_id_constructor_user()376*a749e09eSMichael Kruse void plain_cpp_generator::decl_printer::print_id_constructor_user()
377*a749e09eSMichael Kruse {
378*a749e09eSMichael Kruse print_id_constructor_user_header();
379*a749e09eSMichael Kruse }
380*a749e09eSMichael Kruse
381*a749e09eSMichael Kruse /* Print a declaration for an "id" method
382*a749e09eSMichael Kruse * for retrieving the user object associated to the identifier.
383*a749e09eSMichael Kruse * If "optional" is set, the method returns a std::optional user object.
384*a749e09eSMichael Kruse */
print_id_user(bool optional)385*a749e09eSMichael Kruse void plain_cpp_generator::decl_printer::print_id_user(bool optional)
386*a749e09eSMichael Kruse {
387*a749e09eSMichael Kruse print_id_user_header(optional);
388*a749e09eSMichael Kruse }
389*a749e09eSMichael Kruse
3903f9bf9f4Spatacca /* Print declarations of copy assignment operator.
3913f9bf9f4Spatacca *
3923f9bf9f4Spatacca * Each class has one assignment operator.
3933f9bf9f4Spatacca *
3943f9bf9f4Spatacca * isl:set &set::operator=(set obj)
3953f9bf9f4Spatacca *
3963f9bf9f4Spatacca */
print_copy_assignment()3973f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_copy_assignment()
3983f9bf9f4Spatacca {
3993f9bf9f4Spatacca const char *cppname = cppstring.c_str();
4003f9bf9f4Spatacca
4013f9bf9f4Spatacca osprintf(os, " inline %s &operator=(%s obj);\n", cppname, cppname);
4023f9bf9f4Spatacca }
4033f9bf9f4Spatacca
4043f9bf9f4Spatacca /* Print declaration of destructor.
4053f9bf9f4Spatacca *
4063f9bf9f4Spatacca * No explicit destructor is needed for type based subclasses.
4073f9bf9f4Spatacca */
print_destructor()4083f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_destructor()
4093f9bf9f4Spatacca {
4103f9bf9f4Spatacca const char *cppname = cppstring.c_str();
4113f9bf9f4Spatacca
4123f9bf9f4Spatacca if (clazz.is_type_subclass())
4133f9bf9f4Spatacca return;
4143f9bf9f4Spatacca
4153f9bf9f4Spatacca osprintf(os, " inline ~%s();\n", cppname);
4163f9bf9f4Spatacca }
4173f9bf9f4Spatacca
4183f9bf9f4Spatacca /* Print declaration of pointer functions.
4193f9bf9f4Spatacca * Since type based subclasses share the pointer with their superclass,
4203f9bf9f4Spatacca * they can also reuse these functions from the superclass.
4213f9bf9f4Spatacca *
4223f9bf9f4Spatacca * To obtain a raw pointer three functions are provided:
4233f9bf9f4Spatacca *
4243f9bf9f4Spatacca * 1) __isl_give isl_set *copy()
4253f9bf9f4Spatacca *
4263f9bf9f4Spatacca * Returns a pointer to a _copy_ of the internal object
4273f9bf9f4Spatacca *
4283f9bf9f4Spatacca * 2) __isl_keep isl_set *get()
4293f9bf9f4Spatacca *
4303f9bf9f4Spatacca * Returns a pointer to the internal object
4313f9bf9f4Spatacca *
4323f9bf9f4Spatacca * 3) __isl_give isl_set *release()
4333f9bf9f4Spatacca *
4343f9bf9f4Spatacca * Returns a pointer to the internal object and resets the
4353f9bf9f4Spatacca * internal pointer to nullptr.
4363f9bf9f4Spatacca *
4373f9bf9f4Spatacca * We also provide functionality to explicitly check if a pointer is
4383f9bf9f4Spatacca * currently managed by this object.
4393f9bf9f4Spatacca *
4403f9bf9f4Spatacca * 4) bool is_null()
4413f9bf9f4Spatacca *
4423f9bf9f4Spatacca * Check if the current object is a null pointer.
4433f9bf9f4Spatacca *
4443f9bf9f4Spatacca * The functions get() and release() model the value_ptr proposed in
4453f9bf9f4Spatacca * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
4463f9bf9f4Spatacca * The copy() function is an extension to allow the user to explicitly
4473f9bf9f4Spatacca * copy the underlying object.
4483f9bf9f4Spatacca *
4493f9bf9f4Spatacca * Also generate a declaration to delete copy() for r-values, for
4503f9bf9f4Spatacca * r-values release() should be used to avoid unnecessary copies.
4513f9bf9f4Spatacca */
print_ptr()4523f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_ptr()
4533f9bf9f4Spatacca {
4543f9bf9f4Spatacca const char *name = clazz.name.c_str();
4553f9bf9f4Spatacca
4563f9bf9f4Spatacca if (clazz.is_type_subclass())
4573f9bf9f4Spatacca return;
4583f9bf9f4Spatacca
4593f9bf9f4Spatacca osprintf(os, " inline __isl_give %s *copy() const &;\n", name);
4603f9bf9f4Spatacca osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name);
4613f9bf9f4Spatacca osprintf(os, " inline __isl_keep %s *get() const;\n", name);
4623f9bf9f4Spatacca osprintf(os, " inline __isl_give %s *release();\n", name);
4633f9bf9f4Spatacca osprintf(os, " inline bool is_null() const;\n");
4643f9bf9f4Spatacca }
4653f9bf9f4Spatacca
4663f9bf9f4Spatacca /* Print a template declaration with given indentation
4673f9bf9f4Spatacca * for the "isa_type" method that ensures it is only enabled
4683f9bf9f4Spatacca * when called with a template argument
4693f9bf9f4Spatacca * that represents a type that is equal to that
4703f9bf9f4Spatacca * of the return type of the type function of "super".
4713f9bf9f4Spatacca * In particular, "isa_type" gets called from "isa"
4723f9bf9f4Spatacca * with as template argument the type of the "type" field
4733f9bf9f4Spatacca * of the subclass.
4743f9bf9f4Spatacca * The check ensures that this subclass is in fact a direct subclass
4753f9bf9f4Spatacca * of "super".
4763f9bf9f4Spatacca */
print_isa_type_template(int indent,const isl_class & super)4773f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_isa_type_template(int indent,
4783f9bf9f4Spatacca const isl_class &super)
4793f9bf9f4Spatacca {
4803f9bf9f4Spatacca osprintf(os, indent,
4813f9bf9f4Spatacca "template <typename T,\n");
4823f9bf9f4Spatacca osprintf(os, indent,
4833f9bf9f4Spatacca " typename = typename std::enable_if<std::is_same<\n");
4843f9bf9f4Spatacca osprintf(os, indent,
4853f9bf9f4Spatacca " const decltype(%s(NULL)),\n",
4863f9bf9f4Spatacca super.fn_type->getNameAsString().c_str());
4873f9bf9f4Spatacca osprintf(os, indent,
4883f9bf9f4Spatacca " const T>::value>::type>\n");
4893f9bf9f4Spatacca }
4903f9bf9f4Spatacca
4913f9bf9f4Spatacca /* Print declarations for the "as" and "isa" methods, if the printed class
4923f9bf9f4Spatacca * is a superclass with a type function.
4933f9bf9f4Spatacca *
4943f9bf9f4Spatacca * "isa" checks whether an object is of a given subclass type.
4953f9bf9f4Spatacca * "isa_type" does the same, but gets passed the value of the type field
4963f9bf9f4Spatacca * of the subclass as a function argument and the type of this field
4973f9bf9f4Spatacca * as a template argument.
4983f9bf9f4Spatacca * "as" tries to cast an object to a given subclass type, returning
4993f9bf9f4Spatacca * an invalid object if the object is not of the given type.
5003f9bf9f4Spatacca */
print_downcast()5013f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_downcast()
5023f9bf9f4Spatacca {
5033f9bf9f4Spatacca if (!clazz.fn_type)
5043f9bf9f4Spatacca return;
5053f9bf9f4Spatacca
5063f9bf9f4Spatacca osprintf(os, "private:\n");
5073f9bf9f4Spatacca print_isa_type_template(2, clazz);
5083f9bf9f4Spatacca osprintf(os, " inline %s isa_type(T subtype) const;\n",
5093f9bf9f4Spatacca generator.isl_bool2cpp().c_str());
5103f9bf9f4Spatacca osprintf(os, "public:\n");
5113f9bf9f4Spatacca osprintf(os, " template <class T> inline %s isa() const;\n",
5123f9bf9f4Spatacca generator.isl_bool2cpp().c_str());
5133f9bf9f4Spatacca osprintf(os, " template <class T> inline T as() const;\n");
5143f9bf9f4Spatacca }
5153f9bf9f4Spatacca
5163f9bf9f4Spatacca /* Print the declaration of the ctx method.
5173f9bf9f4Spatacca */
print_ctx()5183f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_ctx()
5193f9bf9f4Spatacca {
5203f9bf9f4Spatacca std::string ns = generator.isl_namespace();
5213f9bf9f4Spatacca
5223f9bf9f4Spatacca osprintf(os, " inline %sctx ctx() const;\n", ns.c_str());
5233f9bf9f4Spatacca }
5243f9bf9f4Spatacca
525*a749e09eSMichael Kruse /* Print a separator between groups of method declarations.
526*a749e09eSMichael Kruse */
print_method_separator()527*a749e09eSMichael Kruse void plain_cpp_generator::decl_printer::print_method_separator()
528*a749e09eSMichael Kruse {
529*a749e09eSMichael Kruse os << "\n";
530*a749e09eSMichael Kruse }
531*a749e09eSMichael Kruse
5323f9bf9f4Spatacca /* Add a space to the return type "type" if needed,
5333f9bf9f4Spatacca * i.e., if it is not the type of a pointer.
5343f9bf9f4Spatacca */
add_space_to_return_type(const string & type)5353f9bf9f4Spatacca static string add_space_to_return_type(const string &type)
5363f9bf9f4Spatacca {
5373f9bf9f4Spatacca if (type[type.size() - 1] == '*')
5383f9bf9f4Spatacca return type;
5393f9bf9f4Spatacca return type + " ";
5403f9bf9f4Spatacca }
5413f9bf9f4Spatacca
5423f9bf9f4Spatacca /* Print the prototype of the static inline method that is used
5433f9bf9f4Spatacca * as the C callback set by "method".
5443f9bf9f4Spatacca */
print_persistent_callback_prototype(FunctionDecl * method)5453f9bf9f4Spatacca void plain_cpp_generator::plain_printer::print_persistent_callback_prototype(
5463f9bf9f4Spatacca FunctionDecl *method)
5473f9bf9f4Spatacca {
5483f9bf9f4Spatacca string callback_name, rettype, c_args;
5493f9bf9f4Spatacca ParmVarDecl *param = persistent_callback_arg(method);
5503f9bf9f4Spatacca const FunctionProtoType *callback;
5513f9bf9f4Spatacca QualType ptype;
5523f9bf9f4Spatacca string classname;
5533f9bf9f4Spatacca
5543f9bf9f4Spatacca ptype = param->getType();
5553f9bf9f4Spatacca callback = extract_prototype(ptype);
5563f9bf9f4Spatacca
5573f9bf9f4Spatacca rettype = callback->getReturnType().getAsString();
5583f9bf9f4Spatacca rettype = add_space_to_return_type(rettype);
5593f9bf9f4Spatacca callback_name = clazz.persistent_callback_name(method);
5603f9bf9f4Spatacca c_args = generator.generate_callback_args(ptype, false);
5613f9bf9f4Spatacca
5623f9bf9f4Spatacca if (!declarations)
5633f9bf9f4Spatacca classname = type2cpp(clazz) + "::";
5643f9bf9f4Spatacca
5653f9bf9f4Spatacca osprintf(os, "%s%s%s(%s)",
5663f9bf9f4Spatacca rettype.c_str(), classname.c_str(),
5673f9bf9f4Spatacca callback_name.c_str(), c_args.c_str());
5683f9bf9f4Spatacca }
5693f9bf9f4Spatacca
5703f9bf9f4Spatacca /* Print the prototype of the method for setting the callback function
5713f9bf9f4Spatacca * set by "method".
5723f9bf9f4Spatacca */
5733f9bf9f4Spatacca void
print_persistent_callback_setter_prototype(FunctionDecl * method)5743f9bf9f4Spatacca plain_cpp_generator::plain_printer::print_persistent_callback_setter_prototype(
5753f9bf9f4Spatacca FunctionDecl *method)
5763f9bf9f4Spatacca {
5773f9bf9f4Spatacca string classname, callback_name, cpptype;
5783f9bf9f4Spatacca ParmVarDecl *param = persistent_callback_arg(method);
5793f9bf9f4Spatacca
5803f9bf9f4Spatacca if (!declarations)
5813f9bf9f4Spatacca classname = type2cpp(clazz) + "::";
5823f9bf9f4Spatacca
5833f9bf9f4Spatacca cpptype = generator.param2cpp(param->getOriginalType());
5843f9bf9f4Spatacca callback_name = clazz.persistent_callback_name(method);
5853f9bf9f4Spatacca osprintf(os, "void %sset_%s_data(const %s &%s)",
5863f9bf9f4Spatacca classname.c_str(), callback_name.c_str(), cpptype.c_str(),
5873f9bf9f4Spatacca param->getName().str().c_str());
5883f9bf9f4Spatacca }
5893f9bf9f4Spatacca
5903f9bf9f4Spatacca /* Given a method "method" for setting a persistent callback,
5913f9bf9f4Spatacca * print the fields that are needed for marshalling the callback.
5923f9bf9f4Spatacca *
5933f9bf9f4Spatacca * In particular, print
5943f9bf9f4Spatacca * - the declaration of a data structure for storing the C++ callback function
5953f9bf9f4Spatacca * - a shared pointer to such a data structure
5963f9bf9f4Spatacca * - the declaration of a static inline method
5973f9bf9f4Spatacca * for use as the C callback function
5983f9bf9f4Spatacca * - the declaration of a private method for setting the callback function
5993f9bf9f4Spatacca */
print_persistent_callback_data(FunctionDecl * method)6003f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_persistent_callback_data(
6013f9bf9f4Spatacca FunctionDecl *method)
6023f9bf9f4Spatacca {
6033f9bf9f4Spatacca string callback_name;
6043f9bf9f4Spatacca ParmVarDecl *param = generator.persistent_callback_arg(method);
6053f9bf9f4Spatacca
6063f9bf9f4Spatacca callback_name = clazz.persistent_callback_name(method);
6073f9bf9f4Spatacca print_callback_data_decl(param, callback_name);
6083f9bf9f4Spatacca osprintf(os, ";\n");
6093f9bf9f4Spatacca osprintf(os, " std::shared_ptr<%s_data> %s_data;\n",
6103f9bf9f4Spatacca callback_name.c_str(), callback_name.c_str());
6113f9bf9f4Spatacca osprintf(os, " static inline ");
6123f9bf9f4Spatacca print_persistent_callback_prototype(method);
6133f9bf9f4Spatacca osprintf(os, ";\n");
6143f9bf9f4Spatacca osprintf(os, " inline ");
6153f9bf9f4Spatacca print_persistent_callback_setter_prototype(method);
6163f9bf9f4Spatacca osprintf(os, ";\n");
6173f9bf9f4Spatacca }
6183f9bf9f4Spatacca
6193f9bf9f4Spatacca /* Print declarations needed for the persistent callbacks of the class.
6203f9bf9f4Spatacca *
6213f9bf9f4Spatacca * In particular, if there are any persistent callbacks, then
6223f9bf9f4Spatacca * print a private method for copying callback data from
6233f9bf9f4Spatacca * one object to another,
6243f9bf9f4Spatacca * private data for keeping track of the persistent callbacks and
6253f9bf9f4Spatacca * public methods for setting the persistent callbacks.
6263f9bf9f4Spatacca */
print_persistent_callbacks()6273f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_persistent_callbacks()
6283f9bf9f4Spatacca {
6293f9bf9f4Spatacca const char *cppname = cppstring.c_str();
6303f9bf9f4Spatacca
6313f9bf9f4Spatacca if (!clazz.has_persistent_callbacks())
6323f9bf9f4Spatacca return;
6333f9bf9f4Spatacca
6343f9bf9f4Spatacca osprintf(os, "private:\n");
6353f9bf9f4Spatacca osprintf(os, " inline %s ©_callbacks(const %s &obj);\n",
6363f9bf9f4Spatacca cppname, cppname);
6373f9bf9f4Spatacca for (const auto &callback : clazz.persistent_callbacks)
6383f9bf9f4Spatacca print_persistent_callback_data(callback);
6393f9bf9f4Spatacca
6403f9bf9f4Spatacca osprintf(os, "public:\n");
6413f9bf9f4Spatacca for (const auto &callback : clazz.persistent_callbacks)
6423f9bf9f4Spatacca print_method(Method(clazz, callback));
6433f9bf9f4Spatacca }
6443f9bf9f4Spatacca
6453f9bf9f4Spatacca /* Print a declaration for the "get" method "fd",
6463f9bf9f4Spatacca * using a name that includes the "get_" prefix.
6473f9bf9f4Spatacca */
print_get_method(FunctionDecl * fd)6483f9bf9f4Spatacca void plain_cpp_generator::decl_printer::print_get_method(FunctionDecl *fd)
6493f9bf9f4Spatacca {
6503f9bf9f4Spatacca string base = clazz.base_method_name(fd);
6513f9bf9f4Spatacca
6523f9bf9f4Spatacca print_method(Method(clazz, fd, base));
6533f9bf9f4Spatacca }
6543f9bf9f4Spatacca
6553f9bf9f4Spatacca /* Print implementations for class "clazz" to "os".
6563f9bf9f4Spatacca */
print_class_impl(ostream & os,const isl_class & clazz)6573f9bf9f4Spatacca void plain_cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
6583f9bf9f4Spatacca {
6593f9bf9f4Spatacca impl_printer printer(os, clazz, *this);
6603f9bf9f4Spatacca const char *cppname = printer.cppstring.c_str();
6613f9bf9f4Spatacca
6623f9bf9f4Spatacca osprintf(os, "// implementations for isl::%s", cppname);
6633f9bf9f4Spatacca
6643f9bf9f4Spatacca printer.print_class_factory();
6653f9bf9f4Spatacca printer.print_protected_constructors();
666*a749e09eSMichael Kruse printer.print_public_methods();
6673f9bf9f4Spatacca printer.print_stream_insertion();
6683f9bf9f4Spatacca }
6693f9bf9f4Spatacca
6703f9bf9f4Spatacca /* Print code for throwing an exception corresponding to the last error
6713f9bf9f4Spatacca * that occurred on "saved_ctx".
6723f9bf9f4Spatacca * This assumes that a valid isl::ctx is available in the "saved_ctx" variable,
6733f9bf9f4Spatacca * e.g., through a prior call to print_save_ctx.
6743f9bf9f4Spatacca */
print_throw_last_error(ostream & os)6753f9bf9f4Spatacca static void print_throw_last_error(ostream &os)
6763f9bf9f4Spatacca {
6773f9bf9f4Spatacca osprintf(os, " exception::throw_last_error(saved_ctx);\n");
6783f9bf9f4Spatacca }
6793f9bf9f4Spatacca
6803f9bf9f4Spatacca /* Print code with the given indentation
6813f9bf9f4Spatacca * for throwing an exception_invalid with the given message.
6823f9bf9f4Spatacca */
print_throw_invalid(ostream & os,int indent,const char * msg)6833f9bf9f4Spatacca static void print_throw_invalid(ostream &os, int indent, const char *msg)
6843f9bf9f4Spatacca {
6853f9bf9f4Spatacca osprintf(os, indent,
6863f9bf9f4Spatacca "exception::throw_invalid(\"%s\", __FILE__, __LINE__);\n", msg);
6873f9bf9f4Spatacca }
6883f9bf9f4Spatacca
6893f9bf9f4Spatacca /* Print code for throwing an exception on NULL input.
6903f9bf9f4Spatacca */
print_throw_NULL_input(ostream & os)6913f9bf9f4Spatacca static void print_throw_NULL_input(ostream &os)
6923f9bf9f4Spatacca {
6933f9bf9f4Spatacca print_throw_invalid(os, 4, "NULL input");
6943f9bf9f4Spatacca }
6953f9bf9f4Spatacca
6963f9bf9f4Spatacca /* Print code with the given indentation
6973f9bf9f4Spatacca * for acting on an invalid error with message "msg".
6983f9bf9f4Spatacca * In particular, throw an exception_invalid.
6993f9bf9f4Spatacca * In the checked C++ bindings, isl_die is called instead with the code
7003f9bf9f4Spatacca * in "checked_code".
7013f9bf9f4Spatacca */
print_invalid(ostream & os,int indent,const char * msg,const char * checked_code)7023f9bf9f4Spatacca void plain_cpp_generator::print_invalid(ostream &os, int indent,
7033f9bf9f4Spatacca const char *msg, const char *checked_code)
7043f9bf9f4Spatacca {
7053f9bf9f4Spatacca if (checked)
7063f9bf9f4Spatacca osprintf(os, indent,
7073f9bf9f4Spatacca "isl_die(ctx().get(), isl_error_invalid, "
7083f9bf9f4Spatacca "\"%s\", %s);\n", msg, checked_code);
7093f9bf9f4Spatacca else
7103f9bf9f4Spatacca print_throw_invalid(os, indent, msg);
7113f9bf9f4Spatacca }
7123f9bf9f4Spatacca
7133f9bf9f4Spatacca /* Print an operator for inserting objects of the class
7143f9bf9f4Spatacca * into an output stream.
7153f9bf9f4Spatacca *
7163f9bf9f4Spatacca * Unless checked C++ bindings are being generated,
7173f9bf9f4Spatacca * the operator requires its argument to be non-NULL.
7183f9bf9f4Spatacca * An exception is thrown if anything went wrong during the printing.
7193f9bf9f4Spatacca * During this printing, isl is made not to print any error message
7203f9bf9f4Spatacca * because the error message is included in the exception.
7213f9bf9f4Spatacca *
7223f9bf9f4Spatacca * If checked C++ bindings are being generated and anything went wrong,
7233f9bf9f4Spatacca * then record this failure in the output stream.
7243f9bf9f4Spatacca */
print_stream_insertion()7253f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_stream_insertion()
7263f9bf9f4Spatacca {
7273f9bf9f4Spatacca const char *name = clazz.name.c_str();
7283f9bf9f4Spatacca const char *cppname = cppstring.c_str();
7293f9bf9f4Spatacca
7303f9bf9f4Spatacca if (!clazz.fn_to_str)
7313f9bf9f4Spatacca return;
7323f9bf9f4Spatacca
7333f9bf9f4Spatacca osprintf(os, "\n");
7343f9bf9f4Spatacca osprintf(os, "inline std::ostream &operator<<(std::ostream &os, ");
7353f9bf9f4Spatacca osprintf(os, "const %s &obj)\n", cppname);
7363f9bf9f4Spatacca osprintf(os, "{\n");
7373f9bf9f4Spatacca print_check_ptr_start("obj.get()");
7383f9bf9f4Spatacca osprintf(os, " char *str = %s_to_str(obj.get());\n", name);
7393f9bf9f4Spatacca print_check_ptr_end("str");
7403f9bf9f4Spatacca if (generator.checked) {
7413f9bf9f4Spatacca osprintf(os, " if (!str) {\n");
7423f9bf9f4Spatacca osprintf(os, " os.setstate(std::ios_base::badbit);\n");
7433f9bf9f4Spatacca osprintf(os, " return os;\n");
7443f9bf9f4Spatacca osprintf(os, " }\n");
7453f9bf9f4Spatacca }
7463f9bf9f4Spatacca osprintf(os, " os << str;\n");
7473f9bf9f4Spatacca osprintf(os, " free(str);\n");
7483f9bf9f4Spatacca osprintf(os, " return os;\n");
7493f9bf9f4Spatacca osprintf(os, "}\n");
7503f9bf9f4Spatacca }
7513f9bf9f4Spatacca
7523f9bf9f4Spatacca /* Print code that checks that "ptr" is not NULL at input.
7533f9bf9f4Spatacca *
7543f9bf9f4Spatacca * Omit the check if checked C++ bindings are being generated.
7553f9bf9f4Spatacca */
print_check_ptr(const char * ptr)7563f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_check_ptr(const char *ptr)
7573f9bf9f4Spatacca {
7583f9bf9f4Spatacca if (generator.checked)
7593f9bf9f4Spatacca return;
7603f9bf9f4Spatacca
7613f9bf9f4Spatacca osprintf(os, " if (!%s)\n", ptr);
7623f9bf9f4Spatacca print_throw_NULL_input(os);
7633f9bf9f4Spatacca }
7643f9bf9f4Spatacca
7653f9bf9f4Spatacca /* Print code that checks that "ptr" is not NULL at input and
7663f9bf9f4Spatacca * that saves a copy of the isl_ctx of "ptr" for a later check.
7673f9bf9f4Spatacca *
7683f9bf9f4Spatacca * Omit the check if checked C++ bindings are being generated.
7693f9bf9f4Spatacca */
print_check_ptr_start(const char * ptr)7703f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_check_ptr_start(const char *ptr)
7713f9bf9f4Spatacca {
7723f9bf9f4Spatacca if (generator.checked)
7733f9bf9f4Spatacca return;
7743f9bf9f4Spatacca
7753f9bf9f4Spatacca print_check_ptr(ptr);
776*a749e09eSMichael Kruse print_save_ctx(clazz.name + "_get_ctx(" + ptr + ")");
7773f9bf9f4Spatacca print_on_error_continue();
7783f9bf9f4Spatacca }
7793f9bf9f4Spatacca
7803f9bf9f4Spatacca /* Print code that checks that "ptr" is not NULL at the end.
7813f9bf9f4Spatacca * A copy of the isl_ctx is expected to have been saved by
7823f9bf9f4Spatacca * code generated by print_check_ptr_start.
7833f9bf9f4Spatacca *
7843f9bf9f4Spatacca * Omit the check if checked C++ bindings are being generated.
7853f9bf9f4Spatacca */
print_check_ptr_end(const char * ptr)7863f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_check_ptr_end(const char *ptr)
7873f9bf9f4Spatacca {
7883f9bf9f4Spatacca if (generator.checked)
7893f9bf9f4Spatacca return;
7903f9bf9f4Spatacca
7913f9bf9f4Spatacca osprintf(os, " if (!%s)\n", ptr);
7923f9bf9f4Spatacca print_throw_last_error(os);
7933f9bf9f4Spatacca }
7943f9bf9f4Spatacca
7953f9bf9f4Spatacca /* Print implementation of global factory functions.
7963f9bf9f4Spatacca *
7973f9bf9f4Spatacca * Each class has two global factory functions:
7983f9bf9f4Spatacca *
7993f9bf9f4Spatacca * set manage(__isl_take isl_set *ptr);
8003f9bf9f4Spatacca * set manage_copy(__isl_keep isl_set *ptr);
8013f9bf9f4Spatacca *
8023f9bf9f4Spatacca * Unless checked C++ bindings are being generated,
8033f9bf9f4Spatacca * both functions require the argument to be non-NULL.
8043f9bf9f4Spatacca * An exception is thrown if anything went wrong during the copying
8053f9bf9f4Spatacca * in manage_copy.
8063f9bf9f4Spatacca * During the copying, isl is made not to print any error message
8073f9bf9f4Spatacca * because the error message is included in the exception.
8083f9bf9f4Spatacca *
8093f9bf9f4Spatacca * For a subclass based on a type function, no factory functions
8103f9bf9f4Spatacca * are introduced because they share the C object type with
8113f9bf9f4Spatacca * the superclass.
8123f9bf9f4Spatacca */
print_class_factory()8133f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_class_factory()
8143f9bf9f4Spatacca {
8153f9bf9f4Spatacca const char *name = clazz.name.c_str();
8163f9bf9f4Spatacca const char *cppname = cppstring.c_str();
8173f9bf9f4Spatacca
8183f9bf9f4Spatacca if (clazz.is_type_subclass())
8193f9bf9f4Spatacca return;
8203f9bf9f4Spatacca
8213f9bf9f4Spatacca osprintf(os, "\n");
8223f9bf9f4Spatacca osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
8233f9bf9f4Spatacca print_check_ptr("ptr");
8243f9bf9f4Spatacca osprintf(os, " return %s(ptr);\n", cppname);
8253f9bf9f4Spatacca osprintf(os, "}\n");
8263f9bf9f4Spatacca
8273f9bf9f4Spatacca osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
8283f9bf9f4Spatacca name);
8293f9bf9f4Spatacca print_check_ptr_start("ptr");
8303f9bf9f4Spatacca osprintf(os, " ptr = %s_copy(ptr);\n", name);
8313f9bf9f4Spatacca print_check_ptr_end("ptr");
8323f9bf9f4Spatacca osprintf(os, " return %s(ptr);\n", cppname);
8333f9bf9f4Spatacca osprintf(os, "}\n");
8343f9bf9f4Spatacca }
8353f9bf9f4Spatacca
8363f9bf9f4Spatacca /* Print implementations of protected constructors.
8373f9bf9f4Spatacca *
8383f9bf9f4Spatacca * The pointer to the isl object is either initialized directly or
8393f9bf9f4Spatacca * through the (immediate) superclass.
8403f9bf9f4Spatacca */
print_protected_constructors()8413f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_protected_constructors()
8423f9bf9f4Spatacca {
8433f9bf9f4Spatacca const char *name = clazz.name.c_str();
8443f9bf9f4Spatacca const char *cppname = cppstring.c_str();
8453f9bf9f4Spatacca bool subclass = clazz.is_type_subclass();
8463f9bf9f4Spatacca
8473f9bf9f4Spatacca osprintf(os, "\n");
8483f9bf9f4Spatacca osprintf(os, "%s::%s(__isl_take %s *ptr)\n", cppname, cppname, name);
8493f9bf9f4Spatacca if (subclass)
8503f9bf9f4Spatacca osprintf(os, " : %s(ptr) {}\n",
8513f9bf9f4Spatacca type2cpp(clazz.superclass_name).c_str());
8523f9bf9f4Spatacca else
8533f9bf9f4Spatacca osprintf(os, " : ptr(ptr) {}\n");
8543f9bf9f4Spatacca }
8553f9bf9f4Spatacca
8563f9bf9f4Spatacca /* Print implementations of public constructors.
8573f9bf9f4Spatacca *
8583f9bf9f4Spatacca * The pointer to the isl object is either initialized directly or
8593f9bf9f4Spatacca * through the (immediate) superclass.
8603f9bf9f4Spatacca *
8613f9bf9f4Spatacca * If the class has any persistent callbacks, then copy them
8623f9bf9f4Spatacca * from the original object in the copy constructor.
8633f9bf9f4Spatacca * If the class is a subclass, then the persistent callbacks
8643f9bf9f4Spatacca * are assumed to be copied by the copy constructor of the superclass.
8653f9bf9f4Spatacca *
8663f9bf9f4Spatacca * Throw an exception from the copy constructor if anything went wrong
8673f9bf9f4Spatacca * during the copying or if the input is NULL, if any copying is performed.
8683f9bf9f4Spatacca * During the copying, isl is made not to print any error message
8693f9bf9f4Spatacca * because the error message is included in the exception.
8703f9bf9f4Spatacca * No exceptions are thrown if checked C++ bindings
8713f9bf9f4Spatacca * are being generated,
8723f9bf9f4Spatacca */
print_public_constructors()8733f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_public_constructors()
8743f9bf9f4Spatacca {
8753f9bf9f4Spatacca std::string super;
8763f9bf9f4Spatacca const char *cppname = cppstring.c_str();
8773f9bf9f4Spatacca bool subclass = clazz.is_type_subclass();
8783f9bf9f4Spatacca
8793f9bf9f4Spatacca osprintf(os, "\n");
8803f9bf9f4Spatacca if (subclass)
8813f9bf9f4Spatacca super = type2cpp(clazz.superclass_name);
8823f9bf9f4Spatacca osprintf(os, "%s::%s()\n", cppname, cppname);
8833f9bf9f4Spatacca if (subclass)
8843f9bf9f4Spatacca osprintf(os, " : %s() {}\n\n", super.c_str());
8853f9bf9f4Spatacca else
8863f9bf9f4Spatacca osprintf(os, " : ptr(nullptr) {}\n\n");
8873f9bf9f4Spatacca osprintf(os, "%s::%s(const %s &obj)\n", cppname, cppname, cppname);
8883f9bf9f4Spatacca if (subclass)
8893f9bf9f4Spatacca osprintf(os, " : %s(obj)\n", super.c_str());
8903f9bf9f4Spatacca else
8913f9bf9f4Spatacca osprintf(os, " : ptr(nullptr)\n");
8923f9bf9f4Spatacca osprintf(os, "{\n");
8933f9bf9f4Spatacca if (!subclass) {
8943f9bf9f4Spatacca print_check_ptr_start("obj.ptr");
8953f9bf9f4Spatacca osprintf(os, " ptr = obj.copy();\n");
8963f9bf9f4Spatacca if (clazz.has_persistent_callbacks())
8973f9bf9f4Spatacca osprintf(os, " copy_callbacks(obj);\n");
8983f9bf9f4Spatacca print_check_ptr_end("ptr");
8993f9bf9f4Spatacca }
9003f9bf9f4Spatacca osprintf(os, "}\n");
9013f9bf9f4Spatacca }
9023f9bf9f4Spatacca
9033f9bf9f4Spatacca /* Print definition for "method",
9043f9bf9f4Spatacca * without any automatic type conversions.
9053f9bf9f4Spatacca *
9063f9bf9f4Spatacca * This method distinguishes three kinds of methods: member methods, static
9073f9bf9f4Spatacca * methods, and constructors.
9083f9bf9f4Spatacca *
9093f9bf9f4Spatacca * Member methods and static methods return a newly managed
9103f9bf9f4Spatacca * isl C++ object.
9113f9bf9f4Spatacca *
9123f9bf9f4Spatacca * Constructors create a new object from a given set of input parameters. They
9133f9bf9f4Spatacca * do not return a value, but instead update the pointer stored inside the
9143f9bf9f4Spatacca * newly created object.
9153f9bf9f4Spatacca *
9163f9bf9f4Spatacca * Unless checked C++ bindings are being generated,
9173f9bf9f4Spatacca * the inputs of the method are first checked for being valid isl objects and
9183f9bf9f4Spatacca * a copy of the associated isl::ctx is saved (if needed).
9193f9bf9f4Spatacca * If any failure occurs, either during the check for the inputs or
9203f9bf9f4Spatacca * during the isl function call, an exception is thrown.
9213f9bf9f4Spatacca * During the function call, isl is made not to print any error message
9223f9bf9f4Spatacca * because the error message is included in the exception.
9233f9bf9f4Spatacca */
print_method(const Method & method)9243f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_method(const Method &method)
9253f9bf9f4Spatacca {
9263f9bf9f4Spatacca string methodname = method.fd->getName().str();
9273f9bf9f4Spatacca int num_params = method.c_num_params();
9283f9bf9f4Spatacca
9293f9bf9f4Spatacca osprintf(os, "\n");
9303f9bf9f4Spatacca print_full_method_header(method);
9313f9bf9f4Spatacca osprintf(os, "{\n");
9323f9bf9f4Spatacca print_argument_validity_check(method);
9333f9bf9f4Spatacca print_save_ctx(method);
9343f9bf9f4Spatacca print_on_error_continue();
9353f9bf9f4Spatacca
936*a749e09eSMichael Kruse for (const auto &callback : method.callbacks)
937*a749e09eSMichael Kruse print_callback_local(callback);
9383f9bf9f4Spatacca
9393f9bf9f4Spatacca osprintf(os, " auto res = %s", methodname.c_str());
9403f9bf9f4Spatacca
941*a749e09eSMichael Kruse method.print_fd_arg_list(os, 0, num_params, [&] (int i, int arg) {
9423f9bf9f4Spatacca method.print_param_use(os, i);
9433f9bf9f4Spatacca });
9443f9bf9f4Spatacca osprintf(os, ";\n");
9453f9bf9f4Spatacca
9463f9bf9f4Spatacca print_exceptional_execution_check(method);
9473f9bf9f4Spatacca if (method.kind == Method::Kind::constructor) {
9483f9bf9f4Spatacca osprintf(os, " ptr = res;\n");
9493f9bf9f4Spatacca } else {
9503f9bf9f4Spatacca print_method_return(method);
9513f9bf9f4Spatacca }
9523f9bf9f4Spatacca
9533f9bf9f4Spatacca osprintf(os, "}\n");
9543f9bf9f4Spatacca }
9553f9bf9f4Spatacca
9563f9bf9f4Spatacca /* Convert argument of type "src" to "dst", with a name specified by "dst".
9573f9bf9f4Spatacca *
9583f9bf9f4Spatacca * If "src" is the same as "dst", then no argument conversion is needed.
9593f9bf9f4Spatacca *
9603f9bf9f4Spatacca * Otherwise, call the conversion function
9613f9bf9f4Spatacca * with as arguments the isl_ctx of the object and the argument name,
9623f9bf9f4Spatacca * or simply the argument name if the source type is an isl type.
9633f9bf9f4Spatacca * This means this isl_ctx should be available.
9643f9bf9f4Spatacca */
print_arg_conversion(ParmVarDecl * dst,ParmVarDecl * src)9653f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_arg_conversion(ParmVarDecl *dst,
9663f9bf9f4Spatacca ParmVarDecl *src)
9673f9bf9f4Spatacca {
9683f9bf9f4Spatacca std::string name = dst->getName().str();
9693f9bf9f4Spatacca QualType type = dst->getOriginalType();
9703f9bf9f4Spatacca string cpptype = generator.param2cpp(type);
9713f9bf9f4Spatacca
9723f9bf9f4Spatacca if (dst == src)
9733f9bf9f4Spatacca os << name;
9743f9bf9f4Spatacca else if (is_isl_type(src->getOriginalType()))
9753f9bf9f4Spatacca os << cpptype << "(" << name << ")";
9763f9bf9f4Spatacca else
9773f9bf9f4Spatacca os << cpptype << "(ctx(), " << name << ")";
9783f9bf9f4Spatacca }
9793f9bf9f4Spatacca
9803f9bf9f4Spatacca /* Print a definition for "method",
9813f9bf9f4Spatacca * where "this" or at least one of the argument types needs to be converted.
9823f9bf9f4Spatacca *
9833f9bf9f4Spatacca * "method" is assumed to be a member method.
9843f9bf9f4Spatacca *
9853f9bf9f4Spatacca * The generated method performs the required conversion(s) and
9863f9bf9f4Spatacca * calls the method generated without conversions.
9873f9bf9f4Spatacca *
9883f9bf9f4Spatacca * Perform a conversion from the argument in the method declaration
9893f9bf9f4Spatacca * (as specified by Method::get_param) to the argument of the C function,
9903f9bf9f4Spatacca * if needed.
9913f9bf9f4Spatacca * Such a conversion may require the isl_ctx to be available.
9923f9bf9f4Spatacca * In order to be able to use this isl_ctx, the current object needs
9933f9bf9f4Spatacca * to valid. The validity of other arguments is checked
9943f9bf9f4Spatacca * by the called method.
9953f9bf9f4Spatacca */
print_method(const ConversionMethod & method)9963f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_method(
9973f9bf9f4Spatacca const ConversionMethod &method)
9983f9bf9f4Spatacca {
9993f9bf9f4Spatacca if (method.kind != Method::Kind::member_method)
10003f9bf9f4Spatacca die("Automatic conversion currently only supported "
10013f9bf9f4Spatacca "for object methods");
10023f9bf9f4Spatacca
10033f9bf9f4Spatacca osprintf(os, "\n");
10043f9bf9f4Spatacca print_full_method_header(method);
10053f9bf9f4Spatacca osprintf(os, "{\n");
10063f9bf9f4Spatacca print_check_ptr("ptr");
10073f9bf9f4Spatacca osprintf(os, " return ");
10083f9bf9f4Spatacca method.print_call(os, generator.isl_namespace());
1009*a749e09eSMichael Kruse method.print_cpp_arg_list(os, [&] (int i, int arg) {
10103f9bf9f4Spatacca ParmVarDecl *param = method.fd->getParamDecl(i);
10113f9bf9f4Spatacca
10123f9bf9f4Spatacca print_arg_conversion(param, method.get_param(i));
10133f9bf9f4Spatacca });
10143f9bf9f4Spatacca osprintf(os, ";\n");
10153f9bf9f4Spatacca osprintf(os, "}\n");
10163f9bf9f4Spatacca }
10173f9bf9f4Spatacca
1018*a749e09eSMichael Kruse /* Print a definition for a constructor for the "id" class
1019*a749e09eSMichael Kruse * that takes a user object.
1020*a749e09eSMichael Kruse *
1021*a749e09eSMichael Kruse * The user object is taken as a std::any and copied into
1022*a749e09eSMichael Kruse * a new std::any object on the heap.
1023*a749e09eSMichael Kruse * A pointer to this heap object is stored in the isl_id and
1024*a749e09eSMichael Kruse * is scheduled to be freed when the reference count of the isl_id
1025*a749e09eSMichael Kruse * drops to zero.
1026*a749e09eSMichael Kruse * If the allocation of the isl_id fails, then the heap object
1027*a749e09eSMichael Kruse * will not be freed automatically, so it needs to be freed manually.
1028*a749e09eSMichael Kruse *
1029*a749e09eSMichael Kruse * Unless checked C++ bindings are being generated,
1030*a749e09eSMichael Kruse * the ctx argument is copied into the save_ctx variable
1031*a749e09eSMichael Kruse * for use by print_throw_last_error, which throws an exception
1032*a749e09eSMichael Kruse * if the construction fails.
1033*a749e09eSMichael Kruse * During the function call, isl is made not to print any error message
1034*a749e09eSMichael Kruse * because the error message is included in the exception.
1035*a749e09eSMichael Kruse */
print_id_constructor_user()1036*a749e09eSMichael Kruse void plain_cpp_generator::impl_printer::print_id_constructor_user()
1037*a749e09eSMichael Kruse {
1038*a749e09eSMichael Kruse print_id_constructor_user_header();
1039*a749e09eSMichael Kruse os << "{\n";
1040*a749e09eSMichael Kruse if (!generator.checked) {
1041*a749e09eSMichael Kruse print_save_ctx("ctx");
1042*a749e09eSMichael Kruse print_on_error_continue();
1043*a749e09eSMichael Kruse }
1044*a749e09eSMichael Kruse os << " std::any *p = new std::any(any);\n";
1045*a749e09eSMichael Kruse os << " auto res = isl_id_alloc(ctx.get(), str.c_str(), p);\n";
1046*a749e09eSMichael Kruse os << " res = isl_id_set_free_user(res, &ctx::free_user);\n";
1047*a749e09eSMichael Kruse os << " if (!res) {\n";
1048*a749e09eSMichael Kruse os << " delete p;\n";
1049*a749e09eSMichael Kruse if (!generator.checked)
1050*a749e09eSMichael Kruse print_throw_last_error(os);
1051*a749e09eSMichael Kruse os << " }\n";
1052*a749e09eSMichael Kruse os << " ptr = res;\n";
1053*a749e09eSMichael Kruse os << "}\n";
1054*a749e09eSMichael Kruse }
1055*a749e09eSMichael Kruse
1056*a749e09eSMichael Kruse /* Print a definition for an "id" method
1057*a749e09eSMichael Kruse * for retrieving the user object associated to the identifier.
1058*a749e09eSMichael Kruse * If "optional" is set, the method returns a std::optional user object.
1059*a749e09eSMichael Kruse * The returned object is of a type specified by template parameter T.
1060*a749e09eSMichael Kruse *
1061*a749e09eSMichael Kruse * The isl_id needs to have been created by the constructor generated
1062*a749e09eSMichael Kruse * by print_id_constructor_user. That is, it needs to have a user pointer and
1063*a749e09eSMichael Kruse * it needs to have its free_user callback set to &ctx::free_user.
1064*a749e09eSMichael Kruse * The object stored in the std::any also needs to be of the required type.
1065*a749e09eSMichael Kruse *
1066*a749e09eSMichael Kruse * If "optional" is set, return a std::nullopt if any of the checks fail.
1067*a749e09eSMichael Kruse * Otherwise, throw an exception_invalid (or call isl_die and
1068*a749e09eSMichael Kruse * return a default T in the checked C++ bindings).
1069*a749e09eSMichael Kruse */
print_id_user(bool optional)1070*a749e09eSMichael Kruse void plain_cpp_generator::impl_printer::print_id_user(bool optional)
1071*a749e09eSMichael Kruse {
1072*a749e09eSMichael Kruse auto fail = [&] (const char *msg) {
1073*a749e09eSMichael Kruse if (optional)
1074*a749e09eSMichael Kruse os << " return std::nullopt;\n";
1075*a749e09eSMichael Kruse else
1076*a749e09eSMichael Kruse generator.print_invalid(os, 4, msg, "return T()");
1077*a749e09eSMichael Kruse };
1078*a749e09eSMichael Kruse os << "\n";
1079*a749e09eSMichael Kruse print_id_user_header(optional);
1080*a749e09eSMichael Kruse os << "{\n";
1081*a749e09eSMichael Kruse print_check_ptr("ptr");
1082*a749e09eSMichael Kruse os << " std::any *p = (std::any *) isl_id_get_user(ptr);\n";
1083*a749e09eSMichael Kruse os << " if (!p)\n";
1084*a749e09eSMichael Kruse fail("no user pointer");
1085*a749e09eSMichael Kruse os << " if (isl_id_get_free_user(ptr) != &ctx::free_user)\n";
1086*a749e09eSMichael Kruse fail("user pointer not attached by C++ interface");
1087*a749e09eSMichael Kruse os << " T *res = std::any_cast<T>(p);\n";
1088*a749e09eSMichael Kruse os << " if (!res)\n";
1089*a749e09eSMichael Kruse fail("user pointer not of given type");
1090*a749e09eSMichael Kruse os << " return *res;\n";
1091*a749e09eSMichael Kruse os << "}\n";
1092*a749e09eSMichael Kruse }
1093*a749e09eSMichael Kruse
10943f9bf9f4Spatacca /* Print implementation of copy assignment operator.
10953f9bf9f4Spatacca *
10963f9bf9f4Spatacca * If the class has any persistent callbacks, then copy them
10973f9bf9f4Spatacca * from the original object.
10983f9bf9f4Spatacca */
print_copy_assignment()10993f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_copy_assignment()
11003f9bf9f4Spatacca {
11013f9bf9f4Spatacca const char *name = clazz.name.c_str();
11023f9bf9f4Spatacca const char *cppname = cppstring.c_str();
11033f9bf9f4Spatacca
11043f9bf9f4Spatacca osprintf(os, "\n");
11053f9bf9f4Spatacca osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname,
11063f9bf9f4Spatacca cppname, cppname);
11073f9bf9f4Spatacca osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name);
11083f9bf9f4Spatacca if (clazz.has_persistent_callbacks())
11093f9bf9f4Spatacca osprintf(os, " copy_callbacks(obj);\n");
11103f9bf9f4Spatacca osprintf(os, " return *this;\n");
11113f9bf9f4Spatacca osprintf(os, "}\n");
11123f9bf9f4Spatacca }
11133f9bf9f4Spatacca
11143f9bf9f4Spatacca /* Print implementation of destructor.
11153f9bf9f4Spatacca *
11163f9bf9f4Spatacca * No explicit destructor is needed for type based subclasses.
11173f9bf9f4Spatacca */
print_destructor()11183f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_destructor()
11193f9bf9f4Spatacca {
11203f9bf9f4Spatacca const char *name = clazz.name.c_str();
11213f9bf9f4Spatacca const char *cppname = cppstring.c_str();
11223f9bf9f4Spatacca
11233f9bf9f4Spatacca if (clazz.is_type_subclass())
11243f9bf9f4Spatacca return;
11253f9bf9f4Spatacca
11263f9bf9f4Spatacca osprintf(os, "\n");
11273f9bf9f4Spatacca osprintf(os, "%s::~%s() {\n", cppname, cppname);
11283f9bf9f4Spatacca osprintf(os, " if (ptr)\n");
11293f9bf9f4Spatacca osprintf(os, " %s_free(ptr);\n", name);
11303f9bf9f4Spatacca osprintf(os, "}\n");
11313f9bf9f4Spatacca }
11323f9bf9f4Spatacca
11333f9bf9f4Spatacca /* Print a check that the persistent callback corresponding to "fd"
11343f9bf9f4Spatacca * is not set, throwing an exception (or printing an error message
11353f9bf9f4Spatacca * and returning nullptr) if it is set.
11363f9bf9f4Spatacca */
print_check_no_persistent_callback(ostream & os,const isl_class & clazz,FunctionDecl * fd)11373f9bf9f4Spatacca void plain_cpp_generator::print_check_no_persistent_callback(ostream &os,
11383f9bf9f4Spatacca const isl_class &clazz, FunctionDecl *fd)
11393f9bf9f4Spatacca {
11403f9bf9f4Spatacca string callback_name = clazz.persistent_callback_name(fd);
11413f9bf9f4Spatacca
11423f9bf9f4Spatacca osprintf(os, " if (%s_data)\n", callback_name.c_str());
11433f9bf9f4Spatacca print_invalid(os, 4, "cannot release object with persistent callbacks",
11443f9bf9f4Spatacca "return nullptr");
11453f9bf9f4Spatacca }
11463f9bf9f4Spatacca
11473f9bf9f4Spatacca /* Print implementation of ptr() functions.
11483f9bf9f4Spatacca * Since type based subclasses share the pointer with their superclass,
11493f9bf9f4Spatacca * they can also reuse these functions from the superclass.
11503f9bf9f4Spatacca *
11513f9bf9f4Spatacca * If an object has persistent callbacks set, then the underlying
11523f9bf9f4Spatacca * C object pointer cannot be released because it references data
11533f9bf9f4Spatacca * in the C++ object.
11543f9bf9f4Spatacca */
print_ptr()11553f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_ptr()
11563f9bf9f4Spatacca {
11573f9bf9f4Spatacca const char *name = clazz.name.c_str();
11583f9bf9f4Spatacca const char *cppname = cppstring.c_str();
11593f9bf9f4Spatacca set<FunctionDecl *>::const_iterator in;
11603f9bf9f4Spatacca const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
11613f9bf9f4Spatacca
11623f9bf9f4Spatacca if (clazz.is_type_subclass())
11633f9bf9f4Spatacca return;
11643f9bf9f4Spatacca
11653f9bf9f4Spatacca osprintf(os, "\n");
11663f9bf9f4Spatacca osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
11673f9bf9f4Spatacca osprintf(os, " return %s_copy(ptr);\n", name);
11683f9bf9f4Spatacca osprintf(os, "}\n\n");
11693f9bf9f4Spatacca osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
11703f9bf9f4Spatacca osprintf(os, " return ptr;\n");
11713f9bf9f4Spatacca osprintf(os, "}\n\n");
11723f9bf9f4Spatacca osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
11733f9bf9f4Spatacca for (in = callbacks.begin(); in != callbacks.end(); ++in)
11743f9bf9f4Spatacca generator.print_check_no_persistent_callback(os, clazz, *in);
11753f9bf9f4Spatacca osprintf(os, " %s *tmp = ptr;\n", name);
11763f9bf9f4Spatacca osprintf(os, " ptr = nullptr;\n");
11773f9bf9f4Spatacca osprintf(os, " return tmp;\n");
11783f9bf9f4Spatacca osprintf(os, "}\n\n");
11793f9bf9f4Spatacca osprintf(os, "bool %s::is_null() const {\n", cppname);
11803f9bf9f4Spatacca osprintf(os, " return ptr == nullptr;\n");
11813f9bf9f4Spatacca osprintf(os, "}\n");
11823f9bf9f4Spatacca }
11833f9bf9f4Spatacca
11843f9bf9f4Spatacca /* Print implementations for the "as" and "isa" methods, if the printed class
11853f9bf9f4Spatacca * is a superclass with a type function.
11863f9bf9f4Spatacca *
11873f9bf9f4Spatacca * "isa" checks whether an object is of a given subclass type.
11883f9bf9f4Spatacca * "isa_type" does the same, but gets passed the value of the type field
11893f9bf9f4Spatacca * of the subclass as a function argument and the type of this field
11903f9bf9f4Spatacca * as a template argument.
11913f9bf9f4Spatacca * "as" casts an object to a given subclass type, erroring out
11923f9bf9f4Spatacca * if the object is not of the given type.
11933f9bf9f4Spatacca *
11943f9bf9f4Spatacca * If the input is an invalid object, then these methods raise
11953f9bf9f4Spatacca * an exception.
11963f9bf9f4Spatacca * If checked bindings are being generated,
11973f9bf9f4Spatacca * then an invalid boolean or object is returned instead.
11983f9bf9f4Spatacca */
print_downcast()11993f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_downcast()
12003f9bf9f4Spatacca {
12013f9bf9f4Spatacca const char *cppname = cppstring.c_str();
12023f9bf9f4Spatacca
12033f9bf9f4Spatacca if (!clazz.fn_type)
12043f9bf9f4Spatacca return;
12053f9bf9f4Spatacca
12063f9bf9f4Spatacca osprintf(os, "\n");
12073f9bf9f4Spatacca osprintf(os, "template <typename T, typename>\n");
12083f9bf9f4Spatacca osprintf(os, "%s %s::isa_type(T subtype) const\n",
12093f9bf9f4Spatacca generator.isl_bool2cpp().c_str(), cppname);
12103f9bf9f4Spatacca osprintf(os, "{\n");
12113f9bf9f4Spatacca osprintf(os, " if (is_null())\n");
12123f9bf9f4Spatacca if (generator.checked)
12133f9bf9f4Spatacca osprintf(os, " return boolean();\n");
12143f9bf9f4Spatacca else
12153f9bf9f4Spatacca print_throw_NULL_input(os);
12163f9bf9f4Spatacca osprintf(os, " return %s(get()) == subtype;\n",
12173f9bf9f4Spatacca clazz.fn_type->getNameAsString().c_str());
12183f9bf9f4Spatacca osprintf(os, "}\n");
12193f9bf9f4Spatacca
12203f9bf9f4Spatacca osprintf(os, "template <class T>\n");
12213f9bf9f4Spatacca osprintf(os, "%s %s::isa() const\n",
12223f9bf9f4Spatacca generator.isl_bool2cpp().c_str(), cppname);
12233f9bf9f4Spatacca osprintf(os, "{\n");
12243f9bf9f4Spatacca osprintf(os, " return isa_type<decltype(T::type)>(T::type);\n");
12253f9bf9f4Spatacca osprintf(os, "}\n");
12263f9bf9f4Spatacca
12273f9bf9f4Spatacca osprintf(os, "template <class T>\n");
12283f9bf9f4Spatacca osprintf(os, "T %s::as() const\n", cppname);
12293f9bf9f4Spatacca osprintf(os, "{\n");
12303f9bf9f4Spatacca if (generator.checked)
12313f9bf9f4Spatacca osprintf(os, " if (isa<T>().is_false())\n");
12323f9bf9f4Spatacca else
12333f9bf9f4Spatacca osprintf(os, " if (!isa<T>())\n");
12343f9bf9f4Spatacca generator.print_invalid(os, 4, "not an object of the requested subtype",
12353f9bf9f4Spatacca "return T()");
12363f9bf9f4Spatacca osprintf(os, " return T(copy());\n");
12373f9bf9f4Spatacca osprintf(os, "}\n");
12383f9bf9f4Spatacca }
12393f9bf9f4Spatacca
12403f9bf9f4Spatacca /* Print the implementation of the ctx method.
12413f9bf9f4Spatacca */
print_ctx()12423f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_ctx()
12433f9bf9f4Spatacca {
12443f9bf9f4Spatacca const char *name = clazz.name.c_str();
12453f9bf9f4Spatacca const char *cppname = cppstring.c_str();
12463f9bf9f4Spatacca std::string ns = generator.isl_namespace();
12473f9bf9f4Spatacca
12483f9bf9f4Spatacca osprintf(os, "\n");
12493f9bf9f4Spatacca osprintf(os, "%sctx %s::ctx() const {\n", ns.c_str(), cppname);
12503f9bf9f4Spatacca osprintf(os, " return %sctx(%s_get_ctx(ptr));\n", ns.c_str(), name);
12513f9bf9f4Spatacca osprintf(os, "}\n");
12523f9bf9f4Spatacca }
12533f9bf9f4Spatacca
1254*a749e09eSMichael Kruse /* Print a separator between groups of method definitions.
1255*a749e09eSMichael Kruse *
1256*a749e09eSMichael Kruse * No additional separator is required between method definitions.
1257*a749e09eSMichael Kruse */
print_method_separator()1258*a749e09eSMichael Kruse void plain_cpp_generator::impl_printer::print_method_separator()
1259*a749e09eSMichael Kruse {
1260*a749e09eSMichael Kruse }
1261*a749e09eSMichael Kruse
12623f9bf9f4Spatacca /* Print the implementations of the methods needed for the persistent callbacks
12633f9bf9f4Spatacca * of the class.
12643f9bf9f4Spatacca */
print_persistent_callbacks()12653f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_persistent_callbacks()
12663f9bf9f4Spatacca {
12673f9bf9f4Spatacca const char *cppname = cppstring.c_str();
12683f9bf9f4Spatacca string classname = type2cpp(clazz);
12693f9bf9f4Spatacca
12703f9bf9f4Spatacca if (!clazz.has_persistent_callbacks())
12713f9bf9f4Spatacca return;
12723f9bf9f4Spatacca
12733f9bf9f4Spatacca osprintf(os, "\n");
12743f9bf9f4Spatacca osprintf(os, "%s &%s::copy_callbacks(const %s &obj)\n",
12753f9bf9f4Spatacca cppname, classname.c_str(), cppname);
12763f9bf9f4Spatacca osprintf(os, "{\n");
12773f9bf9f4Spatacca for (const auto &callback : clazz.persistent_callbacks) {
12783f9bf9f4Spatacca string callback_name = clazz.persistent_callback_name(callback);
12793f9bf9f4Spatacca
12803f9bf9f4Spatacca osprintf(os, " %s_data = obj.%s_data;\n",
12813f9bf9f4Spatacca callback_name.c_str(), callback_name.c_str());
12823f9bf9f4Spatacca }
12833f9bf9f4Spatacca osprintf(os, " return *this;\n");
12843f9bf9f4Spatacca osprintf(os, "}\n");
12853f9bf9f4Spatacca
12863f9bf9f4Spatacca for (const auto &callback : clazz.persistent_callbacks)
12873f9bf9f4Spatacca print_set_persistent_callback(Method(clazz, callback));
12883f9bf9f4Spatacca }
12893f9bf9f4Spatacca
12903f9bf9f4Spatacca /* Print a definition for the "get" method "fd" in class "clazz",
12913f9bf9f4Spatacca * using a name that includes the "get_" prefix, to "os".
12923f9bf9f4Spatacca *
12933f9bf9f4Spatacca * This definition simply calls the variant without the "get_" prefix and
12943f9bf9f4Spatacca * returns its result.
12953f9bf9f4Spatacca * Note that static methods are not considered to be "get" methods.
12963f9bf9f4Spatacca */
print_get_method(FunctionDecl * fd)12973f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_get_method(FunctionDecl *fd)
12983f9bf9f4Spatacca {
12993f9bf9f4Spatacca string get_name = clazz.base_method_name(fd);
13003f9bf9f4Spatacca string name = clazz.method_name(fd);
13013f9bf9f4Spatacca int num_params = fd->getNumParams();
13023f9bf9f4Spatacca
13033f9bf9f4Spatacca osprintf(os, "\n");
13043f9bf9f4Spatacca print_full_method_header(Method(clazz, fd, get_name));
13053f9bf9f4Spatacca osprintf(os, "{\n");
13063f9bf9f4Spatacca osprintf(os, " return %s(", name.c_str());
13073f9bf9f4Spatacca for (int i = 1; i < num_params; ++i) {
13083f9bf9f4Spatacca ParmVarDecl *param = fd->getParamDecl(i);
13093f9bf9f4Spatacca
13103f9bf9f4Spatacca if (i != 1)
13113f9bf9f4Spatacca osprintf(os, ", ");
13123f9bf9f4Spatacca osprintf(os, "%s", param->getName().str().c_str());
13133f9bf9f4Spatacca }
13143f9bf9f4Spatacca osprintf(os, ");\n");
13153f9bf9f4Spatacca osprintf(os, "}\n");
13163f9bf9f4Spatacca }
13173f9bf9f4Spatacca
13183f9bf9f4Spatacca /* Print code that checks that all isl object arguments to "method" are valid
13193f9bf9f4Spatacca * (not NULL) and throws an exception if they are not.
13203f9bf9f4Spatacca *
13213f9bf9f4Spatacca * If checked bindings are being generated,
13223f9bf9f4Spatacca * then no such check is performed.
13233f9bf9f4Spatacca */
print_argument_validity_check(const Method & method)13243f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_argument_validity_check(
13253f9bf9f4Spatacca const Method &method)
13263f9bf9f4Spatacca {
13273f9bf9f4Spatacca int n;
13283f9bf9f4Spatacca bool first = true;
13293f9bf9f4Spatacca
13303f9bf9f4Spatacca if (generator.checked)
13313f9bf9f4Spatacca return;
13323f9bf9f4Spatacca
13333f9bf9f4Spatacca n = method.num_params();
13343f9bf9f4Spatacca for (int i = 0; i < n; ++i) {
13353f9bf9f4Spatacca bool is_this;
13363f9bf9f4Spatacca ParmVarDecl *param = method.fd->getParamDecl(i);
13373f9bf9f4Spatacca string name = param->getName().str();
13383f9bf9f4Spatacca const char *name_str = name.c_str();
13393f9bf9f4Spatacca QualType type = param->getOriginalType();
13403f9bf9f4Spatacca
13413f9bf9f4Spatacca is_this = i == 0 && method.kind == Method::Kind::member_method;
13423f9bf9f4Spatacca if (!is_this && (is_isl_ctx(type) || !is_isl_type(type)))
13433f9bf9f4Spatacca continue;
13443f9bf9f4Spatacca
13453f9bf9f4Spatacca if (first)
13463f9bf9f4Spatacca osprintf(os, " if (");
13473f9bf9f4Spatacca else
13483f9bf9f4Spatacca osprintf(os, " || ");
13493f9bf9f4Spatacca
13503f9bf9f4Spatacca if (is_this)
13513f9bf9f4Spatacca osprintf(os, "!ptr");
13523f9bf9f4Spatacca else
13533f9bf9f4Spatacca osprintf(os, "%s.is_null()", name_str);
13543f9bf9f4Spatacca
13553f9bf9f4Spatacca first = false;
13563f9bf9f4Spatacca }
13573f9bf9f4Spatacca if (first)
13583f9bf9f4Spatacca return;
13593f9bf9f4Spatacca osprintf(os, ")\n");
13603f9bf9f4Spatacca print_throw_NULL_input(os);
13613f9bf9f4Spatacca }
13623f9bf9f4Spatacca
1363*a749e09eSMichael Kruse /* Print code for saving a copy of "ctx" in a "saved_ctx" variable.
1364*a749e09eSMichael Kruse */
print_save_ctx(const std::string & ctx)1365*a749e09eSMichael Kruse void plain_cpp_generator::impl_printer::print_save_ctx(const std::string &ctx)
1366*a749e09eSMichael Kruse {
1367*a749e09eSMichael Kruse os << " auto saved_ctx = " << ctx << ";\n";
1368*a749e09eSMichael Kruse }
1369*a749e09eSMichael Kruse
13703f9bf9f4Spatacca /* Print code for saving a copy of the isl::ctx available at the start
13713f9bf9f4Spatacca * of the method "method" in a "saved_ctx" variable,
13723f9bf9f4Spatacca * for use in exception handling.
13733f9bf9f4Spatacca *
13743f9bf9f4Spatacca * If checked bindings are being generated,
13753f9bf9f4Spatacca * then the "saved_ctx" variable is not needed.
13763f9bf9f4Spatacca * If "method" is a member function, then obtain the isl_ctx from
13773f9bf9f4Spatacca * the "this" object.
13783f9bf9f4Spatacca * If the first argument of the method is an isl::ctx, then use that one.
13793f9bf9f4Spatacca * Otherwise, save a copy of the isl::ctx associated to the first argument
13803f9bf9f4Spatacca * of isl object type.
13813f9bf9f4Spatacca */
print_save_ctx(const Method & method)13823f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_save_ctx(const Method &method)
13833f9bf9f4Spatacca {
13843f9bf9f4Spatacca int n;
13853f9bf9f4Spatacca ParmVarDecl *param = method.fd->getParamDecl(0);
13863f9bf9f4Spatacca QualType type = param->getOriginalType();
13873f9bf9f4Spatacca
13883f9bf9f4Spatacca if (generator.checked)
13893f9bf9f4Spatacca return;
1390*a749e09eSMichael Kruse if (method.kind == Method::Kind::member_method)
1391*a749e09eSMichael Kruse return print_save_ctx("ctx()");
1392*a749e09eSMichael Kruse if (is_isl_ctx(type))
1393*a749e09eSMichael Kruse return print_save_ctx(param->getName().str());
13943f9bf9f4Spatacca n = method.num_params();
13953f9bf9f4Spatacca for (int i = 0; i < n; ++i) {
13963f9bf9f4Spatacca ParmVarDecl *param = method.fd->getParamDecl(i);
13973f9bf9f4Spatacca QualType type = param->getOriginalType();
13983f9bf9f4Spatacca
13993f9bf9f4Spatacca if (!is_isl_type(type))
14003f9bf9f4Spatacca continue;
1401*a749e09eSMichael Kruse print_save_ctx(param->getName().str() + ".ctx()");
14023f9bf9f4Spatacca return;
14033f9bf9f4Spatacca }
14043f9bf9f4Spatacca }
14053f9bf9f4Spatacca
14063f9bf9f4Spatacca /* Print code to make isl not print an error message when an error occurs
14073f9bf9f4Spatacca * within the current scope (if exceptions are available),
14083f9bf9f4Spatacca * since the error message will be included in the exception.
14093f9bf9f4Spatacca * If exceptions are not available, then exception::on_error
14103f9bf9f4Spatacca * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead.
14113f9bf9f4Spatacca *
14123f9bf9f4Spatacca * If checked bindings are being generated,
14133f9bf9f4Spatacca * then leave it to the user to decide what isl should do on error.
14143f9bf9f4Spatacca * Otherwise, assume that a valid isl::ctx is available
14153f9bf9f4Spatacca * in the "saved_ctx" variable,
14163f9bf9f4Spatacca * e.g., through a prior call to print_save_ctx.
14173f9bf9f4Spatacca */
print_on_error_continue()14183f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_on_error_continue()
14193f9bf9f4Spatacca {
14203f9bf9f4Spatacca if (generator.checked)
14213f9bf9f4Spatacca return;
14223f9bf9f4Spatacca osprintf(os, " options_scoped_set_on_error saved_on_error(saved_ctx, "
14233f9bf9f4Spatacca "exception::on_error);\n");
14243f9bf9f4Spatacca }
14253f9bf9f4Spatacca
14263f9bf9f4Spatacca /* Print code to "os" that checks whether any of the persistent callbacks
14273f9bf9f4Spatacca * of the class of "method" is set and if it failed with an exception.
14283f9bf9f4Spatacca * If so, the "eptr" in the corresponding data structure contains the exception
14293f9bf9f4Spatacca * that was caught and that needs to be rethrown.
14303f9bf9f4Spatacca * This field is cleared because the callback and its data may get reused.
14313f9bf9f4Spatacca *
14323f9bf9f4Spatacca * The check only needs to be generated for member methods since
14333f9bf9f4Spatacca * an object is needed for any of the persistent callbacks to be set.
14343f9bf9f4Spatacca */
print_persistent_callback_exceptional_execution_check(ostream & os,const Method & method)14353f9bf9f4Spatacca static void print_persistent_callback_exceptional_execution_check(ostream &os,
14363f9bf9f4Spatacca const Method &method)
14373f9bf9f4Spatacca {
14383f9bf9f4Spatacca if (method.kind != Method::Kind::member_method)
14393f9bf9f4Spatacca return;
14403f9bf9f4Spatacca
14413f9bf9f4Spatacca for (const auto &pcb : method.clazz.persistent_callbacks) {
14423f9bf9f4Spatacca auto callback_name = method.clazz.persistent_callback_name(pcb);
14433f9bf9f4Spatacca
14443f9bf9f4Spatacca osprintf(os, " if (%s_data && %s_data->eptr) {\n",
14453f9bf9f4Spatacca callback_name.c_str(), callback_name.c_str());
14463f9bf9f4Spatacca osprintf(os, " std::exception_ptr eptr = %s_data->eptr;\n",
14473f9bf9f4Spatacca callback_name.c_str());
14483f9bf9f4Spatacca osprintf(os, " %s_data->eptr = nullptr;\n",
14493f9bf9f4Spatacca callback_name.c_str());
14503f9bf9f4Spatacca osprintf(os, " std::rethrow_exception(eptr);\n");
14513f9bf9f4Spatacca osprintf(os, " }\n");
14523f9bf9f4Spatacca }
14533f9bf9f4Spatacca }
14543f9bf9f4Spatacca
14553f9bf9f4Spatacca /* Print code that checks whether the execution of the core of "method"
14563f9bf9f4Spatacca * was successful.
14573f9bf9f4Spatacca *
14583f9bf9f4Spatacca * If checked bindings are being generated,
14593f9bf9f4Spatacca * then no checks are performed.
14603f9bf9f4Spatacca *
14613f9bf9f4Spatacca * Otherwise, first check if any of the callbacks failed with
14623f9bf9f4Spatacca * an exception. If so, the "eptr" in the corresponding data structure
14633f9bf9f4Spatacca * contains the exception that was caught and that needs to be rethrown.
14643f9bf9f4Spatacca * Then check if the function call failed in any other way and throw
14653f9bf9f4Spatacca * the appropriate exception.
14663f9bf9f4Spatacca * In particular, if the return type is isl_stat, isl_bool or isl_size,
14673f9bf9f4Spatacca * then a negative value indicates a failure. If the return type
14683f9bf9f4Spatacca * is an isl type, then a NULL value indicates a failure.
14693f9bf9f4Spatacca * Assume print_save_ctx has made sure that a valid isl::ctx
14703f9bf9f4Spatacca * is available in the "ctx" variable.
14713f9bf9f4Spatacca */
print_exceptional_execution_check(const Method & method)14723f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_exceptional_execution_check(
14733f9bf9f4Spatacca const Method &method)
14743f9bf9f4Spatacca {
14753f9bf9f4Spatacca bool check_null, check_neg;
14763f9bf9f4Spatacca QualType return_type = method.fd->getReturnType();
14773f9bf9f4Spatacca
14783f9bf9f4Spatacca if (generator.checked)
14793f9bf9f4Spatacca return;
14803f9bf9f4Spatacca
14813f9bf9f4Spatacca print_persistent_callback_exceptional_execution_check(os, method);
14823f9bf9f4Spatacca
1483*a749e09eSMichael Kruse for (const auto &callback : method.callbacks) {
14843f9bf9f4Spatacca std::string name;
14853f9bf9f4Spatacca
1486*a749e09eSMichael Kruse name = callback->getName().str();
14873f9bf9f4Spatacca osprintf(os, " if (%s_data.eptr)\n", name.c_str());
14883f9bf9f4Spatacca osprintf(os, " std::rethrow_exception(%s_data.eptr);\n",
14893f9bf9f4Spatacca name.c_str());
14903f9bf9f4Spatacca }
14913f9bf9f4Spatacca
14923f9bf9f4Spatacca check_neg = is_isl_neg_error(return_type);
14933f9bf9f4Spatacca check_null = is_isl_type(return_type);
14943f9bf9f4Spatacca if (!check_null && !check_neg)
14953f9bf9f4Spatacca return;
14963f9bf9f4Spatacca
14973f9bf9f4Spatacca if (check_neg)
14983f9bf9f4Spatacca osprintf(os, " if (res < 0)\n");
14993f9bf9f4Spatacca else
15003f9bf9f4Spatacca osprintf(os, " if (!res)\n");
15013f9bf9f4Spatacca print_throw_last_error(os);
15023f9bf9f4Spatacca }
15033f9bf9f4Spatacca
15043f9bf9f4Spatacca /* Return a pointer to the appropriate type printer,
15053f9bf9f4Spatacca * i.e., the regular type printer or the checked type printer
15063f9bf9f4Spatacca * depending on the setting of this->checked.
15073f9bf9f4Spatacca */
type_printer()15083f9bf9f4Spatacca std::unique_ptr<cpp_type_printer> plain_cpp_generator::type_printer()
15093f9bf9f4Spatacca {
15103f9bf9f4Spatacca cpp_type_printer *printer;
15113f9bf9f4Spatacca
15123f9bf9f4Spatacca if (checked)
15133f9bf9f4Spatacca printer = new checked_cpp_type_printer();
15143f9bf9f4Spatacca else
15153f9bf9f4Spatacca printer = new cpp_type_printer();
15163f9bf9f4Spatacca
15173f9bf9f4Spatacca return std::unique_ptr<cpp_type_printer>(printer);
15183f9bf9f4Spatacca }
15193f9bf9f4Spatacca
15203f9bf9f4Spatacca /* Return the C++ return type of the method "method".
15213f9bf9f4Spatacca *
15223f9bf9f4Spatacca * Use the appropriate type printer.
15233f9bf9f4Spatacca */
get_return_type(const Method & method)15243f9bf9f4Spatacca std::string plain_cpp_generator::get_return_type(const Method &method)
15253f9bf9f4Spatacca {
15263f9bf9f4Spatacca return type_printer()->return_type(method);
15273f9bf9f4Spatacca }
15283f9bf9f4Spatacca
15293f9bf9f4Spatacca /* Given a method "method" for setting a persistent callback of its class,
15303f9bf9f4Spatacca * print the implementations of the methods needed for that callback.
15313f9bf9f4Spatacca *
15323f9bf9f4Spatacca * In particular, print
15333f9bf9f4Spatacca * - the implementation of a static inline method
15343f9bf9f4Spatacca * for use as the C callback function
15353f9bf9f4Spatacca * - the definition of a private method for setting the callback function
15363f9bf9f4Spatacca * - the public method for constructing a new object with the callback set.
15373f9bf9f4Spatacca */
print_set_persistent_callback(const Method & method)15383f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_set_persistent_callback(
15393f9bf9f4Spatacca const Method &method)
15403f9bf9f4Spatacca {
15413f9bf9f4Spatacca string fullname = method.fd->getName().str();
15423f9bf9f4Spatacca ParmVarDecl *param = persistent_callback_arg(method.fd);
15433f9bf9f4Spatacca string pname;
15443f9bf9f4Spatacca string callback_name = clazz.persistent_callback_name(method.fd);
15453f9bf9f4Spatacca
15463f9bf9f4Spatacca osprintf(os, "\n");
15473f9bf9f4Spatacca print_persistent_callback_prototype(method.fd);
15483f9bf9f4Spatacca osprintf(os, "\n");
15493f9bf9f4Spatacca osprintf(os, "{\n");
15503f9bf9f4Spatacca print_callback_body(2, param, callback_name);
15513f9bf9f4Spatacca osprintf(os, "}\n\n");
15523f9bf9f4Spatacca
15533f9bf9f4Spatacca pname = param->getName().str();
15543f9bf9f4Spatacca print_persistent_callback_setter_prototype(method.fd);
15553f9bf9f4Spatacca osprintf(os, "\n");
15563f9bf9f4Spatacca osprintf(os, "{\n");
15573f9bf9f4Spatacca print_check_ptr_start("ptr");
15583f9bf9f4Spatacca osprintf(os, " %s_data = std::make_shared<struct %s_data>();\n",
15593f9bf9f4Spatacca callback_name.c_str(), callback_name.c_str());
15603f9bf9f4Spatacca osprintf(os, " %s_data->func = %s;\n",
15613f9bf9f4Spatacca callback_name.c_str(), pname.c_str());
15623f9bf9f4Spatacca osprintf(os, " ptr = %s(ptr, &%s, %s_data.get());\n",
15633f9bf9f4Spatacca fullname.c_str(), callback_name.c_str(), callback_name.c_str());
15643f9bf9f4Spatacca print_check_ptr_end("ptr");
15653f9bf9f4Spatacca osprintf(os, "}\n\n");
15663f9bf9f4Spatacca
15673f9bf9f4Spatacca print_full_method_header(method);
15683f9bf9f4Spatacca osprintf(os, "{\n");
15693f9bf9f4Spatacca osprintf(os, " auto copy = *this;\n");
15703f9bf9f4Spatacca osprintf(os, " copy.set_%s_data(%s);\n",
15713f9bf9f4Spatacca callback_name.c_str(), pname.c_str());
15723f9bf9f4Spatacca osprintf(os, " return copy;\n");
15733f9bf9f4Spatacca osprintf(os, "}\n");
15743f9bf9f4Spatacca }
15753f9bf9f4Spatacca
15763f9bf9f4Spatacca /* Print the return statement of the C++ method "method".
15773f9bf9f4Spatacca *
15783f9bf9f4Spatacca * The result of the corresponding isl function is returned as a new
15793f9bf9f4Spatacca * object if the underlying isl function returns an isl_* ptr, as a bool
15803f9bf9f4Spatacca * if the isl function returns an isl_bool, as void if the isl functions
15813f9bf9f4Spatacca * returns an isl_stat,
15823f9bf9f4Spatacca * as std::string if the isl function returns 'const char *', and as
15833f9bf9f4Spatacca * unmodified return value otherwise.
15843f9bf9f4Spatacca * If checked C++ bindings are being generated,
15853f9bf9f4Spatacca * then an isl_bool return type is transformed into a boolean and
15863f9bf9f4Spatacca * an isl_stat into a stat since no exceptions can be generated
15873f9bf9f4Spatacca * on negative results from the isl function.
15883f9bf9f4Spatacca * If the method returns a new instance of the same object type and
15893f9bf9f4Spatacca * if the class has any persistent callbacks, then the data
15903f9bf9f4Spatacca * for these callbacks are copied from the original to the new object.
15913f9bf9f4Spatacca * If "clazz" is a subclass that is based on a type function and
15923f9bf9f4Spatacca * if the return type corresponds to the superclass data type,
15933f9bf9f4Spatacca * then it is replaced by the subclass data type.
15943f9bf9f4Spatacca */
print_method_return(const Method & method)15953f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_method_return(
15963f9bf9f4Spatacca const Method &method)
15973f9bf9f4Spatacca {
15983f9bf9f4Spatacca QualType return_type = method.fd->getReturnType();
15993f9bf9f4Spatacca string rettype_str = generator.get_return_type(method);
16003f9bf9f4Spatacca bool returns_super = method.is_subclass_mutator();
16013f9bf9f4Spatacca
16023f9bf9f4Spatacca if (is_isl_type(return_type) ||
16033f9bf9f4Spatacca (generator.checked && is_isl_neg_error(return_type))) {
16043f9bf9f4Spatacca osprintf(os, " return manage(res)");
16053f9bf9f4Spatacca if (is_mutator(clazz, method.fd) &&
16063f9bf9f4Spatacca clazz.has_persistent_callbacks())
16073f9bf9f4Spatacca osprintf(os, ".copy_callbacks(*this)");
16083f9bf9f4Spatacca if (returns_super)
16093f9bf9f4Spatacca osprintf(os, ".as<%s>()", rettype_str.c_str());
16103f9bf9f4Spatacca osprintf(os, ";\n");
16113f9bf9f4Spatacca } else if (is_isl_stat(return_type)) {
16123f9bf9f4Spatacca osprintf(os, " return;\n");
16133f9bf9f4Spatacca } else if (is_string(return_type)) {
16143f9bf9f4Spatacca osprintf(os, " std::string tmp(res);\n");
16153f9bf9f4Spatacca if (gives(method.fd))
16163f9bf9f4Spatacca osprintf(os, " free(res);\n");
16173f9bf9f4Spatacca osprintf(os, " return tmp;\n");
16183f9bf9f4Spatacca } else {
16193f9bf9f4Spatacca osprintf(os, " return res;\n");
16203f9bf9f4Spatacca }
16213f9bf9f4Spatacca }
16223f9bf9f4Spatacca
16233f9bf9f4Spatacca /* Print the header for "method", including the terminating semicolon
16243f9bf9f4Spatacca * in case of a declaration and a newline.
16253f9bf9f4Spatacca *
16263f9bf9f4Spatacca * Use the appropriate type printer to print argument and return types.
16273f9bf9f4Spatacca */
print_full_method_header(const Method & method)16283f9bf9f4Spatacca void plain_cpp_generator::plain_printer::print_full_method_header(
16293f9bf9f4Spatacca const Method &method)
16303f9bf9f4Spatacca {
16313f9bf9f4Spatacca auto type_printer = generator.type_printer();
16323f9bf9f4Spatacca
16333f9bf9f4Spatacca print_method_header(method, *type_printer);
16343f9bf9f4Spatacca
16353f9bf9f4Spatacca if (declarations)
16363f9bf9f4Spatacca osprintf(os, ";");
16373f9bf9f4Spatacca osprintf(os, "\n");
16383f9bf9f4Spatacca }
16393f9bf9f4Spatacca
16403f9bf9f4Spatacca /* Generate the list of argument types for a callback function of
16413f9bf9f4Spatacca * type "type". If "cpp" is set, then generate the C++ type list, otherwise
16423f9bf9f4Spatacca * the C type list.
16433f9bf9f4Spatacca *
16443f9bf9f4Spatacca * Use the appropriate type printer.
16453f9bf9f4Spatacca * For the plain C++ interface, the argument position is irrelevant,
16463f9bf9f4Spatacca * so simply pass in -1.
16473f9bf9f4Spatacca */
generate_callback_args(QualType type,bool cpp)16483f9bf9f4Spatacca string plain_cpp_generator::generate_callback_args(QualType type, bool cpp)
16493f9bf9f4Spatacca {
16503f9bf9f4Spatacca return type_printer()->generate_callback_args(-1, type, cpp);
16513f9bf9f4Spatacca }
16523f9bf9f4Spatacca
16533f9bf9f4Spatacca /* Generate the full cpp type of a callback function of type "type".
16543f9bf9f4Spatacca *
16553f9bf9f4Spatacca * Use the appropriate type printer.
16563f9bf9f4Spatacca * For the plain C++ interface, the argument position is irrelevant,
16573f9bf9f4Spatacca * so simply pass in -1.
16583f9bf9f4Spatacca */
generate_callback_type(QualType type)16593f9bf9f4Spatacca string plain_cpp_generator::generate_callback_type(QualType type)
16603f9bf9f4Spatacca {
16613f9bf9f4Spatacca return type_printer()->generate_callback_type(-1, type);
16623f9bf9f4Spatacca }
16633f9bf9f4Spatacca
16643f9bf9f4Spatacca /* Print the call to the C++ callback function "call",
16653f9bf9f4Spatacca * with the given indentation, wrapped
16663f9bf9f4Spatacca * for use inside the lambda function that is used as the C callback function,
16673f9bf9f4Spatacca * in the case where checked C++ bindings are being generated.
16683f9bf9f4Spatacca *
16693f9bf9f4Spatacca * In particular, print
16703f9bf9f4Spatacca *
16713f9bf9f4Spatacca * auto ret = @call@;
16723f9bf9f4Spatacca * return ret.release();
16733f9bf9f4Spatacca */
print_wrapped_call_checked(int indent,const string & call)16743f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_wrapped_call_checked(int indent,
16753f9bf9f4Spatacca const string &call)
16763f9bf9f4Spatacca {
16773f9bf9f4Spatacca osprintf(os, indent, "auto ret = %s;\n", call.c_str());
16783f9bf9f4Spatacca osprintf(os, indent, "return ret.release();\n");
16793f9bf9f4Spatacca }
16803f9bf9f4Spatacca
16813f9bf9f4Spatacca /* Print the call to the C++ callback function "call",
16823f9bf9f4Spatacca * with the given indentation and with return type "rtype", wrapped
16833f9bf9f4Spatacca * for use inside the lambda function that is used as the C callback function.
16843f9bf9f4Spatacca *
16853f9bf9f4Spatacca * In particular, print
16863f9bf9f4Spatacca *
16873f9bf9f4Spatacca * ISL_CPP_TRY {
16883f9bf9f4Spatacca * @call@;
16893f9bf9f4Spatacca * return isl_stat_ok;
16903f9bf9f4Spatacca * } ISL_CPP_CATCH_ALL {
16913f9bf9f4Spatacca * data->eptr = std::current_exception();
16923f9bf9f4Spatacca * return isl_stat_error;
16933f9bf9f4Spatacca * }
16943f9bf9f4Spatacca * or
16953f9bf9f4Spatacca * ISL_CPP_TRY {
16963f9bf9f4Spatacca * auto ret = @call@;
16973f9bf9f4Spatacca * return ret ? isl_bool_true : isl_bool_false;
16983f9bf9f4Spatacca * } ISL_CPP_CATCH_ALL {
16993f9bf9f4Spatacca * data->eptr = std::current_exception();
17003f9bf9f4Spatacca * return isl_bool_error;
17013f9bf9f4Spatacca * }
17023f9bf9f4Spatacca * or
17033f9bf9f4Spatacca * ISL_CPP_TRY {
17043f9bf9f4Spatacca * auto ret = @call@;
17053f9bf9f4Spatacca * return ret.release();
17063f9bf9f4Spatacca * } ISL_CPP_CATCH_ALL {
17073f9bf9f4Spatacca * data->eptr = std::current_exception();
17083f9bf9f4Spatacca * return NULL;
17093f9bf9f4Spatacca * }
17103f9bf9f4Spatacca *
17113f9bf9f4Spatacca * depending on the return type.
17123f9bf9f4Spatacca *
17133f9bf9f4Spatacca * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)"
17143f9bf9f4Spatacca * (if exceptions are available).
17153f9bf9f4Spatacca *
17163f9bf9f4Spatacca * If checked C++ bindings are being generated, then
17173f9bf9f4Spatacca * the call is wrapped differently.
17183f9bf9f4Spatacca */
print_wrapped_call(int indent,const string & call,QualType rtype)17193f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_wrapped_call(int indent,
17203f9bf9f4Spatacca const string &call, QualType rtype)
17213f9bf9f4Spatacca {
17223f9bf9f4Spatacca if (generator.checked)
17233f9bf9f4Spatacca return print_wrapped_call_checked(indent, call);
17243f9bf9f4Spatacca
17253f9bf9f4Spatacca osprintf(os, indent, "ISL_CPP_TRY {\n");
17263f9bf9f4Spatacca if (is_isl_stat(rtype))
17273f9bf9f4Spatacca osprintf(os, indent, " %s;\n", call.c_str());
17283f9bf9f4Spatacca else
17293f9bf9f4Spatacca osprintf(os, indent, " auto ret = %s;\n", call.c_str());
17303f9bf9f4Spatacca if (is_isl_stat(rtype))
17313f9bf9f4Spatacca osprintf(os, indent, " return isl_stat_ok;\n");
17323f9bf9f4Spatacca else if (is_isl_bool(rtype))
17333f9bf9f4Spatacca osprintf(os, indent,
17343f9bf9f4Spatacca " return ret ? isl_bool_true : isl_bool_false;\n");
17353f9bf9f4Spatacca else
17363f9bf9f4Spatacca osprintf(os, indent, " return ret.release();\n");
17373f9bf9f4Spatacca osprintf(os, indent, "} ISL_CPP_CATCH_ALL {\n");
17383f9bf9f4Spatacca osprintf(os, indent, " data->eptr = std::current_exception();\n");
17393f9bf9f4Spatacca if (is_isl_stat(rtype))
17403f9bf9f4Spatacca osprintf(os, indent, " return isl_stat_error;\n");
17413f9bf9f4Spatacca else if (is_isl_bool(rtype))
17423f9bf9f4Spatacca osprintf(os, indent, " return isl_bool_error;\n");
17433f9bf9f4Spatacca else
17443f9bf9f4Spatacca osprintf(os, indent, " return NULL;\n");
17453f9bf9f4Spatacca osprintf(os, indent, "}\n");
17463f9bf9f4Spatacca }
17473f9bf9f4Spatacca
17483f9bf9f4Spatacca /* Print the declaration for a "prefix"_data data structure
17493f9bf9f4Spatacca * that can be used for passing to a C callback function
17503f9bf9f4Spatacca * containing a copy of the C++ callback function "param",
17513f9bf9f4Spatacca * along with an std::exception_ptr that is used to store any
17523f9bf9f4Spatacca * exceptions thrown in the C++ callback.
17533f9bf9f4Spatacca *
17543f9bf9f4Spatacca * If the C callback is of the form
17553f9bf9f4Spatacca *
17563f9bf9f4Spatacca * isl_stat (*fn)(__isl_take isl_map *map, void *user)
17573f9bf9f4Spatacca *
17583f9bf9f4Spatacca * then the following declaration is printed:
17593f9bf9f4Spatacca *
17603f9bf9f4Spatacca * struct <prefix>_data {
17613f9bf9f4Spatacca * std::function<stat(map)> func;
17623f9bf9f4Spatacca * std::exception_ptr eptr;
17633f9bf9f4Spatacca * }
17643f9bf9f4Spatacca *
17653f9bf9f4Spatacca * (without a newline or a semicolon).
17663f9bf9f4Spatacca *
17673f9bf9f4Spatacca * The std::exception_ptr object is not added to "prefix"_data
17683f9bf9f4Spatacca * if checked C++ bindings are being generated.
17693f9bf9f4Spatacca */
print_callback_data_decl(ParmVarDecl * param,const string & prefix)17703f9bf9f4Spatacca void plain_cpp_generator::plain_printer::print_callback_data_decl(
17713f9bf9f4Spatacca ParmVarDecl *param,
17723f9bf9f4Spatacca const string &prefix)
17733f9bf9f4Spatacca {
17743f9bf9f4Spatacca string cpp_args;
17753f9bf9f4Spatacca
17763f9bf9f4Spatacca cpp_args = generator.generate_callback_type(param->getType());
17773f9bf9f4Spatacca
17783f9bf9f4Spatacca osprintf(os, " struct %s_data {\n", prefix.c_str());
17793f9bf9f4Spatacca osprintf(os, " %s func;\n", cpp_args.c_str());
17803f9bf9f4Spatacca if (!generator.checked)
17813f9bf9f4Spatacca osprintf(os, " std::exception_ptr eptr;\n");
17823f9bf9f4Spatacca osprintf(os, " }");
17833f9bf9f4Spatacca }
17843f9bf9f4Spatacca
17853f9bf9f4Spatacca /* Given a group of methods with the same name,
17863f9bf9f4Spatacca * should extra methods be added that take as arguments
17873f9bf9f4Spatacca * those types that can be converted to the original argument type
17883f9bf9f4Spatacca * through a unary constructor?
17893f9bf9f4Spatacca *
17903f9bf9f4Spatacca * Note that even if this method returns true,
17913f9bf9f4Spatacca * the extra methods are only printed by the caller
17923f9bf9f4Spatacca * if exactly one of the methods in the group was originally defined
17933f9bf9f4Spatacca * in the printed class.
17943f9bf9f4Spatacca * Signal that they should be printed if the group contains
17953f9bf9f4Spatacca * both methods originally defined in the printed class and
17963f9bf9f4Spatacca * methods that have been copied from an ancestor
17973f9bf9f4Spatacca * by checking whether there are at least two methods in the group.
17983f9bf9f4Spatacca */
want_descendent_overloads(const function_set & methods)17993f9bf9f4Spatacca bool plain_cpp_generator::plain_printer::want_descendent_overloads(
18003f9bf9f4Spatacca const function_set &methods)
18013f9bf9f4Spatacca {
18023f9bf9f4Spatacca return methods.size() > 1;
18033f9bf9f4Spatacca }
18043f9bf9f4Spatacca
1805*a749e09eSMichael Kruse /* Print the header of the constructor for the "id" class
1806*a749e09eSMichael Kruse * that takes a user object.
1807*a749e09eSMichael Kruse *
1808*a749e09eSMichael Kruse * The user object is taken as a std::any.
1809*a749e09eSMichael Kruse */
print_id_constructor_user_header()1810*a749e09eSMichael Kruse void plain_cpp_generator::plain_printer::print_id_constructor_user_header()
1811*a749e09eSMichael Kruse {
1812*a749e09eSMichael Kruse if (declarations)
1813*a749e09eSMichael Kruse os << " inline explicit ";
1814*a749e09eSMichael Kruse else
1815*a749e09eSMichael Kruse os << "id::";
1816*a749e09eSMichael Kruse os << "id(" << generator.isl_namespace() << "ctx ctx, "
1817*a749e09eSMichael Kruse << "const std::string &str, const std::any &any)";
1818*a749e09eSMichael Kruse if (declarations)
1819*a749e09eSMichael Kruse os << ";";
1820*a749e09eSMichael Kruse os << "\n";
1821*a749e09eSMichael Kruse }
1822*a749e09eSMichael Kruse
1823*a749e09eSMichael Kruse /* Print the header of the "id" method
1824*a749e09eSMichael Kruse * for retrieving the user object associated to the identifier.
1825*a749e09eSMichael Kruse * If "optional" is set, the method returns a std::optional user object.
1826*a749e09eSMichael Kruse * The returned object is of a type specified by template parameter T.
1827*a749e09eSMichael Kruse */
print_id_user_header(bool optional)1828*a749e09eSMichael Kruse void plain_cpp_generator::plain_printer::print_id_user_header(bool optional)
1829*a749e09eSMichael Kruse {
1830*a749e09eSMichael Kruse auto indent = declarations ? " " : "";
1831*a749e09eSMichael Kruse os << indent << "template <class T>\n";
1832*a749e09eSMichael Kruse os << indent << (optional ? "std::optional<T> " : "T ");
1833*a749e09eSMichael Kruse if (!declarations)
1834*a749e09eSMichael Kruse os << "id::";
1835*a749e09eSMichael Kruse os << (optional ? "try_" : "");
1836*a749e09eSMichael Kruse os << "user() const";
1837*a749e09eSMichael Kruse if (declarations)
1838*a749e09eSMichael Kruse os << ";";
1839*a749e09eSMichael Kruse os << "\n";
1840*a749e09eSMichael Kruse }
1841*a749e09eSMichael Kruse
1842*a749e09eSMichael Kruse /* Perform printing by "fn" in a context that only gets compiled
1843*a749e09eSMichael Kruse * by C++17 compilers.
1844*a749e09eSMichael Kruse */
on_cplusplus17(ostream & os,const std::function<void (void)> & fn)1845*a749e09eSMichael Kruse static void on_cplusplus17(ostream &os, const std::function<void(void)> &fn)
1846*a749e09eSMichael Kruse {
1847*a749e09eSMichael Kruse os << "#if __cplusplus >= 201703L\n";
1848*a749e09eSMichael Kruse fn();
1849*a749e09eSMichael Kruse os << "#endif\n";
1850*a749e09eSMichael Kruse }
1851*a749e09eSMichael Kruse
1852*a749e09eSMichael Kruse /* Print declarations or definitions of the special methods of the "id" class
1853*a749e09eSMichael Kruse * that are not automatically derived from the C interface.
1854*a749e09eSMichael Kruse *
1855*a749e09eSMichael Kruse * In particular, print a constructor that takes a user pointer
1856*a749e09eSMichael Kruse * as well as methods for retrieving this user pointer.
1857*a749e09eSMichael Kruse *
1858*a749e09eSMichael Kruse * These methods require C++17 features.
1859*a749e09eSMichael Kruse */
print_special_id()1860*a749e09eSMichael Kruse void plain_cpp_generator::plain_printer::print_special_id()
1861*a749e09eSMichael Kruse {
1862*a749e09eSMichael Kruse os << "\n";
1863*a749e09eSMichael Kruse on_cplusplus17(os, [this] () {
1864*a749e09eSMichael Kruse print_id_constructor_user();
1865*a749e09eSMichael Kruse print_id_user(true);
1866*a749e09eSMichael Kruse print_id_user(false);
1867*a749e09eSMichael Kruse });
1868*a749e09eSMichael Kruse }
1869*a749e09eSMichael Kruse
1870*a749e09eSMichael Kruse /* Print declarations or definitions of any special methods of this class
1871*a749e09eSMichael Kruse * not automatically derived from the C interface.
1872*a749e09eSMichael Kruse *
1873*a749e09eSMichael Kruse * In particular, print special methods for the "id" class.
1874*a749e09eSMichael Kruse */
print_special()1875*a749e09eSMichael Kruse void plain_cpp_generator::plain_printer::print_special()
1876*a749e09eSMichael Kruse {
1877*a749e09eSMichael Kruse if (clazz.name == "isl_id")
1878*a749e09eSMichael Kruse print_special_id();
1879*a749e09eSMichael Kruse }
1880*a749e09eSMichael Kruse
1881*a749e09eSMichael Kruse /* Print declarations or definitions of the public methods.
1882*a749e09eSMichael Kruse */
print_public_methods()1883*a749e09eSMichael Kruse void plain_cpp_generator::plain_printer::print_public_methods()
1884*a749e09eSMichael Kruse {
1885*a749e09eSMichael Kruse print_public_constructors();
1886*a749e09eSMichael Kruse print_constructors();
1887*a749e09eSMichael Kruse print_copy_assignment();
1888*a749e09eSMichael Kruse print_destructor();
1889*a749e09eSMichael Kruse print_ptr();
1890*a749e09eSMichael Kruse print_downcast();
1891*a749e09eSMichael Kruse print_ctx();
1892*a749e09eSMichael Kruse print_method_separator();
1893*a749e09eSMichael Kruse print_persistent_callbacks();
1894*a749e09eSMichael Kruse print_methods();
1895*a749e09eSMichael Kruse print_set_enums();
1896*a749e09eSMichael Kruse print_special();
1897*a749e09eSMichael Kruse }
1898*a749e09eSMichael Kruse
18993f9bf9f4Spatacca /* Print the body of C function callback with the given indentation
19003f9bf9f4Spatacca * that can be use as an argument to "param" for marshalling
19013f9bf9f4Spatacca * the corresponding C++ callback.
19023f9bf9f4Spatacca * The data structure that contains the C++ callback is of type
19033f9bf9f4Spatacca * "prefix"_data.
19043f9bf9f4Spatacca *
19053f9bf9f4Spatacca * For a callback of the form
19063f9bf9f4Spatacca *
19073f9bf9f4Spatacca * isl_stat (*fn)(__isl_take isl_map *map, void *user)
19083f9bf9f4Spatacca *
19093f9bf9f4Spatacca * the following code is generated:
19103f9bf9f4Spatacca *
19113f9bf9f4Spatacca * auto *data = static_cast<struct <prefix>_data *>(arg_1);
19123f9bf9f4Spatacca * ISL_CPP_TRY {
19133f9bf9f4Spatacca * stat ret = (data->func)(manage(arg_0));
19143f9bf9f4Spatacca * return isl_stat_ok;
19153f9bf9f4Spatacca * } ISL_CPP_CATCH_ALL {
19163f9bf9f4Spatacca * data->eptr = std::current_exception();
19173f9bf9f4Spatacca * return isl_stat_error;
19183f9bf9f4Spatacca * }
19193f9bf9f4Spatacca *
19203f9bf9f4Spatacca * If checked C++ bindings are being generated, then
19213f9bf9f4Spatacca * generate the following code:
19223f9bf9f4Spatacca *
19233f9bf9f4Spatacca * auto *data = static_cast<struct <prefix>_data *>(arg_1);
19243f9bf9f4Spatacca * stat ret = (data->func)(manage(arg_0));
19253f9bf9f4Spatacca * return isl_stat(ret);
19263f9bf9f4Spatacca */
print_callback_body(int indent,ParmVarDecl * param,const string & prefix)19273f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_callback_body(int indent,
19283f9bf9f4Spatacca ParmVarDecl *param, const string &prefix)
19293f9bf9f4Spatacca {
19303f9bf9f4Spatacca QualType ptype, rtype;
19313f9bf9f4Spatacca string call, last_idx;
19323f9bf9f4Spatacca const FunctionProtoType *callback;
19333f9bf9f4Spatacca int num_params;
19343f9bf9f4Spatacca
19353f9bf9f4Spatacca ptype = param->getType();
19363f9bf9f4Spatacca
19373f9bf9f4Spatacca callback = extract_prototype(ptype);
19383f9bf9f4Spatacca rtype = callback->getReturnType();
19393f9bf9f4Spatacca num_params = callback->getNumArgs();
19403f9bf9f4Spatacca
19413f9bf9f4Spatacca last_idx = ::to_string(num_params - 1);
19423f9bf9f4Spatacca
19433f9bf9f4Spatacca call = "(data->func)(";
19443f9bf9f4Spatacca for (long i = 0; i < num_params - 1; i++) {
19453f9bf9f4Spatacca if (!generator.callback_takes_argument(param, i))
19463f9bf9f4Spatacca call += "manage_copy";
19473f9bf9f4Spatacca else
19483f9bf9f4Spatacca call += "manage";
19493f9bf9f4Spatacca call += "(arg_" + ::to_string(i) + ")";
19503f9bf9f4Spatacca if (i != num_params - 2)
19513f9bf9f4Spatacca call += ", ";
19523f9bf9f4Spatacca }
19533f9bf9f4Spatacca call += ")";
19543f9bf9f4Spatacca
19553f9bf9f4Spatacca osprintf(os, indent,
19563f9bf9f4Spatacca "auto *data = static_cast<struct %s_data *>(arg_%s);\n",
19573f9bf9f4Spatacca prefix.c_str(), last_idx.c_str());
19583f9bf9f4Spatacca print_wrapped_call(indent, call, rtype);
19593f9bf9f4Spatacca }
19603f9bf9f4Spatacca
19613f9bf9f4Spatacca /* Print the local variables that are needed for a callback argument,
19623f9bf9f4Spatacca * in particular, print a lambda function that wraps the callback and
19633f9bf9f4Spatacca * a pointer to the actual C++ callback function.
19643f9bf9f4Spatacca *
19653f9bf9f4Spatacca * For a callback of the form
19663f9bf9f4Spatacca *
19673f9bf9f4Spatacca * isl_stat (*fn)(__isl_take isl_map *map, void *user)
19683f9bf9f4Spatacca *
19693f9bf9f4Spatacca * the following lambda function is generated:
19703f9bf9f4Spatacca *
19713f9bf9f4Spatacca * auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
19723f9bf9f4Spatacca * auto *data = static_cast<struct fn_data *>(arg_1);
19733f9bf9f4Spatacca * try {
19743f9bf9f4Spatacca * stat ret = (data->func)(manage(arg_0));
19753f9bf9f4Spatacca * return isl_stat_ok;
19763f9bf9f4Spatacca * } catch (...) {
19773f9bf9f4Spatacca * data->eptr = std::current_exception();
19783f9bf9f4Spatacca * return isl_stat_error;
19793f9bf9f4Spatacca * }
19803f9bf9f4Spatacca * };
19813f9bf9f4Spatacca *
19823f9bf9f4Spatacca * A copy of the std::function C++ callback function is stored in
19833f9bf9f4Spatacca * a fn_data data structure for passing to the C callback function,
19843f9bf9f4Spatacca * along with an std::exception_ptr that is used to store any
19853f9bf9f4Spatacca * exceptions thrown in the C++ callback.
19863f9bf9f4Spatacca *
19873f9bf9f4Spatacca * struct fn_data {
19883f9bf9f4Spatacca * std::function<stat(map)> func;
19893f9bf9f4Spatacca * std::exception_ptr eptr;
19903f9bf9f4Spatacca * } fn_data = { fn };
19913f9bf9f4Spatacca *
19923f9bf9f4Spatacca * This std::function object represents the actual user
19933f9bf9f4Spatacca * callback function together with the locally captured state at the caller.
19943f9bf9f4Spatacca *
19953f9bf9f4Spatacca * The lambda function is expected to be used as a C callback function
19963f9bf9f4Spatacca * where the lambda itself is provided as the function pointer and
19973f9bf9f4Spatacca * where the user void pointer is a pointer to fn_data.
19983f9bf9f4Spatacca * The std::function object is extracted from the pointer to fn_data
19993f9bf9f4Spatacca * inside the lambda function.
20003f9bf9f4Spatacca *
20013f9bf9f4Spatacca * The std::exception_ptr object is not added to fn_data
20023f9bf9f4Spatacca * if checked C++ bindings are being generated.
20033f9bf9f4Spatacca * The body of the generated lambda function then is as follows:
20043f9bf9f4Spatacca *
20053f9bf9f4Spatacca * stat ret = (data->func)(manage(arg_0));
20063f9bf9f4Spatacca * return isl_stat(ret);
20073f9bf9f4Spatacca *
20083f9bf9f4Spatacca * If the C callback does not take its arguments, then
20093f9bf9f4Spatacca * manage_copy is used instead of manage.
20103f9bf9f4Spatacca */
print_callback_local(ParmVarDecl * param)20113f9bf9f4Spatacca void plain_cpp_generator::impl_printer::print_callback_local(ParmVarDecl *param)
20123f9bf9f4Spatacca {
20133f9bf9f4Spatacca string pname;
20143f9bf9f4Spatacca QualType ptype, rtype;
20153f9bf9f4Spatacca string c_args, cpp_args, rettype;
20163f9bf9f4Spatacca const FunctionProtoType *callback;
20173f9bf9f4Spatacca
20183f9bf9f4Spatacca pname = param->getName().str();
20193f9bf9f4Spatacca ptype = param->getType();
20203f9bf9f4Spatacca
20213f9bf9f4Spatacca c_args = generator.generate_callback_args(ptype, false);
20223f9bf9f4Spatacca
20233f9bf9f4Spatacca callback = extract_prototype(ptype);
20243f9bf9f4Spatacca rtype = callback->getReturnType();
20253f9bf9f4Spatacca rettype = rtype.getAsString();
20263f9bf9f4Spatacca
20273f9bf9f4Spatacca print_callback_data_decl(param, pname);
20283f9bf9f4Spatacca osprintf(os, " %s_data = { %s };\n", pname.c_str(), pname.c_str());
20293f9bf9f4Spatacca osprintf(os, " auto %s_lambda = [](%s) -> %s {\n",
20303f9bf9f4Spatacca pname.c_str(), c_args.c_str(), rettype.c_str());
20313f9bf9f4Spatacca print_callback_body(4, param, pname);
20323f9bf9f4Spatacca osprintf(os, " };\n");
20333f9bf9f4Spatacca }
20343f9bf9f4Spatacca
20353f9bf9f4Spatacca /* Return the C++ counterpart to the isl_bool type.
20363f9bf9f4Spatacca *
20373f9bf9f4Spatacca * For the checked C++ bindings this is "boolean".
20383f9bf9f4Spatacca */
isl_bool() const20393f9bf9f4Spatacca std::string checked_cpp_type_printer::isl_bool() const
20403f9bf9f4Spatacca {
20413f9bf9f4Spatacca return "boolean";
20423f9bf9f4Spatacca }
20433f9bf9f4Spatacca
20443f9bf9f4Spatacca /* Return the C++ counterpart to the isl_bool type.
20453f9bf9f4Spatacca *
20463f9bf9f4Spatacca * Use the appropriate type printer.
20473f9bf9f4Spatacca */
isl_bool2cpp()20483f9bf9f4Spatacca string plain_cpp_generator::isl_bool2cpp()
20493f9bf9f4Spatacca {
20503f9bf9f4Spatacca return type_printer()->isl_bool();
20513f9bf9f4Spatacca }
20523f9bf9f4Spatacca
20533f9bf9f4Spatacca /* Return the C++ counterpart to the isl_stat type.
20543f9bf9f4Spatacca *
20553f9bf9f4Spatacca * For the checked C++ bindings this is "stat".
20563f9bf9f4Spatacca */
isl_stat() const20573f9bf9f4Spatacca string checked_cpp_type_printer::isl_stat() const
20583f9bf9f4Spatacca {
20593f9bf9f4Spatacca return "stat";
20603f9bf9f4Spatacca }
20613f9bf9f4Spatacca
20623f9bf9f4Spatacca /* Return the C++ counterpart to the isl_size type.
20633f9bf9f4Spatacca *
20643f9bf9f4Spatacca * For the checked C++ bindings this is "class size".
20653f9bf9f4Spatacca */
isl_size() const20663f9bf9f4Spatacca string checked_cpp_type_printer::isl_size() const
20673f9bf9f4Spatacca {
20683f9bf9f4Spatacca return "class size";
20693f9bf9f4Spatacca }
20703f9bf9f4Spatacca
20713f9bf9f4Spatacca /* Return the namespace of the generated C++ bindings.
20723f9bf9f4Spatacca *
20733f9bf9f4Spatacca * For the checked C++ bindings this is "isl::checked::".
20743f9bf9f4Spatacca */
isl_namespace() const20753f9bf9f4Spatacca std::string checked_cpp_type_printer::isl_namespace() const
20763f9bf9f4Spatacca {
20773f9bf9f4Spatacca return "isl::checked::";
20783f9bf9f4Spatacca }
20793f9bf9f4Spatacca
20803f9bf9f4Spatacca /* Return the namespace of the generated C++ bindings.
20813f9bf9f4Spatacca *
20823f9bf9f4Spatacca * Use the appropriate type printer.
20833f9bf9f4Spatacca */
isl_namespace()20843f9bf9f4Spatacca string plain_cpp_generator::isl_namespace()
20853f9bf9f4Spatacca {
20863f9bf9f4Spatacca return type_printer()->isl_namespace();
20873f9bf9f4Spatacca }
20883f9bf9f4Spatacca
20893f9bf9f4Spatacca /* Translate parameter or return type "type" to its C++ name counterpart.
20903f9bf9f4Spatacca *
20913f9bf9f4Spatacca * Use the appropriate type printer.
20923f9bf9f4Spatacca * For the plain C++ interface, the argument position is irrelevant,
20933f9bf9f4Spatacca * so simply pass in -1.
20943f9bf9f4Spatacca */
param2cpp(QualType type)20953f9bf9f4Spatacca string plain_cpp_generator::param2cpp(QualType type)
20963f9bf9f4Spatacca {
20973f9bf9f4Spatacca return type_printer()->param(-1, type);
20983f9bf9f4Spatacca }
2099