@@ -177,7 +177,48 @@ void cpp_generator::print_implementations(ostream &os)
}
}
+/* If "clazz" is a subclass that is based on a type function,
+ * then introduce a "type" field that holds the value of the type
+ * corresponding to the subclass and make the fields of the class
+ * accessible to the "isa" and "as" methods of the (immediate) superclass.
+ * In particular, "isa" needs access to the type field itself,
+ * while "as" needs access to the private constructor.
+ * In case of the "isa" method, all instances are made friends
+ * to avoid access right confusion.
+ */
+void cpp_generator::print_subclass_type(ostream &os, const isl_class &clazz)
+{
+ std::string cppstring = type2cpp(clazz);
+ std::string super;
+ const char *cppname = cppstring.c_str();
+ const char *supername;
+
+ if (!clazz.is_type_subclass())
+ return;
+
+ super = type2cpp(clazz.superclass_name);
+ supername = super.c_str();
+ osprintf(os, " template <class T>\n");
+ osprintf(os, " friend %s %s::isa() const;\n",
+ isl_bool2cpp().c_str(), supername);
+ osprintf(os, " friend %s %s::as<%s>() const;\n",
+ cppname, supername, cppname);
+ osprintf(os, " static const auto type = %s;\n",
+ clazz.subclass_name.c_str());
+}
+
/* Print declarations for class "clazz" to "os".
+ *
+ * If "clazz" is a subclass based on a type function,
+ * then it is made to inherit from the (immediate) superclass and
+ * a "type" attribute is added for use in the "as" and "isa"
+ * methods of the superclass.
+ *
+ * Conversely, if "clazz" is a superclass with a type function,
+ * then declare those "as" and "isa" methods.
+ *
+ * The pointer to the isl object is only added for classes that
+ * are not subclasses, since subclasses refer to the same isl object.
*/
void cpp_generator::print_class(ostream &os, const isl_class &clazz)
{
@@ -189,12 +230,19 @@ void cpp_generator::print_class(ostream &os, const isl_class &clazz)
print_class_factory_decl(os, clazz);
osprintf(os, "\n");
- osprintf(os, "class %s {\n", cppname);
+ osprintf(os, "class %s ", cppname);
+ if (clazz.is_type_subclass())
+ osprintf(os, ": public %s ",
+ type2cpp(clazz.superclass_name).c_str());
+ osprintf(os, "{\n");
+ print_subclass_type(os, clazz);
print_class_factory_decl(os, clazz, " friend ");
osprintf(os, "\n");
osprintf(os, "protected:\n");
- osprintf(os, " %s *ptr = nullptr;\n", name);
- osprintf(os, "\n");
+ if (!clazz.is_type_subclass()) {
+ osprintf(os, " %s *ptr = nullptr;\n", name);
+ osprintf(os, "\n");
+ }
print_protected_constructors_decl(os, clazz);
osprintf(os, "\n");
osprintf(os, "public:\n");
@@ -203,6 +251,7 @@ void cpp_generator::print_class(ostream &os, const isl_class &clazz)
print_copy_assignment_decl(os, clazz);
print_destructor_decl(os, clazz);
print_ptr_decl(os, clazz);
+ print_downcast_decl(os, clazz);
print_get_ctx_decl(os);
osprintf(os, "\n");
print_methods_decl(os, clazz);
@@ -235,6 +284,10 @@ void cpp_generator::print_class_forward_decl(ostream &os,
* manage_copy() can be called on any isl raw pointer and the corresponding
* object is automatically created, without the user having to choose the right
* isl object type.
+ *
+ * For a subclass based on a type function, no factory functions
+ * are introduced because they share the C object type with
+ * the superclass.
*/
void cpp_generator::print_class_factory_decl(ostream &os,
const isl_class &clazz, const std::string &prefix)
@@ -243,6 +296,9 @@ void cpp_generator::print_class_factory_decl(ostream &os,
std::string cppstring = type2cpp(clazz);
const char *cppname = cppstring.c_str();
+ if (clazz.is_type_subclass())
+ return;
+
os << prefix;
osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name);
os << prefix;
@@ -340,16 +396,23 @@ void cpp_generator::print_copy_assignment_decl(ostream &os,
}
/* Print declaration of destructor for class "clazz" to "os".
+ *
+ * No explicit destructor is needed for type based subclasses.
*/
void cpp_generator::print_destructor_decl(ostream &os, const isl_class &clazz)
{
std::string cppstring = type2cpp(clazz);
const char *cppname = cppstring.c_str();
+ if (clazz.is_type_subclass())
+ return;
+
osprintf(os, " inline ~%s();\n", cppname);
}
/* Print declaration of pointer functions for class "clazz" to "os".
+ * Since type based subclasses share the pointer with their superclass,
+ * they can also reuse these functions from the superclass.
*
* To obtain a raw pointer three functions are provided:
*
@@ -385,6 +448,9 @@ void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz)
{
const char *name = clazz.name.c_str();
+ if (clazz.is_type_subclass())
+ return;
+
osprintf(os, " inline __isl_give %s *copy() const &;\n", name);
osprintf(os, " inline __isl_give %s *copy() && = delete;\n", name);
osprintf(os, " inline __isl_keep %s *get() const;\n", name);
@@ -392,6 +458,56 @@ void cpp_generator::print_ptr_decl(ostream &os, const isl_class &clazz)
osprintf(os, " inline bool is_null() const;\n");
}
+/* Print a template declaration with given indentation
+ * for the "isa_type" method that ensures it is only enabled
+ * when called with a template argument
+ * that represents a type that is equal to that
+ * of the return type of the type function of "super".
+ * In particular, "isa_type" gets called from "isa"
+ * with as template argument the type of the "type" field
+ * of the subclass.
+ * The check ensures that this subclass is in fact a direct subclass
+ * of "super".
+ */
+void cpp_generator::print_isa_type_template(ostream &os, int indent,
+ const isl_class &super)
+{
+ osprintf(os, indent,
+ "template <typename T,\n");
+ osprintf(os, indent,
+ " typename = typename std::enable_if<std::is_same<\n");
+ osprintf(os, indent,
+ " const decltype(%s(NULL)),\n",
+ super.fn_type->getNameAsString().c_str());
+ osprintf(os, indent,
+ " const T>::value>::type>\n");
+}
+
+/* Print declarations for the "as" and "isa" methods, if "clazz"
+ * is a superclass with a type function.
+ *
+ * "isa" checks whether an object is of a given subclass type.
+ * "isa_type" does the same, but gets passed the value of the type field
+ * of the subclass as a function argument and the type of this field
+ * as a template argument.
+ * "as" tries to cast an object to a given subclass type, returning
+ * an invalid object if the object is not of the given type.
+ */
+void cpp_generator::print_downcast_decl(ostream &os, const isl_class &clazz)
+{
+ if (!clazz.fn_type)
+ return;
+
+ osprintf(os, "private:\n");
+ print_isa_type_template(os, 2, clazz);
+ osprintf(os, " inline %s isa_type(T subtype) const;\n",
+ isl_bool2cpp().c_str());
+ osprintf(os, "public:\n");
+ osprintf(os, " template <class T> inline %s isa() const;\n",
+ isl_bool2cpp().c_str());
+ osprintf(os, " template <class T> inline T as() const;\n");
+}
+
/* Print the declaration of the get_ctx method.
*/
void cpp_generator::print_get_ctx_decl(ostream &os)
@@ -455,6 +571,8 @@ void cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
osprintf(os, "\n");
print_ptr_impl(os, clazz);
osprintf(os, "\n");
+ if (print_downcast_impl(os, clazz))
+ osprintf(os, "\n");
print_get_ctx_impl(os, clazz);
osprintf(os, "\n");
print_methods_impl(os, clazz);
@@ -487,6 +605,23 @@ static void print_throw_NULL_input(ostream &os)
print_throw_invalid(os, 4, "NULL input");
}
+/* Print code with the given indentation
+ * for acting on an invalid error with message "msg".
+ * In particular, throw an exception_invalid.
+ * In the checked C++ bindings, isl_die is called instead with the code
+ * in "checked_code".
+ */
+void cpp_generator::print_invalid(ostream &os, int indent, const char *msg,
+ const char *checked_code)
+{
+ if (checked)
+ osprintf(os, indent,
+ "isl_die(get_ctx().get(), isl_error_invalid, "
+ "\"%s\", %s);\n", msg, checked_code);
+ else
+ print_throw_invalid(os, indent, msg);
+}
+
/* Print an operator for inserting objects of "class"
* into an output stream.
*
@@ -584,6 +719,10 @@ void cpp_generator::print_check_ptr_end(ostream &os, const char *ptr)
* in manage_copy.
* During the copying, isl is made not to print any error message
* because the error message is included in the exception.
+ *
+ * For a subclass based on a type function, no factory functions
+ * are introduced because they share the C object type with
+ * the superclass.
*/
void cpp_generator::print_class_factory_impl(ostream &os,
const isl_class &clazz)
@@ -592,6 +731,9 @@ void cpp_generator::print_class_factory_impl(ostream &os,
std::string cppstring = type2cpp(clazz);
const char *cppname = cppstring.c_str();
+ if (clazz.is_type_subclass())
+ return;
+
osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
print_check_ptr(os, "ptr");
osprintf(os, " return %s(ptr);\n", cppname);
@@ -607,6 +749,9 @@ void cpp_generator::print_class_factory_impl(ostream &os,
}
/* Print implementations of protected constructors for class "clazz" to "os".
+ *
+ * The pointer to the isl object is either initialized directly or
+ * through the (immediate) superclass.
*/
void cpp_generator::print_protected_constructors_impl(ostream &os,
const isl_class &clazz)
@@ -614,15 +759,23 @@ void cpp_generator::print_protected_constructors_impl(ostream &os,
const char *name = clazz.name.c_str();
std::string cppstring = type2cpp(clazz);
const char *cppname = cppstring.c_str();
+ bool subclass = clazz.is_type_subclass();
osprintf(os, "%s::%s(__isl_take %s *ptr)\n", cppname, cppname, name);
- osprintf(os, " : ptr(ptr) {}\n");
+ if (subclass)
+ osprintf(os, " : %s(ptr) {}\n",
+ type2cpp(clazz.superclass_name).c_str());
+ else
+ osprintf(os, " : ptr(ptr) {}\n");
}
/* Print implementations of public constructors for class "clazz" to "os".
*
+ * The pointer to the isl object is either initialized directly or
+ * through the (immediate) superclass.
+ *
* Throw an exception from the copy constructor if anything went wrong
- * during the copying or if the input is NULL.
+ * during the copying or if the input is NULL, if any copying is performed.
* During the copying, isl is made not to print any error message
* because the error message is included in the exception.
* No exceptions are thrown if checked C++ bindings
@@ -632,16 +785,28 @@ void cpp_generator::print_public_constructors_impl(ostream &os,
const isl_class &clazz)
{
std::string cppstring = type2cpp(clazz);
+ std::string super;
const char *cppname = cppstring.c_str();
+ bool subclass = clazz.is_type_subclass();
+ if (subclass)
+ super = type2cpp(clazz.superclass_name);
osprintf(os, "%s::%s()\n", cppname, cppname);
- osprintf(os, " : ptr(nullptr) {}\n\n");
+ if (subclass)
+ osprintf(os, " : %s() {}\n\n", super.c_str());
+ else
+ osprintf(os, " : ptr(nullptr) {}\n\n");
osprintf(os, "%s::%s(const %s &obj)\n", cppname, cppname, cppname);
- osprintf(os, " : ptr(nullptr)\n");
+ if (subclass)
+ osprintf(os, " : %s(obj)\n", super.c_str());
+ else
+ osprintf(os, " : ptr(nullptr)\n");
osprintf(os, "{\n");
- print_check_ptr_start(os, clazz, "obj.ptr");
- osprintf(os, " ptr = obj.copy();\n");
- print_check_ptr_end(os, "ptr");
+ if (!subclass) {
+ print_check_ptr_start(os, clazz, "obj.ptr");
+ osprintf(os, " ptr = obj.copy();\n");
+ print_check_ptr_end(os, "ptr");
+ }
osprintf(os, "}\n");
}
@@ -677,6 +842,8 @@ void cpp_generator::print_copy_assignment_impl(ostream &os,
}
/* Print implementation of destructor for class "clazz" to "os".
+ *
+ * No explicit destructor is needed for type based subclasses.
*/
void cpp_generator::print_destructor_impl(ostream &os,
const isl_class &clazz)
@@ -685,6 +852,9 @@ void cpp_generator::print_destructor_impl(ostream &os,
std::string cppstring = type2cpp(clazz);
const char *cppname = cppstring.c_str();
+ if (clazz.is_type_subclass())
+ return;
+
osprintf(os, "%s::~%s() {\n", cppname, cppname);
osprintf(os, " if (ptr)\n");
osprintf(os, " %s_free(ptr);\n", name);
@@ -692,6 +862,8 @@ void cpp_generator::print_destructor_impl(ostream &os,
}
/* Print implementation of ptr() functions for class "clazz" to "os".
+ * Since type based subclasses share the pointer with their superclass,
+ * they can also reuse these functions from the superclass.
*/
void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
{
@@ -699,6 +871,9 @@ void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
std::string cppstring = type2cpp(clazz);
const char *cppname = cppstring.c_str();
+ if (clazz.is_type_subclass())
+ return;
+
osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
osprintf(os, " return %s_copy(ptr);\n", name);
osprintf(os, "}\n\n");
@@ -715,6 +890,65 @@ void cpp_generator::print_ptr_impl(ostream &os, const isl_class &clazz)
osprintf(os, "}\n");
}
+/* Print implementations for the "as" and "isa" methods, if "clazz"
+ * is a superclass with a type function.
+ *
+ * "isa" checks whether an object is of a given subclass type.
+ * "isa_type" does the same, but gets passed the value of the type field
+ * of the subclass as a function argument and the type of this field
+ * as a template argument.
+ * "as" casts an object to a given subclass type, erroring out
+ * if the object is not of the given type.
+ *
+ * If the input is an invalid object, then these methods raise
+ * an exception.
+ * If checked bindings are being generated,
+ * then an invalid boolean or object is returned instead.
+ *
+ * Return true if anything was printed.
+ */
+bool cpp_generator::print_downcast_impl(ostream &os, const isl_class &clazz)
+{
+ std::string cppstring = type2cpp(clazz);
+ const char *cppname = cppstring.c_str();
+
+ if (!clazz.fn_type)
+ return false;
+
+ osprintf(os, "template <typename T, typename>\n");
+ osprintf(os, "%s %s::isa_type(T subtype) const\n",
+ isl_bool2cpp().c_str(), cppname);
+ osprintf(os, "{\n");
+ osprintf(os, " if (is_null())\n");
+ if (checked)
+ osprintf(os, " return boolean();\n");
+ else
+ print_throw_NULL_input(os);
+ osprintf(os, " return %s(get()) == subtype;\n",
+ clazz.fn_type->getNameAsString().c_str());
+ osprintf(os, "}\n");
+
+ osprintf(os, "template <class T>\n");
+ osprintf(os, "%s %s::isa() const\n", isl_bool2cpp().c_str(), cppname);
+ osprintf(os, "{\n");
+ osprintf(os, " return isa_type<decltype(T::type)>(T::type);\n");
+ osprintf(os, "}\n");
+
+ osprintf(os, "template <class T>\n");
+ osprintf(os, "T %s::as() const\n", cppname);
+ osprintf(os, "{\n");
+ if (checked)
+ osprintf(os, " if (isa<T>().is_false())\n");
+ else
+ osprintf(os, " if (!isa<T>())\n");
+ print_invalid(os, 4, "not an object of the requested subtype",
+ "return T()");
+ osprintf(os, " return T(copy());\n");
+ osprintf(os, "}\n");
+
+ return true;
+}
+
/* Print the implementation of the get_ctx method.
*/
void cpp_generator::print_get_ctx_impl(ostream &os, const isl_class &clazz)
@@ -983,12 +1217,26 @@ void cpp_generator::print_exceptional_execution_check(ostream &os,
print_throw_last_error(os);
}
+/* Does "fd" modify an object of a subclass based on a type function?
+ */
+static bool is_subclass_mutator(const isl_class &clazz, FunctionDecl *fd)
+{
+ return clazz.is_type_subclass() && generator::is_mutator(clazz, fd);
+}
+
/* Return the C++ return type of the method corresponding to "fd" in "clazz".
+ *
+ * If "fd" modifies an object of a subclass, then return
+ * the type of this subclass.
+ * Otherwise, return the C++ counterpart of the actual return type.
*/
std::string cpp_generator::get_return_type(const isl_class &clazz,
FunctionDecl *fd)
{
- return type2cpp(fd->getReturnType());
+ if (is_subclass_mutator(clazz, fd))
+ return type2cpp(clazz);
+ else
+ return type2cpp(fd->getReturnType());
}
/* Print the return statement of the C++ method corresponding
@@ -1004,15 +1252,23 @@ std::string cpp_generator::get_return_type(const isl_class &clazz,
* then an isl_bool return type is transformed into a boolean and
* an isl_stat into a stat since no exceptions can be generated
* on negative results from the isl function.
+ * If "clazz" is a subclass that is based on a type function and
+ * if the return type corresponds to the superclass data type,
+ * then it is replaced by the subclass data type.
*/
void cpp_generator::print_method_return(ostream &os, const isl_class &clazz,
FunctionDecl *method)
{
QualType return_type = method->getReturnType();
+ string rettype_str = get_return_type(clazz, method);
+ bool returns_super = is_subclass_mutator(clazz, method);
if (is_isl_type(return_type) ||
(checked && is_isl_neg_error(return_type))) {
- osprintf(os, " return manage(res);\n");
+ osprintf(os, " return manage(res)");
+ if (returns_super)
+ osprintf(os, ".as<%s>()", rettype_str.c_str());
+ osprintf(os, ";\n");
} else if (is_isl_stat(return_type)) {
osprintf(os, " return;\n");
} else if (is_string(return_type)) {
@@ -1482,10 +1738,11 @@ std::string cpp_generator::rename_method(std::string name)
}
/* Translate isl class "clazz" to its corresponding C++ type.
+ * Use the name of the type based subclass, if any.
*/
string cpp_generator::type2cpp(const isl_class &clazz)
{
- return type2cpp(clazz.name);
+ return type2cpp(clazz.subclass_name);
}
/* Translate type string "type_str" to its C++ name counterpart.
#include <stdio.h>
#include <string.h>
+#include <algorithm>
#include <iostream>
#include <clang/AST/Attr.h>
@@ -103,18 +104,69 @@ FunctionDecl *generator::find_by_name(const string &name, bool required)
return NULL;
}
+/* Add a subclass derived from "decl" called "sub_name" to the set of classes,
+ * keeping track of the _to_str, _copy and _free functions, if any, separately.
+ * "sub_name" is either the name of the class itself or
+ * the name of a type based subclass.
+ * If the class is a proper subclass, then "super_name" is the name
+ * of its immediate superclass.
+ */
+void generator::add_subclass(RecordDecl *decl, const string &super_name,
+ const string &sub_name)
+{
+ string name = decl->getName();
+
+ classes[sub_name].name = name;
+ classes[sub_name].superclass_name = super_name;
+ classes[sub_name].subclass_name = sub_name;
+ classes[sub_name].type = decl;
+ classes[sub_name].fn_to_str = find_by_name(name + "_to_str", false);
+ classes[sub_name].fn_copy = find_by_name(name + "_copy", true);
+ classes[sub_name].fn_free = find_by_name(name + "_free", true);
+}
+
/* Add a class derived from "decl" to the set of classes,
* keeping track of the _to_str, _copy and _free functions, if any, separately.
*/
void generator::add_class(RecordDecl *decl)
{
- string name = decl->getName();
+ return add_subclass(decl, "", decl->getName());
+}
- classes[name].name = name;
- classes[name].type = decl;
- classes[name].fn_to_str = find_by_name(name + "_to_str", false);
- classes[name].fn_copy = find_by_name(name + "_copy", true);
- classes[name].fn_free = find_by_name(name + "_free", true);
+/* Given a function "fn_type" that returns the subclass type
+ * of a C object, create subclasses for each of the (non-negative)
+ * return values.
+ *
+ * The function "fn_type" is also stored in the superclass,
+ * along with all pairs of type values and subclass names.
+ */
+void generator::add_type_subclasses(FunctionDecl *fn_type)
+{
+ QualType return_type = fn_type->getReturnType();
+ const EnumType *enum_type = return_type->getAs<EnumType>();
+ EnumDecl *decl = enum_type->getDecl();
+ isl_class *c = method2class(fn_type);
+ DeclContext::decl_iterator i;
+
+ c->fn_type = fn_type;
+ for (i = decl->decls_begin(); i != decl->decls_end(); ++i) {
+ EnumConstantDecl *ecd = dyn_cast<EnumConstantDecl>(*i);
+ int val = (int) ecd->getInitVal().getSExtValue();
+ string name = ecd->getNameAsString();
+
+ if (val < 0)
+ continue;
+ c->type_subclasses[val] = name;
+ add_subclass(c->type, c->subclass_name, name);
+ }
+}
+
+/* Sorting function that places declaration of functions
+ * with a shorter name first.
+ */
+static bool less_name(const FunctionDecl *a, const FunctionDecl *b)
+{
+ return a->getName().size() < b->getName().size();
}
/* Collect all functions that belong to a certain type, separating
@@ -122,6 +174,11 @@ void generator::add_class(RecordDecl *decl)
* _copy and _free functions, if any, separately. If there are any overloaded
* functions, then they are grouped based on their name after removing the
* argument type suffix.
+ * Check for functions that describe subclasses before considering
+ * any other functions in order to be able to detect those other
+ * functions as belonging to the subclasses.
+ * Sort the names of the functions based on their lengths
+ * to ensure that nested subclasses are handled later.
*/
generator::generator(SourceManager &SM, set<RecordDecl *> &exported_types,
set<FunctionDecl *> exported_functions, set<FunctionDecl *> functions) :
@@ -129,6 +186,8 @@ generator::generator(SourceManager &SM, set<RecordDecl *> &exported_types,
{
set<FunctionDecl *>::iterator in;
set<RecordDecl *>::iterator it;
+ vector<FunctionDecl *> type_subclasses;
+ vector<FunctionDecl *>::iterator iv;
for (in = functions.begin(); in != functions.end(); ++in) {
FunctionDecl *decl = *in;
@@ -140,9 +199,23 @@ generator::generator(SourceManager &SM, set<RecordDecl *> &exported_types,
for (in = exported_functions.begin(); in != exported_functions.end();
++in) {
+ if (is_subclass(*in))
+ type_subclasses.push_back(*in);
+ }
+ std::sort(type_subclasses.begin(), type_subclasses.end(), &less_name);
+ for (iv = type_subclasses.begin(); iv != type_subclasses.end(); ++iv) {
+ add_type_subclasses(*iv);
+ }
+
+ for (in = exported_functions.begin(); in != exported_functions.end();
+ ++in) {
FunctionDecl *method = *in;
- isl_class *c = method2class(method);
+ isl_class *c;
+
+ if (is_subclass(method))
+ continue;
+ c = method2class(method);
if (!c)
continue;
if (is_constructor(method)) {
@@ -200,6 +273,13 @@ std::vector<string> generator::find_superclasses(Decl *decl)
return super;
}
+/* Is "decl" marked as describing subclasses?
+ */
+bool generator::is_subclass(FunctionDecl *decl)
+{
+ return find_superclasses(decl).size() > 0;
+}
+
/* Is decl marked as being part of an overloaded method?
*/
bool generator::is_overload(Decl *decl)
@@ -499,9 +499,34 @@ void python_generator::print_constructor(const isl_class &clazz,
printf(" return\n");
}
+/* If "clazz" has a type function describing subclasses,
+ * then add constructors that allow each of these subclasses
+ * to be treated as an object to the superclass.
+ */
+void python_generator::print_upcast_constructors(const isl_class &clazz)
+{
+ map<int, string>::const_iterator i;
+
+ if (!clazz.fn_type)
+ return;
+
+ for (i = clazz.type_subclasses.begin();
+ i != clazz.type_subclasses.end(); ++i) {
+ printf(" if len(args) == 1 and "
+ "isinstance(args[0], %s):\n",
+ type2python(i->second).c_str());
+ printf(" self.ctx = args[0].ctx\n");
+ printf(" self.ptr = isl.%s_copy(args[0].ptr)\n",
+ clazz.name.c_str());
+ printf(" return\n");
+ }
+}
+
/* Print the header of the class "name" with superclasses "super".
* The order of the superclasses is the opposite of the order
* in which the corresponding annotations appear in the source code.
+ * If "clazz" is a subclass derived from a type function,
+ * then the immediate superclass is recorded in "clazz" itself.
*/
void python_generator::print_class_header(const isl_class &clazz,
const string &name, const vector<string> &super)
@@ -515,6 +540,8 @@ void python_generator::print_class_header(const isl_class &clazz,
printf("%s", type2python(super[i]).c_str());
}
printf(")");
+ } else if (clazz.is_type_subclass()) {
+ printf("(%s)", type2python(clazz.superclass_name).c_str());
} else {
printf("(object)");
}
@@ -580,6 +607,41 @@ void python_generator::print_method_type(FunctionDecl *fd)
print_argtypes(fd);
}
+/* If "clazz" has a type function describing subclasses or
+ * if it is one of those type subclasses, then print a __new__ method.
+ *
+ * In the superclass, the __new__ method constructs an object
+ * of the subclass type specified by the type function.
+ * In the subclass, the __new__ method reverts to the original behavior.
+ */
+void python_generator::print_new(const isl_class &clazz,
+ const string &python_name)
+{
+ if (!clazz.fn_type && !clazz.is_type_subclass())
+ return;
+
+ printf(" def __new__(cls, *args, **keywords):\n");
+
+ if (clazz.fn_type) {
+ map<int, string>::const_iterator i;
+
+ printf(" if \"ptr\" in keywords:\n");
+ printf(" type = isl.%s(keywords[\"ptr\"])\n",
+ clazz.fn_type->getNameAsString().c_str());
+
+ for (i = clazz.type_subclasses.begin();
+ i != clazz.type_subclasses.end(); ++i) {
+ printf(" if type == %d:\n", i->first);
+ printf(" return %s(**keywords)\n",
+ type2python(i->second).c_str());
+ }
+ printf(" raise\n");
+ }
+
+ printf(" return super(%s, cls).__new__(cls)\n",
+ python_name.c_str());
+}
+
/* Print declarations for methods printing the class representation,
* provided there is a corresponding *_to_str function.
*
@@ -622,7 +684,7 @@ void python_generator::print_representation(const isl_class &clazz,
*
* To be able to call C functions it is necessary to explicitly set their
* argument and result types. Do this for all exported constructors and
- * methods, as well as for the *_to_str method, if it exists.
+ * methods, as well as for the *_to_str and the type function, if they exist.
* Assuming each exported class has a *_copy and a *_free method,
* also unconditionally set the type of such methods.
*/
@@ -643,6 +705,8 @@ void python_generator::print_method_types(const isl_class &clazz)
print_method_type(clazz.fn_free);
if (clazz.fn_to_str)
print_method_type(clazz.fn_to_str);
+ if (clazz.fn_type)
+ print_method_type(clazz.fn_type);
}
/* Print out the definition of this isl_class.
@@ -651,8 +715,8 @@ void python_generator::print_method_types(const isl_class &clazz)
* If it is, we make sure those superclasses are printed out first.
*
* Then we print a constructor with several cases, one for constructing
- * a Python object from a return value and one for each function that
- * was marked as a constructor.
+ * a Python object from a return value, one for each function that
+ * was marked as a constructor and for each type based subclass.
*
* Next, we print out some common methods and the methods corresponding
* to functions that are not marked as constructors.
@@ -663,7 +727,7 @@ void python_generator::print_method_types(const isl_class &clazz)
*/
void python_generator::print(const isl_class &clazz)
{
- string p_name = type2python(clazz.name);
+ string p_name = type2python(clazz.subclass_name);
set<FunctionDecl *>::const_iterator in;
map<string, set<FunctionDecl *> >::const_iterator it;
vector<string> super = find_superclasses(clazz.type);
@@ -671,7 +735,9 @@ void python_generator::print(const isl_class &clazz)
for (unsigned i = 0; i < super.size(); ++i)
if (done.find(super[i]) == done.end())
print(classes[super[i]]);
- done.insert(clazz.name);
+ if (clazz.is_type_subclass() && done.find(clazz.name) == done.end())
+ print(classes[clazz.name]);
+ done.insert(clazz.subclass_name);
printf("\n");
print_class_header(clazz, p_name, super);
@@ -685,11 +751,13 @@ void python_generator::print(const isl_class &clazz)
for (in = clazz.constructors.begin(); in != clazz.constructors.end();
++in)
print_constructor(clazz, *in);
+ print_upcast_constructors(clazz);
printf(" raise Error\n");
printf(" def __del__(self):\n");
printf(" if hasattr(self, 'ptr'):\n");
printf(" isl.%s_free(self.ptr)\n", clazz.name.c_str());
+ print_new(clazz, p_name);
print_representation(clazz, p_name);
for (it = clazz.methods.begin(); it != clazz.methods.end(); ++it)