1 | /* |
2 | * Copyright 2020 Cerebras Systems. 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 CEREBRAS SYSTEMS ''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 CEREBRAS SYSTEMS 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 | * Cerebras Systems. |
32 | */ |
33 | |
34 | #include <ctype.h> |
35 | |
36 | #include <algorithm> |
37 | #include <iostream> |
38 | #include <set> |
39 | #include <sstream> |
40 | #include <string> |
41 | #include <unordered_map> |
42 | #include <unordered_set> |
43 | |
44 | #include "template_cpp.h" |
45 | #include "isl_config.h" |
46 | |
47 | /* The textual representation of this tuple kind. |
48 | * |
49 | * By default, the textual representation is just the name. |
50 | */ |
51 | std::string TupleKind::to_string() const |
52 | { |
53 | return name; |
54 | } |
55 | |
56 | /* Return the parameters of this tuple kind. |
57 | * |
58 | * By default, there are no parameters. |
59 | */ |
60 | std::vector<std::string> TupleKind::params() const |
61 | { |
62 | return { }; |
63 | } |
64 | |
65 | /* Apply the substitution "subs" to this tuple kind and return the result. |
66 | * "self" is a shared pointer to this. |
67 | * |
68 | * If the name of this tuple kind appears in the substitution, |
69 | * then return the corresponding tuple kind pointer. |
70 | * Otherwise, return "self". |
71 | */ |
72 | TupleKindPtr TupleKind::apply(const Substitution &subs, |
73 | const TupleKindPtr &self) const |
74 | { |
75 | if (subs.count(x: name) != 0) |
76 | return subs.at(k: name); |
77 | return self; |
78 | } |
79 | |
80 | /* Apply the substitution "subs" to "tuple" and return the result. |
81 | */ |
82 | static TupleKindPtr apply(const TupleKindPtr tuple, const Substitution &subs) |
83 | { |
84 | return tuple->apply(subs, self: tuple); |
85 | } |
86 | |
87 | /* Return the left child of this tuple kind. |
88 | * |
89 | * Since this is not a pair, there is no left child. |
90 | */ |
91 | TupleKindPtr TupleKind::left() const |
92 | { |
93 | return TupleKindPtr(); |
94 | } |
95 | |
96 | /* Return the right child of this tuple kind. |
97 | * |
98 | * Since this is not a pair, there is no right child. |
99 | */ |
100 | TupleKindPtr TupleKind::right() const |
101 | { |
102 | return TupleKindPtr(); |
103 | } |
104 | |
105 | /* Helper class used to construct a pointer to a tuple kind |
106 | * that refers to a non-template type. |
107 | */ |
108 | struct Fixed { |
109 | }; |
110 | |
111 | /* Construct a pointer to a tuple kind that refers to a non-template type. |
112 | * |
113 | * Use an empty string as name. Since this is a non-template type, |
114 | * the kind name will never appear in the generated code. |
115 | */ |
116 | TupleKindPtr::TupleKindPtr(Fixed) : Base(std::make_shared<TupleKind>(args: "" )) |
117 | { |
118 | } |
119 | |
120 | /* Tuple pointers for non-template types. |
121 | */ |
122 | static TupleKindPtr Ctx{Fixed()}; |
123 | static TupleKindPtr Integer{Fixed()}; |
124 | static TupleKindPtr Str{Fixed()}; |
125 | static TupleKindPtr Res{Fixed()}; |
126 | |
127 | /* Special tuple pointers. |
128 | * Anonymous appears in the generated code but cannot be unified |
129 | * with anything else since it is a predefined template argument. |
130 | * Leaf can only be unified with something that is not a pair and |
131 | * does not appear in the generated code. |
132 | */ |
133 | static TupleKindPtr Anonymous("Anonymous" ); |
134 | static TupleKindPtr Leaf("Leaf" ); |
135 | |
136 | /* Placeholder tuple pointers that refer to (part of) the domain or range. |
137 | */ |
138 | static TupleKindPtr Domain("Domain" ); |
139 | static TupleKindPtr Domain2("Domain2" ); |
140 | static TupleKindPtr Domain3("Domain3" ); |
141 | static TupleKindPtr Range("Range" ); |
142 | static TupleKindPtr Range2("Range2" ); |
143 | static TupleKindPtr Range3("Range3" ); |
144 | |
145 | /* A representation of a proper tuple kind that is used as a template |
146 | * parameter or a template argument. |
147 | */ |
148 | struct ProperTupleKind : public TupleKind { |
149 | ProperTupleKind(const std::string &name) : TupleKind(name) {} |
150 | |
151 | virtual std::vector<std::string> params() const override; |
152 | }; |
153 | |
154 | /* Return the parameters of this tuple kind. |
155 | * |
156 | * Return the name of this tuple kind, unless it is the special Anonymous |
157 | * predefined template argument. |
158 | */ |
159 | std::vector<std::string> ProperTupleKind::params() const |
160 | { |
161 | if (Anonymous.get() == this) |
162 | return { }; |
163 | return { name }; |
164 | } |
165 | |
166 | /* Construct a pointer to a tuple kind that refers |
167 | * to a proper tuple kind with the given name. |
168 | */ |
169 | TupleKindPtr::TupleKindPtr(const std::string &name) : |
170 | Base(std::make_shared<ProperTupleKind>(args: name)) |
171 | { |
172 | } |
173 | |
174 | /* A tuple kind that represents an anonymous pair of nested tuple kinds. |
175 | */ |
176 | struct Pair : public TupleKind { |
177 | Pair(const TupleKindPtr &tuple1, const TupleKindPtr &tuple2) : |
178 | TupleKind("" ), tuple1(tuple1), tuple2(tuple2) {} |
179 | |
180 | virtual std::string to_string() const override; |
181 | virtual std::vector<std::string> params() const override; |
182 | virtual TupleKindPtr apply(const Substitution &match, |
183 | const TupleKindPtr &self) const override; |
184 | virtual TupleKindPtr left() const override; |
185 | virtual TupleKindPtr right() const override; |
186 | |
187 | const TupleKindPtr tuple1; |
188 | const TupleKindPtr tuple2; |
189 | }; |
190 | |
191 | /* The textual representation of this tuple kind. |
192 | * |
193 | * The textual representation of a pair is of the form "pair<tuple1, tuple2>". |
194 | */ |
195 | std::string Pair::to_string() const |
196 | { |
197 | return std::string("pair<" ) + tuple1->to_string() + ", " + |
198 | tuple2->to_string() + ">" ; |
199 | } |
200 | |
201 | /* Add the elements of "vec2" that do not already appear in "vec1" |
202 | * at the end of "vec1". |
203 | * |
204 | * The two vectors are assumed not to have any repeated elements. |
205 | * The updated vector will then also not have repeated elements. |
206 | */ |
207 | static void combine(std::vector<std::string> &vec1, |
208 | const std::vector<std::string> &vec2) |
209 | { |
210 | for (const auto &s : vec2) |
211 | if (std::find(first: vec1.begin(), last: vec1.end(), val: s) == vec1.end()) |
212 | vec1.emplace_back(args: s); |
213 | } |
214 | |
215 | /* Return the parameters of this tuple kind. |
216 | * |
217 | * Combine the parameters of the two nested tuple kinds. |
218 | */ |
219 | std::vector<std::string> Pair::params() const |
220 | { |
221 | auto names1 = tuple1->params(); |
222 | auto names2 = tuple2->params(); |
223 | |
224 | combine(vec1&: names1, vec2: names2); |
225 | |
226 | return names1; |
227 | } |
228 | |
229 | /* Apply the substitution "subs" to this tuple kind and return the result. |
230 | * "self" is a shared pointer to this. |
231 | * |
232 | * Construct a new tuple kind consisting of the result of applying |
233 | * the substitution to the two nested tuple kinds. |
234 | */ |
235 | TupleKindPtr Pair::apply(const Substitution &subs, const TupleKindPtr &self) |
236 | const |
237 | { |
238 | return TupleKindPtr(::apply(tuple: tuple1, subs), ::apply(tuple: tuple2, subs)); |
239 | } |
240 | |
241 | /* Return the left child of this tuple kind. |
242 | */ |
243 | TupleKindPtr Pair::left() const |
244 | { |
245 | return tuple1; |
246 | } |
247 | |
248 | /* Return the right child of this tuple kind. |
249 | */ |
250 | TupleKindPtr Pair::right() const |
251 | { |
252 | return tuple2; |
253 | } |
254 | |
255 | /* Construct a pointer to a tuple kind that refers |
256 | * to the given pair of nested tuple kinds. |
257 | */ |
258 | TupleKindPtr::TupleKindPtr(const TupleKindPtr &left, const TupleKindPtr &right) |
259 | : Base(std::make_shared<Pair>(args: left, args: right)) |
260 | { |
261 | } |
262 | |
263 | /* Is this a kind of object representing an anonymous function? |
264 | */ |
265 | bool Kind::is_anon() const |
266 | { |
267 | return size() != 0 && back() == Anonymous; |
268 | } |
269 | |
270 | /* Is this a kind of object with a single tuple? |
271 | */ |
272 | bool Kind::is_set() const |
273 | { |
274 | return size() == 1; |
275 | } |
276 | |
277 | /* Is this a kind of object with a single, anonymous tuple? |
278 | */ |
279 | bool Kind::is_anon_set() const |
280 | { |
281 | return is_set() && is_anon(); |
282 | } |
283 | |
284 | /* Return the parameters of this kind. |
285 | * |
286 | * Collect the parameters of the tuple kinds in the sequence. |
287 | */ |
288 | std::vector<std::string> Kind::params() const |
289 | { |
290 | std::vector<std::string> params; |
291 | |
292 | for (const auto &tuple : *this) |
293 | combine(vec1&: params, vec2: tuple->params()); |
294 | |
295 | return params; |
296 | } |
297 | |
298 | /* Apply the substitution "subs" to this kind and return the result. |
299 | * |
300 | * Apply the substitution to each of the tuple kinds in the sequence. |
301 | */ |
302 | Kind Kind::apply(const Substitution &subs) const |
303 | { |
304 | Kind applied; |
305 | |
306 | for (const auto &tuple : *this) |
307 | applied.emplace_back(args: ::apply(tuple, subs)); |
308 | |
309 | return applied; |
310 | } |
311 | |
312 | /* A signature of a method in terms of kinds, |
313 | * consisting of a return kind and a sequence of argument kinds. |
314 | */ |
315 | struct Signature { |
316 | Kind ret; |
317 | std::vector<Kind> args; |
318 | |
319 | std::vector<std::string> params() const; |
320 | Signature apply(const Substitution &match) const; |
321 | }; |
322 | |
323 | /* Return the parameters of this signature. |
324 | * |
325 | * Collect the parameters of the argument kinds and the return kind. |
326 | */ |
327 | std::vector<std::string> Signature::params() const |
328 | { |
329 | std::vector<std::string> params; |
330 | |
331 | for (const auto &arg : args) |
332 | combine(vec1&: params, vec2: arg.params()); |
333 | combine(vec1&: params, vec2: ret.params()); |
334 | |
335 | return params; |
336 | } |
337 | |
338 | /* Apply the substitution "subs" to this kind and return the result. |
339 | * |
340 | * Apply the substitution to the argument kinds and the return kind. |
341 | */ |
342 | Signature Signature::apply(const Substitution &subs) const |
343 | { |
344 | std::vector<Kind> applied_args; |
345 | |
346 | for (const auto &arg : args) |
347 | applied_args.emplace_back(args: arg.apply(subs)); |
348 | |
349 | return { .ret: ret.apply(subs), .args: applied_args }; |
350 | } |
351 | |
352 | /* Return a renaming substitution that renames the elements of "params" |
353 | * using names starting with "prefix". |
354 | */ |
355 | static Substitution param_renamer(const std::vector<std::string> ¶ms, |
356 | const std::string &prefix) |
357 | { |
358 | Substitution renamer; |
359 | int n = 0; |
360 | |
361 | for (const auto &name : params) { |
362 | auto suffix = std::to_string(val: ++n); |
363 | auto arg_name = prefix + suffix; |
364 | auto arg = TupleKindPtr(arg_name); |
365 | |
366 | if (name == Leaf->name) |
367 | generator::die(msg: "Leaf cannot be renamed" ); |
368 | |
369 | renamer.emplace(args: name, args&: arg); |
370 | } |
371 | |
372 | return renamer; |
373 | } |
374 | |
375 | /* Does the vector "v" contain the element "el"? |
376 | */ |
377 | static bool contains(const std::vector<std::string> &v, const std::string &el) |
378 | { |
379 | return find(first: v.begin(), last: v.end(), val: el) != v.end(); |
380 | } |
381 | |
382 | |
383 | /* Return the shared elements of "v1" and "v2", preserving the order |
384 | * of those elements in "v1". |
385 | */ |
386 | static std::vector<std::string> intersect(const std::vector<std::string> &v1, |
387 | const std::vector<std::string> &v2) |
388 | { |
389 | std::vector<std::string> intersection; |
390 | |
391 | for (const auto &el : v1) |
392 | if (contains(v: v2, el)) |
393 | intersection.push_back(x: el); |
394 | |
395 | return intersection; |
396 | } |
397 | |
398 | /* Return a renaming substitution that renames |
399 | * any parameters that appears in both "sig" and "kind". |
400 | */ |
401 | static Substitution shared_param_renamer(const Signature &sig, const Kind &kind) |
402 | { |
403 | return param_renamer(params: intersect(v1: sig.params(), v2: kind.params()), prefix: "Arg" ); |
404 | } |
405 | |
406 | /* Signatures for unary operations. |
407 | * Functions have at least one tuple. |
408 | */ |
409 | static Signature un_params = { .ret: { }, .args: { { } } }; |
410 | static Signature un_set = { .ret: { Domain }, .args: { { Domain } } }; |
411 | static Signature un_map = { .ret: { Domain, Range }, .args: { { Domain, Range } } }; |
412 | static std::vector<Signature> un_op = { un_params, un_set, un_map }; |
413 | static std::vector<Signature> fn_un_op = { un_set, un_map }; |
414 | |
415 | /* Signatures for binary operations, with the second argument |
416 | * possibly referring to part of the first argument. |
417 | * Functions have at least one tuple. |
418 | */ |
419 | static Signature bin_params = { .ret: { }, .args: { { }, { } } }; |
420 | static Signature bin_set = { .ret: { Domain }, .args: { { Domain }, { Domain } } }; |
421 | static Signature bin_map = |
422 | { .ret: { Domain, Range }, .args: { { Domain, Range }, { Domain, Range } } }; |
423 | static std::vector<Signature> bin_op = { bin_params, bin_set, bin_map }; |
424 | static std::vector<Signature> fn_bin_op = { bin_set, bin_map }; |
425 | static Signature bin_set_params = { .ret: { Domain }, .args: { { Domain }, { } } }; |
426 | static Signature bin_map_params = |
427 | { .ret: { Domain, Range }, .args: { { Domain, Range }, { } } }; |
428 | static Signature bin_map_domain = |
429 | { .ret: { Domain, Range }, .args: { { Domain, Range }, { Domain } } }; |
430 | static Signature bin_map_range = |
431 | { .ret: { Domain, Range }, .args: { { Domain, Range }, { Range } } }; |
432 | static Signature bin_map_domain_wrapped_domain = |
433 | { .ret: { { Domain, Domain2 }, Range }, |
434 | .args: { { { Domain, Domain2 }, Range }, { Domain } } }; |
435 | static Signature bin_map_range_wrapped_domain = |
436 | { .ret: { Domain, { Range, Range2 } }, |
437 | .args: { { Domain, { Range, Range2 } }, { Range } } }; |
438 | |
439 | /* Signatures for binary operations, where the second argument |
440 | * is an identifier (with an anonymous tuple). |
441 | */ |
442 | static Signature bin_params_anon = { .ret: { }, .args: { { }, { Anonymous } } }; |
443 | static Signature bin_set_anon = { .ret: { Domain }, .args: { { Domain }, { Anonymous } } }; |
444 | static Signature bin_map_anon = |
445 | { .ret: { Domain, Range }, .args: { { Domain, Range }, { Anonymous } } }; |
446 | static std::vector<Signature> bin_op_anon = |
447 | { bin_params_anon, bin_set_anon, bin_map_anon }; |
448 | |
449 | /* Signatures for ternary operations, where the last two arguments are integers. |
450 | */ |
451 | static Signature ter_params_int_int = |
452 | { .ret: { }, .args: { { }, { Integer }, { Integer } } }; |
453 | static Signature ter_set_int_int = |
454 | { .ret: { Domain }, .args: { { Domain }, { Integer }, { Integer } } }; |
455 | static Signature ter_map_int_int = |
456 | { .ret: { Domain, Range }, .args: { { Domain, Range }, { Integer }, { Integer } } }; |
457 | static std::vector<Signature> ter_int_int = |
458 | { ter_params_int_int, ter_set_int_int, ter_map_int_int }; |
459 | |
460 | /* Signatures for ternary operations. |
461 | * Functions have at least one tuple. |
462 | */ |
463 | static Signature ter_set = |
464 | { .ret: { Domain }, .args: { { Domain }, { Domain }, { Domain } } }; |
465 | static Signature ter_map = |
466 | { .ret: { Domain, Range }, |
467 | .args: { { Domain, Range }, { Domain, Range }, { Domain, Range } } }; |
468 | static std::vector<Signature> fn_ter_op = { ter_set, ter_map }; |
469 | |
470 | /* Signatures for naming a leaf tuple using an identifier (with an anonymous |
471 | * tuple). |
472 | */ |
473 | static Signature update_set = { .ret: { Domain2 }, .args: { { Leaf }, { Anonymous } } }; |
474 | static Signature update_domain = |
475 | { .ret: { Domain2, Range }, .args: { { Leaf, Range }, { Anonymous } } }; |
476 | static Signature update_range = |
477 | { .ret: { Domain, Range2 }, .args: { { Domain, Leaf }, { Anonymous } } }; |
478 | |
479 | /* Signatures for the functions "min" and "max", which can be either |
480 | * unary or binary operations. |
481 | */ |
482 | static std::vector<Signature> min_max = { un_set, bin_set, un_map, bin_map }; |
483 | |
484 | /* Signatures for adding an unnamed tuple to an object with zero or one tuple. |
485 | */ |
486 | static Signature to_set = { .ret: { Domain }, .args: { { }, { Integer } } }; |
487 | static Signature add_range = { .ret: { Domain, Range }, .args: { { Domain }, { Integer } } }; |
488 | /* Signatures for adding a named tuple to an object with zero or one tuple. |
489 | */ |
490 | static Signature to_set_named = |
491 | { .ret: { Domain }, .args: { { }, { Anonymous }, { Integer } } }; |
492 | static Signature add_range_named = |
493 | { .ret: { Domain, Range }, .args: { { Domain }, { Anonymous }, { Integer } } }; |
494 | |
495 | /* Signatures for methods applying a map to a set, a function or |
496 | * part of a map. |
497 | */ |
498 | static Signature set_forward = { .ret: { Range }, .args: { { Domain }, { Domain, Range } } }; |
499 | static Signature domain_forward = |
500 | { .ret: { Domain2, Range }, .args: { { Domain, Range }, { Domain, Domain2 } } }; |
501 | static Signature range_forward = |
502 | { .ret: { Domain, Range2 }, .args: { { Domain, Range }, { Range, Range2 } } }; |
503 | |
504 | /* Signatures for methods plugging in a function into a set, a function or |
505 | * part of a map. |
506 | */ |
507 | static Signature set_backward = |
508 | { .ret: { Domain2 }, .args: { { Domain }, { Domain2, Domain } } }; |
509 | static Signature domain_backward = |
510 | { .ret: { Domain2, Range }, .args: { { Domain, Range }, { Domain2, Domain } } }; |
511 | static Signature range_backward = |
512 | { .ret: { Domain, Range2 }, .args: { { Domain, Range }, { Range2, Range } } }; |
513 | static Signature domain_wrapped_domain_backward = |
514 | { .ret: { { Domain3, Domain2 }, Range }, |
515 | .args: { { { Domain, Domain2 }, Range }, { Domain3, Domain } } }; |
516 | |
517 | /* Signatures for methods binding a set, a function, |
518 | * or (part of) a map to parameters or an object of the same kind. |
519 | */ |
520 | static Signature bind_set = { .ret: { }, .args: { { Domain }, { Domain } } }; |
521 | static Signature bind_domain = { .ret: { Range }, .args: { { Domain, Range }, { Domain } } }; |
522 | static Signature bind_range = { .ret: { Domain }, .args: { { Domain, Range }, { Range } } }; |
523 | static Signature bind_domain_wrapped_domain = |
524 | { .ret: { Range2, Range }, .args: { { { Domain2, Range2 }, Range }, { Domain2 } } }; |
525 | |
526 | /* Signatures for functions that take a callback accepting |
527 | * objects of the same kind (but a different type). |
528 | * |
529 | * The return and argument kinds of the callback appear |
530 | * at the position of the callback. |
531 | */ |
532 | static Signature each_params = { .ret: { Res }, .args: { { }, { Res }, { } } }; |
533 | static Signature each_set = { .ret: { Res }, .args: { { Domain }, { Res }, { Domain } } }; |
534 | static Signature each_map = |
535 | { .ret: { Res }, .args: { { Domain, Range }, { Res }, { Domain, Range } } }; |
536 | static std::vector<Signature> each = { each_params, each_set, each_map }; |
537 | |
538 | /* Signatures for isl_*_list_foreach_scc. |
539 | * |
540 | * The first callback takes two elements with the same tuple kinds. |
541 | * The second callback takes a list with the same tuple kinds. |
542 | */ |
543 | static Signature each_scc_params = |
544 | { .ret: { Res }, .args: { { }, { Res }, { }, { }, { Res }, { } } }; |
545 | static Signature each_scc_set = |
546 | { .ret: { Res }, .args: { { Domain }, |
547 | { Res }, { Domain }, { Domain }, |
548 | { Res }, { Domain } } }; |
549 | static Signature each_scc_map = |
550 | { .ret: { Res }, .args: { { Domain, Range }, |
551 | { Res }, { Domain, Range }, { Domain, Range }, |
552 | { Res }, { Domain, Range } } }; |
553 | static std::vector<Signature> each_scc = |
554 | { each_scc_params, each_scc_set, each_scc_map }; |
555 | |
556 | /* Signature for creating a map from a range, |
557 | * where the domain is given by an extra argument. |
558 | */ |
559 | static Signature map_from_range_and_domain = |
560 | { .ret: { Domain, Range }, .args: { { Range }, { Domain } } }; |
561 | |
562 | /* Signature for creating a map from a domain, |
563 | * where the range is given by an extra argument. |
564 | */ |
565 | static Signature map_from_domain_and_range = |
566 | { .ret: { Domain, Range }, .args: { { Domain }, { Range } } }; |
567 | |
568 | /* Signatures for creating an anonymous set from a parameter set |
569 | * or a map from a domain, where the range is anonymous. |
570 | */ |
571 | static Signature anonymous_set_from_params = { .ret: { Anonymous }, .args: { { } } }; |
572 | static Signature anonymous_map_from_domain = |
573 | { .ret: { Domain, Anonymous }, .args: { { Domain } } }; |
574 | static std::vector<Signature> anonymous_from_domain = |
575 | { anonymous_set_from_params, anonymous_map_from_domain }; |
576 | |
577 | /* Signature for creating a set from a parameter set, |
578 | * where the domain is given by an extra argument. |
579 | */ |
580 | static Signature set_from_params = { .ret: { Domain }, .args: { { }, { Domain } } }; |
581 | |
582 | /* Signatures for creating an anonymous function from a domain, |
583 | * where the second argument is an identifier (with an anonymous tuple). |
584 | */ |
585 | static Signature anonymous_set_from_params_bin_anon = |
586 | { .ret: { Anonymous }, .args: { { }, { Anonymous } } }; |
587 | static Signature anonymous_map_from_domain_bin_anon = |
588 | { .ret: { Domain, Anonymous }, .args: { { Domain }, { Anonymous } } }; |
589 | static std::vector<Signature> anonymous_from_domain_bin_anon = { |
590 | anonymous_set_from_params_bin_anon, |
591 | anonymous_map_from_domain_bin_anon |
592 | }; |
593 | |
594 | /* Signature for creating a map from a domain, |
595 | * where the range tuple is equal to the domain tuple. |
596 | */ |
597 | static Signature set_to_map = { .ret: { Domain, Domain }, .args: { { Domain } } }; |
598 | |
599 | /* Signatures for obtaining the range or the domain of a map. |
600 | * In case of a transformation, the domain and range are the same. |
601 | */ |
602 | static Signature domain = { .ret: { Domain }, .args: { { Domain, Range } } }; |
603 | static Signature range = { .ret: { Range }, .args: { { Domain, Range } } }; |
604 | static Signature transformation_domain = { .ret: { Domain }, .args: { { Domain, Domain } } }; |
605 | |
606 | /* Signatures for obtaining the parameter domain of a set or map. |
607 | */ |
608 | static Signature set_params = { .ret: { }, .args: { { Domain } } }; |
609 | static Signature map_params = { .ret: { }, .args: { { Domain, Range } } }; |
610 | |
611 | /* Signatures for obtaining the domain of a function. |
612 | */ |
613 | static std::vector<Signature> fn_domain = { domain, set_params }; |
614 | |
615 | /* Signatures for interchanging (wrapped) domain and range. |
616 | */ |
617 | static Signature map_reverse = { .ret: { Range, Domain }, .args: { { Domain, Range } } }; |
618 | static Signature map_range_reverse = |
619 | { .ret: { Domain, { Range2, Range } }, .args: { { Domain, { Range, Range2 } } } }; |
620 | |
621 | /* Signatures for constructing products. |
622 | */ |
623 | static Signature set_product = |
624 | { .ret: { { Domain, Range } }, .args: { { Domain }, { Range } } }; |
625 | static Signature map_product = |
626 | { .ret: { { Domain, Domain2 }, { Range, Range2 } }, |
627 | .args: { { Domain, Range }, { Domain2, Range2 } } }; |
628 | static Signature domain_product = |
629 | { .ret: { { Domain, Domain2 }, Range }, |
630 | .args: { { Domain, Range }, { Domain2, Range } } }; |
631 | static Signature range_product = |
632 | { .ret: { Domain, { Range, Range2 } }, |
633 | .args: { { Domain, Range }, { Domain, Range2 } } }; |
634 | |
635 | /* Signatures for obtaining factors from a product. |
636 | */ |
637 | static Signature domain_factor_domain = |
638 | { .ret: { Domain, Range }, .args: { { { Domain, Domain2 }, Range } } }; |
639 | static Signature domain_factor_range = |
640 | { .ret: { Domain2, Range }, .args: { { { Domain, Domain2 }, Range } } }; |
641 | static Signature range_factor_domain = |
642 | { .ret: { Domain, Range }, .args: { { Domain, { Range, Range2 } } } }; |
643 | static Signature range_factor_range = |
644 | { .ret: { Domain, Range2 }, .args: { { Domain, { Range, Range2 } } } }; |
645 | |
646 | /* Signatures for (un)currying. |
647 | */ |
648 | static Signature curry = |
649 | { .ret: { Domain, { Range, Range2 } }, |
650 | .args: { { { Domain, Range }, Range2 } } }; |
651 | static Signature uncurry = |
652 | { .ret: { { Domain, Range }, Range2 }, |
653 | .args: { { Domain, { Range, Range2 } } } }; |
654 | |
655 | /* Signatures for (un)wrapping. |
656 | */ |
657 | static Signature wrap = { .ret: { { Domain, Range } }, .args: { { Domain, Range } } }; |
658 | static Signature unwrap = { .ret: { Domain, Range }, .args: { { { Domain, Range } } } }; |
659 | |
660 | /* Signatures for constructing objects that map to the domain or range |
661 | * of a map. |
662 | */ |
663 | static Signature domain_map = |
664 | { .ret: { { Domain, Range }, Domain }, .args: { { Domain, Range } } }; |
665 | static Signature range_map = |
666 | { .ret: { { Domain, Range }, Range }, .args: { { Domain, Range } } }; |
667 | |
668 | /* Signature for applying a comparison between the domain and the range |
669 | * of a map. |
670 | */ |
671 | static Signature map_cmp = |
672 | { .ret: { Domain, Domain }, .args: { { Domain, Domain }, { Domain, Range } } }; |
673 | |
674 | /* Signature for creating a set corresponding to the domains |
675 | * of two functions. |
676 | */ |
677 | static Signature set_join = |
678 | { .ret: { Domain }, .args: { { Domain, Range }, { Domain, Range } } }; |
679 | |
680 | /* Signatures for flattening the domain or range of a map, |
681 | * replacing it with either an anonymous tuple or a tuple with a given name. |
682 | */ |
683 | static Signature anonymize_nested_domain = |
684 | { .ret: { Anonymous, Range2 }, .args: { { { Domain, Range }, Range2 } } }; |
685 | static Signature anonymize_nested_range = |
686 | { .ret: { Domain, Anonymous }, .args: { { Domain, { Range, Range2 } } } }; |
687 | static Signature replace_nested_domain = |
688 | { .ret: { Domain2, Range2 }, |
689 | .args: { { { Domain, Range }, Range2 }, { Anonymous} } }; |
690 | static Signature replace_nested_range = |
691 | { .ret: { Domain, Range3 }, .args: { { Domain, { Range, Range2 } }, { Anonymous} } }; |
692 | static std::vector<Signature> flatten_domain = |
693 | { anonymize_nested_domain, replace_nested_domain }; |
694 | static std::vector<Signature> flatten_range = |
695 | { anonymize_nested_range, replace_nested_range }; |
696 | |
697 | /* Signatures for "set_at" methods. |
698 | */ |
699 | static Signature set_at_set = |
700 | { .ret: { Domain }, .args: { { Domain }, { Integer }, { Anonymous } } }; |
701 | static Signature set_at_map = |
702 | { .ret: { Domain, Range }, |
703 | .args: { { Domain, Range }, { Integer }, { Domain, Anonymous } } }; |
704 | static std::vector<Signature> set_at = { set_at_set, set_at_map }; |
705 | |
706 | /* Signatures for "list" methods, extracting a list |
707 | * from a multi-expression. |
708 | */ |
709 | static Signature to_list_set = { .ret: { Anonymous }, .args: { { Domain } } }; |
710 | static Signature to_list_map = { .ret: { Domain, Anonymous }, .args: { { Domain, Range } } }; |
711 | |
712 | /* Signatures for functions constructing an object from only an isl::ctx. |
713 | */ |
714 | static Signature ctx_params = { .ret: { }, .args: { { Ctx } } }; |
715 | static Signature ctx_set = { .ret: { Domain }, .args: { { Ctx } } }; |
716 | static Signature ctx_map = { .ret: { Domain, Range }, .args: { { Ctx } } }; |
717 | |
718 | /* Helper structure for sorting the keys of static_methods and |
719 | * special_member_methods such that the larger keys appear first. |
720 | * In particular, a key should appear before any key that appears |
721 | * as a substring in the key. |
722 | * Note that this sorting is currently only important |
723 | * for special_member_methods. |
724 | */ |
725 | struct larger_infix { |
726 | bool operator()(const std::string &x, const std::string &y) const { |
727 | if (x.length() > y. length()) |
728 | return true; |
729 | return x < y; |
730 | } |
731 | }; |
732 | |
733 | /* A map from part of a type name to a sequence of signatures. |
734 | */ |
735 | typedef std::map<std::string, std::vector<Signature>, larger_infix> infix_map; |
736 | |
737 | /* A map from a method name to a map from part of a type name |
738 | * to a sequence of signatures. |
739 | */ |
740 | typedef std::map<std::string, infix_map> infix_map_map; |
741 | |
742 | /* Signatures for static methods. |
743 | * |
744 | * The "unit" static method is only available in a 0-tuple space. |
745 | * |
746 | * The "empty" static method creates union objects with the relevant |
747 | * number of tuples. |
748 | * |
749 | * The "universe" static methods create objects from the corresponding spaces. |
750 | */ |
751 | static const infix_map_map static_methods { |
752 | { "unit" , |
753 | { { "space" , { ctx_params } } } |
754 | }, |
755 | { "empty" , |
756 | { |
757 | { "union_set" , { ctx_params, ctx_set } }, |
758 | { "union_map" , { ctx_map } }, |
759 | { "union_pw_multi_aff" , { ctx_set, ctx_map } }, |
760 | } |
761 | }, |
762 | { "universe" , |
763 | { |
764 | { "set" , { un_params, un_set } }, |
765 | { "map" , { un_map } }, |
766 | } |
767 | }, |
768 | }; |
769 | |
770 | /* Signatures for unary operations that either take something in a set space |
771 | * and return something in the same space or take something in a map space |
772 | * and return something in the range of that space. |
773 | */ |
774 | static std::vector<Signature> range_op = { un_set, range }; |
775 | |
776 | /* Signatures for binary operations where the second argument |
777 | * is a (multi-)value. |
778 | */ |
779 | static std::vector<Signature> bin_val = { bin_set, bin_map_range }; |
780 | |
781 | /* The (default) signatures for methods with a given name. |
782 | * Some of these are overridden by special_member_methods. |
783 | */ |
784 | static const std::unordered_map<std::string, std::vector<Signature>> |
785 | member_methods { |
786 | { "add" , bin_op }, |
787 | { "add_constant" , bin_val }, |
788 | { "add_named_tuple" , { to_set_named, add_range_named } }, |
789 | { "add_param" , bin_op_anon }, |
790 | { "add_unnamed_tuple" , { to_set, add_range } }, |
791 | { "apply" , { set_forward, range_forward } }, |
792 | { "apply_domain" , { domain_forward } }, |
793 | { "apply_range" , { range_forward } }, |
794 | { "as" , un_op }, |
795 | { "as_map" , { un_map } }, |
796 | { "as_union_map" , { un_map } }, |
797 | { "as_set" , { un_set } }, |
798 | { "bind" , { bind_set, bind_range } }, |
799 | { "bind_domain" , { bind_domain } }, |
800 | { "bind_range" , { bind_range } }, |
801 | { "bind_domain_wrapped_domain" , |
802 | { bind_domain_wrapped_domain } }, |
803 | { "ceil" , fn_un_op }, |
804 | { "coalesce" , un_op }, |
805 | { "cond" , fn_ter_op }, |
806 | { "constant" , range_op }, |
807 | { "curry" , { curry } }, |
808 | { "deltas" , { transformation_domain } }, |
809 | { "detect_equalities" , un_op }, |
810 | { "domain" , fn_domain }, |
811 | { "domain_factor_domain" , |
812 | { domain_factor_domain } }, |
813 | { "domain_factor_range" , |
814 | { domain_factor_range } }, |
815 | { "domain_map" , { domain_map } }, |
816 | { "domain_product" , { domain_product } }, |
817 | { "drop" , ter_int_int }, |
818 | { "eq_at" , { map_cmp } }, |
819 | { "every" , each }, |
820 | { "extract" , bin_op }, |
821 | { "flatten_domain" , flatten_domain }, |
822 | { "flatten_range" , flatten_range }, |
823 | { "floor" , fn_un_op }, |
824 | { "foreach" , each }, |
825 | { "foreach_scc" , each_scc }, |
826 | { "ge_set" , { set_join } }, |
827 | { "gt_set" , { set_join } }, |
828 | { "gist" , bin_op }, |
829 | { "gist_domain" , { bin_map_domain } }, |
830 | { "gist_params" , { bin_set_params, bin_map_params } }, |
831 | { "identity" , { un_map, set_to_map } }, |
832 | { "identity_on_domain" , { set_to_map } }, |
833 | { "indicator_function" , anonymous_from_domain }, |
834 | { "insert_domain" , { map_from_range_and_domain } }, |
835 | { "intersect" , bin_op }, |
836 | { "intersect_params" , { bin_set_params, bin_map_params } }, |
837 | { "intersect_domain" , { bin_map_domain } }, |
838 | { "intersect_domain_wrapped_domain" , |
839 | { bin_map_domain_wrapped_domain } }, |
840 | { "intersect_range" , { bin_map_range } }, |
841 | { "intersect_range_wrapped_domain" , |
842 | { bin_map_range_wrapped_domain } }, |
843 | { "lattice_tile" , { un_set } }, |
844 | { "le_set" , { set_join } }, |
845 | { "lt_set" , { set_join } }, |
846 | { "lex_le_at" , { map_cmp } }, |
847 | { "lex_lt_at" , { map_cmp } }, |
848 | { "lex_ge_at" , { map_cmp } }, |
849 | { "lex_gt_at" , { map_cmp } }, |
850 | { "lexmin" , fn_un_op }, |
851 | { "lexmax" , fn_un_op }, |
852 | { "list" , { to_list_set, to_list_map } }, |
853 | { "lower_bound" , fn_bin_op }, |
854 | { "map_from_set" , { set_to_map } }, |
855 | { "max" , min_max }, |
856 | { "max_val" , range_op }, |
857 | { "max_multi_val" , range_op }, |
858 | { "min" , min_max }, |
859 | { "min_val" , range_op }, |
860 | { "min_multi_val" , range_op }, |
861 | { "mod" , bin_val }, |
862 | { "on_domain" , { map_from_domain_and_range } }, |
863 | { "neg" , fn_un_op }, |
864 | { "offset" , fn_un_op }, |
865 | { "param_on_domain" , anonymous_from_domain_bin_anon }, |
866 | { "params" , { set_params, map_params } }, |
867 | { "plain_multi_val_if_fixed" , |
868 | { un_set } }, |
869 | { "preimage" , { set_backward } }, |
870 | { "preimage_domain" , { domain_backward } }, |
871 | { "preimage_domain_wrapped_domain" , |
872 | { domain_wrapped_domain_backward } }, |
873 | { "preimage_range" , { range_backward } }, |
874 | { "product" , { set_product, map_product } }, |
875 | { "project_out_param" , bin_op_anon }, |
876 | { "project_out_all_params" , |
877 | un_op }, |
878 | { "pullback" , { domain_backward, bind_domain } }, |
879 | { "range" , { range } }, |
880 | { "range_factor_domain" , |
881 | { range_factor_domain } }, |
882 | { "range_factor_range" , { range_factor_range } }, |
883 | { "range_lattice_tile" , { un_map } }, |
884 | { "range_map" , { range_map } }, |
885 | { "range_product" , { range_product } }, |
886 | { "range_reverse" , { map_range_reverse } }, |
887 | { "range_simple_fixed_box_hull" , |
888 | { un_map } }, |
889 | { "reverse" , { map_reverse } }, |
890 | { "scale" , bin_val }, |
891 | { "scale_down" , bin_val }, |
892 | { "set_at" , set_at }, |
893 | { "set_domain_tuple" , { update_domain } }, |
894 | { "set_range_tuple" , { update_set, update_range } }, |
895 | { "simple_fixed_box_hull" , |
896 | { un_set } }, |
897 | { "sub" , fn_bin_op }, |
898 | { "subtract" , bin_op }, |
899 | { "subtract_domain" , { bin_map_domain } }, |
900 | { "subtract_range" , { bin_map_range } }, |
901 | { "translation" , { set_to_map } }, |
902 | { "to" , un_op }, |
903 | { "unbind_params" , { set_from_params } }, |
904 | { "unbind_params_insert_domain" , |
905 | { map_from_range_and_domain } }, |
906 | { "uncurry" , { uncurry } }, |
907 | { "union_add" , fn_bin_op }, |
908 | { "unite" , bin_op }, |
909 | { "universe" , un_op }, |
910 | { "unwrap" , { unwrap } }, |
911 | { "upper_bound" , fn_bin_op }, |
912 | { "wrap" , { wrap } }, |
913 | { "zero" , fn_un_op }, |
914 | { "zero_on_domain" , { anonymous_map_from_domain } }, |
915 | }; |
916 | |
917 | /* Signatures for methods of types containing a given substring |
918 | * that override the default signatures, where larger substrings |
919 | * appear first. |
920 | * |
921 | * In particular, "gist" is usually a regular binary operation, |
922 | * but for any type derived from "aff", the argument refers |
923 | * to the domain of the function. |
924 | * |
925 | * The "size" method can usually simply be inherited from |
926 | * the corresponding plain C++ type, but for a "fixed_box", |
927 | * the size lives in the space of the box or its range. |
928 | * |
929 | * The "space" method is usually a regular unary operation |
930 | * that returns the single space of the elements in the object, |
931 | * with the same number of tuples. |
932 | * However, a "union" object may contain elements from many spaces and |
933 | * therefore its space only refers to the symbolic constants and |
934 | * has zero tuples, except if it is also a "multi_union" object, |
935 | * in which case it has a fixed range space and the space of the object |
936 | * has a single tuple. |
937 | * Note that since "space' is also the name of a template class, |
938 | * the default space method is handled by print_type_named_member_method. |
939 | */ |
940 | static const infix_map_map special_member_methods { |
941 | { "gist" , |
942 | { { "aff" , { bin_set_params, bin_map_domain } } } |
943 | }, |
944 | { "size" , |
945 | { { "fixed_box" , range_op } }, |
946 | }, |
947 | { "space" , |
948 | { |
949 | { "multi_union" , range_op }, |
950 | { "union" , { un_params, set_params, map_params } }, |
951 | } |
952 | }, |
953 | }; |
954 | |
955 | /* Generic kinds for objects with zero, one or two tuples, |
956 | * the last of which may be anonymous. |
957 | */ |
958 | static Kind params{}; |
959 | static Kind set_type{ Domain }; |
960 | static Kind set_anon{ Anonymous }; |
961 | static Kind map_type{ Domain, Range }; |
962 | static Kind map_anon{ Domain, Anonymous }; |
963 | |
964 | /* The initial sequence of specialization kinds for base types. |
965 | * The specialization kinds for other types are derived |
966 | * from the corresponding base types. |
967 | * |
968 | * In particular, this sequence specifies how many tuples |
969 | * a given type can have and whether it is anonymous. |
970 | * |
971 | * "space" can have any number of tuples. |
972 | * "set" and "point" can have zero or one tuple. |
973 | * "map" can only have two tuples. |
974 | * "aff" can have one or two tuples, the last of which is anonymous. |
975 | * "fixed_box" can represent a (proper) set) or a map. |
976 | * "val" and "id" are treated as anonymous sets so that |
977 | * they can form the basis of "multi_val" and "multi_id". |
978 | */ |
979 | static const std::unordered_map<std::string, std::vector<Kind>> base_kinds { |
980 | { "space" , { params, set_type, map_type } }, |
981 | { "set" , { params, set_type } }, |
982 | { "point" , { params, set_type } }, |
983 | { "map" , { map_type } }, |
984 | { "aff" , { set_anon, map_anon } }, |
985 | { "fixed_box" , { set_type, map_type } }, |
986 | { "val" , { set_anon } }, |
987 | { "id" , { set_anon } }, |
988 | }; |
989 | |
990 | /* Prefixes introduced by type constructors. |
991 | */ |
992 | static const std::unordered_set<std::string> type_prefixes { |
993 | "basic" , |
994 | "multi" , |
995 | "pw" , |
996 | "union" , |
997 | }; |
998 | |
999 | /* If "type" has a "_list" suffix, then return "type" with this suffix removed. |
1000 | * Otherwise, simply return "type". |
1001 | */ |
1002 | static std::string drop_list(const std::string &type) |
1003 | { |
1004 | size_t pos = type.rfind(c: '_'); |
1005 | |
1006 | if (pos == std::string::npos) |
1007 | return type; |
1008 | if (type.substr(pos: pos + 1) == "list" ) |
1009 | return type.substr(pos: 0, n: pos); |
1010 | return type; |
1011 | } |
1012 | |
1013 | /* Given the name of a plain C++ type, return the base type |
1014 | * from which it was derived using type constructors. |
1015 | * |
1016 | * In particular, drop any "list" suffix and |
1017 | * drop any prefixes from type_prefixes, stopping |
1018 | * as soon as a base type is found for which kinds have been registered |
1019 | * in base_kinds. |
1020 | */ |
1021 | static std::string base_type(const std::string &type) |
1022 | { |
1023 | auto base = type; |
1024 | size_t pos; |
1025 | |
1026 | base = drop_list(type: base); |
1027 | while (base_kinds.count(x: base) == 0 && |
1028 | (pos = base.find(c: '_')) != std::string::npos && |
1029 | type_prefixes.count(x: base.substr(pos: 0, n: pos)) != 0) { |
1030 | base = base.substr(pos: pos + 1); |
1031 | } |
1032 | |
1033 | return base; |
1034 | } |
1035 | |
1036 | /* A mapping from anonymous kinds to named kinds. |
1037 | */ |
1038 | static std::map<Kind, Kind> anon_to_named { |
1039 | { set_anon, set_type }, |
1040 | { map_anon, map_type }, |
1041 | }; |
1042 | |
1043 | /* Given a sequence of anonymous kinds, replace them |
1044 | * by the corresponding named kinds. |
1045 | */ |
1046 | static std::vector<Kind> add_name(const std::vector<Kind> &tuples) |
1047 | { |
1048 | std::vector<Kind> named; |
1049 | |
1050 | for (const auto &tuple : tuples) |
1051 | named.emplace_back(args&: anon_to_named.at(k: tuple)); |
1052 | |
1053 | return named; |
1054 | } |
1055 | |
1056 | /* Look up the (initial) specializations of the class called "name". |
1057 | * If no specializations have been defined, then return an empty vector. |
1058 | * |
1059 | * Start from the initial specializations of the corresponding base type. |
1060 | * If this template class is a multi-expression, then it was derived |
1061 | * from an anonymous function type. Replace the final Anonymous |
1062 | * tuple kind by a placeholder in this case. |
1063 | */ |
1064 | static std::vector<Kind> lookup_class_tuples(const std::string &name) |
1065 | { |
1066 | std::string base = base_type(type: name); |
1067 | |
1068 | if (base_kinds.count(x: base) == 0) |
1069 | return { }; |
1070 | if (name.find(s: "multi_" ) != std::string::npos) |
1071 | return add_name(tuples: base_kinds.at(k: base)); |
1072 | return base_kinds.at(k: base); |
1073 | } |
1074 | |
1075 | /* Add a template class called "name", of which the methods are described |
1076 | * by "clazz" and the initial specializations by "class_tuples". |
1077 | */ |
1078 | void template_cpp_generator::add_template_class(const isl_class &clazz, |
1079 | const std::string &name, const std::vector<Kind> &class_tuples) |
1080 | { |
1081 | auto isl_namespace = cpp_type_printer().isl_namespace(); |
1082 | auto super = isl_namespace + name; |
1083 | |
1084 | template_classes.emplace(args: name, |
1085 | args: template_class{.class_name: name, .super_name: super, .clazz: clazz, .class_tuples: class_tuples}); |
1086 | } |
1087 | |
1088 | /* Construct a templated C++ bindings generator from |
1089 | * the exported types and functions and the set of all declared functions. |
1090 | * |
1091 | * On top of the initialization of the shared parts |
1092 | * of C++ bindings generators, add a template class |
1093 | * for each plain C++ class for which template kinds |
1094 | * have been defined. |
1095 | * In particular, determine the base type from which the plain C++ class |
1096 | * was derived using type constructors and check if any template kinds |
1097 | * have been registered for this base type. |
1098 | */ |
1099 | template_cpp_generator::template_cpp_generator(clang::SourceManager &SM, |
1100 | std::set<clang::RecordDecl *> &exported_types, |
1101 | std::set<clang::FunctionDecl *> exported_functions, |
1102 | std::set<clang::FunctionDecl *> functions) : |
1103 | cpp_generator(SM, exported_types, exported_functions, |
1104 | functions) |
1105 | { |
1106 | for (const auto &kvp : classes) { |
1107 | const auto &clazz = kvp.second; |
1108 | std::string name = type2cpp(clazz); |
1109 | const auto &class_tuples = lookup_class_tuples(name); |
1110 | |
1111 | if (class_tuples.empty()) |
1112 | continue; |
1113 | add_template_class(clazz: clazz, name, class_tuples: class_tuples); |
1114 | } |
1115 | } |
1116 | |
1117 | /* Call "fn" on each template class. |
1118 | */ |
1119 | void template_cpp_generator::foreach_template_class( |
1120 | const std::function<void(const template_class &)> &fn) const |
1121 | { |
1122 | for (const auto &kvp : template_classes) |
1123 | fn(kvp.second); |
1124 | } |
1125 | |
1126 | /* Print forward declarations for all template classes to "os". |
1127 | * |
1128 | * For template classes that represent an anonymous function |
1129 | * that can also have a domain tuple, provide an <name>_on alias |
1130 | * that adds the fixed Anonymous tuple kind. |
1131 | */ |
1132 | void template_cpp_generator::print_forward_declarations(std::ostream &os) |
1133 | { |
1134 | foreach_template_class(fn: [&os] (const template_class &template_class) { |
1135 | auto name = template_class.class_name; |
1136 | |
1137 | os << "\n" ; |
1138 | os << "template <typename...>\n" ; |
1139 | os << "struct " << name << ";\n" ; |
1140 | |
1141 | if (!template_class.is_anon()) |
1142 | return; |
1143 | if (template_class.is_anon_set()) |
1144 | return; |
1145 | |
1146 | os << "\n" ; |
1147 | os << "template <typename...Ts>\n" ; |
1148 | os << "using " << name << "_on = " |
1149 | << name << "<Ts..., Anonymous>;\n" ; |
1150 | }); |
1151 | } |
1152 | |
1153 | /* Print friend declarations for all template classes to "os". |
1154 | */ |
1155 | void template_cpp_generator::print_friends(std::ostream &os) |
1156 | { |
1157 | foreach_template_class(fn: [&os] (const template_class &template_class) { |
1158 | os << " template <typename...>\n" ; |
1159 | os << " friend struct " << template_class.class_name << ";\n" ; |
1160 | }); |
1161 | } |
1162 | |
1163 | /* Print a template parameter or argument. |
1164 | * In case of a std::string, it's a template parameter |
1165 | * that needs to be declared. |
1166 | */ |
1167 | static void print_template_arg(std::ostream &os, const std::string &arg) |
1168 | { |
1169 | os << "typename " << arg; |
1170 | } |
1171 | |
1172 | /* Print a template parameter or argument. |
1173 | * In case of a TupleKindPtr, it's a template argument. |
1174 | */ |
1175 | static void print_template_arg(std::ostream &os, const TupleKindPtr &kind) |
1176 | { |
1177 | os << kind->to_string(); |
1178 | } |
1179 | |
1180 | /* Print a sequence of template parameters (std::string) or |
1181 | * arguments (TupleKindPtr) "args", without the enclosing angle brackets. |
1182 | */ |
1183 | template <typename List> |
1184 | static void print_pure_template_args(std::ostream &os, const List &args) |
1185 | { |
1186 | for (size_t i = 0; i < args.size(); ++i) { |
1187 | if (i != 0) |
1188 | os << ", " ; |
1189 | print_template_arg(os, args[i]); |
1190 | } |
1191 | } |
1192 | |
1193 | /* Print a sequence of template parameters (std::string) or |
1194 | * arguments (TupleKindPtr) "args". |
1195 | */ |
1196 | template <typename List> |
1197 | static void print_template_args(std::ostream &os, const List &args) |
1198 | { |
1199 | os << "<" ; |
1200 | print_pure_template_args(os, args); |
1201 | os << ">" ; |
1202 | } |
1203 | |
1204 | /* Print a declaration of the template parameters "params". |
1205 | */ |
1206 | static void print_template(std::ostream &os, |
1207 | const std::vector<std::string> ¶ms) |
1208 | { |
1209 | os << "template " ; |
1210 | print_template_args(os, args: params); |
1211 | os << "\n" ; |
1212 | } |
1213 | |
1214 | /* Print a declaration of the template parameters "params", |
1215 | * if there are any. |
1216 | */ |
1217 | static void print_non_empty_template(std::ostream &os, |
1218 | const std::vector<std::string> ¶ms) |
1219 | { |
1220 | if (params.size() > 0) |
1221 | print_template(os, params); |
1222 | } |
1223 | |
1224 | /* Print a bare template type, i.e., without namespace, |
1225 | * consisting of the type "type" and the kind "kind" to "os". |
1226 | * |
1227 | * In particular, print "type" followed by the template arguments |
1228 | * as specified by "kind". |
1229 | */ |
1230 | static void print_bare_template_type(std::ostream &os, const std::string &type, |
1231 | const Kind &kind) |
1232 | { |
1233 | os << type; |
1234 | print_template_args(os, args: kind); |
1235 | } |
1236 | |
1237 | /* A specific instance of "template_class", with tuple kinds given by "kind". |
1238 | */ |
1239 | struct specialization { |
1240 | struct template_class &template_class; |
1241 | Kind kind; |
1242 | |
1243 | const std::string &base_name() const; |
1244 | const std::string &class_name() const; |
1245 | }; |
1246 | |
1247 | /* The name of the plain C++ interface class |
1248 | * from which this template class (instance) derives. |
1249 | */ |
1250 | const std::string &specialization::base_name() const |
1251 | { |
1252 | return template_class.super_name; |
1253 | } |
1254 | |
1255 | /* The name of the template class. |
1256 | */ |
1257 | const std::string &specialization::class_name() const |
1258 | { |
1259 | return template_class.class_name; |
1260 | } |
1261 | |
1262 | /* Helper class for printing the specializations of template classes |
1263 | * that is used to print both the class declarations and the class definitions. |
1264 | * |
1265 | * "os" is the stream onto which the classes should be printed. |
1266 | * "generator" is the templated C++ interface generator printing the classes. |
1267 | */ |
1268 | struct specialization_printer { |
1269 | specialization_printer(std::ostream &os, |
1270 | template_cpp_generator &generator) : |
1271 | os(os), generator(generator) {} |
1272 | |
1273 | virtual void print_class(const specialization &instance) const = 0; |
1274 | void print_classes() const; |
1275 | |
1276 | std::ostream &os; |
1277 | template_cpp_generator &generator; |
1278 | }; |
1279 | |
1280 | /* Print all specializations of all template classes. |
1281 | * |
1282 | * Each class has a predefined set of initial specializations, |
1283 | * but while such a specialization is being printed, |
1284 | * the need for other specializations may arise and |
1285 | * these are added at the end of the list of specializations. |
1286 | * That is, class_tuples.size() may change during the execution |
1287 | * of the loop. |
1288 | * |
1289 | * For each specialization of a template class, call |
1290 | * the print_class virtual method. |
1291 | */ |
1292 | void specialization_printer::print_classes() const |
1293 | { |
1294 | for (auto &kvp : generator.template_classes) { |
1295 | auto &template_class = kvp.second; |
1296 | const auto &class_tuples = template_class.class_tuples; |
1297 | |
1298 | for (size_t i = 0; i < class_tuples.size(); ++i) |
1299 | print_class(instance: { .template_class: template_class, .kind: class_tuples[i] }); |
1300 | } |
1301 | } |
1302 | |
1303 | /* A helper class for printing method declarations and definitions |
1304 | * of a template class specialization. |
1305 | * |
1306 | * "instance" is the template class specialization for which methods |
1307 | * are printed. |
1308 | * "generator" is the templated C++ interface generator printing the classes. |
1309 | */ |
1310 | struct template_cpp_generator::class_printer : |
1311 | public cpp_generator::class_printer { |
1312 | class_printer(const specialization &instance, |
1313 | const specialization_printer &instance_printer, |
1314 | bool is_declaration); |
1315 | |
1316 | void print_return_type(const Method &method, const Kind &kind) |
1317 | const; |
1318 | void print_method_template_arguments(const Signature &sig); |
1319 | void print_method_header(const Method &method, const Signature &sig); |
1320 | bool print_special_method(const Method &method, |
1321 | const infix_map_map &special_methods); |
1322 | void print_static_method(const Method &method); |
1323 | void print_constructor(const Method &method); |
1324 | bool is_return_kind(const Method &method, const Kind &return_kind); |
1325 | void add_specialization(const Kind &kind); |
1326 | bool print_matching_method(const Method &method, const Signature &sig, |
1327 | const Kind &match_arg); |
1328 | bool print_matching_method(const Method &method, const Signature &sig); |
1329 | void print_matching_method(const Method &method, |
1330 | const std::vector<Signature> &signatures); |
1331 | void print_at_method(const Method &method); |
1332 | bool print_special_member_method(const Method &method); |
1333 | bool print_type_named_member_method(const Method &method); |
1334 | bool print_member_method_with_name(const Method &method, |
1335 | const std::string &name); |
1336 | void print_member_method(const Method &method); |
1337 | void print_any_method(const Method &method); |
1338 | virtual void print_method(const Method &method) override; |
1339 | virtual void print_method(const ConversionMethod &method) override; |
1340 | virtual void print_method_sig(const Method &method, |
1341 | const Signature &sig, bool deleted) = 0; |
1342 | virtual bool want_descendent_overloads(const function_set &methods) |
1343 | override; |
1344 | void print_all_methods(); |
1345 | |
1346 | const specialization &instance; |
1347 | template_cpp_generator &generator; |
1348 | }; |
1349 | |
1350 | /* Construct a class_printer from the template class specialization |
1351 | * for which methods are printed and |
1352 | * the printer of the template class. |
1353 | * |
1354 | * The template class printer is only used to obtain the output stream and |
1355 | * the templated C++ interface generator printing the classes. |
1356 | */ |
1357 | template_cpp_generator::class_printer::class_printer( |
1358 | const specialization &instance, |
1359 | const specialization_printer &instance_printer, |
1360 | bool is_declaration) : |
1361 | cpp_generator::class_printer(instance_printer.os, |
1362 | instance.template_class.clazz, instance_printer.generator, |
1363 | is_declaration), |
1364 | instance(instance), generator(instance_printer.generator) |
1365 | { |
1366 | } |
1367 | |
1368 | /* An abstract template type printer, where the way of obtaining |
1369 | * the argument kind is specified by the subclasses. |
1370 | */ |
1371 | struct template_cpp_type_printer : public cpp_type_printer { |
1372 | template_cpp_type_printer() {} |
1373 | |
1374 | std::string base(const std::string &type, const Kind &kind) const; |
1375 | virtual Kind kind(int arg) const = 0; |
1376 | virtual std::string qualified(int arg, const std::string &cpp_type) |
1377 | const override; |
1378 | }; |
1379 | |
1380 | /* Print a template type consisting of the type "type" and the kind "kind", |
1381 | * including the "typed::" namespace specifier. |
1382 | */ |
1383 | std::string template_cpp_type_printer::base(const std::string &type, |
1384 | const Kind &kind) const |
1385 | { |
1386 | std::ostringstream ss; |
1387 | |
1388 | ss << "typed::" ; |
1389 | print_bare_template_type(os&: ss, type, kind); |
1390 | return ss.str(); |
1391 | } |
1392 | |
1393 | /* Return the qualified form of the given C++ isl type name appearing |
1394 | * in argument position "arg" (-1 for return type). |
1395 | * |
1396 | * isl::ctx is not templated, so if "cpp_type" is "ctx", |
1397 | * then print a non-templated version. |
1398 | * Otherwise, look up the kind of the argument and print |
1399 | * the corresponding template type. |
1400 | */ |
1401 | std::string template_cpp_type_printer::qualified(int arg, |
1402 | const std::string &cpp_type) const |
1403 | { |
1404 | if (cpp_type == "ctx" ) |
1405 | return cpp_type_printer::qualified(arg, cpp_type); |
1406 | |
1407 | return base(type: cpp_type, kind: kind(arg)); |
1408 | } |
1409 | |
1410 | /* A template type printer for printing types with a fixed kind. |
1411 | * |
1412 | * "fixed_kind" is the fixed kind. |
1413 | */ |
1414 | struct template_cpp_kind_type_printer : public template_cpp_type_printer { |
1415 | template_cpp_kind_type_printer(const Kind &kind) : |
1416 | template_cpp_type_printer(), fixed_kind(kind) {} |
1417 | |
1418 | virtual Kind kind(int arg) const override; |
1419 | |
1420 | const Kind &fixed_kind; |
1421 | }; |
1422 | |
1423 | /* Return the kind of the argument at position "arg", |
1424 | * where position -1 refers to the return type. |
1425 | * |
1426 | * Always use the fixed kind. |
1427 | */ |
1428 | Kind template_cpp_kind_type_printer::kind(int arg) const |
1429 | { |
1430 | return fixed_kind; |
1431 | } |
1432 | |
1433 | /* A template type printer for printing a method with a given signature. |
1434 | * |
1435 | * "sig" is the signature of the method being printed. |
1436 | */ |
1437 | struct template_cpp_arg_type_printer : public template_cpp_type_printer { |
1438 | template_cpp_arg_type_printer(const Signature &sig) : |
1439 | template_cpp_type_printer(), sig(sig) {} |
1440 | |
1441 | virtual Kind kind(int arg) const override; |
1442 | |
1443 | const Signature &sig; |
1444 | }; |
1445 | |
1446 | /* Return the kind of the argument at position "arg", |
1447 | * where position -1 refers to the return type. |
1448 | * |
1449 | * Look up the kind in the signature. |
1450 | */ |
1451 | Kind template_cpp_arg_type_printer::kind(int arg) const |
1452 | { |
1453 | int n_args = sig.args.size(); |
1454 | |
1455 | if (arg < 0) |
1456 | return sig.ret; |
1457 | if (arg >= n_args) |
1458 | generator::die(msg: "argument out of bounds" ); |
1459 | return sig.args[arg]; |
1460 | } |
1461 | |
1462 | /* A template type printer for printing a method with a given signature |
1463 | * as part of a template class specialization of a given kind. |
1464 | * |
1465 | * "class_kind" is the template class specialization kind. |
1466 | */ |
1467 | struct template_method_type_printer : public template_cpp_arg_type_printer { |
1468 | template_method_type_printer(const Signature &sig, |
1469 | const Kind &class_kind) : |
1470 | template_cpp_arg_type_printer(sig), |
1471 | class_kind(class_kind) {} |
1472 | |
1473 | virtual std::string class_type(const std::string &cpp_name) |
1474 | const override; |
1475 | |
1476 | const Kind &class_kind; |
1477 | }; |
1478 | |
1479 | /* Print the class type "cpp_name". |
1480 | * |
1481 | * Print the templated version using the template class specialization kind. |
1482 | */ |
1483 | std::string template_method_type_printer::class_type( |
1484 | const std::string &cpp_name) const |
1485 | { |
1486 | return base(type: cpp_name, kind: class_kind); |
1487 | } |
1488 | |
1489 | /* Print the templated return type of "method" of the kind "return_kind". |
1490 | * |
1491 | * Construct a type printer with "return_kind" as fixed kind and |
1492 | * use it to print the return type. |
1493 | */ |
1494 | void template_cpp_generator::class_printer::print_return_type( |
1495 | const Method &method, const Kind &return_kind) const |
1496 | { |
1497 | template_cpp_kind_type_printer printer(return_kind); |
1498 | |
1499 | os << printer.return_type(method); |
1500 | } |
1501 | |
1502 | /* Remove the initial "n" elements from "v". |
1503 | */ |
1504 | template <typename T> |
1505 | static void drop_initial(std::vector<T> &v, size_t n) |
1506 | { |
1507 | v.erase(v.begin(), v.begin() + n); |
1508 | } |
1509 | |
1510 | /* If a method with signature "sig" requires additional template parameters |
1511 | * compared to those of the class, then print a declaration for them. |
1512 | * If this->declarations is set, then this will be part of a method declaration, |
1513 | * requiring extra indentation. |
1514 | * |
1515 | * Construct the sequence of all required template parameters |
1516 | * with those of the template class appearing first. |
1517 | * If this sequence has any parameters not induced by the template class itself, |
1518 | * then print a declaration for these extra parameters. |
1519 | */ |
1520 | void template_cpp_generator::class_printer::print_method_template_arguments( |
1521 | const Signature &sig) |
1522 | { |
1523 | std::vector<std::string> class_params, method_params; |
1524 | |
1525 | class_params = instance.kind.params(); |
1526 | method_params = class_params; |
1527 | combine(vec1&: method_params, vec2: sig.params()); |
1528 | |
1529 | if (class_params.size() == method_params.size()) |
1530 | return; |
1531 | |
1532 | drop_initial(v&: method_params, n: class_params.size()); |
1533 | |
1534 | if (declarations) |
1535 | os << " " ; |
1536 | print_template(os, params: method_params); |
1537 | } |
1538 | |
1539 | /* Print the header for "method" with signature "sig". |
1540 | * |
1541 | * First print any additional template parameters that may be required and |
1542 | * then print a regular method header, using a template type printer. |
1543 | */ |
1544 | void template_cpp_generator::class_printer::( |
1545 | const Method &method, const Signature &sig) |
1546 | { |
1547 | template_method_type_printer type_printer(sig, instance.kind); |
1548 | |
1549 | print_method_template_arguments(sig); |
1550 | cpp_generator::class_printer::print_method_header(method, |
1551 | type_printer); |
1552 | } |
1553 | |
1554 | /* Given a group of methods with the same name, |
1555 | * should extra methods be added that take as arguments |
1556 | * those types that can be converted to the original argument type |
1557 | * through a unary constructor? |
1558 | * |
1559 | * Since type deduction does not consider implicit conversions, |
1560 | * these extra methods should always be printed. |
1561 | */ |
1562 | bool template_cpp_generator::class_printer::want_descendent_overloads( |
1563 | const function_set &methods) |
1564 | { |
1565 | return true; |
1566 | } |
1567 | |
1568 | /* Print all constructors and methods that forward |
1569 | * to the corresponding methods in the plain C++ interface class. |
1570 | */ |
1571 | void template_cpp_generator::class_printer::print_all_methods() |
1572 | { |
1573 | print_constructors(); |
1574 | print_methods(); |
1575 | } |
1576 | |
1577 | /* A helper class for printing method declarations |
1578 | * of a template class specialization. |
1579 | */ |
1580 | struct template_cpp_generator::method_decl_printer : |
1581 | public template_cpp_generator::class_printer { |
1582 | method_decl_printer(const specialization &instance, |
1583 | const struct specialization_printer &instance_printer) : |
1584 | class_printer(instance, instance_printer, true) {} |
1585 | |
1586 | virtual void print_method_sig(const Method &method, |
1587 | const Signature &sig, bool deleted) override; |
1588 | virtual void print_get_method(FunctionDecl *fd) override; |
1589 | }; |
1590 | |
1591 | /* Print a declaration of the method "method" with signature "sig". |
1592 | * Mark is "delete" if "deleted" is set. |
1593 | */ |
1594 | void template_cpp_generator::method_decl_printer::print_method_sig( |
1595 | const Method &method, const Signature &sig, bool deleted) |
1596 | { |
1597 | print_method_header(method, sig); |
1598 | if (deleted) |
1599 | os << " = delete" ; |
1600 | os << ";\n" ; |
1601 | } |
1602 | |
1603 | /* Return the total number of arguments in the signature for "method", |
1604 | * taking into account any possible callback arguments. |
1605 | * |
1606 | * In particular, if the method has a callback argument, |
1607 | * then the return kind of the callback appears at the position |
1608 | * of the callback and the kinds of the arguments (except |
1609 | * the user pointer argument) appear in the following positions. |
1610 | * The user pointer argument that follows the callback argument |
1611 | * is also removed. |
1612 | */ |
1613 | static int total_params(const Method &method) |
1614 | { |
1615 | int n = method.num_params(); |
1616 | |
1617 | for (const auto &callback : method.callbacks) { |
1618 | auto callback_type = callback->getType(); |
1619 | auto proto = generator::extract_prototype(callback_type); |
1620 | |
1621 | n += proto->getNumArgs() - 1; |
1622 | n -= 1; |
1623 | } |
1624 | |
1625 | return n; |
1626 | } |
1627 | |
1628 | /* Return a signature for "method" that matches "instance". |
1629 | */ |
1630 | static Signature instance_sig(const Method &method, |
1631 | const specialization &instance) |
1632 | { |
1633 | std::vector<Kind> args(total_params(method)); |
1634 | |
1635 | args[0] = instance.kind; |
1636 | return { .ret: instance.kind, .args: args }; |
1637 | } |
1638 | |
1639 | /* Print a declaration for the "get" method "fd", |
1640 | * using a name that includes the "get_" prefix. |
1641 | * |
1642 | * These methods are only included in the plain interface. |
1643 | * Explicitly delete them from the templated interface. |
1644 | */ |
1645 | void template_cpp_generator::method_decl_printer::print_get_method( |
1646 | FunctionDecl *fd) |
1647 | { |
1648 | Method method(clazz, fd, clazz.base_method_name(fd)); |
1649 | |
1650 | print_method_sig(method, sig: instance_sig(method, instance), deleted: true); |
1651 | } |
1652 | |
1653 | /* A helper class for printing method definitions |
1654 | * of a template class specialization. |
1655 | */ |
1656 | struct template_cpp_generator::method_impl_printer : |
1657 | public template_cpp_generator::class_printer { |
1658 | method_impl_printer(const specialization &instance, |
1659 | const struct specialization_printer &instance_printer) : |
1660 | class_printer(instance, instance_printer, false) {} |
1661 | |
1662 | void print_callback_method_body(const Method &method, |
1663 | const Signature &sig); |
1664 | void print_method_body(const Method &method, const Signature &sig); |
1665 | void print_constructor_body(const Method &method, const Signature &sig); |
1666 | virtual void print_method_sig(const Method &method, |
1667 | const Signature &sig, bool deleted) override; |
1668 | virtual void print_get_method(FunctionDecl *fd) override; |
1669 | }; |
1670 | |
1671 | /* Print a definition of the constructor "method" with signature "sig". |
1672 | * |
1673 | * Simply pass all arguments to the constructor of the corresponding |
1674 | * plain type. |
1675 | */ |
1676 | void template_cpp_generator::method_impl_printer::print_constructor_body( |
1677 | const Method &method, const Signature &sig) |
1678 | { |
1679 | const auto &base_name = instance.base_name(); |
1680 | |
1681 | os << " : " << base_name; |
1682 | method.print_cpp_arg_list(os, print_arg: [&] (int i, int arg) { |
1683 | os << method.fd->getParamDecl(i)->getName().str(); |
1684 | }); |
1685 | os << "\n" ; |
1686 | |
1687 | os << "{\n" ; |
1688 | os << "}\n" ; |
1689 | } |
1690 | |
1691 | /* Print the arguments of the callback function "callback" to "os", |
1692 | * calling "print_arg" with the type and the name of the arguments, |
1693 | * where the type is obtained from "type_printer" with argument positions |
1694 | * shifted by "shift". |
1695 | * None of the arguments should be skipped. |
1696 | */ |
1697 | static void print_callback_args(std::ostream &os, |
1698 | const FunctionProtoType *callback, const cpp_type_printer &type_printer, |
1699 | int shift, |
1700 | const std::function<void(const std::string &type, |
1701 | const std::string &name)> &print_arg) |
1702 | { |
1703 | auto n_arg = callback->getNumArgs() - 1; |
1704 | |
1705 | Method::print_arg_list(os, start: 0, end: n_arg, print_arg_skip_next: [&] (int i) { |
1706 | auto type = callback->getArgType(i); |
1707 | auto name = "arg" + std::to_string(val: i); |
1708 | auto cpptype = type_printer.param(shift + i, type); |
1709 | |
1710 | print_arg(cpptype, name); |
1711 | |
1712 | return false; |
1713 | }); |
1714 | } |
1715 | |
1716 | /* Print a lambda corresponding to "callback" |
1717 | * with signature "sig" and argument positions shifted by "shift". |
1718 | * |
1719 | * The lambda takes arguments with plain isl types and |
1720 | * calls the callback of "method" with templated arguments. |
1721 | */ |
1722 | static void print_callback_lambda(std::ostream &os, ParmVarDecl *callback, |
1723 | const Signature &sig, int shift) |
1724 | { |
1725 | auto callback_type = callback->getType(); |
1726 | auto callback_name = callback->getName().str(); |
1727 | auto proto = generator::extract_prototype(callback_type); |
1728 | |
1729 | os << " auto lambda_" << callback_name << " = [&] " ; |
1730 | print_callback_args(os, proto, cpp_type_printer(), shift, |
1731 | [&] (const std::string &type, const std::string &name) { |
1732 | os << type << " " << name; |
1733 | }); |
1734 | os << " {\n" ; |
1735 | |
1736 | os << " return " << callback_name; |
1737 | print_callback_args(os, proto, template_cpp_arg_type_printer(sig), |
1738 | shift, |
1739 | [&] (const std::string &type, const std::string &name) { |
1740 | os << type << "(" << name << ")" ; |
1741 | }); |
1742 | os << ";\n" ; |
1743 | |
1744 | os << " };\n" ; |
1745 | } |
1746 | |
1747 | /* Print lambdas for passing to the plain method corresponding to "method" |
1748 | * with signature "sig". |
1749 | * |
1750 | * The method is assumed to have only callbacks as argument, |
1751 | * which means the arguments of the first callback are shifted by 2 |
1752 | * with respect to the arguments of the signature |
1753 | * (one for the position of the callback argument plus |
1754 | * one for the return kind of the callback). |
1755 | * The arguments of a subsequent callback are shifted by |
1756 | * the number of arguments of the previous callback minus one |
1757 | * for the user pointer plus one for the return kind. |
1758 | */ |
1759 | static void print_callback_lambdas(std::ostream &os, const Method &method, |
1760 | const Signature &sig) |
1761 | { |
1762 | int shift; |
1763 | |
1764 | if (method.num_params() != 1 + 2 * method.callbacks.size()) |
1765 | generator::die(msg: "callbacks are assumed to be only arguments" ); |
1766 | |
1767 | shift = 2; |
1768 | for (const auto &callback : method.callbacks) { |
1769 | print_callback_lambda(os, callback, sig, shift); |
1770 | shift += generator::prototype_n_args(callback->getType()); |
1771 | } |
1772 | } |
1773 | |
1774 | /* Print a definition of the member method "method", which is known |
1775 | * to have a callback argument, with signature "sig". |
1776 | * |
1777 | * First print lambdas for passing to the corresponding plain method and |
1778 | * calling the callback of "method" with templated arguments. |
1779 | * Then call the plain method, replacing the original callbacks |
1780 | * by the lambdas. |
1781 | * |
1782 | * The return value is assumed to be isl_bool or isl_stat |
1783 | * so that no conversion to a template type is required. |
1784 | */ |
1785 | void template_cpp_generator::method_impl_printer::print_callback_method_body( |
1786 | const Method &method, const Signature &sig) |
1787 | { |
1788 | const auto &base_name = instance.base_name(); |
1789 | auto return_type = method.fd->getReturnType(); |
1790 | |
1791 | if (!is_isl_bool(return_type) && !is_isl_stat(return_type)) |
1792 | die(msg: "only isl_bool and isl_stat return types are supported" ); |
1793 | |
1794 | os << "{\n" ; |
1795 | |
1796 | print_callback_lambdas(os, method, sig); |
1797 | |
1798 | os << " return " ; |
1799 | os << base_name << "::" << method.name; |
1800 | method.print_cpp_arg_list(os, print_arg: [&] (int i, int arg) { |
1801 | auto param = method.fd->getParamDecl(i); |
1802 | |
1803 | if (generator::is_callback(param->getType())) |
1804 | os << "lambda_" ; |
1805 | os << param->getName().str(); |
1806 | }); |
1807 | os << ";\n" ; |
1808 | |
1809 | os << "}\n" ; |
1810 | } |
1811 | |
1812 | /* Print a definition of the member or static method "method" |
1813 | * with signature "sig". |
1814 | * |
1815 | * The body calls the corresponding method of the base class |
1816 | * in the plain interface and |
1817 | * then casts the result to the templated result type. |
1818 | */ |
1819 | void template_cpp_generator::method_impl_printer::print_method_body( |
1820 | const Method &method, const Signature &sig) |
1821 | { |
1822 | const auto &base_name = instance.base_name(); |
1823 | |
1824 | os << "{\n" ; |
1825 | os << " auto res = " ; |
1826 | os << base_name << "::" << method.name; |
1827 | method.print_cpp_arg_list(os, print_arg: [&] (int i, int arg) { |
1828 | os << method.fd->getParamDecl(i)->getName().str(); |
1829 | }); |
1830 | os << ";\n" ; |
1831 | |
1832 | os << " return " ; |
1833 | print_return_type(method, return_kind: sig.ret); |
1834 | os << "(res);\n" ; |
1835 | os << "}\n" ; |
1836 | } |
1837 | |
1838 | /* Print a definition of the method "method" with signature "sig", |
1839 | * if "deleted" is not set. |
1840 | * |
1841 | * If "deleted" is set, then the corresponding declaration |
1842 | * is marked "delete" and no definition needs to be printed. |
1843 | * |
1844 | * Otherwise print the method header, preceded by the template parameters, |
1845 | * if needed. |
1846 | * The body depends on whether the method is a constructor or |
1847 | * takes any callbacks. |
1848 | */ |
1849 | void template_cpp_generator::method_impl_printer::print_method_sig( |
1850 | const Method &method, const Signature &sig, bool deleted) |
1851 | { |
1852 | if (deleted) |
1853 | return; |
1854 | |
1855 | os << "\n" ; |
1856 | print_non_empty_template(os, params: instance.kind.params()); |
1857 | print_method_header(method, sig); |
1858 | os << "\n" ; |
1859 | if (method.kind == Method::Kind::constructor) |
1860 | print_constructor_body(method, sig); |
1861 | else if (method.callbacks.size() != 0) |
1862 | print_callback_method_body(method, sig); |
1863 | else |
1864 | print_method_body(method, sig); |
1865 | } |
1866 | |
1867 | /* Print a definition for the "get" method "fd" in class "clazz", |
1868 | * using a name that includes the "get_" prefix, to "os". |
1869 | * |
1870 | * The declarations of these methods are explicitly delete'd |
1871 | * so no definition needs to be printed. |
1872 | */ |
1873 | void template_cpp_generator::method_impl_printer::print_get_method( |
1874 | FunctionDecl *fd) |
1875 | { |
1876 | } |
1877 | |
1878 | /* Print a declaration or definition of the static method "method", |
1879 | * if it has a signature specified by static_methods. |
1880 | */ |
1881 | void template_cpp_generator::class_printer::print_static_method( |
1882 | const Method &method) |
1883 | { |
1884 | print_special_method(method, special_methods: static_methods); |
1885 | } |
1886 | |
1887 | /* Signatures for constructors of multi-expressions |
1888 | * from a space and a list. |
1889 | */ |
1890 | static Signature from_list_set = { .ret: { Domain }, .args: { { Domain }, { Anonymous } } }; |
1891 | static Signature from_list_map = |
1892 | { .ret: { Domain, Range }, .args: { { Domain, Range }, { Domain, Anonymous } } }; |
1893 | |
1894 | /* Signatures for constructors from a string. |
1895 | */ |
1896 | static Signature params_from_str = { .ret: { }, .args: { { Ctx }, { Str } } }; |
1897 | static Signature set_from_str = { .ret: { Domain }, .args: { { Ctx }, { Str } } }; |
1898 | static Signature map_from_str = { .ret: { Domain, Range }, .args: { { Ctx }, { Str } } }; |
1899 | static std::vector<Signature> from_str = |
1900 | { params_from_str, set_from_str, map_from_str }; |
1901 | |
1902 | /* Signature for a constructor from an integer. |
1903 | */ |
1904 | static Signature int_from_si = { .ret: { Anonymous }, .args: { { Ctx }, { Integer } } }; |
1905 | |
1906 | /* Signatures for constructors of lists from the initial number |
1907 | * of elements. |
1908 | */ |
1909 | static Signature alloc_params = { .ret: { }, .args: { { Ctx }, { Integer } } }; |
1910 | static Signature alloc_set = { .ret: { Domain }, .args: { { Ctx }, { Integer } } }; |
1911 | static Signature alloc_map = { .ret: { Domain, Range }, .args: { { Ctx }, { Integer } } }; |
1912 | |
1913 | /* Signatures for constructors and methods named after some other class. |
1914 | * |
1915 | * Two forms of constructors are handled |
1916 | * - conversion from another object |
1917 | * - construction of a multi-expression from a space and a list |
1918 | * |
1919 | * Methods named after some other class also come in two forms |
1920 | * - extraction of information such as the space or a list |
1921 | * - construction of a multi-expression from a space and a list |
1922 | * |
1923 | * In both cases, the first form is a unary operation and |
1924 | * the second has an extra argument with a kind that is equal |
1925 | * to that of the first argument, except that the final tuple is anonymous. |
1926 | */ |
1927 | static std::vector<Signature> constructor_sig = { |
1928 | un_params, |
1929 | un_set, |
1930 | un_map, |
1931 | from_list_set, |
1932 | from_list_map, |
1933 | }; |
1934 | |
1935 | /* Signatures for constructors derived from methods |
1936 | * with the given names that override the default signatures. |
1937 | */ |
1938 | static const std::unordered_map<std::string, std::vector<Signature>> |
1939 | special_constructors { |
1940 | { "alloc" , { alloc_params, alloc_set, alloc_map } }, |
1941 | { "int_from_si" , { int_from_si } }, |
1942 | { "read_from_str" , from_str }, |
1943 | }; |
1944 | |
1945 | /* Print a declaration or definition of the constructor "method". |
1946 | */ |
1947 | void template_cpp_generator::class_printer::print_constructor( |
1948 | const Method &method) |
1949 | { |
1950 | if (special_constructors.count(x: method.name) != 0) { |
1951 | const auto &sigs = special_constructors.at(k: method.name); |
1952 | return print_matching_method(method, signatures: sigs); |
1953 | } |
1954 | print_matching_method(method, signatures: constructor_sig); |
1955 | } |
1956 | |
1957 | /* Does this template class represent an anonymous function? |
1958 | * |
1959 | * If any specialization represents an anonymous function, |
1960 | * then every specialization does, so simply check |
1961 | * the first specialization. |
1962 | */ |
1963 | bool template_class::is_anon() const |
1964 | { |
1965 | return class_tuples[0].is_anon(); |
1966 | } |
1967 | |
1968 | /* Does this template class represent an anonymous value? |
1969 | * |
1970 | * That is, is there only a single specialization that moreover |
1971 | * has a single, anonymous tuple? |
1972 | */ |
1973 | bool template_class::is_anon_set() const |
1974 | { |
1975 | return class_tuples.size() == 1 && class_tuples[0].is_anon_set(); |
1976 | } |
1977 | |
1978 | /* Update the substitution "sub" to map "general" to "specific" |
1979 | * if "specific" is a special case of "general" consistent with "sub", |
1980 | * given that "general" is not a pair and can be assigned "specific". |
1981 | * Return true if successful. |
1982 | * Otherwise, return false. |
1983 | * |
1984 | * Check whether "general" is already assigned something in "sub". |
1985 | * If so, it must be assigned "specific". |
1986 | * Otherwise, there is a conflict. |
1987 | */ |
1988 | static bool update_sub_base(Substitution &sub, const TupleKindPtr &general, |
1989 | const TupleKindPtr &specific) |
1990 | { |
1991 | auto name = general->name; |
1992 | |
1993 | if (sub.count(x: name) != 0 && sub.at(k: name) != specific) |
1994 | return false; |
1995 | sub.emplace(args&: name, args: specific); |
1996 | return true; |
1997 | } |
1998 | |
1999 | /* Update the substitution "sub" to map "general" to "specific" |
2000 | * if "specific" is a special case of "general" consistent with "sub". |
2001 | * Return true if successful. |
2002 | * Otherwise, return false. |
2003 | * |
2004 | * If "general" is a pair and "specific" is not, |
2005 | * then "specific" cannot be a special case. |
2006 | * If both are pairs, then update the substitution based |
2007 | * on both sides. |
2008 | * If "general" is Anonymous, then "specific" must be Anonymous as well. |
2009 | * If "general" is Leaf, then "specific" cannot be a pair. |
2010 | * |
2011 | * Otherwise, assign "specific" to "general", if possible. |
2012 | */ |
2013 | static bool update_sub(Substitution &sub, const TupleKindPtr &general, |
2014 | const TupleKindPtr &specific) |
2015 | { |
2016 | if (general->left() && !specific->left()) |
2017 | return false; |
2018 | if (general->left()) |
2019 | return update_sub(sub, general: general->left(), specific: specific->left()) && |
2020 | update_sub(sub, general: general->right(), specific: specific->right()); |
2021 | if (general == Anonymous && specific != Anonymous) |
2022 | return false; |
2023 | if (general == Leaf && specific->left()) |
2024 | return false; |
2025 | |
2026 | return update_sub_base(sub, general, specific); |
2027 | } |
2028 | |
2029 | /* Check if "specific" is a special case of "general" and, |
2030 | * if so, return true along with a substitution |
2031 | * that maps "general" to "specific". |
2032 | * Otherwise return false. |
2033 | * |
2034 | * This can only happen if the number of tuple kinds is the same. |
2035 | * If so, start with an empty substitution and update it |
2036 | * for each pair of tuple kinds, checking that each update succeeds. |
2037 | */ |
2038 | static std::pair<bool, Substitution> specializer(const Kind &general, |
2039 | const Kind &specific) |
2040 | { |
2041 | Substitution specializer; |
2042 | |
2043 | if (general.size() != specific.size()) |
2044 | return { false, Substitution() }; |
2045 | |
2046 | for (size_t i = 0; i < general.size(); ++i) { |
2047 | auto general_tuple = general[i]; |
2048 | |
2049 | if (!update_sub(sub&: specializer, general: general[i], specific: specific[i])) |
2050 | return { false, Substitution() }; |
2051 | } |
2052 | |
2053 | return { true, specializer }; |
2054 | } |
2055 | |
2056 | /* Is "kind1" equivalent to "kind2"? |
2057 | * That is, is each a special case of the other? |
2058 | */ |
2059 | static bool equivalent(const Kind &kind1, const Kind &kind2) |
2060 | { |
2061 | return specializer(general: kind1, specific: kind2).first && |
2062 | specializer(general: kind2, specific: kind1).first; |
2063 | } |
2064 | |
2065 | /* Add the specialization "kind" to the sequence of specializations, |
2066 | * provided there is no equivalent specialization already in there. |
2067 | */ |
2068 | void template_class::add_specialization(const Kind &kind) |
2069 | { |
2070 | for (const auto &special : class_tuples) |
2071 | if (equivalent(kind1: special, kind2: kind)) |
2072 | return; |
2073 | class_tuples.emplace_back(args: kind); |
2074 | } |
2075 | |
2076 | /* A type printer that prints the plain interface type, |
2077 | * without namespace. |
2078 | */ |
2079 | struct plain_cpp_type_printer : public cpp_type_printer { |
2080 | plain_cpp_type_printer() {} |
2081 | |
2082 | virtual std::string qualified(int arg, const std::string &cpp_type) |
2083 | const override; |
2084 | }; |
2085 | |
2086 | /* Return the qualified form of the given C++ isl type name appearing |
2087 | * in argument position "arg" (-1 for return type). |
2088 | * |
2089 | * For printing the plain type without namespace, no modifications |
2090 | * are required. |
2091 | */ |
2092 | std::string plain_cpp_type_printer::qualified(int arg, |
2093 | const std::string &cpp_type) const |
2094 | { |
2095 | return cpp_type; |
2096 | } |
2097 | |
2098 | /* Return a string representation of the plain type "type". |
2099 | * |
2100 | * For the plain printer, the argument position is irrelevant, |
2101 | * so simply pass in -1. |
2102 | */ |
2103 | static std::string plain_type(QualType type) |
2104 | { |
2105 | return plain_cpp_type_printer().param(-1, type); |
2106 | } |
2107 | |
2108 | /* Return a string representation of the plain return type of "method". |
2109 | */ |
2110 | static std::string plain_return_type(const Method &method) |
2111 | { |
2112 | return plain_type(method.fd->getReturnType()); |
2113 | } |
2114 | |
2115 | /* Return that part of the signature "sig" that should match |
2116 | * the template class specialization for the given method. |
2117 | * |
2118 | * In particular, if the method is a regular member method, |
2119 | * then the instance should match the first argument. |
2120 | * Otherwise, it should match the return kind. |
2121 | */ |
2122 | static const Kind &matching_kind(const Method &method, const Signature &sig) |
2123 | { |
2124 | if (method.kind == Method::Kind::member_method) |
2125 | return sig.args[0]; |
2126 | else |
2127 | return sig.ret; |
2128 | } |
2129 | |
2130 | /* Is it possible for "template_class" to have the given kind? |
2131 | * |
2132 | * If the template class represents an anonymous function, |
2133 | * then so must the given kind. |
2134 | * There should also be specialization with the same number of tuple kinds. |
2135 | */ |
2136 | static bool has_kind(const template_class &template_class, const Kind &kind) |
2137 | { |
2138 | if (template_class.is_anon() && !kind.is_anon()) |
2139 | return false; |
2140 | for (const auto &class_tuple : template_class.class_tuples) |
2141 | if (class_tuple.size() == kind.size()) |
2142 | return true; |
2143 | return false; |
2144 | } |
2145 | |
2146 | /* Is "return_kind" a possible kind for the return type of "method"? |
2147 | * |
2148 | * If the return type is not a template class, |
2149 | * then "return_kind" should not have any template parameters. |
2150 | * Otherwise, "return_kind" should be a valid kind for the template class. |
2151 | */ |
2152 | bool template_cpp_generator::class_printer::is_return_kind( |
2153 | const Method &method, const Kind &return_kind) |
2154 | { |
2155 | const auto &template_classes = generator.template_classes; |
2156 | auto return_type = plain_return_type(method); |
2157 | |
2158 | if (template_classes.count(x: return_type) == 0) |
2159 | return return_kind.params().size() == 0; |
2160 | return has_kind(template_class: template_classes.at(k: return_type), kind: return_kind); |
2161 | } |
2162 | |
2163 | /* Is "kind" a placeholder that can be assigned something else |
2164 | * in a substitution? |
2165 | * |
2166 | * Anonymous can only be mapped to itself. This is taken care of |
2167 | * by assign(). |
2168 | * Leaf can only be assigned a placeholder, but there is no need |
2169 | * to handle this specifically since Leaf can still be assigned |
2170 | * to the placeholder. |
2171 | */ |
2172 | static bool assignable(const TupleKindPtr &kind) |
2173 | { |
2174 | return kind != Anonymous && kind != Leaf; |
2175 | } |
2176 | |
2177 | /* Return a substitution that maps "kind1" to "kind2", if possible. |
2178 | * Otherwise return an empty substitution. |
2179 | * |
2180 | * Check if "kind1" can be assigned anything or |
2181 | * if "kind1" and "kind2" are identical. |
2182 | * The latter case handles mapping Anonymous to itself. |
2183 | */ |
2184 | static Substitution assign(const TupleKindPtr &kind1, const TupleKindPtr &kind2) |
2185 | { |
2186 | Substitution res; |
2187 | |
2188 | if (assignable(kind: kind1) || kind1 == kind2) |
2189 | res.emplace(args: kind1->name, args: kind2); |
2190 | return res; |
2191 | } |
2192 | |
2193 | /* Return a substitution that first applies "first" and then "second". |
2194 | * |
2195 | * The result consists of "second" and of "second" applied to "first". |
2196 | */ |
2197 | static Substitution compose(const Substitution &first, |
2198 | const Substitution &second) |
2199 | { |
2200 | Substitution res = second; |
2201 | |
2202 | for (const auto &kvp : first) |
2203 | res.emplace(args: kvp.first, args: apply(tuple: kvp.second, subs: second)); |
2204 | |
2205 | return res; |
2206 | } |
2207 | |
2208 | static Substitution compute_unifier(const TupleKindPtr &kind1, |
2209 | const TupleKindPtr &kind2); |
2210 | |
2211 | /* Try and extend "unifier" with a unifier for "kind1" and "kind2". |
2212 | * Return the resulting unifier if successful. |
2213 | * Otherwise, return an empty substitution. |
2214 | * |
2215 | * First apply "unifier" to "kind1" and "kind2". |
2216 | * Then compute a unifier for the resulting tuple kinds and |
2217 | * combine it with "unifier". |
2218 | */ |
2219 | static Substitution combine_unifiers(const TupleKindPtr &kind1, |
2220 | const TupleKindPtr &kind2, const Substitution &unifier) |
2221 | { |
2222 | auto k1 = apply(tuple: kind1, subs: unifier); |
2223 | auto k2 = apply(tuple: kind2, subs: unifier); |
2224 | auto u = compute_unifier(kind1: k1, kind2: k2); |
2225 | if (u.size() == 0) |
2226 | return Substitution(); |
2227 | return compose(first: unifier, second: u); |
2228 | } |
2229 | |
2230 | /* Try and compute a unifier of "kind1" and "kind2", |
2231 | * i.e., a substitution that produces the same result when |
2232 | * applied to both "kind1" and "kind2", |
2233 | * for the case where both "kind1" and "kind2" are pairs. |
2234 | * Return this unifier if it was found. |
2235 | * Return an empty substitution if no unifier can be found. |
2236 | * |
2237 | * First compute a unifier for the left parts of the pairs and, |
2238 | * if successful, combine it with a unifier for the right parts. |
2239 | */ |
2240 | static Substitution compute_pair_unifier(const TupleKindPtr &kind1, |
2241 | const TupleKindPtr &kind2) |
2242 | { |
2243 | auto unifier_left = compute_unifier(kind1: kind1->left(), kind2: kind2->left()); |
2244 | if (unifier_left.size() == 0) |
2245 | return Substitution(); |
2246 | return combine_unifiers(kind1: kind1->right(), kind2: kind2->right(), unifier: unifier_left); |
2247 | } |
2248 | |
2249 | /* Try and compute a unifier of "kind1" and "kind2", |
2250 | * i.e., a substitution that produces the same result when |
2251 | * applied to both "kind1" and "kind2". |
2252 | * Return this unifier if it was found. |
2253 | * Return an empty substitution if no unifier can be found. |
2254 | * |
2255 | * If one of the tuple kinds is a pair then assign it |
2256 | * to the other tuple kind, if possible. |
2257 | * If neither is a pair, then try and assign one to the other. |
2258 | * Otherwise, let compute_pair_unifier compute a unifier. |
2259 | * |
2260 | * Note that an assignment is added to the unifier even |
2261 | * if "kind1" and "kind2" are identical. |
2262 | * This ensures that a successful substitution is never empty. |
2263 | */ |
2264 | static Substitution compute_unifier(const TupleKindPtr &kind1, |
2265 | const TupleKindPtr &kind2) |
2266 | { |
2267 | if (kind1->left() && !kind2->left()) |
2268 | return assign(kind1: kind2, kind2: kind1); |
2269 | if (!kind1->left() && kind2->left()) |
2270 | return assign(kind1, kind2); |
2271 | if (!kind1->left() && !kind2->left()) { |
2272 | if (assignable(kind: kind1)) |
2273 | return assign(kind1, kind2); |
2274 | else |
2275 | return assign(kind1: kind2, kind2: kind1); |
2276 | } |
2277 | |
2278 | return compute_pair_unifier(kind1, kind2); |
2279 | } |
2280 | |
2281 | /* Try and compute a unifier of "kind1" and "kind2", |
2282 | * i.e., a substitution that produces the same result when |
2283 | * applied to both "kind1" and "kind2". |
2284 | * Return this unifier if it was found. |
2285 | * Return an empty substitution if no unifier can be found. |
2286 | * |
2287 | * Start with an empty substitution and compute a unifier for |
2288 | * each pair of tuple kinds, combining the results. |
2289 | * If no combined unifier can be found or |
2290 | * if the numbers of tuple kinds are different, then return |
2291 | * an empty substitution. |
2292 | * This assumes that the number of tuples is greater than zero, |
2293 | * as otherwise an empty substitution would be returned as well. |
2294 | */ |
2295 | static Substitution compute_unifier(const Kind &kind1, const Kind &kind2) |
2296 | { |
2297 | Substitution unifier; |
2298 | |
2299 | if (kind1.size() != kind2.size()) |
2300 | return Substitution(); |
2301 | |
2302 | for (size_t i = 0; i < kind1.size(); ++i) |
2303 | unifier = combine_unifiers(kind1: kind1[i], kind2: kind2[i], unifier); |
2304 | |
2305 | return unifier; |
2306 | } |
2307 | |
2308 | /* Try and construct a Kind that is a specialization of both "general" and |
2309 | * "specific", where "specific" is known _not_ to be a specialization |
2310 | * of "general" and not to contain any Leaf. |
2311 | * |
2312 | * First check whether "general" is a specialization of "specific". |
2313 | * If so, simply return "general". |
2314 | * Otherwise, rename the placeholders in the two kinds apart and |
2315 | * try and compute a unifier. |
2316 | * If this succeeds, then return the result of applying the unifier. |
2317 | */ |
2318 | static std::pair<bool, Kind> unify(const Kind &general, const Kind &specific) |
2319 | { |
2320 | if (specializer(general: specific, specific: general).first) { |
2321 | return { true, general }; |
2322 | } else { |
2323 | auto rename = param_renamer(params: specific.params(), prefix: "T" ); |
2324 | auto renamed = specific.apply(subs: rename); |
2325 | auto unifier = compute_unifier(kind1: general, kind2: renamed); |
2326 | |
2327 | if (unifier.size() == 0) |
2328 | return { false, { } }; |
2329 | |
2330 | return { true, general.apply(subs: unifier) }; |
2331 | } |
2332 | } |
2333 | |
2334 | /* Try and add a template class specialization corresponding to "kind". |
2335 | * The new specialization needs to be a specialization of both |
2336 | * the current specialization and "kind". |
2337 | * |
2338 | * The current template class specialization is known not to be a special case |
2339 | * of "kind". |
2340 | * |
2341 | * Try and unify the two kinds and, if this succeeds, add the result |
2342 | * to this list of template class specializations. |
2343 | */ |
2344 | void template_cpp_generator::class_printer::add_specialization( |
2345 | const Kind &kind) |
2346 | { |
2347 | auto maybe_unified = unify(general: kind, specific: instance.kind); |
2348 | |
2349 | if (!maybe_unified.first) |
2350 | return; |
2351 | instance.template_class.add_specialization(kind: maybe_unified.second); |
2352 | } |
2353 | |
2354 | /* Does the type of the parameter at position "i" of "method" necessarily |
2355 | * have a final Anonymous tuple? |
2356 | * |
2357 | * If the parameter is not of an isl type or if no specializations |
2358 | * have been defined for the type, then it can be considered anonymous. |
2359 | * Otherwise, if any specialization represents an anonymous function, |
2360 | * then every specialization does, so simply check |
2361 | * the first specialization. |
2362 | */ |
2363 | static bool param_is_anon(const Method &method, int i) |
2364 | { |
2365 | ParmVarDecl *param = method.get_param(i); |
2366 | QualType type = param->getOriginalType(); |
2367 | |
2368 | if (cpp_generator::is_isl_type(type)) { |
2369 | const auto &name = type->getPointeeType().getAsString(); |
2370 | const auto &cpp = cpp_generator::type2cpp(name); |
2371 | const auto &tuples = lookup_class_tuples(cpp); |
2372 | |
2373 | if (tuples.empty()) |
2374 | return true; |
2375 | return tuples[0].is_anon(); |
2376 | } |
2377 | |
2378 | return true; |
2379 | } |
2380 | |
2381 | /* Replace the final tuple of "arg_kind" by Anonymous in "sig" and |
2382 | * return the update signature, |
2383 | * unless this would affect the class instance "instance_kind". |
2384 | * |
2385 | * If the original "instance_kind" is a special case |
2386 | * of the result of the substitution, then "instance_kind" |
2387 | * is not affected and the substitution can be applied |
2388 | * to the entire signature. |
2389 | */ |
2390 | static Signature specialize_anonymous_arg(const Signature &sig, |
2391 | const Kind &arg_kind, const Kind &instance_kind) |
2392 | { |
2393 | const auto &subs = compute_unifier(kind1: arg_kind.back(), kind2: Anonymous); |
2394 | const auto &specialized_instance = instance_kind.apply(subs); |
2395 | |
2396 | if (!specializer(general: specialized_instance, specific: instance_kind).first) |
2397 | return sig; |
2398 | |
2399 | return sig.apply(subs); |
2400 | } |
2401 | |
2402 | /* If any of the arguments of "method" is of a type that necessarily |
2403 | * has a final Anonymous tuple, but the corresponding entry |
2404 | * in the signature "sig" is not Anonymous, then replace |
2405 | * that entry by Anonymous and return the updated signature, |
2406 | * unless this would affect the class instance "instance_kind". |
2407 | */ |
2408 | static Signature specialize_anonymous_args(const Signature &sig, |
2409 | const Method &method, const Kind &instance_kind) |
2410 | { |
2411 | auto specialized_sig = sig; |
2412 | |
2413 | method.on_cpp_arg_list(on_arg: [&] (int i, int arg) { |
2414 | const auto &arg_kind = sig.args[arg]; |
2415 | |
2416 | if (arg_kind.is_anon()) |
2417 | return; |
2418 | if (!param_is_anon(method, i)) |
2419 | return; |
2420 | specialized_sig = specialize_anonymous_arg(sig: specialized_sig, |
2421 | arg_kind, instance_kind); |
2422 | }); |
2423 | |
2424 | return specialized_sig; |
2425 | } |
2426 | |
2427 | /* Print a declaration or definition of the method "method" |
2428 | * if the template class specialization matches "match_arg". |
2429 | * Return true if so. |
2430 | * "sig" is the complete signature, of which "match_arg" refers |
2431 | * to the first argument or the return type. |
2432 | * |
2433 | * Since "sig" may have parameters with the same names as |
2434 | * those in instance.kind, rename them apart first. |
2435 | * |
2436 | * If the template class specialization is a special case of |
2437 | * (the renamed) "match_arg" |
2438 | * then apply the specializer to the complete (renamed) signature, |
2439 | * specialize any anonymous arguments, |
2440 | * check that the return kind is allowed and, if so, |
2441 | * print the declaration or definition using the specialized signature. |
2442 | * |
2443 | * If the template class specialization is not a special case of "match_arg" |
2444 | * then add a further specialization to the list of specializations |
2445 | * of the template class. |
2446 | */ |
2447 | bool template_cpp_generator::class_printer::print_matching_method( |
2448 | const Method &method, const Signature &sig, const Kind &match_arg) |
2449 | { |
2450 | auto rename = shared_param_renamer(sig, kind: instance.kind); |
2451 | auto renamed_arg = match_arg.apply(subs: rename); |
2452 | auto maybe_specializer = specializer(general: renamed_arg, specific: instance.kind); |
2453 | if (maybe_specializer.first) { |
2454 | const auto &specializer = maybe_specializer.second; |
2455 | auto specialized_sig = sig.apply(subs: rename).apply(subs: specializer); |
2456 | specialized_sig = specialize_anonymous_args(sig: specialized_sig, |
2457 | method, instance_kind: instance.kind); |
2458 | if (!is_return_kind(method, return_kind: specialized_sig.ret)) |
2459 | return false; |
2460 | |
2461 | print_method_sig(method, sig: specialized_sig, deleted: false); |
2462 | } else { |
2463 | add_specialization(kind: match_arg); |
2464 | } |
2465 | return maybe_specializer.first; |
2466 | } |
2467 | |
2468 | /* Is the first argument of "method" of type "isl_ctx *"? |
2469 | */ |
2470 | static bool first_arg_is_ctx(const Method &method) |
2471 | { |
2472 | return generator::first_arg_is_isl_ctx(method.fd); |
2473 | } |
2474 | |
2475 | /* Is the first signature argument set to { Ctx }? |
2476 | */ |
2477 | static bool first_kind_is_ctx(const Signature &sig) |
2478 | { |
2479 | return sig.args[0].size() > 0 && sig.args[0][0] == Ctx; |
2480 | } |
2481 | |
2482 | /* Print a declaration or definition of the member method "method" |
2483 | * if it matches the signature "sig". |
2484 | * Return true if so. |
2485 | * |
2486 | * First determine the part of the signature that needs to match |
2487 | * the template class specialization and |
2488 | * check that it has the same number of template arguments. |
2489 | * Also check that the number of arguments of the signature |
2490 | * matches that of the method. |
2491 | * If there is at least one argument, then check that the first method argument |
2492 | * is an isl_ctx if and only if the first signature argument is Ctx. |
2493 | * |
2494 | * If these tests succeed, proceed with the actual matching. |
2495 | */ |
2496 | bool template_cpp_generator::class_printer::print_matching_method( |
2497 | const Method &method, const Signature &sig) |
2498 | { |
2499 | auto match_arg = matching_kind(method, sig); |
2500 | int n_args = sig.args.size(); |
2501 | |
2502 | if (match_arg.size() != instance.kind.size()) |
2503 | return false; |
2504 | if (n_args != total_params(method)) |
2505 | return false; |
2506 | if (n_args > 0 && first_arg_is_ctx(method) != first_kind_is_ctx(sig)) |
2507 | return false; |
2508 | |
2509 | return print_matching_method(method, sig, match_arg); |
2510 | } |
2511 | |
2512 | /* Print a declaration or definition of the member method "method" |
2513 | * for each matching signature in "signatures". |
2514 | * |
2515 | * If there is no matching signature in "signatures", |
2516 | * then explicitly delete the method (using a signature based on |
2517 | * the specialization) so that it is not inherited from the base class. |
2518 | */ |
2519 | void template_cpp_generator::class_printer::print_matching_method( |
2520 | const Method &method, const std::vector<Signature> &signatures) |
2521 | { |
2522 | auto any = false; |
2523 | |
2524 | for (const auto &sig : signatures) |
2525 | if (print_matching_method(method, sig)) |
2526 | any = true; |
2527 | |
2528 | if (!any) |
2529 | print_method_sig(method, sig: instance_sig(method, instance), deleted: true); |
2530 | } |
2531 | |
2532 | /* Signatures for "at" methods applied to a multi-expression, |
2533 | * which make the final tuple anonymous. |
2534 | */ |
2535 | static Signature select_set = { .ret: { Anonymous }, .args: { { Domain }, { Integer } } }; |
2536 | static Signature select_map = |
2537 | { .ret: { Domain, Anonymous }, .args: { { Domain, Range }, { Integer } } }; |
2538 | static std::vector<Signature> at_select = { select_set, select_map }; |
2539 | |
2540 | /* Signatures for other "at" methods applied to a list, |
2541 | * which do not modify the tuple kind. |
2542 | */ |
2543 | static Signature bin_set_int = { .ret: { Domain }, .args: { { Domain }, { Integer } } }; |
2544 | static Signature bin_map_int = |
2545 | { .ret: { Domain, Range }, .args: { { Domain, Range }, { Integer } } }; |
2546 | static std::vector<Signature> at_keep = { bin_set_int, bin_map_int }; |
2547 | |
2548 | /* Print a declaration or definition of the "at" member method "method". |
2549 | * |
2550 | * There are two types of methods called "at". |
2551 | * One type extracts an element from a multi-expression and |
2552 | * the other extracts an element from a list. |
2553 | * |
2554 | * In the first case, the return type is an anonymous function |
2555 | * while the object type is not. In this case, the return kind |
2556 | * should have a final Anonymous tuple. |
2557 | * Otherwise, the return kind should be the same as the object kind. |
2558 | */ |
2559 | void template_cpp_generator::class_printer::print_at_method( |
2560 | const Method &method) |
2561 | { |
2562 | auto anon = instance.template_class.is_anon(); |
2563 | auto return_type = plain_return_type(method); |
2564 | auto return_class = generator.template_classes.at(k: return_type); |
2565 | |
2566 | if (!anon && return_class.is_anon()) |
2567 | return print_matching_method(method, signatures: at_select); |
2568 | else |
2569 | return print_matching_method(method, signatures: at_keep); |
2570 | } |
2571 | |
2572 | /* Does the string "s" contain "sub" as a substring? |
2573 | */ |
2574 | static bool contains(const std::string &s, const std::string &sub) |
2575 | { |
2576 | return s.find(str: sub) != std::string::npos; |
2577 | } |
2578 | |
2579 | /* Print a declaration or definition of the member method "method", |
2580 | * if it has a special signature in "special_methods". |
2581 | * Return true if this is the case. |
2582 | * |
2583 | * Check if any special signatures are specified for this method and |
2584 | * if the class name matches any of those with special signatures. |
2585 | * If so, pick the one with the best match, i.e., the first match |
2586 | * since the largest keys appear first. |
2587 | */ |
2588 | bool template_cpp_generator::class_printer::print_special_method( |
2589 | const Method &method, const infix_map_map &special_methods) |
2590 | { |
2591 | if (special_methods.count(x: method.name) == 0) |
2592 | return false; |
2593 | |
2594 | for (const auto &kvp : special_methods.at(k: method.name)) { |
2595 | if (!contains(s: instance.template_class.class_name, sub: kvp.first)) |
2596 | continue; |
2597 | print_matching_method(method, signatures: kvp.second); |
2598 | return true; |
2599 | } |
2600 | |
2601 | return false; |
2602 | } |
2603 | |
2604 | /* Print a declaration or definition of the member method "method", |
2605 | * if it has a special signature specified by special_member_methods. |
2606 | * Return true if this is the case. |
2607 | */ |
2608 | bool template_cpp_generator::class_printer::print_special_member_method( |
2609 | const Method &method) |
2610 | { |
2611 | return print_special_method(method, special_methods: special_member_methods); |
2612 | } |
2613 | |
2614 | /* Print a declaration or definition of the member method "method", |
2615 | * if it is named after a template class. Return true if this is the case. |
2616 | */ |
2617 | bool template_cpp_generator::class_printer::print_type_named_member_method( |
2618 | const Method &method) |
2619 | { |
2620 | if (generator.template_classes.count(x: method.name) == 0) |
2621 | return false; |
2622 | |
2623 | print_matching_method(method, signatures: constructor_sig); |
2624 | |
2625 | return true; |
2626 | } |
2627 | |
2628 | /* Print a declaration or definition of the member method "method" |
2629 | * using a signature associated to method name "name", if there is any. |
2630 | * Return true if this is the case. |
2631 | */ |
2632 | bool template_cpp_generator::class_printer::print_member_method_with_name( |
2633 | const Method &method, const std::string &name) |
2634 | { |
2635 | if (member_methods.count(x: name) == 0) |
2636 | return false; |
2637 | |
2638 | print_matching_method(method, signatures: member_methods.at(k: name)); |
2639 | return true; |
2640 | } |
2641 | |
2642 | /* If "sub" appears inside "str", then remove the first occurrence and |
2643 | * return the result. Otherwise, simply return "str". |
2644 | */ |
2645 | static std::string drop_occurrence(const std::string &str, |
2646 | const std::string &sub) |
2647 | { |
2648 | auto res = str; |
2649 | auto pos = str.find(str: sub); |
2650 | |
2651 | if (pos != std::string::npos) |
2652 | res.erase(pos: pos, n: sub.length()); |
2653 | |
2654 | return res; |
2655 | } |
2656 | |
2657 | /* If "sub" appears in "str" next to an underscore, then remove the combination. |
2658 | * Otherwise, simply return "str". |
2659 | */ |
2660 | static std::string drop_underscore_occurrence(const std::string &str, |
2661 | const std::string &sub) |
2662 | { |
2663 | auto res = drop_occurrence(str, sub: sub + "_" ); |
2664 | if (res != str) |
2665 | return res; |
2666 | return drop_occurrence(str: res, sub: std::string("_" ) + sub); |
2667 | } |
2668 | |
2669 | /* Return the name of "method", with the name of the return type, |
2670 | * along with an underscore, removed, if this combination appears in the name. |
2671 | * Otherwise, simply return the name. |
2672 | */ |
2673 | const std::string name_without_return(const Method &method) |
2674 | { |
2675 | auto return_infix = plain_return_type(method); |
2676 | return drop_underscore_occurrence(str: method.name, sub: return_infix); |
2677 | } |
2678 | |
2679 | /* If this method has a callback, then remove the type |
2680 | * of the first argument of the first callback from the name of the method. |
2681 | * Otherwise, simply return the name of the method. |
2682 | */ |
2683 | const std::string callback_name(const Method &method) |
2684 | { |
2685 | if (method.callbacks.size() == 0) |
2686 | return method.name; |
2687 | |
2688 | auto type = method.callbacks.at(0)->getType(); |
2689 | auto callback = cpp_generator::extract_prototype(type); |
2690 | auto arg_type = plain_type(callback->getArgType(0)); |
2691 | return generator::drop_suffix(s: method.name, suffix: "_" + arg_type); |
2692 | } |
2693 | |
2694 | /* Print a declaration or definition of the member method "method". |
2695 | * |
2696 | * If the method is called "at", then it requires special treatment. |
2697 | * Otherwise, check if the signature is overridden for this class or |
2698 | * if the method is named after some other type. |
2699 | * Otherwise look for an appropriate signature using different variations |
2700 | * of the method name. First try the method name itself, |
2701 | * then the method name with the return type removed and |
2702 | * finally the method name with the callback argument type removed. |
2703 | */ |
2704 | void template_cpp_generator::class_printer::print_member_method( |
2705 | const Method &method) |
2706 | { |
2707 | if (method.name == "at" ) |
2708 | return print_at_method(method); |
2709 | if (print_special_member_method(method)) |
2710 | return; |
2711 | if (print_type_named_member_method(method)) |
2712 | return; |
2713 | if (print_member_method_with_name(method, name: method.name)) |
2714 | return; |
2715 | if (print_member_method_with_name(method, name: name_without_return(method))) |
2716 | return; |
2717 | if (print_member_method_with_name(method, name: callback_name(method))) |
2718 | return; |
2719 | } |
2720 | |
2721 | /* Print a declaration or definition of "method" based on its type. |
2722 | */ |
2723 | void template_cpp_generator::class_printer::print_any_method( |
2724 | const Method &method) |
2725 | { |
2726 | switch (method.kind) { |
2727 | case Method::Kind::static_method: |
2728 | print_static_method(method); |
2729 | break; |
2730 | case Method::Kind::constructor: |
2731 | print_constructor(method); |
2732 | break; |
2733 | case Method::Kind::member_method: |
2734 | print_member_method(method); |
2735 | break; |
2736 | } |
2737 | } |
2738 | |
2739 | /* Print a declaration or definition of "method". |
2740 | * |
2741 | * Mark the method as not requiring copies of the arguments. |
2742 | */ |
2743 | void template_cpp_generator::class_printer::print_method(const Method &method) |
2744 | { |
2745 | print_any_method(NoCopyMethod(method)); |
2746 | } |
2747 | |
2748 | /* Print a declaration or definition of "method". |
2749 | * |
2750 | * Note that a ConversionMethod is already marked |
2751 | * as not requiring copies of the arguments. |
2752 | */ |
2753 | void template_cpp_generator::class_printer::print_method( |
2754 | const ConversionMethod &method) |
2755 | { |
2756 | print_any_method(method); |
2757 | } |
2758 | |
2759 | /* Helper class for printing the declarations for |
2760 | * template class specializations. |
2761 | */ |
2762 | struct template_cpp_generator::class_decl_printer : |
2763 | public specialization_printer |
2764 | { |
2765 | class_decl_printer(std::ostream &os, |
2766 | template_cpp_generator &generator) : |
2767 | specialization_printer(os, generator) {} |
2768 | |
2769 | void print_arg_subclass_constructor(const specialization &instance, |
2770 | const std::vector<std::string> ¶ms) const; |
2771 | void print_super_constructor(const specialization &instance) const; |
2772 | virtual void print_class(const specialization &instance) const override; |
2773 | }; |
2774 | |
2775 | /* Print the declaration and definition of a constructor |
2776 | * for the template class specialization "instance" taking |
2777 | * an instance with more specialized template arguments, |
2778 | * where "params" holds the template parameters of "instance". |
2779 | * It is assumed that there is at least one template parameter as otherwise |
2780 | * there are no template arguments to be specialized and |
2781 | * no constructor needs to be printed. |
2782 | * |
2783 | * In particular, the constructor takes an object of the same instance where |
2784 | * for each template parameter, the corresponding template argument |
2785 | * of the input object is a subclass of the template argument |
2786 | * of the constructed object. |
2787 | * |
2788 | * Pick fresh names for all template parameters and |
2789 | * add a constructor with these fresh names as extra template parameters and |
2790 | * a constraint requiring that each of them is a subclass |
2791 | * of the corresponding class template parameter. |
2792 | * The plain C++ interface object of the constructed object is initialized with |
2793 | * the plain C++ interface object of the constructor argument. |
2794 | */ |
2795 | void template_cpp_generator::class_decl_printer::print_arg_subclass_constructor( |
2796 | const specialization &instance, |
2797 | const std::vector<std::string> ¶ms) const |
2798 | { |
2799 | const auto &class_name = instance.class_name(); |
2800 | auto rename = param_renamer(params, prefix: "Arg" ); |
2801 | auto derived = instance.kind.apply(subs: rename); |
2802 | |
2803 | os << " template " ; |
2804 | os << "<" ; |
2805 | print_pure_template_args(os, args: derived.params()); |
2806 | os << ",\n" ; |
2807 | os << " typename std::enable_if<\n" ; |
2808 | for (size_t i = 0; i < params.size(); ++i) { |
2809 | if (i != 0) |
2810 | os << " &&\n" ; |
2811 | os << " std::is_base_of<" |
2812 | << params[i] << ", " |
2813 | << rename.at(k: params[i])->params()[0] << ">{}" ; |
2814 | } |
2815 | os << ",\n" ; |
2816 | os << " bool>::type = true>" ; |
2817 | os << "\n" ; |
2818 | os << " " << class_name << "(const " ; |
2819 | print_bare_template_type(os, type: class_name, kind: derived); |
2820 | os << " &obj) : " << instance.base_name() << "(obj) {}\n" ; |
2821 | } |
2822 | |
2823 | /* Print the declaration and definition of a constructor |
2824 | * for the template class specialization "instance" taking |
2825 | * an instance of the base class. |
2826 | * |
2827 | * If the instance kind is that of an anonymous set |
2828 | * (i.e., it has a single tuple that is set to Anonymous), |
2829 | * then allow the constructor to be called externally. |
2830 | * This is mostly useful for being able to use isl::val and |
2831 | * isl::typed::val<Anonymous> interchangeably and similarly for isl::id. |
2832 | * |
2833 | * If the instance is of any other kind, then make this constructor private |
2834 | * to avoid objects of the plain interface being converted automatically. |
2835 | * Also make sure that it does not apply to any type derived |
2836 | * from the base class. In particular, this makes sure it does |
2837 | * not apply to any other specializations of this template class as |
2838 | * otherwise any conflict in specializations would simply point |
2839 | * to the private constructor. |
2840 | * |
2841 | * A factory method is added to be able to perform the conversion explicitly, |
2842 | * with an explicit specification of the template arguments. |
2843 | */ |
2844 | void template_cpp_generator::class_decl_printer::print_super_constructor( |
2845 | const specialization &instance) const |
2846 | { |
2847 | bool hide = !instance.kind.is_anon_set(); |
2848 | const auto &base_name = instance.base_name(); |
2849 | const auto &arg_name = hide ? "base" : base_name; |
2850 | |
2851 | if (hide) { |
2852 | os << " private:\n" ; |
2853 | os << " template <typename base,\n" ; |
2854 | os << " typename std::enable_if<\n" ; |
2855 | os << " std::is_same<base, " << base_name |
2856 | << ">{}, bool>::type = true>\n" ; |
2857 | } |
2858 | os << " " << instance.class_name() |
2859 | << "(const " << arg_name << " &obj) : " |
2860 | << base_name << "(obj) {}\n" ; |
2861 | if (hide) |
2862 | os << " public:\n" ; |
2863 | os << " static " << instance.class_name() << " from" |
2864 | << "(const " << base_name << " &obj) {\n" ; |
2865 | os << " return " << instance.class_name() << "(obj);\n" ; |
2866 | os << " }\n" ; |
2867 | } |
2868 | |
2869 | /* Print a "declaration" for the given template class specialization. |
2870 | * In particular, print the class definition and the method declarations. |
2871 | * |
2872 | * The template parameters are the distinct variable names |
2873 | * in the instance kind. |
2874 | * |
2875 | * Each instance of the template class derives from the corresponding |
2876 | * plain C++ interface class. |
2877 | * |
2878 | * All (other) template classes are made friends of this template class |
2879 | * to allow them to call the private constructor taking an object |
2880 | * of the plain interface. |
2881 | * |
2882 | * Besides the constructors and methods that forward |
2883 | * to the corresponding methods in the plain C++ interface class, |
2884 | * some extra constructors are defined. |
2885 | * The default zero-argument constructor is useful for declaring |
2886 | * a variable that only gets assigned a value at a later stage. |
2887 | * The constructor taking an instance with more specialized |
2888 | * template arguments is useful for lifting the class hierarchy |
2889 | * of the template arguments to the template class. |
2890 | * The constructor taking an instance of the base class |
2891 | * is useful for (explicitly) constructing a template type |
2892 | * from a plain type. |
2893 | */ |
2894 | void template_cpp_generator::class_decl_printer::print_class( |
2895 | const specialization &instance) const |
2896 | { |
2897 | const auto &class_name = instance.class_name(); |
2898 | auto params = instance.kind.params(); |
2899 | |
2900 | os << "\n" ; |
2901 | |
2902 | print_template(os, params); |
2903 | |
2904 | os << "struct " ; |
2905 | print_bare_template_type(os, type: class_name, kind: instance.kind); |
2906 | os << " : public " << instance.base_name() << " {\n" ; |
2907 | |
2908 | generator.print_friends(os); |
2909 | os << "\n" ; |
2910 | |
2911 | os << " " << class_name << "() = default;\n" ; |
2912 | if (params.size() != 0) |
2913 | print_arg_subclass_constructor(instance, params); |
2914 | print_super_constructor(instance); |
2915 | method_decl_printer(instance, *this).print_all_methods(); |
2916 | |
2917 | os << "};\n" ; |
2918 | } |
2919 | |
2920 | /* Helper class for printing the definitions of template class specializations. |
2921 | */ |
2922 | struct template_cpp_generator::class_impl_printer : |
2923 | public specialization_printer |
2924 | { |
2925 | class_impl_printer(std::ostream &os, |
2926 | template_cpp_generator &generator) : |
2927 | specialization_printer(os, generator) {} |
2928 | |
2929 | virtual void print_class(const specialization &instance) const override; |
2930 | }; |
2931 | |
2932 | /* Print a definition for the given template class specialization. |
2933 | * |
2934 | * In particular, print definitions |
2935 | * for the constructors and methods that forward |
2936 | * to the corresponding methods in the plain C++ interface class. |
2937 | * The extra constructors declared in the class definition |
2938 | * are defined inline. |
2939 | */ |
2940 | void template_cpp_generator::class_impl_printer::print_class( |
2941 | const specialization &instance) const |
2942 | { |
2943 | method_impl_printer(instance, *this).print_all_methods(); |
2944 | } |
2945 | |
2946 | /* Generate a templated cpp interface |
2947 | * based on the extracted types and functions. |
2948 | * |
2949 | * First print forward declarations for all template classes, |
2950 | * then the declarations of the classes, and at the end all |
2951 | * method implementations. |
2952 | */ |
2953 | void template_cpp_generator::generate() |
2954 | { |
2955 | ostream &os = std::cout; |
2956 | |
2957 | os << "\n" ; |
2958 | |
2959 | print_forward_declarations(os); |
2960 | class_decl_printer(os, *this).print_classes(); |
2961 | class_impl_printer(os, *this).print_classes(); |
2962 | } |
2963 | |