brintos

brintos / llvm-project-archived public Read only

0
0
Text · 39.4 KiB · d5c08eb Raw
1312 lines · plain
1/*2 * Copyright 2016, 2017 Tobias Grosser. All rights reserved.3 *4 * Redistribution and use in source and binary forms, with or without5 * modification, are permitted provided that the following conditions6 * are met:7 *8 *    1. Redistributions of source code must retain the above copyright9 *       notice, this list of conditions and the following disclaimer.10 *11 *    2. Redistributions in binary form must reproduce the above12 *       copyright notice, this list of conditions and the following13 *       disclaimer in the documentation and/or other materials provided14 *       with the distribution.15 *16 * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOBIAS GROSSER OR20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.27 *28 * The views and conclusions contained in the software and documentation29 * are those of the authors and should not be interpreted as30 * representing official policies, either expressed or implied, of31 * Tobias Grosser.32 */33 34#include <iostream>35#include <string>36#include <vector>37 38#include "cpp.h"39#include "isl_config.h"40 41/* Determine the isl types from which the given class can be implicitly42 * constructed using a unary constructor.43 *44 * Look through all constructors for implicit conversion constructors that take45 * an isl type and add those types, along with the corresponding46 * constructor argument.47 */48void cpp_generator::set_class_construction_types(isl_class &clazz)49{50	for (const auto &cons : clazz.constructors) {51		ParmVarDecl *param;52		QualType type;53		std::string arg_type;54 55		if (!is_implicit_conversion(Method(clazz, cons)))56			continue;57 58		param = cons->getParamDecl(0);59		type = param->getOriginalType();60		arg_type = extract_type(type);61		clazz.construction_types.emplace(arg_type, param);62	}63}64 65/* Determine the isl types from which any (proper) class can be constructed66 * using a unary constructor.67 */68void cpp_generator::set_construction_types()69{70	for (auto &kvp : classes) {71		auto &clazz = kvp.second;72		set_class_construction_types(clazz);73	}74}75 76/* Construct a generator for C++ bindings.77 *78 * The classes and methods are extracted by the constructor79 * of the generator superclass.80 *81 * Additionally extract information about types82 * that can be converted to a class and copy all methods83 * from superclasses that can be converted to a given class84 * to that class.85 */86cpp_generator::cpp_generator(SourceManager &SM,87	set<RecordDecl *> &exported_types,88	set<FunctionDecl *> exported_functions, set<FunctionDecl *> functions) :89		generator(SM, exported_types, exported_functions, functions)90{91	set_construction_types();92	copy_super_methods();93}94 95/* Copy the method called "name" described by "fd" from "super" to "clazz"96 * with the distance to the original ancestor given by "depth".97 *98 * In particular, keep track of "fd" as well as the superclass99 * from which it was copied and the distance to the original ancestor.100 */101static void copy_method(isl_class &clazz, const isl_class &super,102	const std::string &name, FunctionDecl *fd, int depth)103{104	clazz.methods[name].insert(fd);105	clazz.copied_from.emplace(fd, super);106	clazz.copy_depth.emplace(fd, depth);107}108 109/* Do "fd1" and "fd2" have the same signature (ignoring the first argument110 * which represents the object class on which the corresponding method111 * gets called).112 */113static bool same_signature(FunctionDecl *fd1, FunctionDecl *fd2)114{115	int n1 = fd1->getNumParams();116	int n2 = fd2->getNumParams();117 118	if (n1 != n2)119		return false;120 121	for (int i = 1; i < n1; ++i) {122		ParmVarDecl *p1 = fd1->getParamDecl(i);123		ParmVarDecl *p2 = fd2->getParamDecl(i);124 125		if (p1->getOriginalType() != p2->getOriginalType())126			return false;127	}128 129	return true;130}131 132/* Return the distance between "clazz" and the ancestor133 * from which "fd" got copied.134 * If no distance was recorded, then the method has not been copied135 * but appears in "clazz" itself and so the distance is zero.136 */137static int copy_depth(const isl_class &clazz, FunctionDecl *fd)138{139	if (clazz.copy_depth.count(fd) == 0)140		return 0;141	return clazz.copy_depth.at(fd);142}143 144/* Is the method derived from "fd", with method name "name" and145 * with distance to the original ancestor "depth",146 * overridden by a method already in "clazz"?147 *148 * A method is considered to have been overridden if there149 * is a method with the same name in "clazz" that has the same signature and150 * that comes from an ancestor closer to "clazz",151 * where an ancestor is closer if the distance in the class hierarchy152 * is smaller or the distance is the same and the ancestor appears153 * closer in the declaration of the type (in which case it gets added first).154 *155 * If a method with the same signature has already been added,156 * but it does not override the method derived from "fd",157 * then this method is removed since it is overridden by "fd".158 */159static bool is_overridden(FunctionDecl *fd, isl_class &clazz,160	const std::string &name, int depth)161{162	if (clazz.methods.count(name) == 0)163		return false;164 165	for (const auto &m : clazz.methods.at(name)) {166		if (!same_signature(fd, m))167			continue;168		if (copy_depth(clazz, m) <= depth)169			return true;170		clazz.methods[name].erase(m);171		return false;172	}173	return false;174}175 176/* Add the methods "methods" with method name "name" from "super" to "clazz"177 * provided they have not been overridden by a method already in "clazz".178 *179 * Methods that are static in their original class are not copied.180 */181void cpp_generator::copy_methods(isl_class &clazz, const std::string &name,182	const isl_class &super, const function_set &methods)183{184	for (auto fd : methods) {185		int depth;186 187		if (method2class(fd)->is_static(fd))188			continue;189		depth = copy_depth(super, fd) + 1;190		if (is_overridden(fd, clazz, name, depth))191			continue;192		copy_method(clazz, super, name, fd, depth);193	}194}195 196/* Add all methods from "super" to "clazz" that have not been overridden197 * by a method already in "clazz".198 *199 * Look through all groups of methods with the same name.200 */201void cpp_generator::copy_super_methods(isl_class &clazz, const isl_class &super)202{203	for (const auto &kvp : super.methods) {204		const auto &name = kvp.first;205		const auto &methods = kvp.second;206 207		copy_methods(clazz, name, super, methods);208	}209}210 211/* Copy methods from the superclasses of "clazz"212 * if an object of this class can be implicitly converted to an object213 * from the superclass, keeping track214 * of the classes that have already been handled in "done".215 *216 * Make sure the superclasses have copied methods from their superclasses first217 * since those methods could be copied further down to this class.218 *219 * Consider the superclass that appears closest to the subclass first.220 */221void cpp_generator::copy_super_methods(isl_class &clazz, set<string> &done)222{223	auto supers = find_superclasses(clazz.type);224 225	for (const auto &super : supers)226		if (done.count(super) == 0)227			copy_super_methods(classes[super], done);228	done.insert(clazz.name);229 230	for (const auto &super_name : supers) {231		const auto &super = classes[super_name];232 233		if (super.construction_types.count(clazz.name) == 0)234			continue;235		copy_super_methods(clazz, super);236	}237}238 239/* For each (proper) class, copy methods from its superclasses,240 * if an object from the class can be converted to an object241 * from the superclass.242 *243 * Type based subclasses are not considered for now since244 * they do not have any explicit superclasses.245 *246 * Iterate through all (proper) classes and copy methods247 * from their superclasses,248 * unless they have already been determined by a recursive call.249 */250void cpp_generator::copy_super_methods()251{252	set<string> done;253 254	for (auto &kvp : classes) {255		auto &clazz = kvp.second;256 257		if (clazz.is_type_subclass())258			continue;259		if (done.count(clazz.name) != 0)260			continue;261		copy_super_methods(clazz, done);262	}263}264 265/* Print declarations or implementations of constructors.266 *267 * For each isl function that is marked as __isl_constructor,268 * add a corresponding C++ constructor.269 *270 * Example of declarations:271 *272 * 	inline /\* implicit *\/ union_set(basic_set bset);273 * 	inline /\* implicit *\/ union_set(set set);274 * 	inline explicit val(ctx ctx, long i);275 * 	inline explicit val(ctx ctx, const std::string &str);276 */277void cpp_generator::class_printer::print_constructors()278{279	for (const auto &cons : clazz.constructors)280		print_method(Method(clazz, cons));281}282 283/* Print declarations or definitions for methods in the class.284 */285void cpp_generator::class_printer::print_methods()286{287	for (const auto &kvp : clazz.methods)288		print_method_group(kvp.second, kvp.first);289}290 291/* Print declarations or implementations for the methods derived from "fd",292 * which sets an enum.293 *294 * A method is generated for each value in the enum, setting295 * the enum to that value.296 */297void cpp_generator::class_printer::print_set_enums(FunctionDecl *fd)298{299	for (const auto &set : clazz.set_enums.at(fd)) {300		EnumMethod method(clazz, fd, set.method_name, set.name);301 302		print_method(method);303	}304}305 306/* Print declarations or implementations for methods derived from functions307 * that set an enum.308 */309void cpp_generator::class_printer::print_set_enums()310{311	for (const auto &kvp : clazz.set_enums)312		print_set_enums(kvp.first);313}314 315/* Update "convert" to reflect the next combination of automatic conversions316 * for the arguments of "fd",317 * returning false if there are no more combinations.318 *319 * In particular, find the last argument for which an automatic320 * conversion function is available mapping to the type of this argument and321 * that is not already marked for conversion.322 * Mark this argument, if any, for conversion and clear the markings323 * of all subsequent arguments.324 * Repeated calls to this method therefore run through325 * all possible combinations.326 *327 * Note that the first function argument is never considered328 * for automatic conversion since this is the argument329 * from which the isl_ctx used in the conversion is extracted.330 */331bool cpp_generator::class_printer::next_variant(FunctionDecl *fd,332	std::vector<bool> &convert)333{334	size_t n = convert.size();335 336	for (int i = n - 1; i >= 1; --i) {337		ParmVarDecl *param = fd->getParamDecl(i);338		const Type *type = param->getOriginalType().getTypePtr();339 340		if (generator.conversions.count(type) == 0)341			continue;342		if (convert[i])343			continue;344		convert[i] = true;345		for (size_t j = i + 1; j < n; ++j)346			convert[j] = false;347		return true;348	}349 350	return false;351}352 353/* Print a declaration or definition for a method called "name"354 * derived from "fd".355 *356 * If the method was copied from a superclass, then print a definition357 * that calls the corresponding method in the superclass.358 * Otherwise, for methods that are identified as "get" methods, also359 * print a declaration or definition for the method360 * using a name that includes the "get_" prefix.361 *362 * If the generated method is an object method, then check363 * whether any of its arguments can be automatically converted364 * from something else, and, if so, generate a method365 * for each combination of converted arguments.366 * Do so by constructing a ConversionMethod that changes the converted arguments367 * to those of the sources of the conversions.368 *369 * Note that a method may be both copied from a superclass and370 * have arguments that can be automatically converted.371 * In this case, the conversion methods for the arguments372 * call the corresponding method in this class, which373 * in turn will call the method in the superclass.374 */375void cpp_generator::class_printer::print_method_variants(FunctionDecl *fd,376	const std::string &name)377{378	Method method(clazz, fd, name);379	std::vector<bool> convert(method.num_params());380 381	if (method.clazz.copied_from.count(method.fd) == 0) {382		print_method(method);383		if (clazz.is_get_method(fd))384			print_get_method(fd);385	} else {386		auto super = method.clazz.copied_from.at(method.fd);387		print_method(ConversionMethod(method, super.name));388	}389	if (method.kind != Method::Kind::member_method)390		return;391	while (next_variant(fd, convert)) {392		print_method(ConversionMethod(method, [&] (int pos) {393			return get_param(fd, pos, convert);394		}));395	}396}397 398/* Given a function declaration representing a method,399 * does this method have a single argument (beyond the object400 * on which the method is called) that corresponds to401 * an isl object?402 */403static bool has_single_isl_argument(FunctionDecl *fd)404{405	ParmVarDecl *param;406 407	if (fd->getNumParams() != 2)408		return false;409 410	param = fd->getParamDecl(1);411	return generator::is_isl_type(param->getOriginalType());412}413 414/* Does the set "methods" contain exactly one function declaration415 * that corresponds to a method of "clazz" itself (i.e., that416 * was not copied from an ancestor)?417 */418static FunctionDecl *single_local(const isl_class &clazz,419	const function_set &methods)420{421	int count = 0;422	FunctionDecl *local;423 424	for (const auto &fn : methods) {425		if (!clazz.first_arg_matches_class(fn))426			continue;427		++count;428		local = fn;429	}430 431	return count == 1 ? local : NULL;432}433 434/* Given a function declaration "fd" for a method called "name"435 * with a single argument representing an isl object,436 * generate declarations or definitions for methods with the same name,437 * but with as argument an isl object of a class that can be implicitly438 * converted to that of the original argument.439 * In particular, generate methods for converting this argument.440 */441void cpp_generator::class_printer::print_descendent_overloads(442	FunctionDecl *fd, const std::string &name)443{444	Method method(clazz, fd, name);445	ParmVarDecl *param = fd->getParamDecl(1);446	QualType type = param->getOriginalType();447	std::string arg = type->getPointeeType().getAsString();448 449	for (const auto &kvp : generator.classes[arg].construction_types) {450		const auto sub = kvp.second;451		print_method(ConversionMethod(method, [&] (int pos) {452			return sub;453		}));454	}455}456 457/* Print declarations or definitions for methods called "name"458 * derived from "methods".459 *460 * If want_descendent_overloads signals that variants should be added that take461 * as arguments those types that can be converted to the original argument type462 * through a unary constructor and if only one of the methods in the group463 * was originally defined in "clazz", then effectively add those variants.464 * Only do this for methods with a single (isl object) argument.465 */466void cpp_generator::class_printer::print_method_group(467	const function_set &methods, const std::string &name)468{469	FunctionDecl *local;470 471	for (const auto &fd : methods)472		print_method_variants(fd, name);473	if (!want_descendent_overloads(methods))474		return;475	local = single_local(clazz, methods);476	if (!local)477		return;478	if (!has_single_isl_argument(local))479		return;480	print_descendent_overloads(local, name);481}482 483/* Print the use of the argument at position "pos" to "os".484 *485 * Member methods pass the isl object corresponding to "this"486 * as first argument (at position 0).487 * Any other arguments are passed along from the method arguments.488 *489 * If the argument value is loaded from a this pointer, the original490 * value must be preserved and must consequently be copied.  Values that are491 * loaded from method parameters do not need to be preserved, as such values492 * will already be copies of the actual parameters.  It is consequently possible493 * to directly take the pointer from these values, which saves494 * an unnecessary copy.495 *496 * In case the parameter is a callback function, two parameters get printed,497 * a wrapper for the callback function and a pointer to the actual498 * callback function.  The wrapper is expected to be available499 * in a previously declared variable <name>_lambda, while500 * the actual callback function is expected to be stored501 * in a structure called <name>_data.502 * The caller of this function must ensure that these variables exist.503 */504void Method::print_param_use(ostream &os, int pos) const505{506	ParmVarDecl *param = fd->getParamDecl(pos);507	bool load_from_this_ptr = pos == 0 && kind == member_method;508	string name = param->getName().str();509	QualType type = param->getOriginalType();510 511	if (type->isIntegerType()) {512		os << name;513		return;514	}515 516	if (generator::is_string(type)) {517		os << name << ".c_str()";518		return;519	}520 521	if (generator::is_callback(type)) {522		os << name << "_lambda, ";523		os << "&" << name << "_data";524		return;525	}526 527	if (!load_from_this_ptr)528		os << name << ".";529 530	if (generator::keeps(param)) {531		os << "get()";532	} else {533		if (load_from_this_ptr)534			os << "copy()";535		else536			os << "release()";537	}538}539 540/* Does the isl function from which this method is derived541 * modify an object of a subclass based on a type function?542 */543bool Method::is_subclass_mutator() const544{545	return clazz.is_type_subclass() && generator::is_mutator(clazz, fd);546}547 548/* Return the C++ return type of the method "method".549 *550 * If the corresponding function modifies an object of a subclass, then return551 * the type of this subclass.552 * Otherwise, return the C++ counterpart of the actual return type.553 */554std::string cpp_type_printer::return_type(const Method &method) const555{556	if (method.is_subclass_mutator())557		return cpp_generator::type2cpp(method.clazz);558	else559		return param(-1, method.fd->getReturnType());560}561 562/* Return the formal parameter at position "pos" of "fd".563 * However, if this parameter should be converted, as indicated564 * by "convert", then return the second formal parameter565 * of the conversion function instead.566 */567ParmVarDecl *cpp_generator::class_printer::get_param(FunctionDecl *fd,568	int pos, const std::vector<bool> &convert)569{570	ParmVarDecl *param = fd->getParamDecl(pos);571 572	if (!convert[pos])573		return param;574	return generator.conversions[param->getOriginalType().getTypePtr()];575}576 577/* Print the header for "method", without newline or semicolon,578 * using "type_printer" to print argument and return types.579 *580 * Print the header of a declaration if this->declarations is set,581 * otherwise print the header of a method definition.582 *583 * This function prints headers for member methods, static methods, and584 * constructors, either for their declaration or definition.585 *586 * Member functions are declared as "const", as they do not change the current587 * object, but instead create a new object. They always retrieve the first588 * parameter of the original isl function from the this-pointer of the object,589 * such that only starting at the second parameter the parameters of the590 * original function become part of the method's interface.591 *592 * A function593 *594 * 	__isl_give isl_set *isl_set_intersect(__isl_take isl_set *s1,595 * 		__isl_take isl_set *s2);596 *597 * is translated into:598 *599 * 	inline set intersect(set set2) const600 *601 * For static functions and constructors all parameters of the original isl602 * function are exposed.603 *604 * Parameters of which no copy is required, are passed605 * as const reference, which allows the compiler to optimize the parameter606 * transfer.607 *608 * Constructors are marked as explicit using the C++ keyword 'explicit' or as609 * implicit using a comment in place of the explicit keyword. By annotating610 * implicit constructors with a comment, users of the interface are made611 * aware of the potential danger that implicit construction is possible612 * for these constructors, whereas without a comment not every user would613 * know that implicit construction is allowed in absence of an explicit keyword.614 *615 * Note that in case "method" is a ConversionMethod, the argument returned616 * by Method::get_param may be different from the original argument.617 * The name of the argument is, however, derived from the original618 * function argument.619 */620void cpp_generator::class_printer::print_method_header(621	const Method &method, const cpp_type_printer &type_printer)622{623	string rettype_str = type_printer.return_type(method);624 625	if (declarations) {626		os << "  ";627 628		if (method.kind == Method::Kind::static_method)629			os << "static ";630 631		os << "inline ";632 633		if (method.kind == Method::Kind::constructor) {634			if (generator.is_implicit_conversion(method))635				os << "/* implicit */ ";636			else637				os << "explicit ";638		}639	}640 641	if (method.kind != Method::Kind::constructor)642		os << rettype_str << " ";643 644	if (!declarations)645		os << type_printer.class_type(cppstring) << "::";646 647	if (method.kind != Method::Kind::constructor)648		os << method.name;649	else650		os << cppstring;651 652	method.print_cpp_arg_list(os, [&] (int i, int arg) {653		std::string name = method.fd->getParamDecl(i)->getName().str();654		ParmVarDecl *param = method.get_param(i);655		QualType type = param->getOriginalType();656		string cpptype = type_printer.param(arg, type);657 658		if (!method.param_needs_copy(i))659			os << "const " << cpptype << " &" << name;660		else661			os << cpptype << " " << name;662	});663 664	if (method.kind == Method::Kind::member_method)665		os << " const";666}667 668/* Generate the list of argument types for a callback function of669 * type "type", appearing in argument position "arg".670 * If "cpp" is set, then generate the C++ type list, otherwise671 * the C type list.672 *673 * For a callback of type674 *675 *      isl_stat (*)(__isl_take isl_map *map, void *user)676 *677 * the following C++ argument list is generated:678 *679 *      map680 *681 * The arguments of the callback are considered to appear682 * after the position of the callback itself.683 */684std::string cpp_type_printer::generate_callback_args(int arg, QualType type,685	bool cpp) const686{687	std::string type_str;688	const FunctionProtoType *callback;689	int num_params;690 691	callback = generator::extract_prototype(type);692	num_params = callback->getNumArgs();693	if (cpp)694		num_params--;695 696	for (long i = 0; i < num_params; i++) {697		QualType type = callback->getArgType(i);698 699		if (cpp)700			type_str += param(arg + 1 + i, type);701		else702			type_str += type.getAsString();703 704		if (!cpp)705			type_str += "arg_" + ::to_string(i);706 707		if (i != num_params - 1)708			type_str += ", ";709	}710 711	return type_str;712}713 714/* Generate the full cpp type of a callback function of type "type",715 * appearing in argument position "arg".716 *717 * For a callback of type718 *719 *      isl_stat (*)(__isl_take isl_map *map, void *user)720 *721 * the following type is generated:722 *723 *      std::function<stat(map)>724 */725std::string cpp_type_printer::generate_callback_type(int arg, QualType type)726	const727{728	std::string type_str;729	const FunctionProtoType *callback = generator::extract_prototype(type);730	QualType return_type = callback->getReturnType();731	string rettype_str = param(arg, return_type);732 733	type_str = "std::function<";734	type_str += rettype_str;735	type_str += "(";736	type_str += generate_callback_args(arg, type, true);737	type_str += ")>";738 739	return type_str;740}741 742/* An array listing functions that must be renamed and the function name they743 * should be renamed to. We currently rename functions in case their name would744 * match a reserved C++ keyword, which is not allowed in C++.745 */746static const char *rename_map[][2] = {747	{ "union", "unite" },748};749 750/* Rename method "name" in case the method name in the C++ bindings should not751 * match the name in the C bindings. We do this for example to avoid752 * C++ keywords.753 */754static std::string rename_method(std::string name)755{756	for (size_t i = 0; i < sizeof(rename_map) / sizeof(rename_map[0]); i++)757		if (name.compare(rename_map[i][0]) == 0)758			return rename_map[i][1];759 760	return name;761}762 763/* Translate isl class "clazz" to its corresponding C++ type.764 * Use the name of the type based subclass, if any.765 */766string cpp_generator::type2cpp(const isl_class &clazz)767{768	return type2cpp(clazz.subclass_name);769}770 771/* Translate type string "type_str" to its C++ name counterpart.772*/773string cpp_generator::type2cpp(string type_str)774{775	return type_str.substr(4);776}777 778/* Return the C++ counterpart to the isl_bool type.779 *780 * By default, this is simply "bool" since781 * the exceptional case is handled through exceptions.782 */783std::string cpp_type_printer::isl_bool() const784{785	return "bool";786}787 788/* Return the C++ counterpart to the isl_stat type.789 *790 * By default, this is simply "void" since791 * the exceptional case is handled through exceptions.792 */793string cpp_type_printer::isl_stat() const794{795	return "void";796}797 798/* Return the C++ counterpart to the isl_size type.799 *800 * By default, this is simply "unsigned" since801 * the exceptional case is handled through exceptions.802 */803string cpp_type_printer::isl_size() const804{805	return "unsigned";806}807 808/* Return the namespace of the generated C++ bindings.809 *810 * By default, this is "isl::".811 */812std::string cpp_type_printer::isl_namespace() const813{814	return "isl::";815}816 817/* Return the class type given the C++ name.818 *819 * By default, directly use the C++ name.820 */821std::string cpp_type_printer::class_type(const std::string &cpp_name) const822{823	return cpp_name;824}825 826/* Return the qualified form of the given C++ isl type name appearing827 * in argument position "arg" (-1 for return type).828 *829 * By default, the argument position is ignored.830 */831std::string cpp_type_printer::qualified(int arg, const std::string &cpp_type)832	const833{834	return isl_namespace() + cpp_type;835}836 837/* Return the C++ counterpart to the given isl type appearing838 * in argument position "arg" (-1 for return type).839 */840std::string cpp_type_printer::isl_type(int arg, QualType type) const841{842	auto name = type->getPointeeType().getAsString();843	return qualified(arg, cpp_generator::type2cpp(name));844}845 846/* Translate parameter or return type "type" to its C++ name counterpart.847 * "arg" is the position of the argument, or -1 in case of the return type.848 * If any callback is involved, then the return type and arguments types849 * of the callback are considered to start at the position of the callback.850 */851std::string cpp_type_printer::param(int arg, QualType type) const852{853	if (cpp_generator::is_isl_type(type))854		return isl_type(arg, type);855 856	if (cpp_generator::is_isl_bool(type))857		return isl_bool();858 859	if (cpp_generator::is_isl_stat(type))860		return isl_stat();861 862	if (cpp_generator::is_isl_size(type))863		return isl_size();864 865	if (type->isIntegerType())866		return type.getAsString();867 868	if (cpp_generator::is_string(type))869		return "std::string";870 871	if (cpp_generator::is_callback(type))872		return generate_callback_type(arg, type);873 874	generator::die("Cannot convert type to C++ type");875}876 877/* Check if "subclass_type" is a subclass of "class_type".878 */879bool cpp_generator::is_subclass(QualType subclass_type,880	const isl_class &class_type)881{882	std::string type_str = subclass_type->getPointeeType().getAsString();883	std::vector<std::string> superclasses;884	std::vector<const isl_class *> parents;885	std::vector<std::string>::iterator ci;886 887	superclasses = generator::find_superclasses(classes[type_str].type);888 889	for (ci = superclasses.begin(); ci < superclasses.end(); ci++)890		parents.push_back(&classes[*ci]);891 892	while (!parents.empty()) {893		const isl_class *candidate = parents.back();894 895		parents.pop_back();896 897		if (&class_type == candidate)898			return true;899 900		superclasses = generator::find_superclasses(candidate->type);901 902		for (ci = superclasses.begin(); ci < superclasses.end(); ci++)903			parents.push_back(&classes[*ci]);904	}905 906	return false;907}908 909/* Check if "cons" is an implicit conversion constructor of class "clazz".910 *911 * An implicit conversion constructor is generated in case "cons" has a single912 * parameter, where the parameter type is a subclass of the class that is913 * currently being generated.914 */915bool cpp_generator::is_implicit_conversion(const Method &cons)916{917	const auto &clazz = cons.clazz;918	ParmVarDecl *param = cons.fd->getParamDecl(0);919	QualType type = param->getOriginalType();920 921	int num_params = cons.fd->getNumParams();922	if (num_params != 1)923		return false;924 925	if (is_isl_type(type) && !is_isl_ctx(type) && is_subclass(type, clazz))926		return true;927 928	return false;929}930 931/* Construct a list combiner for printing a list.932 */933Method::list_combiner Method::print_combiner(std::ostream &os)934{935	return {936		[&] () { os << "("; },937		[&] () { os << ", "; },938		[&] () { os << ")"; }939	};940}941 942/* Construct a list combiner for simply iterating over a list.943 */944Method::list_combiner Method::empty_combiner()945{946	return { [&] () { }, [&] () { }, [&] () { } };947}948 949/* Get kind of "method" in "clazz".950 *951 * Given the declaration of a static or member method, returns its kind.952 */953static Method::Kind get_kind(const isl_class &clazz, FunctionDecl *method)954{955	if (generator::is_constructor(method))956		return Method::Kind::constructor;957	else if (generator::is_static(clazz, method))958		return Method::Kind::static_method;959	else960		return Method::Kind::member_method;961}962 963/* Return the callback arguments of "fd".964 */965static std::vector<ParmVarDecl *> find_callback_args(FunctionDecl *fd)966{967	std::vector<ParmVarDecl *> callbacks;968	int num_params = fd->getNumParams();969 970	for (int i = 0; i < num_params; ++i) {971		ParmVarDecl *param = fd->getParamDecl(i);972		if (generator::is_callback(param->getType()))973			callbacks.emplace_back(param);974	}975 976	return callbacks;977}978 979/* Construct a C++ method object from the class to which is belongs,980 * the isl function from which it is derived and the method name.981 *982 * Perform any renaming of the method that may be required and983 * determine the type of the method.984 */985Method::Method(const isl_class &clazz, FunctionDecl *fd,986	const std::string &name) :987		clazz(clazz), fd(fd), name(rename_method(name)),988		kind(get_kind(clazz, fd)),989		callbacks(find_callback_args(fd))990{991}992 993/* Construct a C++ method object from the class to which is belongs and994 * the isl function from which it is derived.995 *996 * Obtain the default method name and continue997 * with the generic constructor.998 */999Method::Method(const isl_class &clazz, FunctionDecl *fd) :1000	Method(clazz, fd, clazz.method_name(fd))1001{1002}1003 1004/* Return the number of parameters of the corresponding C function.1005 *1006 * This number includes any possible user pointers that follow callback1007 * arguments.  These are skipped by Method::print_fd_arg_list1008 * during the actual argument printing.1009 */1010int Method::c_num_params() const1011{1012	return fd->getNumParams();1013}1014 1015/* Return the number of parameters of the method1016 * (including the implicit "this").1017 *1018 * By default, it is the same as the number of parameters1019 * of the corresponding C function.1020 */1021int Method::num_params() const1022{1023	return c_num_params();1024}1025 1026/* Call "on_arg_skip_next" on the arguments from "start" (inclusive)1027 * to "end" (exclusive), calling the methods of "combiner"1028 * before, between and after the arguments.1029 * If "on_arg_skip_next" returns true then the next argument is skipped.1030 */1031void Method::on_arg_list(int start, int end,1032	const Method::list_combiner &combiner,1033	const std::function<bool(int i)> &on_arg_skip_next)1034{1035	combiner.before();1036	for (int i = start; i < end; ++i) {1037		if (i != start)1038			combiner.between();1039		if (on_arg_skip_next(i))1040			++i;1041	}1042	combiner.after();1043}1044 1045/* Print the arguments from "start" (inclusive) to "end" (exclusive)1046 * as arguments to a method of C function call, using "print_arg_skip_next"1047 * to print each individual argument.  If this callback return true1048 * then the next argument is skipped.1049 */1050void Method::print_arg_list(std::ostream &os, int start, int end,1051	const std::function<bool(int i)> &print_arg_skip_next)1052{1053	on_arg_list(start, end, print_combiner(os), [&] (int i) {1054		return print_arg_skip_next(i);1055	});1056}1057 1058/* Call "on_arg" on the arguments from "start" (inclusive) to "end" (exclusive),1059 * calling the methods of "combiner" before, between and after the arguments.1060 * The first argument to "on_arg" is the position of the argument1061 * in this->fd.1062 * The second argument is the (first) position in the list of arguments1063 * with all callback arguments spliced in.1064 *1065 * Call on_arg_list to do the actual iteration over the arguments, skipping1066 * the user argument that comes after every callback argument.1067 * On the C++ side no user pointer is needed, as arguments can be forwarded1068 * as part of the std::function argument which specifies the callback function.1069 * The user pointer is also removed from the number of parameters1070 * of the C function because the pair of callback and user pointer1071 * is considered as a single argument that is printed as a whole1072 * by Method::print_param_use.1073 *1074 * In case of a callback argument, the second argument to "print_arg"1075 * is also adjusted to account for the spliced-in arguments of the callback.1076 * The return value takes the place of the callback itself,1077 * while the arguments (excluding the final user pointer)1078 * take the following positions.1079 */1080void Method::on_fd_arg_list(int start, int end,1081	const Method::list_combiner &combiner,1082	const std::function<void(int i, int arg)> &on_arg) const1083{1084	int arg = start;1085 1086	on_arg_list(start, end, combiner, [this, &on_arg, &arg] (int i) {1087		auto type = fd->getParamDecl(i)->getType();1088 1089		on_arg(i, arg++);1090		if (!generator::is_callback(type))1091			return false;1092		arg += generator::prototype_n_args(type) - 1;1093		return true;1094	});1095}1096 1097/* Print the arguments from "start" (inclusive) to "end" (exclusive)1098 * as arguments to a method of C function call, using "print_arg"1099 * to print each individual argument.1100 * The first argument to this callback is the position of the argument1101 * in this->fd.1102 * The second argument is the (first) position in the list of arguments1103 * with all callback arguments spliced in.1104 */1105void Method::print_fd_arg_list(std::ostream &os, int start, int end,1106	const std::function<void(int i, int arg)> &print_arg) const1107{1108	on_fd_arg_list(start, end, print_combiner(os), print_arg);1109}1110 1111/* Call "on_arg" on the arguments to the method call,1112 * calling the methods of "combiner" before, between and after the arguments.1113 * The first argument to "on_arg" is the position of the argument1114 * in this->fd.1115 * The second argument is the (first) position in the list of arguments1116 * with all callback arguments spliced in.1117 */1118void Method::on_cpp_arg_list(const Method::list_combiner &combiner,1119	const std::function<void(int i, int arg)> &on_arg) const1120{1121	int first_param = kind == member_method ? 1 : 0;1122	on_fd_arg_list(first_param, num_params(), combiner, on_arg);1123}1124 1125/* Call "on_arg" on the arguments to the method call.1126 * The first argument to "on_arg" is the position of the argument1127 * in this->fd.1128 * The second argument is the (first) position in the list of arguments1129 * with all callback arguments spliced in.1130 */1131void Method::on_cpp_arg_list(1132	const std::function<void(int i, int arg)> &on_arg) const1133{1134	on_cpp_arg_list(empty_combiner(), on_arg);1135}1136 1137/* Print the arguments to the method call, using "print_arg"1138 * to print each individual argument.1139 * The first argument to this callback is the position of the argument1140 * in this->fd.1141 * The second argument is the (first) position in the list of arguments1142 * with all callback arguments spliced in.1143 */1144void Method::print_cpp_arg_list(std::ostream &os,1145	const std::function<void(int i, int arg)> &print_arg) const1146{1147	on_cpp_arg_list(print_combiner(os), print_arg);1148}1149 1150/* Should the parameter at position "pos" be a copy (rather than1151 * a const reference)?1152 *1153 * Strictly speaking, a copy is only needed on isl types that are1154 * not marked __isl_keep, since those will be release()'d1155 * by code printed by Method::print_param_use.1156 *1157 * However, there may be other arguments such as integer types1158 * that are more naturally passed as a copy.1159 * The default is therefore to require a copy, except for1160 * arguments marked __isl_keep, string arguments or callback arguments.1161 */1162bool Method::param_needs_copy(int pos) const1163{1164	ParmVarDecl *param = get_param(pos);1165	QualType type = param->getOriginalType();1166 1167	if (generator::keeps(param))1168		return false;1169	if (generator::is_string(type) || generator::is_callback(type))1170		return false;1171	return true;1172}1173 1174/* Return the method argument at position "pos".1175 */1176clang::ParmVarDecl *Method::get_param(int pos) const1177{1178	return fd->getParamDecl(pos);1179}1180 1181/* Construct a method that performs one or more conversions1182 * from the original Method (without conversions),1183 * the name of the type to which "this" should be converted and1184 * a function for determining the arguments of the constructed method.1185 */1186ConversionMethod::ConversionMethod(const Method &method,1187	const std::string &this_type,1188	const std::function<clang::ParmVarDecl *(int pos)> &get_param) :1189		NoCopyMethod(method), this_type(this_type),1190		get_param_fn(get_param)1191{1192}1193 1194/* Construct a method that only performs a conversion on "this"1195 * from the original Method (without conversions) and1196 * the name of the type to which "this" should be converted.1197 *1198 * Call the generic constructor with1199 * a function for determining the arguments of the constructed method1200 * that performs no conversion.1201 */1202ConversionMethod::ConversionMethod(const Method &method,1203	const std::string &this_type) :1204		ConversionMethod(method, this_type, [this] (int pos) {1205			return Method::get_param(pos);1206		})1207{1208}1209 1210/* Construct a method that performs one or more argument conversions1211 * from the original Method (without conversions) and1212 * a function for determining the arguments of the constructed method.1213 *1214 * Call the generic constructor with method.clazz.name as "this" type,1215 * indicating that "this" should not be converted.1216 */1217ConversionMethod::ConversionMethod(const Method &method,1218	const std::function<clang::ParmVarDecl *(int pos)> &get_param) :1219		ConversionMethod(method, method.clazz.name, get_param)1220{1221}1222 1223/* Should the parameter at position "pos" be a copy (rather than1224 * a const reference)?1225 *1226 * Parameters of isl type do not need to be a copy.1227 * For other types, use the same defaults as Method.1228 */1229bool NoCopyMethod::param_needs_copy(int pos) const1230{1231	ParmVarDecl *param = get_param(pos);1232	QualType type = param->getOriginalType();1233 1234	if (generator::is_isl_type(type))1235		return false;1236 1237	return Method::param_needs_copy(pos);1238}1239 1240/* Return the method argument at position "pos".1241 *1242 * Call get_param_fn to determine this argument.1243 */1244clang::ParmVarDecl *ConversionMethod::get_param(int pos) const1245{1246	return get_param_fn(pos);1247}1248 1249/* Print a call to the method (without the arguments),1250 * with "ns" the namespace of the generated C++ bindings.1251 *1252 * If "this_type" is different from the name of the class of the method,1253 * then "this" needs to be converted to that type before1254 * the call is performed.1255 */1256void ConversionMethod::print_call(std::ostream &os, const std::string &ns) const1257{1258	if (clazz.name == this_type) {1259		os << "this->";1260	} else {1261		auto cpp_type = ns + cpp_generator::type2cpp(this_type);1262		os << cpp_type << "(*this).";1263	}1264	os << name;1265}1266 1267/* Construct an object representing a C++ method for setting an enum1268 * from the class to which is belongs,1269 * the isl function from which it is derived and the method and enum names.1270 */1271EnumMethod::EnumMethod(const isl_class &clazz, FunctionDecl *fd,1272	const std::string &method_name, const std::string &enum_name) :1273		Method(clazz, fd, method_name), enum_name(enum_name)1274{1275}1276 1277/* Print the use of the argument at position "pos" to "os".1278 *1279 * If the position is beyond the number of method arguments,1280 * then it corresponds to the enum value corresponding to this EnumMethod.1281 * Otherwise, delegate to Method::print_param_use.1282 */1283void EnumMethod::print_param_use(ostream &os, int pos) const1284{1285	if (pos == num_params())1286		os << enum_name;1287	else1288		Method::print_param_use(os, pos);1289}1290 1291/* Return the number of parameters of the method1292 * (including the implicit "this").1293 *1294 * The last argument of the C function does not appear in the method call,1295 * because it is replaced by a break-up into several methods.1296 */1297int EnumMethod::num_params() const1298{1299	return Method::num_params() - 1;1300}1301 1302/* Initialize a class method printer from the stream onto which the methods1303 * are printed, the class method description and the C++ interface generator.1304 */1305cpp_generator::class_printer::class_printer(std::ostream &os,1306		const isl_class &clazz, cpp_generator &generator,1307		bool declarations) :1308	os(os), clazz(clazz), cppstring(type2cpp(clazz)), generator(generator),1309	declarations(declarations)1310{1311}1312