#include <cstdarg>
#include <cstdio>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "plain_cpp.h"
#include "isl_config.h"
static void osprintf(ostream &os, const char *format, va_list arguments)
{
va_list copy;
char *string_pointer;
size_t size;
va_copy(copy, arguments);
size = vsnprintf(NULL, 0, format, copy);
string_pointer = new char[size + 1];
va_end(copy);
vsnprintf(string_pointer, size + 1, format, arguments);
os << string_pointer;
delete[] string_pointer;
}
static void osprintf(ostream &os, const char *format, ...)
{
va_list arguments;
va_start(arguments, format);
osprintf(os, format, arguments);
va_end(arguments);
}
static void osprintf(ostream &os, int indent, const char *format, ...)
{
va_list arguments;
osprintf(os, "%*s", indent, " ");
va_start(arguments, format);
osprintf(os, format, arguments);
va_end(arguments);
}
static std::string to_string(long l)
{
std::ostringstream strm;
strm << l;
return strm.str();
}
plain_cpp_generator::plain_cpp_generator(SourceManager &SM,
set<RecordDecl *> &exported_types,
set<FunctionDecl *> exported_functions, set<FunctionDecl *> functions,
bool checked) :
cpp_generator(SM, exported_types, exported_functions,
functions),
checked(checked)
{
}
void plain_cpp_generator::generate()
{
ostream &os = cout;
osprintf(os, "\n");
osprintf(os, "namespace isl {\n\n");
if (checked)
osprintf(os, "namespace checked {\n\n");
print_forward_declarations(os);
osprintf(os, "\n");
print_declarations(os);
osprintf(os, "\n");
print_implementations(os);
if (checked)
osprintf(os, "} // namespace checked\n");
osprintf(os, "} // namespace isl\n");
}
void plain_cpp_generator::print_forward_declarations(ostream &os)
{
map<string, isl_class>::iterator ci;
osprintf(os, "// forward declarations\n");
for (ci = classes.begin(); ci != classes.end(); ++ci)
print_class_forward_decl(os, ci->second);
}
void plain_cpp_generator::print_declarations(ostream &os)
{
map<string, isl_class>::iterator ci;
bool first = true;
for (ci = classes.begin(); ci != classes.end(); ++ci) {
if (first)
first = false;
else
osprintf(os, "\n");
print_class(os, ci->second);
}
}
void plain_cpp_generator::print_implementations(ostream &os)
{
map<string, isl_class>::iterator ci;
bool first = true;
for (ci = classes.begin(); ci != classes.end(); ++ci) {
if (first)
first = false;
else
osprintf(os, "\n");
print_class_impl(os, ci->second);
}
}
void plain_cpp_generator::decl_printer::print_subclass_type()
{
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",
generator.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());
}
void plain_cpp_generator::print_class(ostream &os, const isl_class &clazz)
{
decl_printer printer(os, clazz, *this);
const char *name = clazz.name.c_str();
const char *cppname = printer.cppstring.c_str();
osprintf(os, "// declarations for isl::%s\n", cppname);
printer.print_class_factory();
osprintf(os, "\n");
osprintf(os, "class %s ", cppname);
if (clazz.is_type_subclass())
osprintf(os, ": public %s ",
type2cpp(clazz.superclass_name).c_str());
osprintf(os, "{\n");
printer.print_subclass_type();
printer.print_class_factory(" friend ");
osprintf(os, "\n");
osprintf(os, " protected:\n");
if (!clazz.is_type_subclass()) {
osprintf(os, " %s *ptr = nullptr;\n", name);
osprintf(os, "\n");
}
printer.print_protected_constructors();
osprintf(os, "\n");
osprintf(os, " public:\n");
printer.print_public_methods();
osprintf(os, "};\n");
}
void plain_cpp_generator::print_class_forward_decl(ostream &os,
const isl_class &clazz)
{
std::string cppstring = type2cpp(clazz);
const char *cppname = cppstring.c_str();
osprintf(os, "class %s;\n", cppname);
}
void plain_cpp_generator::decl_printer::print_class_factory(
const std::string &prefix)
{
const char *name = clazz.name.c_str();
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;
osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n",
cppname, name);
}
void plain_cpp_generator::decl_printer::print_protected_constructors()
{
const char *name = clazz.name.c_str();
const char *cppname = cppstring.c_str();
osprintf(os, " inline explicit %s(__isl_take %s *ptr);\n", cppname,
name);
}
void plain_cpp_generator::decl_printer::print_public_constructors()
{
const char *cppname = cppstring.c_str();
osprintf(os, " inline /* implicit */ %s();\n", cppname);
osprintf(os, " inline /* implicit */ %s(const %s &obj);\n",
cppname, cppname);
}
void plain_cpp_generator::decl_printer::print_method(
const ConversionMethod &method)
{
print_full_method_header(method);
}
void plain_cpp_generator::decl_printer::print_method(const Method &method)
{
print_full_method_header(method);
}
void plain_cpp_generator::decl_printer::print_id_constructor_user()
{
print_id_constructor_user_header();
}
void plain_cpp_generator::decl_printer::print_id_user(bool optional)
{
print_id_user_header(optional);
}
void plain_cpp_generator::decl_printer::print_copy_assignment()
{
const char *cppname = cppstring.c_str();
osprintf(os, " inline %s &operator=(%s obj);\n", cppname, cppname);
}
void plain_cpp_generator::decl_printer::print_destructor()
{
const char *cppname = cppstring.c_str();
if (clazz.is_type_subclass())
return;
osprintf(os, " inline ~%s();\n", cppname);
}
void plain_cpp_generator::decl_printer::print_ptr()
{
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);
osprintf(os, " inline __isl_give %s *release();\n", name);
osprintf(os, " inline bool is_null() const;\n");
}
void plain_cpp_generator::decl_printer::print_isa_type_template(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");
}
void plain_cpp_generator::decl_printer::print_downcast()
{
if (!clazz.fn_type)
return;
osprintf(os, " private:\n");
print_isa_type_template(2, clazz);
osprintf(os, " inline %s isa_type(T subtype) const;\n",
generator.isl_bool2cpp().c_str());
osprintf(os, " public:\n");
osprintf(os, " template <class T> inline %s isa() const;\n",
generator.isl_bool2cpp().c_str());
osprintf(os, " template <class T> inline T as() const;\n");
}
void plain_cpp_generator::decl_printer::print_ctx()
{
std::string ns = generator.isl_namespace();
osprintf(os, " inline %sctx ctx() const;\n", ns.c_str());
}
void plain_cpp_generator::decl_printer::print_method_separator()
{
os << "\n";
}
static string add_space_to_return_type(const string &type)
{
if (type[type.size() - 1] == '*')
return type;
return type + " ";
}
void plain_cpp_generator::plain_printer::print_persistent_callback_prototype(
FunctionDecl *method)
{
string callback_name, rettype, c_args;
ParmVarDecl *param = persistent_callback_arg(method);
const FunctionProtoType *callback;
QualType ptype;
string classname;
ptype = param->getType();
callback = extract_prototype(ptype);
rettype = callback->getReturnType().getAsString();
rettype = add_space_to_return_type(rettype);
callback_name = clazz.persistent_callback_name(method);
c_args = generator.generate_callback_args(ptype, false);
if (!declarations)
classname = type2cpp(clazz) + "::";
osprintf(os, "%s%s%s(%s)",
rettype.c_str(), classname.c_str(),
callback_name.c_str(), c_args.c_str());
}
void
plain_cpp_generator::plain_printer::print_persistent_callback_setter_prototype(
FunctionDecl *method)
{
string classname, callback_name, cpptype;
ParmVarDecl *param = persistent_callback_arg(method);
if (!declarations)
classname = type2cpp(clazz) + "::";
cpptype = generator.param2cpp(param->getOriginalType());
callback_name = clazz.persistent_callback_name(method);
osprintf(os, "void %sset_%s_data(const %s &%s)",
classname.c_str(), callback_name.c_str(), cpptype.c_str(),
param->getName().str().c_str());
}
void plain_cpp_generator::decl_printer::print_persistent_callback_data(
FunctionDecl *method)
{
string callback_name;
ParmVarDecl *param = generator.persistent_callback_arg(method);
callback_name = clazz.persistent_callback_name(method);
print_callback_data_decl(param, callback_name);
osprintf(os, ";\n");
osprintf(os, " std::shared_ptr<%s_data> %s_data;\n",
callback_name.c_str(), callback_name.c_str());
osprintf(os, " static inline ");
print_persistent_callback_prototype(method);
osprintf(os, ";\n");
osprintf(os, " inline ");
print_persistent_callback_setter_prototype(method);
osprintf(os, ";\n");
}
void plain_cpp_generator::decl_printer::print_persistent_callbacks()
{
const char *cppname = cppstring.c_str();
if (!clazz.has_persistent_callbacks())
return;
osprintf(os, " private:\n");
osprintf(os, " inline %s ©_callbacks(const %s &obj);\n",
cppname, cppname);
for (const auto &callback : clazz.persistent_callbacks)
print_persistent_callback_data(callback);
osprintf(os, " public:\n");
for (const auto &callback : clazz.persistent_callbacks)
print_method(Method(clazz, callback));
}
void plain_cpp_generator::decl_printer::print_get_method(FunctionDecl *fd)
{
string base = clazz.base_method_name(fd);
print_method(Method(clazz, fd, base));
}
void plain_cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
{
impl_printer printer(os, clazz, *this);
const char *cppname = printer.cppstring.c_str();
osprintf(os, "// implementations for isl::%s", cppname);
printer.print_class_factory();
printer.print_protected_constructors();
printer.print_public_methods();
printer.print_stream_insertion();
}
static void print_throw_last_error(ostream &os)
{
osprintf(os, " exception::throw_last_error(saved_ctx);\n");
}
static void print_throw_invalid(ostream &os, int indent, const char *msg)
{
osprintf(os, indent,
"exception::throw_invalid(\"%s\", __FILE__, __LINE__);\n", msg);
}
static void print_throw_NULL_input(ostream &os)
{
print_throw_invalid(os, 4, "NULL input");
}
void plain_cpp_generator::print_invalid(ostream &os, int indent,
const char *msg, const char *checked_code)
{
if (checked)
osprintf(os, indent,
"isl_die(ctx().get(), isl_error_invalid, "
"\"%s\", %s);\n", msg, checked_code);
else
print_throw_invalid(os, indent, msg);
}
void plain_cpp_generator::impl_printer::print_stream_insertion()
{
const char *name = clazz.name.c_str();
const char *cppname = cppstring.c_str();
if (!clazz.fn_to_str)
return;
osprintf(os, "\n");
osprintf(os, "inline std::ostream &operator<<(std::ostream &os, ");
osprintf(os, "const %s &obj)\n", cppname);
osprintf(os, "{\n");
print_check_ptr_start("obj.get()");
osprintf(os, " char *str = %s_to_str(obj.get());\n", name);
print_check_ptr_end("str");
if (generator.checked) {
osprintf(os, " if (!str) {\n");
osprintf(os, " os.setstate(std::ios_base::badbit);\n");
osprintf(os, " return os;\n");
osprintf(os, " }\n");
}
osprintf(os, " os << str;\n");
osprintf(os, " free(str);\n");
osprintf(os, " return os;\n");
osprintf(os, "}\n");
}
void plain_cpp_generator::impl_printer::print_check_ptr(const char *ptr)
{
if (generator.checked)
return;
osprintf(os, " if (!%s)\n", ptr);
print_throw_NULL_input(os);
}
void plain_cpp_generator::impl_printer::print_check_ptr_start(const char *ptr)
{
if (generator.checked)
return;
print_check_ptr(ptr);
print_save_ctx(clazz.name + "_get_ctx(" + ptr + ")");
print_on_error_continue();
}
void plain_cpp_generator::impl_printer::print_check_ptr_end(const char *ptr)
{
if (generator.checked)
return;
osprintf(os, " if (!%s)\n", ptr);
print_throw_last_error(os);
}
void plain_cpp_generator::impl_printer::print_class_factory()
{
const char *name = clazz.name.c_str();
const char *cppname = cppstring.c_str();
if (clazz.is_type_subclass())
return;
osprintf(os, "\n");
osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
print_check_ptr("ptr");
osprintf(os, " return %s(ptr);\n", cppname);
osprintf(os, "}\n");
osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
name);
print_check_ptr_start("ptr");
osprintf(os, " ptr = %s_copy(ptr);\n", name);
print_check_ptr_end("ptr");
osprintf(os, " return %s(ptr);\n", cppname);
osprintf(os, "}\n");
}
void plain_cpp_generator::impl_printer::print_protected_constructors()
{
const char *name = clazz.name.c_str();
const char *cppname = cppstring.c_str();
bool subclass = clazz.is_type_subclass();
osprintf(os, "\n");
osprintf(os, "%s::%s(__isl_take %s *ptr)\n", cppname, cppname, name);
if (subclass)
osprintf(os, " : %s(ptr) {}\n",
type2cpp(clazz.superclass_name).c_str());
else
osprintf(os, " : ptr(ptr) {}\n");
}
void plain_cpp_generator::impl_printer::print_public_constructors()
{
std::string super;
const char *cppname = cppstring.c_str();
bool subclass = clazz.is_type_subclass();
osprintf(os, "\n");
if (subclass)
super = type2cpp(clazz.superclass_name);
osprintf(os, "%s::%s()\n", cppname, cppname);
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);
if (subclass)
osprintf(os, " : %s(obj)\n", super.c_str());
else
osprintf(os, " : ptr(nullptr)\n");
osprintf(os, "{\n");
if (!subclass) {
print_check_ptr_start("obj.ptr");
osprintf(os, " ptr = obj.copy();\n");
if (clazz.has_persistent_callbacks())
osprintf(os, " copy_callbacks(obj);\n");
print_check_ptr_end("ptr");
}
osprintf(os, "}\n");
}
void plain_cpp_generator::impl_printer::print_method(const Method &method)
{
string methodname = method.fd->getName().str();
int num_params = method.c_num_params();
osprintf(os, "\n");
print_full_method_header(method);
osprintf(os, "{\n");
print_argument_validity_check(method);
print_save_ctx(method);
print_on_error_continue();
for (const auto &callback : method.callbacks)
print_callback_local(callback);
osprintf(os, " auto res = %s", methodname.c_str());
method.print_fd_arg_list(os, 0, num_params, [&] (int i, int arg) {
method.print_param_use(os, i);
});
osprintf(os, ";\n");
print_exceptional_execution_check(method);
if (method.kind == Method::Kind::constructor) {
osprintf(os, " ptr = res;\n");
} else {
print_method_return(method);
}
osprintf(os, "}\n");
}
void plain_cpp_generator::impl_printer::print_arg_conversion(ParmVarDecl *dst,
ParmVarDecl *src)
{
std::string name = dst->getName().str();
QualType type = dst->getOriginalType();
string cpptype = generator.param2cpp(type);
if (dst == src)
os << name;
else if (is_isl_type(src->getOriginalType()))
os << cpptype << "(" << name << ")";
else
os << cpptype << "(ctx(), " << name << ")";
}
void plain_cpp_generator::impl_printer::print_method(
const ConversionMethod &method)
{
if (method.kind != Method::Kind::member_method)
die("Automatic conversion currently only supported "
"for object methods");
osprintf(os, "\n");
print_full_method_header(method);
osprintf(os, "{\n");
print_check_ptr("ptr");
osprintf(os, " return ");
method.print_call(os, generator.isl_namespace());
method.print_cpp_arg_list(os, [&] (int i, int arg) {
ParmVarDecl *param = method.fd->getParamDecl(i);
print_arg_conversion(param, method.get_param(i));
});
osprintf(os, ";\n");
osprintf(os, "}\n");
}
void plain_cpp_generator::impl_printer::print_id_constructor_user()
{
print_id_constructor_user_header();
os << "{\n";
if (!generator.checked) {
print_save_ctx("ctx");
print_on_error_continue();
}
os << " std::any *p = new std::any(any);\n";
os << " auto res = isl_id_alloc(ctx.get(), str.c_str(), p);\n";
os << " res = isl_id_set_free_user(res, &ctx::free_user);\n";
os << " if (!res) {\n";
os << " delete p;\n";
if (!generator.checked)
print_throw_last_error(os);
os << " }\n";
os << " ptr = res;\n";
os << "}\n";
}
void plain_cpp_generator::impl_printer::print_id_user(bool optional)
{
auto fail = [&] (const char *msg) {
if (optional)
os << " return std::nullopt;\n";
else
generator.print_invalid(os, 4, msg, "return T()");
};
os << "\n";
print_id_user_header(optional);
os << "{\n";
print_check_ptr("ptr");
os << " std::any *p = (std::any *) isl_id_get_user(ptr);\n";
os << " if (!p)\n";
fail("no user pointer");
os << " if (isl_id_get_free_user(ptr) != &ctx::free_user)\n";
fail("user pointer not attached by C++ interface");
os << " T *res = std::any_cast<T>(p);\n";
os << " if (!res)\n";
fail("user pointer not of given type");
os << " return *res;\n";
os << "}\n";
}
void plain_cpp_generator::impl_printer::print_copy_assignment()
{
const char *name = clazz.name.c_str();
const char *cppname = cppstring.c_str();
osprintf(os, "\n");
osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname,
cppname, cppname);
osprintf(os, " std::swap(this->ptr, obj.ptr);\n", name);
if (clazz.has_persistent_callbacks())
osprintf(os, " copy_callbacks(obj);\n");
osprintf(os, " return *this;\n");
osprintf(os, "}\n");
}
void plain_cpp_generator::impl_printer::print_destructor()
{
const char *name = clazz.name.c_str();
const char *cppname = cppstring.c_str();
if (clazz.is_type_subclass())
return;
osprintf(os, "\n");
osprintf(os, "%s::~%s() {\n", cppname, cppname);
osprintf(os, " if (ptr)\n");
osprintf(os, " %s_free(ptr);\n", name);
osprintf(os, "}\n");
}
void plain_cpp_generator::print_check_no_persistent_callback(ostream &os,
const isl_class &clazz, FunctionDecl *fd)
{
string callback_name = clazz.persistent_callback_name(fd);
osprintf(os, " if (%s_data)\n", callback_name.c_str());
print_invalid(os, 4, "cannot release object with persistent callbacks",
"return nullptr");
}
void plain_cpp_generator::impl_printer::print_ptr()
{
const char *name = clazz.name.c_str();
const char *cppname = cppstring.c_str();
set<FunctionDecl *>::const_iterator in;
const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
if (clazz.is_type_subclass())
return;
osprintf(os, "\n");
osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
osprintf(os, " return %s_copy(ptr);\n", name);
osprintf(os, "}\n\n");
osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
osprintf(os, " return ptr;\n");
osprintf(os, "}\n\n");
osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
for (in = callbacks.begin(); in != callbacks.end(); ++in)
generator.print_check_no_persistent_callback(os, clazz, *in);
osprintf(os, " %s *tmp = ptr;\n", name);
osprintf(os, " ptr = nullptr;\n");
osprintf(os, " return tmp;\n");
osprintf(os, "}\n\n");
osprintf(os, "bool %s::is_null() const {\n", cppname);
osprintf(os, " return ptr == nullptr;\n");
osprintf(os, "}\n");
}
void plain_cpp_generator::impl_printer::print_downcast()
{
const char *cppname = cppstring.c_str();
if (!clazz.fn_type)
return;
osprintf(os, "\n");
osprintf(os, "template <typename T, typename>\n");
osprintf(os, "%s %s::isa_type(T subtype) const\n",
generator.isl_bool2cpp().c_str(), cppname);
osprintf(os, "{\n");
osprintf(os, " if (is_null())\n");
if (generator.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",
generator.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 (generator.checked)
osprintf(os, " if (isa<T>().is_false())\n");
else
osprintf(os, " if (!isa<T>())\n");
generator.print_invalid(os, 4, "not an object of the requested subtype",
"return T()");
osprintf(os, " return T(copy());\n");
osprintf(os, "}\n");
}
void plain_cpp_generator::impl_printer::print_ctx()
{
const char *name = clazz.name.c_str();
const char *cppname = cppstring.c_str();
std::string ns = generator.isl_namespace();
osprintf(os, "\n");
osprintf(os, "%sctx %s::ctx() const {\n", ns.c_str(), cppname);
osprintf(os, " return %sctx(%s_get_ctx(ptr));\n", ns.c_str(), name);
osprintf(os, "}\n");
}
void plain_cpp_generator::impl_printer::print_method_separator()
{
}
void plain_cpp_generator::impl_printer::print_persistent_callbacks()
{
const char *cppname = cppstring.c_str();
string classname = type2cpp(clazz);
if (!clazz.has_persistent_callbacks())
return;
osprintf(os, "\n");
osprintf(os, "%s &%s::copy_callbacks(const %s &obj)\n",
cppname, classname.c_str(), cppname);
osprintf(os, "{\n");
for (const auto &callback : clazz.persistent_callbacks) {
string callback_name = clazz.persistent_callback_name(callback);
osprintf(os, " %s_data = obj.%s_data;\n",
callback_name.c_str(), callback_name.c_str());
}
osprintf(os, " return *this;\n");
osprintf(os, "}\n");
for (const auto &callback : clazz.persistent_callbacks)
print_set_persistent_callback(Method(clazz, callback));
}
void plain_cpp_generator::impl_printer::print_get_method(FunctionDecl *fd)
{
string get_name = clazz.base_method_name(fd);
string name = clazz.method_name(fd);
int num_params = fd->getNumParams();
osprintf(os, "\n");
print_full_method_header(Method(clazz, fd, get_name));
osprintf(os, "{\n");
osprintf(os, " return %s(", name.c_str());
for (int i = 1; i < num_params; ++i) {
ParmVarDecl *param = fd->getParamDecl(i);
if (i != 1)
osprintf(os, ", ");
osprintf(os, "%s", param->getName().str().c_str());
}
osprintf(os, ");\n");
osprintf(os, "}\n");
}
void plain_cpp_generator::impl_printer::print_argument_validity_check(
const Method &method)
{
int n;
bool first = true;
if (generator.checked)
return;
n = method.num_params();
for (int i = 0; i < n; ++i) {
bool is_this;
ParmVarDecl *param = method.fd->getParamDecl(i);
string name = param->getName().str();
const char *name_str = name.c_str();
QualType type = param->getOriginalType();
is_this = i == 0 && method.kind == Method::Kind::member_method;
if (!is_this && (is_isl_ctx(type) || !is_isl_type(type)))
continue;
if (first)
osprintf(os, " if (");
else
osprintf(os, " || ");
if (is_this)
osprintf(os, "!ptr");
else
osprintf(os, "%s.is_null()", name_str);
first = false;
}
if (first)
return;
osprintf(os, ")\n");
print_throw_NULL_input(os);
}
void plain_cpp_generator::impl_printer::print_save_ctx(const std::string &ctx)
{
os << " auto saved_ctx = " << ctx << ";\n";
}
void plain_cpp_generator::impl_printer::print_save_ctx(const Method &method)
{
int n;
ParmVarDecl *param = method.fd->getParamDecl(0);
QualType type = param->getOriginalType();
if (generator.checked)
return;
if (method.kind == Method::Kind::member_method)
return print_save_ctx("ctx()");
if (is_isl_ctx(type))
return print_save_ctx(param->getName().str());
n = method.num_params();
for (int i = 0; i < n; ++i) {
ParmVarDecl *param = method.fd->getParamDecl(i);
QualType type = param->getOriginalType();
if (!is_isl_type(type))
continue;
print_save_ctx(param->getName().str() + ".ctx()");
return;
}
}
void plain_cpp_generator::impl_printer::print_on_error_continue()
{
if (generator.checked)
return;
osprintf(os, " options_scoped_set_on_error saved_on_error(saved_ctx, "
"exception::on_error);\n");
}
static void print_persistent_callback_exceptional_execution_check(ostream &os,
const Method &method)
{
if (method.kind != Method::Kind::member_method)
return;
for (const auto &pcb : method.clazz.persistent_callbacks) {
auto callback_name = method.clazz.persistent_callback_name(pcb);
osprintf(os, " if (%s_data && %s_data->eptr) {\n",
callback_name.c_str(), callback_name.c_str());
osprintf(os, " std::exception_ptr eptr = %s_data->eptr;\n",
callback_name.c_str());
osprintf(os, " %s_data->eptr = nullptr;\n",
callback_name.c_str());
osprintf(os, " std::rethrow_exception(eptr);\n");
osprintf(os, " }\n");
}
}
void plain_cpp_generator::impl_printer::print_exceptional_execution_check(
const Method &method)
{
bool check_null, check_neg;
QualType return_type = method.fd->getReturnType();
if (generator.checked)
return;
print_persistent_callback_exceptional_execution_check(os, method);
for (const auto &callback : method.callbacks) {
std::string name;
name = callback->getName().str();
osprintf(os, " if (%s_data.eptr)\n", name.c_str());
osprintf(os, " std::rethrow_exception(%s_data.eptr);\n",
name.c_str());
}
check_neg = is_isl_neg_error(return_type);
check_null = is_isl_type(return_type);
if (!check_null && !check_neg)
return;
if (check_neg)
osprintf(os, " if (res < 0)\n");
else
osprintf(os, " if (!res)\n");
print_throw_last_error(os);
}
std::unique_ptr<cpp_type_printer> plain_cpp_generator::type_printer()
{
cpp_type_printer *printer;
if (checked)
printer = new checked_cpp_type_printer();
else
printer = new cpp_type_printer();
return std::unique_ptr<cpp_type_printer>(printer);
}
std::string plain_cpp_generator::get_return_type(const Method &method)
{
return type_printer()->return_type(method);
}
void plain_cpp_generator::impl_printer::print_set_persistent_callback(
const Method &method)
{
string fullname = method.fd->getName().str();
ParmVarDecl *param = persistent_callback_arg(method.fd);
string pname;
string callback_name = clazz.persistent_callback_name(method.fd);
osprintf(os, "\n");
print_persistent_callback_prototype(method.fd);
osprintf(os, "\n");
osprintf(os, "{\n");
print_callback_body(2, param, callback_name);
osprintf(os, "}\n\n");
pname = param->getName().str();
print_persistent_callback_setter_prototype(method.fd);
osprintf(os, "\n");
osprintf(os, "{\n");
print_check_ptr_start("ptr");
osprintf(os, " %s_data = std::make_shared<struct %s_data>();\n",
callback_name.c_str(), callback_name.c_str());
osprintf(os, " %s_data->func = %s;\n",
callback_name.c_str(), pname.c_str());
osprintf(os, " ptr = %s(ptr, &%s, %s_data.get());\n",
fullname.c_str(), callback_name.c_str(), callback_name.c_str());
print_check_ptr_end("ptr");
osprintf(os, "}\n\n");
print_full_method_header(method);
osprintf(os, "{\n");
osprintf(os, " auto copy = *this;\n");
osprintf(os, " copy.set_%s_data(%s);\n",
callback_name.c_str(), pname.c_str());
osprintf(os, " return copy;\n");
osprintf(os, "}\n");
}
void plain_cpp_generator::impl_printer::print_method_return(
const Method &method)
{
QualType return_type = method.fd->getReturnType();
string rettype_str = generator.get_return_type(method);
bool returns_super = method.is_subclass_mutator();
if (is_isl_type(return_type) ||
(generator.checked && is_isl_neg_error(return_type))) {
osprintf(os, " return manage(res)");
if (is_mutator(clazz, method.fd) &&
clazz.has_persistent_callbacks())
osprintf(os, ".copy_callbacks(*this)");
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)) {
osprintf(os, " std::string tmp(res);\n");
if (gives(method.fd))
osprintf(os, " free(res);\n");
osprintf(os, " return tmp;\n");
} else {
osprintf(os, " return res;\n");
}
}
void plain_cpp_generator::plain_printer::print_full_method_header(
const Method &method)
{
auto type_printer = generator.type_printer();
print_method_header(method, *type_printer);
if (declarations)
osprintf(os, ";");
osprintf(os, "\n");
}
string plain_cpp_generator::generate_callback_args(QualType type, bool cpp)
{
return type_printer()->generate_callback_args(-1, type, cpp);
}
string plain_cpp_generator::generate_callback_type(QualType type)
{
return type_printer()->generate_callback_type(-1, type);
}
void plain_cpp_generator::impl_printer::print_wrapped_call_checked(int indent,
const string &call)
{
osprintf(os, indent, "auto ret = %s;\n", call.c_str());
osprintf(os, indent, "return ret.release();\n");
}
void plain_cpp_generator::impl_printer::print_wrapped_call(int indent,
const string &call, QualType rtype)
{
if (generator.checked)
return print_wrapped_call_checked(indent, call);
osprintf(os, indent, "ISL_CPP_TRY {\n");
if (is_isl_stat(rtype))
osprintf(os, indent, " %s;\n", call.c_str());
else
osprintf(os, indent, " auto ret = %s;\n", call.c_str());
if (is_isl_stat(rtype))
osprintf(os, indent, " return isl_stat_ok;\n");
else if (is_isl_bool(rtype))
osprintf(os, indent,
" return ret ? isl_bool_true : isl_bool_false;\n");
else
osprintf(os, indent, " return ret.release();\n");
osprintf(os, indent, "} ISL_CPP_CATCH_ALL {\n");
osprintf(os, indent, " data->eptr = std::current_exception();\n");
if (is_isl_stat(rtype))
osprintf(os, indent, " return isl_stat_error;\n");
else if (is_isl_bool(rtype))
osprintf(os, indent, " return isl_bool_error;\n");
else
osprintf(os, indent, " return NULL;\n");
osprintf(os, indent, "}\n");
}
void plain_cpp_generator::plain_printer::print_callback_data_decl(
ParmVarDecl *param,
const string &prefix)
{
string cpp_args;
cpp_args = generator.generate_callback_type(param->getType());
osprintf(os, " struct %s_data {\n", prefix.c_str());
osprintf(os, " %s func;\n", cpp_args.c_str());
if (!generator.checked)
osprintf(os, " std::exception_ptr eptr;\n");
osprintf(os, " }");
}
bool plain_cpp_generator::plain_printer::want_descendent_overloads(
const function_set &methods)
{
return methods.size() > 1;
}
void plain_cpp_generator::plain_printer::print_id_constructor_user_header()
{
if (declarations)
os << " inline explicit ";
else
os << "id::";
os << "id(" << generator.isl_namespace() << "ctx ctx, "
<< "const std::string &str, const std::any &any)";
if (declarations)
os << ";";
os << "\n";
}
void plain_cpp_generator::plain_printer::print_id_user_header(bool optional)
{
auto indent = declarations ? " " : "";
os << indent << "template <class T>\n";
os << indent << (optional ? "std::optional<T> " : "T ");
if (!declarations)
os << "id::";
os << (optional ? "try_" : "");
os << "user() const";
if (declarations)
os << ";";
os << "\n";
}
static void on_cplusplus17(ostream &os, const std::function<void(void)> &fn)
{
os << "#if __cplusplus >= 201703L\n";
fn();
os << "#endif\n";
}
void plain_cpp_generator::plain_printer::print_special_id()
{
os << "\n";
on_cplusplus17(os, [this] () {
print_id_constructor_user();
print_id_user(true);
print_id_user(false);
});
}
void plain_cpp_generator::plain_printer::print_special()
{
if (clazz.name == "isl_id")
print_special_id();
}
void plain_cpp_generator::plain_printer::print_public_methods()
{
print_public_constructors();
print_constructors();
print_copy_assignment();
print_destructor();
print_ptr();
print_downcast();
print_ctx();
print_method_separator();
print_persistent_callbacks();
print_methods();
print_set_enums();
print_special();
}
void plain_cpp_generator::impl_printer::print_callback_body(int indent,
ParmVarDecl *param, const string &prefix)
{
QualType ptype, rtype;
string call, last_idx;
const FunctionProtoType *callback;
int num_params;
ptype = param->getType();
callback = extract_prototype(ptype);
rtype = callback->getReturnType();
num_params = callback->getNumArgs();
last_idx = ::to_string(num_params - 1);
call = "(data->func)(";
for (long i = 0; i < num_params - 1; i++) {
if (!generator.callback_takes_argument(param, i))
call += "manage_copy";
else
call += "manage";
call += "(arg_" + ::to_string(i) + ")";
if (i != num_params - 2)
call += ", ";
}
call += ")";
osprintf(os, indent,
"auto *data = static_cast<struct %s_data *>(arg_%s);\n",
prefix.c_str(), last_idx.c_str());
print_wrapped_call(indent, call, rtype);
}
void plain_cpp_generator::impl_printer::print_callback_local(ParmVarDecl *param)
{
string pname;
QualType ptype, rtype;
string c_args, cpp_args, rettype;
const FunctionProtoType *callback;
pname = param->getName().str();
ptype = param->getType();
c_args = generator.generate_callback_args(ptype, false);
callback = extract_prototype(ptype);
rtype = callback->getReturnType();
rettype = rtype.getAsString();
print_callback_data_decl(param, pname);
osprintf(os, " %s_data = { %s };\n", pname.c_str(), pname.c_str());
osprintf(os, " auto %s_lambda = [](%s) -> %s {\n",
pname.c_str(), c_args.c_str(), rettype.c_str());
print_callback_body(4, param, pname);
osprintf(os, " };\n");
}
std::string checked_cpp_type_printer::isl_bool() const
{
return "boolean";
}
string plain_cpp_generator::isl_bool2cpp()
{
return type_printer()->isl_bool();
}
string checked_cpp_type_printer::isl_stat() const
{
return "stat";
}
string checked_cpp_type_printer::isl_size() const
{
return "class size";
}
std::string checked_cpp_type_printer::isl_namespace() const
{
return "isl::checked::";
}
string plain_cpp_generator::isl_namespace()
{
return type_printer()->isl_namespace();
}
string plain_cpp_generator::param2cpp(QualType type)
{
return type_printer()->param(-1, type);
}