1/*
2 * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOBIAS GROSSER OR
20 * 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 ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * The views and conclusions contained in the software and documentation
29 * are those of the authors and should not be interpreted as
30 * representing official policies, either expressed or implied, of
31 * 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 implicitly
42 * constructed using a unary constructor.
43 *
44 * Look through all constructors for implicit conversion constructors that take
45 * an isl type and add those types, along with the corresponding
46 * 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 constructed
66 * 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 constructor
79 * of the generator superclass.
80 *
81 * Additionally extract information about types
82 * that can be converted to a class and copy all methods
83 * from superclasses that can be converted to a given class
84 * 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 superclass
99 * 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 argument
110 * which represents the object class on which the corresponding method
111 * 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 ancestor
133 * from which "fd" got copied.
134 * If no distance was recorded, then the method has not been copied
135 * 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" and
145 * 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 there
149 * is a method with the same name in "clazz" that has the same signature and
150 * that comes from an ancestor closer to "clazz",
151 * where an ancestor is closer if the distance in the class hierarchy
152 * is smaller or the distance is the same and the ancestor appears
153 * 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(x: 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 overridden
197 * 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 object
213 * from the superclass, keeping track
214 * of the classes that have already been handled in "done".
215 *
216 * Make sure the superclasses have copied methods from their superclasses first
217 * 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(x: 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 object
241 * from the superclass.
242 *
243 * Type based subclasses are not considered for now since
244 * they do not have any explicit superclasses.
245 *
246 * Iterate through all (proper) classes and copy methods
247 * 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(methods: kvp.second, name: 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, setting
295 * 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 functions
307 * 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 conversions
316 * 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 automatic
320 * conversion function is available mapping to the type of this argument and
321 * that is not already marked for conversion.
322 * Mark this argument, if any, for conversion and clear the markings
323 * of all subsequent arguments.
324 * Repeated calls to this method therefore run through
325 * all possible combinations.
326 *
327 * Note that the first function argument is never considered
328 * for automatic conversion since this is the argument
329 * 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 definition
357 * that calls the corresponding method in the superclass.
358 * Otherwise, for methods that are identified as "get" methods, also
359 * print a declaration or definition for the method
360 * using a name that includes the "get_" prefix.
361 *
362 * If the generated method is an object method, then check
363 * whether any of its arguments can be automatically converted
364 * from something else, and, if so, generate a method
365 * for each combination of converted arguments.
366 * Do so by constructing a ConversionMethod that changes the converted arguments
367 * to those of the sources of the conversions.
368 *
369 * Note that a method may be both copied from a superclass and
370 * have arguments that can be automatically converted.
371 * In this case, the conversion methods for the arguments
372 * call the corresponding method in this class, which
373 * 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(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(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 object
400 * on which the method is called) that corresponds to
401 * 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 declaration
415 * that corresponds to a method of "clazz" itself (i.e., that
416 * 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 implicitly
438 * 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 take
461 * as arguments those types that can be converted to the original argument type
462 * through a unary constructor and if only one of the methods in the group
463 * 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 original
490 * value must be preserved and must consequently be copied. Values that are
491 * loaded from method parameters do not need to be preserved, as such values
492 * will already be copies of the actual parameters. It is consequently possible
493 * to directly take the pointer from these values, which saves
494 * 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 actual
498 * callback function. The wrapper is expected to be available
499 * in a previously declared variable <name>_lambda, while
500 * the actual callback function is expected to be stored
501 * 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) const
505{
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 else
536 os << "release()";
537 }
538}
539
540/* Does the isl function from which this method is derived
541 * modify an object of a subclass based on a type function?
542 */
543bool Method::is_subclass_mutator() const
544{
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 return
551 * 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) const
555{
556 if (method.is_subclass_mutator())
557 return cpp_generator::type2cpp(clazz: method.clazz);
558 else
559 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 indicated
564 * by "convert", then return the second formal parameter
565 * 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, and
584 * constructors, either for their declaration or definition.
585 *
586 * Member functions are declared as "const", as they do not change the current
587 * object, but instead create a new object. They always retrieve the first
588 * 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 the
590 * original function become part of the method's interface.
591 *
592 * A function
593 *
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) const
600 *
601 * For static functions and constructors all parameters of the original isl
602 * function are exposed.
603 *
604 * Parameters of which no copy is required, are passed
605 * as const reference, which allows the compiler to optimize the parameter
606 * transfer.
607 *
608 * Constructors are marked as explicit using the C++ keyword 'explicit' or as
609 * implicit using a comment in place of the explicit keyword. By annotating
610 * implicit constructors with a comment, users of the interface are made
611 * aware of the potential danger that implicit construction is possible
612 * for these constructors, whereas without a comment not every user would
613 * know that implicit construction is allowed in absence of an explicit keyword.
614 *
615 * Note that in case "method" is a ConversionMethod, the argument returned
616 * by Method::get_param may be different from the original argument.
617 * The name of the argument is, however, derived from the original
618 * 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(cons: method))
635 os << "/* implicit */ ";
636 else
637 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(cpp_name: cppstring) << "::";
646
647 if (method.kind != Method::Kind::constructor)
648 os << method.name;
649 else
650 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(pos: i))
659 os << "const " << cpptype << " &" << name;
660 else
661 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 of
669 * type "type", appearing in argument position "arg".
670 * If "cpp" is set, then generate the C++ type list, otherwise
671 * the C type list.
672 *
673 * For a callback of type
674 *
675 * isl_stat (*)(__isl_take isl_map *map, void *user)
676 *
677 * the following C++ argument list is generated:
678 *
679 * map
680 *
681 * The arguments of the callback are considered to appear
682 * after the position of the callback itself.
683 */
684std::string cpp_type_printer::generate_callback_args(int arg, QualType type,
685 bool cpp) const
686{
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 else
702 type_str += type.getAsString();
703
704 if (!cpp)
705 type_str += "arg_" + ::to_string(val: 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 type
718 *
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 const
727{
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 they
743 * should be renamed to. We currently rename functions in case their name would
744 * 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 not
751 * match the name in the C bindings. We do this for example to avoid
752 * 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(s: 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(type_string: 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(pos: 4);
776}
777
778/* Return the C++ counterpart to the isl_bool type.
779 *
780 * By default, this is simply "bool" since
781 * the exceptional case is handled through exceptions.
782 */
783std::string cpp_type_printer::isl_bool() const
784{
785 return "bool";
786}
787
788/* Return the C++ counterpart to the isl_stat type.
789 *
790 * By default, this is simply "void" since
791 * the exceptional case is handled through exceptions.
792 */
793string cpp_type_printer::isl_stat() const
794{
795 return "void";
796}
797
798/* Return the C++ counterpart to the isl_size type.
799 *
800 * By default, this is simply "unsigned" since
801 * the exceptional case is handled through exceptions.
802 */
803string cpp_type_printer::isl_size() const
804{
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() const
813{
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) const
822{
823 return cpp_name;
824}
825
826/* Return the qualified form of the given C++ isl type name appearing
827 * 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 const
833{
834 return isl_namespace() + cpp_type;
835}
836
837/* Return the C++ counterpart to the given isl type appearing
838 * in argument position "arg" (-1 for return type).
839 */
840std::string cpp_type_printer::isl_type(int arg, QualType type) const
841{
842 auto name = type->getPointeeType().getAsString();
843 return qualified(arg, cpp_type: 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 types
849 * of the callback are considered to start at the position of the callback.
850 */
851std::string cpp_type_printer::param(int arg, QualType type) const
852{
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(msg: "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(x: &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(x: &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 single
912 * parameter, where the parameter type is a subclass of the class that is
913 * 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 else
960 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 and
983 * 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 and
994 * the isl function from which it is derived.
995 *
996 * Obtain the default method name and continue
997 * 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 callback
1007 * arguments. These are skipped by Method::print_fd_arg_list
1008 * during the actual argument printing.
1009 */
1010int Method::c_num_params() const
1011{
1012 return fd->getNumParams();
1013}
1014
1015/* Return the number of parameters of the method
1016 * (including the implicit "this").
1017 *
1018 * By default, it is the same as the number of parameters
1019 * of the corresponding C function.
1020 */
1021int Method::num_params() const
1022{
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 true
1048 * 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 argument
1061 * in this->fd.
1062 * The second argument is the (first) position in the list of arguments
1063 * with all callback arguments spliced in.
1064 *
1065 * Call on_arg_list to do the actual iteration over the arguments, skipping
1066 * the user argument that comes after every callback argument.
1067 * On the C++ side no user pointer is needed, as arguments can be forwarded
1068 * as part of the std::function argument which specifies the callback function.
1069 * The user pointer is also removed from the number of parameters
1070 * of the C function because the pair of callback and user pointer
1071 * is considered as a single argument that is printed as a whole
1072 * 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) const
1083{
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 argument
1101 * in this->fd.
1102 * The second argument is the (first) position in the list of arguments
1103 * 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) const
1107{
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 argument
1114 * in this->fd.
1115 * The second argument is the (first) position in the list of arguments
1116 * 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) const
1120{
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 argument
1127 * in this->fd.
1128 * The second argument is the (first) position in the list of arguments
1129 * with all callback arguments spliced in.
1130 */
1131void Method::on_cpp_arg_list(
1132 const std::function<void(int i, int arg)> &on_arg) const
1133{
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 argument
1140 * in this->fd.
1141 * The second argument is the (first) position in the list of arguments
1142 * 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) const
1146{
1147 on_cpp_arg_list(print_combiner(os), print_arg);
1148}
1149
1150/* Should the parameter at position "pos" be a copy (rather than
1151 * a const reference)?
1152 *
1153 * Strictly speaking, a copy is only needed on isl types that are
1154 * not marked __isl_keep, since those will be release()'d
1155 * by code printed by Method::print_param_use.
1156 *
1157 * However, there may be other arguments such as integer types
1158 * that are more naturally passed as a copy.
1159 * The default is therefore to require a copy, except for
1160 * arguments marked __isl_keep, string arguments or callback arguments.
1161 */
1162bool Method::param_needs_copy(int pos) const
1163{
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) const
1177{
1178 return fd->getParamDecl(pos);
1179}
1180
1181/* Construct a method that performs one or more conversions
1182 * from the original Method (without conversions),
1183 * the name of the type to which "this" should be converted and
1184 * 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) and
1196 * the name of the type to which "this" should be converted.
1197 *
1198 * Call the generic constructor with
1199 * a function for determining the arguments of the constructed method
1200 * 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 conversions
1211 * from the original Method (without conversions) and
1212 * 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 than
1224 * 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) const
1230{
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) const
1245{
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 before
1254 * the call is performed.
1255 */
1256void ConversionMethod::print_call(std::ostream &os, const std::string &ns) const
1257{
1258 if (clazz.name == this_type) {
1259 os << "this->";
1260 } else {
1261 auto cpp_type = ns + cpp_generator::type2cpp(type_str: this_type);
1262 os << cpp_type << "(*this).";
1263 }
1264 os << name;
1265}
1266
1267/* Construct an object representing a C++ method for setting an enum
1268 * 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) const
1284{
1285 if (pos == num_params())
1286 os << enum_name;
1287 else
1288 Method::print_param_use(os, pos);
1289}
1290
1291/* Return the number of parameters of the method
1292 * (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() const
1298{
1299 return Method::num_params() - 1;
1300}
1301
1302/* Initialize a class method printer from the stream onto which the methods
1303 * 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

source code of polly/lib/External/isl/interface/cpp.cc