1 /*
2  * Copyright 2016, 2017 Tobias Grosser. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *    1. Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *
11  *    2. Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY TOBIAS GROSSER ''AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOBIAS GROSSER OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * The views and conclusions contained in the software and documentation
29  * are those of the authors and should not be interpreted as
30  * representing official policies, either expressed or implied, of
31  * Tobias Grosser.
32  */
33 
34 #include <cstdarg>
35 #include <cstdio>
36 #include <iostream>
37 #include <map>
38 #include <memory>
39 #include <sstream>
40 #include <string>
41 #include <vector>
42 
43 #include "plain_cpp.h"
44 #include "isl_config.h"
45 
46 /* Print string formatted according to "fmt" to ostream "os".
47  *
48  * This osprintf method allows us to use printf style formatting constructs when
49  * writing to an ostream.
50  */
osprintf(ostream & os,const char * format,va_list arguments)51 static void osprintf(ostream &os, const char *format, va_list arguments)
52 {
53 	va_list copy;
54 	char *string_pointer;
55 	size_t size;
56 
57 	va_copy(copy, arguments);
58 	size = vsnprintf(NULL, 0, format, copy);
59 	string_pointer = new char[size + 1];
60 	va_end(copy);
61 	vsnprintf(string_pointer, size + 1, format, arguments);
62 	os << string_pointer;
63 	delete[] string_pointer;
64 }
65 
66 /* Print string formatted according to "fmt" to ostream "os".
67  *
68  * This osprintf method allows us to use printf style formatting constructs when
69  * writing to an ostream.
70  */
osprintf(ostream & os,const char * format,...)71 static void osprintf(ostream &os, const char *format, ...)
72 {
73 	va_list arguments;
74 
75 	va_start(arguments, format);
76 	osprintf(os, format, arguments);
77 	va_end(arguments);
78 }
79 
80 /* Print string formatted according to "fmt" to ostream "os"
81  * with the given indentation.
82  *
83  * This osprintf method allows us to use printf style formatting constructs when
84  * writing to an ostream.
85  */
osprintf(ostream & os,int indent,const char * format,...)86 static void osprintf(ostream &os, int indent, const char *format, ...)
87 {
88 	va_list arguments;
89 
90 	osprintf(os, "%*s", indent, " ");
91 	va_start(arguments, format);
92 	osprintf(os, format, arguments);
93 	va_end(arguments);
94 }
95 
96 /* Convert "l" to a string.
97  */
to_string(long l)98 static std::string to_string(long l)
99 {
100 	std::ostringstream strm;
101 	strm << l;
102 	return strm.str();
103 }
104 
105 /* Construct a generator for plain C++ bindings.
106  *
107  * "checked" is set if C++ bindings should be generated
108  * that rely on the user to check for error conditions.
109  */
plain_cpp_generator(SourceManager & SM,set<RecordDecl * > & exported_types,set<FunctionDecl * > exported_functions,set<FunctionDecl * > functions,bool checked)110 plain_cpp_generator::plain_cpp_generator(SourceManager &SM,
111 	set<RecordDecl *> &exported_types,
112 	set<FunctionDecl *> exported_functions, set<FunctionDecl *> functions,
113 	bool checked) :
114 		cpp_generator(SM, exported_types, exported_functions,
115 			functions),
116 		checked(checked)
117 {
118 }
119 
120 /* Generate a cpp interface based on the extracted types and functions.
121  *
122  * Print first a set of forward declarations for all isl wrapper
123  * classes, then the declarations of the classes, and at the end all
124  * implementations.
125  *
126  * If checked C++ bindings are being generated,
127  * then wrap them in a namespace to avoid conflicts
128  * with the default C++ bindings (with automatic checks using exceptions).
129  */
generate()130 void plain_cpp_generator::generate()
131 {
132 	ostream &os = cout;
133 
134 	osprintf(os, "\n");
135 	osprintf(os, "namespace isl {\n\n");
136 	if (checked)
137 		osprintf(os, "namespace checked {\n\n");
138 
139 	print_forward_declarations(os);
140 	osprintf(os, "\n");
141 	print_declarations(os);
142 	osprintf(os, "\n");
143 	print_implementations(os);
144 
145 	if (checked)
146 		osprintf(os, "} // namespace checked\n");
147 	osprintf(os, "} // namespace isl\n");
148 }
149 
150 /* Print forward declarations for all classes to "os".
151 */
print_forward_declarations(ostream & os)152 void plain_cpp_generator::print_forward_declarations(ostream &os)
153 {
154 	map<string, isl_class>::iterator ci;
155 
156 	osprintf(os, "// forward declarations\n");
157 
158 	for (ci = classes.begin(); ci != classes.end(); ++ci)
159 		print_class_forward_decl(os, ci->second);
160 }
161 
162 /* Print all declarations to "os".
163  */
print_declarations(ostream & os)164 void plain_cpp_generator::print_declarations(ostream &os)
165 {
166 	map<string, isl_class>::iterator ci;
167 	bool first = true;
168 
169 	for (ci = classes.begin(); ci != classes.end(); ++ci) {
170 		if (first)
171 			first = false;
172 		else
173 			osprintf(os, "\n");
174 
175 		print_class(os, ci->second);
176 	}
177 }
178 
179 /* Print all implementations to "os".
180  */
print_implementations(ostream & os)181 void plain_cpp_generator::print_implementations(ostream &os)
182 {
183 	map<string, isl_class>::iterator ci;
184 	bool first = true;
185 
186 	for (ci = classes.begin(); ci != classes.end(); ++ci) {
187 		if (first)
188 			first = false;
189 		else
190 			osprintf(os, "\n");
191 
192 		print_class_impl(os, ci->second);
193 	}
194 }
195 
196 /* If the printed class is a subclass that is based on a type function,
197  * then introduce a "type" field that holds the value of the type
198  * corresponding to the subclass and make the fields of the class
199  * accessible to the "isa" and "as" methods of the (immediate) superclass.
200  * In particular, "isa" needs access to the type field itself,
201  * while "as" needs access to the private constructor.
202  * In case of the "isa" method, all instances are made friends
203  * to avoid access right confusion.
204  */
print_subclass_type()205 void plain_cpp_generator::decl_printer::print_subclass_type()
206 {
207 	std::string super;
208 	const char *cppname = cppstring.c_str();
209 	const char *supername;
210 
211 	if (!clazz.is_type_subclass())
212 		return;
213 
214 	super = type2cpp(clazz.superclass_name);
215 	supername = super.c_str();
216 	osprintf(os, "  template <class T>\n");
217 	osprintf(os, "  friend %s %s::isa() const;\n",
218 		generator.isl_bool2cpp().c_str(), supername);
219 	osprintf(os, "  friend %s %s::as<%s>() const;\n",
220 		cppname, supername, cppname);
221 	osprintf(os, "  static const auto type = %s;\n",
222 		clazz.subclass_name.c_str());
223 }
224 
225 /* Print declarations for class "clazz" to "os".
226  *
227  * If "clazz" is a subclass based on a type function,
228  * then it is made to inherit from the (immediate) superclass and
229  * a "type" attribute is added for use in the "as" and "isa"
230  * methods of the superclass.
231  *
232  * Conversely, if "clazz" is a superclass with a type function,
233  * then declare those "as" and "isa" methods.
234  *
235  * The pointer to the isl object is only added for classes that
236  * are not subclasses, since subclasses refer to the same isl object.
237  */
print_class(ostream & os,const isl_class & clazz)238 void plain_cpp_generator::print_class(ostream &os, const isl_class &clazz)
239 {
240 	decl_printer printer(os, clazz, *this);
241 	const char *name = clazz.name.c_str();
242 	const char *cppname = printer.cppstring.c_str();
243 
244 	osprintf(os, "// declarations for isl::%s\n", cppname);
245 
246 	printer.print_class_factory();
247 	osprintf(os, "\n");
248 	osprintf(os, "class %s ", cppname);
249 	if (clazz.is_type_subclass())
250 		osprintf(os, ": public %s ",
251 			type2cpp(clazz.superclass_name).c_str());
252 	osprintf(os, "{\n");
253 	printer.print_subclass_type();
254 	printer.print_class_factory("  friend ");
255 	osprintf(os, "\n");
256 	osprintf(os, "protected:\n");
257 	if (!clazz.is_type_subclass()) {
258 		osprintf(os, "  %s *ptr = nullptr;\n", name);
259 		osprintf(os, "\n");
260 	}
261 	printer.print_protected_constructors();
262 	osprintf(os, "\n");
263 	osprintf(os, "public:\n");
264 	printer.print_public_constructors();
265 	printer.print_constructors();
266 	printer.print_copy_assignment();
267 	printer.print_destructor();
268 	printer.print_ptr();
269 	printer.print_downcast();
270 	printer.print_ctx();
271 	osprintf(os, "\n");
272 	printer.print_persistent_callbacks();
273 	printer.print_methods();
274 	printer.print_set_enums();
275 
276 	osprintf(os, "};\n");
277 }
278 
279 /* Print forward declaration of class "clazz" to "os".
280  */
print_class_forward_decl(ostream & os,const isl_class & clazz)281 void plain_cpp_generator::print_class_forward_decl(ostream &os,
282 	const isl_class &clazz)
283 {
284 	std::string cppstring = type2cpp(clazz);
285 	const char *cppname = cppstring.c_str();
286 
287 	osprintf(os, "class %s;\n", cppname);
288 }
289 
290 /* Print global factory functions.
291  *
292  * Each class has two global factory functions:
293  *
294  * 	set manage(__isl_take isl_set *ptr);
295  * 	set manage_copy(__isl_keep isl_set *ptr);
296  *
297  * A user can construct isl C++ objects from a raw pointer and indicate whether
298  * they intend to take the ownership of the object or not through these global
299  * factory functions. This ensures isl object creation is very explicit and
300  * pointers are not converted by accident. Thanks to overloading, manage() and
301  * manage_copy() can be called on any isl raw pointer and the corresponding
302  * object is automatically created, without the user having to choose the right
303  * isl object type.
304  *
305  * For a subclass based on a type function, no factory functions
306  * are introduced because they share the C object type with
307  * the superclass.
308  */
print_class_factory(const std::string & prefix)309 void plain_cpp_generator::decl_printer::print_class_factory(
310 	const std::string &prefix)
311 {
312 	const char *name = clazz.name.c_str();
313 	const char *cppname = cppstring.c_str();
314 
315 	if (clazz.is_type_subclass())
316 		return;
317 
318 	os << prefix;
319 	osprintf(os, "inline %s manage(__isl_take %s *ptr);\n", cppname, name);
320 	os << prefix;
321 	osprintf(os, "inline %s manage_copy(__isl_keep %s *ptr);\n",
322 		cppname, name);
323 }
324 
325 /* Print declarations of protected constructors.
326  *
327  * Each class has currently one protected constructor:
328  *
329  * 	1) Constructor from a plain isl_* C pointer
330  *
331  * Example:
332  *
333  * 	set(__isl_take isl_set *ptr);
334  *
335  * The raw pointer constructor is kept protected. Object creation is only
336  * possible through manage() or manage_copy().
337  */
print_protected_constructors()338 void plain_cpp_generator::decl_printer::print_protected_constructors()
339 {
340 	const char *name = clazz.name.c_str();
341 	const char *cppname = cppstring.c_str();
342 
343 	osprintf(os, "  inline explicit %s(__isl_take %s *ptr);\n", cppname,
344 		 name);
345 }
346 
347 /* Print declarations of public constructors.
348  *
349  * Each class currently has two public constructors:
350  *
351  * 	1) A default constructor
352  * 	2) A copy constructor
353  *
354  * Example:
355  *
356  *	set();
357  *	set(const set &set);
358  */
print_public_constructors()359 void plain_cpp_generator::decl_printer::print_public_constructors()
360 {
361 	const char *cppname = cppstring.c_str();
362 	osprintf(os, "  inline /* implicit */ %s();\n", cppname);
363 
364 	osprintf(os, "  inline /* implicit */ %s(const %s &obj);\n",
365 		 cppname, cppname);
366 }
367 
368 /* Print declarations for "method".
369  */
print_method(const ConversionMethod & method)370 void plain_cpp_generator::decl_printer::print_method(
371 	const ConversionMethod &method)
372 {
373 	print_full_method_header(method);
374 }
375 
376 /* Print declarations for "method".
377  */
print_method(const Method & method)378 void plain_cpp_generator::decl_printer::print_method(const Method &method)
379 {
380 	print_full_method_header(method);
381 }
382 
383 /* Print declarations of copy assignment operator.
384  *
385  * Each class has one assignment operator.
386  *
387  * 	isl:set &set::operator=(set obj)
388  *
389  */
print_copy_assignment()390 void plain_cpp_generator::decl_printer::print_copy_assignment()
391 {
392 	const char *cppname = cppstring.c_str();
393 
394 	osprintf(os, "  inline %s &operator=(%s obj);\n", cppname, cppname);
395 }
396 
397 /* Print declaration of destructor.
398  *
399  * No explicit destructor is needed for type based subclasses.
400  */
print_destructor()401 void plain_cpp_generator::decl_printer::print_destructor()
402 {
403 	const char *cppname = cppstring.c_str();
404 
405 	if (clazz.is_type_subclass())
406 		return;
407 
408 	osprintf(os, "  inline ~%s();\n", cppname);
409 }
410 
411 /* Print declaration of pointer functions.
412  * Since type based subclasses share the pointer with their superclass,
413  * they can also reuse these functions from the superclass.
414  *
415  * To obtain a raw pointer three functions are provided:
416  *
417  * 	1) __isl_give isl_set *copy()
418  *
419  * 	  Returns a pointer to a _copy_ of the internal object
420  *
421  * 	2) __isl_keep isl_set *get()
422  *
423  * 	  Returns a pointer to the internal object
424  *
425  * 	3) __isl_give isl_set *release()
426  *
427  * 	  Returns a pointer to the internal object and resets the
428  * 	  internal pointer to nullptr.
429  *
430  * We also provide functionality to explicitly check if a pointer is
431  * currently managed by this object.
432  *
433  * 	4) bool is_null()
434  *
435  * 	  Check if the current object is a null pointer.
436  *
437  * The functions get() and release() model the value_ptr proposed in
438  * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3339.pdf.
439  * The copy() function is an extension to allow the user to explicitly
440  * copy the underlying object.
441  *
442  * Also generate a declaration to delete copy() for r-values, for
443  * r-values release() should be used to avoid unnecessary copies.
444  */
print_ptr()445 void plain_cpp_generator::decl_printer::print_ptr()
446 {
447 	const char *name = clazz.name.c_str();
448 
449 	if (clazz.is_type_subclass())
450 		return;
451 
452 	osprintf(os, "  inline __isl_give %s *copy() const &;\n", name);
453 	osprintf(os, "  inline __isl_give %s *copy() && = delete;\n", name);
454 	osprintf(os, "  inline __isl_keep %s *get() const;\n", name);
455 	osprintf(os, "  inline __isl_give %s *release();\n", name);
456 	osprintf(os, "  inline bool is_null() const;\n");
457 }
458 
459 /* Print a template declaration with given indentation
460  * for the "isa_type" method that ensures it is only enabled
461  * when called with a template argument
462  * that represents a type that is equal to that
463  * of the return type of the type function of "super".
464  * In particular, "isa_type" gets called from "isa"
465  * with as template argument the type of the "type" field
466  * of the subclass.
467  * The check ensures that this subclass is in fact a direct subclass
468  * of "super".
469  */
print_isa_type_template(int indent,const isl_class & super)470 void plain_cpp_generator::decl_printer::print_isa_type_template(int indent,
471 	const isl_class &super)
472 {
473 	osprintf(os, indent,
474 		"template <typename T,\n");
475 	osprintf(os, indent,
476 		"        typename = typename std::enable_if<std::is_same<\n");
477 	osprintf(os, indent,
478 		"                const decltype(%s(NULL)),\n",
479 		super.fn_type->getNameAsString().c_str());
480 	osprintf(os, indent,
481 		"                const T>::value>::type>\n");
482 }
483 
484 /* Print declarations for the "as" and "isa" methods, if the printed class
485  * is a superclass with a type function.
486  *
487  * "isa" checks whether an object is of a given subclass type.
488  * "isa_type" does the same, but gets passed the value of the type field
489  * of the subclass as a function argument and the type of this field
490  * as a template argument.
491  * "as" tries to cast an object to a given subclass type, returning
492  * an invalid object if the object is not of the given type.
493  */
print_downcast()494 void plain_cpp_generator::decl_printer::print_downcast()
495 {
496 	if (!clazz.fn_type)
497 		return;
498 
499 	osprintf(os, "private:\n");
500 	print_isa_type_template(2, clazz);
501 	osprintf(os, "  inline %s isa_type(T subtype) const;\n",
502 		generator.isl_bool2cpp().c_str());
503 	osprintf(os, "public:\n");
504 	osprintf(os, "  template <class T> inline %s isa() const;\n",
505 		generator.isl_bool2cpp().c_str());
506 	osprintf(os, "  template <class T> inline T as() const;\n");
507 }
508 
509 /* Print the declaration of the ctx method.
510  */
print_ctx()511 void plain_cpp_generator::decl_printer::print_ctx()
512 {
513 	std::string ns = generator.isl_namespace();
514 
515 	osprintf(os, "  inline %sctx ctx() const;\n", ns.c_str());
516 }
517 
518 /* Add a space to the return type "type" if needed,
519  * i.e., if it is not the type of a pointer.
520  */
add_space_to_return_type(const string & type)521 static string add_space_to_return_type(const string &type)
522 {
523 	if (type[type.size() - 1] == '*')
524 		return type;
525 	return type + " ";
526 }
527 
528 /* Print the prototype of the static inline method that is used
529  * as the C callback set by "method".
530  */
print_persistent_callback_prototype(FunctionDecl * method)531 void plain_cpp_generator::plain_printer::print_persistent_callback_prototype(
532 	FunctionDecl *method)
533 {
534 	string callback_name, rettype, c_args;
535 	ParmVarDecl *param = persistent_callback_arg(method);
536 	const FunctionProtoType *callback;
537 	QualType ptype;
538 	string classname;
539 
540 	ptype = param->getType();
541 	callback = extract_prototype(ptype);
542 
543 	rettype = callback->getReturnType().getAsString();
544 	rettype = add_space_to_return_type(rettype);
545 	callback_name = clazz.persistent_callback_name(method);
546 	c_args = generator.generate_callback_args(ptype, false);
547 
548 	if (!declarations)
549 		classname = type2cpp(clazz) + "::";
550 
551 	osprintf(os, "%s%s%s(%s)",
552 		 rettype.c_str(), classname.c_str(),
553 		 callback_name.c_str(), c_args.c_str());
554 }
555 
556 /* Print the prototype of the method for setting the callback function
557  * set by "method".
558  */
559 void
print_persistent_callback_setter_prototype(FunctionDecl * method)560 plain_cpp_generator::plain_printer::print_persistent_callback_setter_prototype(
561 	FunctionDecl *method)
562 {
563 	string classname, callback_name, cpptype;
564 	ParmVarDecl *param = persistent_callback_arg(method);
565 
566 	if (!declarations)
567 		classname = type2cpp(clazz) + "::";
568 
569 	cpptype = generator.param2cpp(param->getOriginalType());
570 	callback_name = clazz.persistent_callback_name(method);
571 	osprintf(os, "void %sset_%s_data(const %s &%s)",
572 		classname.c_str(), callback_name.c_str(), cpptype.c_str(),
573 		param->getName().str().c_str());
574 }
575 
576 /* Given a method "method" for setting a persistent callback,
577  * print the fields that are needed for marshalling the callback.
578  *
579  * In particular, print
580  * - the declaration of a data structure for storing the C++ callback function
581  * - a shared pointer to such a data structure
582  * - the declaration of a static inline method
583  *   for use as the C callback function
584  * - the declaration of a private method for setting the callback function
585  */
print_persistent_callback_data(FunctionDecl * method)586 void plain_cpp_generator::decl_printer::print_persistent_callback_data(
587 	FunctionDecl *method)
588 {
589 	string callback_name;
590 	ParmVarDecl *param = generator.persistent_callback_arg(method);
591 
592 	callback_name = clazz.persistent_callback_name(method);
593 	print_callback_data_decl(param, callback_name);
594 	osprintf(os, ";\n");
595 	osprintf(os, "  std::shared_ptr<%s_data> %s_data;\n",
596 		callback_name.c_str(), callback_name.c_str());
597 	osprintf(os, "  static inline ");
598 	print_persistent_callback_prototype(method);
599 	osprintf(os, ";\n");
600 	osprintf(os, "  inline ");
601 	print_persistent_callback_setter_prototype(method);
602 	osprintf(os, ";\n");
603 }
604 
605 /* Print declarations needed for the persistent callbacks of the class.
606  *
607  * In particular, if there are any persistent callbacks, then
608  * print a private method for copying callback data from
609  * one object to another,
610  * private data for keeping track of the persistent callbacks and
611  * public methods for setting the persistent callbacks.
612  */
print_persistent_callbacks()613 void plain_cpp_generator::decl_printer::print_persistent_callbacks()
614 {
615 	const char *cppname = cppstring.c_str();
616 
617 	if (!clazz.has_persistent_callbacks())
618 		return;
619 
620 	osprintf(os, "private:\n");
621 	osprintf(os, "  inline %s &copy_callbacks(const %s &obj);\n",
622 		cppname, cppname);
623 	for (const auto &callback : clazz.persistent_callbacks)
624 		print_persistent_callback_data(callback);
625 
626 	osprintf(os, "public:\n");
627 	for (const auto &callback : clazz.persistent_callbacks)
628 		print_method(Method(clazz, callback));
629 }
630 
631 /* Print a declaration for the "get" method "fd",
632  * using a name that includes the "get_" prefix.
633  */
print_get_method(FunctionDecl * fd)634 void plain_cpp_generator::decl_printer::print_get_method(FunctionDecl *fd)
635 {
636 	string base = clazz.base_method_name(fd);
637 
638 	print_method(Method(clazz, fd, base));
639 }
640 
641 /* Print implementations for class "clazz" to "os".
642  */
print_class_impl(ostream & os,const isl_class & clazz)643 void plain_cpp_generator::print_class_impl(ostream &os, const isl_class &clazz)
644 {
645 	impl_printer printer(os, clazz, *this);
646 	const char *cppname = printer.cppstring.c_str();
647 
648 	osprintf(os, "// implementations for isl::%s", cppname);
649 
650 	printer.print_class_factory();
651 	printer.print_public_constructors();
652 	printer.print_protected_constructors();
653 	printer.print_constructors();
654 	printer.print_copy_assignment();
655 	printer.print_destructor();
656 	printer.print_ptr();
657 	printer.print_downcast();
658 	printer.print_ctx();
659 	printer.print_persistent_callbacks();
660 	printer.print_methods();
661 	printer.print_set_enums();
662 	printer.print_stream_insertion();
663 }
664 
665 /* Print code for throwing an exception corresponding to the last error
666  * that occurred on "saved_ctx".
667  * This assumes that a valid isl::ctx is available in the "saved_ctx" variable,
668  * e.g., through a prior call to print_save_ctx.
669  */
print_throw_last_error(ostream & os)670 static void print_throw_last_error(ostream &os)
671 {
672 	osprintf(os, "    exception::throw_last_error(saved_ctx);\n");
673 }
674 
675 /* Print code with the given indentation
676  * for throwing an exception_invalid with the given message.
677  */
print_throw_invalid(ostream & os,int indent,const char * msg)678 static void print_throw_invalid(ostream &os, int indent, const char *msg)
679 {
680 	osprintf(os, indent,
681 		"exception::throw_invalid(\"%s\", __FILE__, __LINE__);\n", msg);
682 }
683 
684 /* Print code for throwing an exception on NULL input.
685  */
print_throw_NULL_input(ostream & os)686 static void print_throw_NULL_input(ostream &os)
687 {
688 	print_throw_invalid(os, 4, "NULL input");
689 }
690 
691 /* Print code with the given indentation
692  * for acting on an invalid error with message "msg".
693  * In particular, throw an exception_invalid.
694  * In the checked C++ bindings, isl_die is called instead with the code
695  * in "checked_code".
696  */
print_invalid(ostream & os,int indent,const char * msg,const char * checked_code)697 void plain_cpp_generator::print_invalid(ostream &os, int indent,
698 	const char *msg, const char *checked_code)
699 {
700 	if (checked)
701 		osprintf(os, indent,
702 			"isl_die(ctx().get(), isl_error_invalid, "
703 			"\"%s\", %s);\n", msg, checked_code);
704 	else
705 		print_throw_invalid(os, indent, msg);
706 }
707 
708 /* Print an operator for inserting objects of the class
709  * into an output stream.
710  *
711  * Unless checked C++ bindings are being generated,
712  * the operator requires its argument to be non-NULL.
713  * An exception is thrown if anything went wrong during the printing.
714  * During this printing, isl is made not to print any error message
715  * because the error message is included in the exception.
716  *
717  * If checked C++ bindings are being generated and anything went wrong,
718  * then record this failure in the output stream.
719  */
print_stream_insertion()720 void plain_cpp_generator::impl_printer::print_stream_insertion()
721 {
722 	const char *name = clazz.name.c_str();
723 	const char *cppname = cppstring.c_str();
724 
725 	if (!clazz.fn_to_str)
726 		return;
727 
728 	osprintf(os, "\n");
729 	osprintf(os, "inline std::ostream &operator<<(std::ostream &os, ");
730 	osprintf(os, "const %s &obj)\n", cppname);
731 	osprintf(os, "{\n");
732 	print_check_ptr_start("obj.get()");
733 	osprintf(os, "  char *str = %s_to_str(obj.get());\n", name);
734 	print_check_ptr_end("str");
735 	if (generator.checked) {
736 		osprintf(os, "  if (!str) {\n");
737 		osprintf(os, "    os.setstate(std::ios_base::badbit);\n");
738 		osprintf(os, "    return os;\n");
739 		osprintf(os, "  }\n");
740 	}
741 	osprintf(os, "  os << str;\n");
742 	osprintf(os, "  free(str);\n");
743 	osprintf(os, "  return os;\n");
744 	osprintf(os, "}\n");
745 }
746 
747 /* Print code that checks that "ptr" is not NULL at input.
748  *
749  * Omit the check if checked C++ bindings are being generated.
750  */
print_check_ptr(const char * ptr)751 void plain_cpp_generator::impl_printer::print_check_ptr(const char *ptr)
752 {
753 	if (generator.checked)
754 		return;
755 
756 	osprintf(os, "  if (!%s)\n", ptr);
757 	print_throw_NULL_input(os);
758 }
759 
760 /* Print code that checks that "ptr" is not NULL at input and
761  * that saves a copy of the isl_ctx of "ptr" for a later check.
762  *
763  * Omit the check if checked C++ bindings are being generated.
764  */
print_check_ptr_start(const char * ptr)765 void plain_cpp_generator::impl_printer::print_check_ptr_start(const char *ptr)
766 {
767 	if (generator.checked)
768 		return;
769 
770 	print_check_ptr(ptr);
771 	osprintf(os, "  auto saved_ctx = %s_get_ctx(%s);\n",
772 		clazz.name.c_str(), ptr);
773 	print_on_error_continue();
774 }
775 
776 /* Print code that checks that "ptr" is not NULL at the end.
777  * A copy of the isl_ctx is expected to have been saved by
778  * code generated by print_check_ptr_start.
779  *
780  * Omit the check if checked C++ bindings are being generated.
781  */
print_check_ptr_end(const char * ptr)782 void plain_cpp_generator::impl_printer::print_check_ptr_end(const char *ptr)
783 {
784 	if (generator.checked)
785 		return;
786 
787 	osprintf(os, "  if (!%s)\n", ptr);
788 	print_throw_last_error(os);
789 }
790 
791 /* Print implementation of global factory functions.
792  *
793  * Each class has two global factory functions:
794  *
795  * 	set manage(__isl_take isl_set *ptr);
796  * 	set manage_copy(__isl_keep isl_set *ptr);
797  *
798  * Unless checked C++ bindings are being generated,
799  * both functions require the argument to be non-NULL.
800  * An exception is thrown if anything went wrong during the copying
801  * in manage_copy.
802  * During the copying, isl is made not to print any error message
803  * because the error message is included in the exception.
804  *
805  * For a subclass based on a type function, no factory functions
806  * are introduced because they share the C object type with
807  * the superclass.
808  */
print_class_factory()809 void plain_cpp_generator::impl_printer::print_class_factory()
810 {
811 	const char *name = clazz.name.c_str();
812 	const char *cppname = cppstring.c_str();
813 
814 	if (clazz.is_type_subclass())
815 		return;
816 
817 	osprintf(os, "\n");
818 	osprintf(os, "%s manage(__isl_take %s *ptr) {\n", cppname, name);
819 	print_check_ptr("ptr");
820 	osprintf(os, "  return %s(ptr);\n", cppname);
821 	osprintf(os, "}\n");
822 
823 	osprintf(os, "%s manage_copy(__isl_keep %s *ptr) {\n", cppname,
824 		name);
825 	print_check_ptr_start("ptr");
826 	osprintf(os, "  ptr = %s_copy(ptr);\n", name);
827 	print_check_ptr_end("ptr");
828 	osprintf(os, "  return %s(ptr);\n", cppname);
829 	osprintf(os, "}\n");
830 }
831 
832 /* Print implementations of protected constructors.
833  *
834  * The pointer to the isl object is either initialized directly or
835  * through the (immediate) superclass.
836  */
print_protected_constructors()837 void plain_cpp_generator::impl_printer::print_protected_constructors()
838 {
839 	const char *name = clazz.name.c_str();
840 	const char *cppname = cppstring.c_str();
841 	bool subclass = clazz.is_type_subclass();
842 
843 	osprintf(os, "\n");
844 	osprintf(os, "%s::%s(__isl_take %s *ptr)\n", cppname, cppname, name);
845 	if (subclass)
846 		osprintf(os, "    : %s(ptr) {}\n",
847 			type2cpp(clazz.superclass_name).c_str());
848 	else
849 		osprintf(os, "    : ptr(ptr) {}\n");
850 }
851 
852 /* Print implementations of public constructors.
853  *
854  * The pointer to the isl object is either initialized directly or
855  * through the (immediate) superclass.
856  *
857  * If the class has any persistent callbacks, then copy them
858  * from the original object in the copy constructor.
859  * If the class is a subclass, then the persistent callbacks
860  * are assumed to be copied by the copy constructor of the superclass.
861  *
862  * Throw an exception from the copy constructor if anything went wrong
863  * during the copying or if the input is NULL, if any copying is performed.
864  * During the copying, isl is made not to print any error message
865  * because the error message is included in the exception.
866  * No exceptions are thrown if checked C++ bindings
867  * are being generated,
868  */
print_public_constructors()869 void plain_cpp_generator::impl_printer::print_public_constructors()
870 {
871 	std::string super;
872 	const char *cppname = cppstring.c_str();
873 	bool subclass = clazz.is_type_subclass();
874 
875 	osprintf(os, "\n");
876 	if (subclass)
877 		super = type2cpp(clazz.superclass_name);
878 	osprintf(os, "%s::%s()\n", cppname, cppname);
879 	if (subclass)
880 		osprintf(os, "    : %s() {}\n\n", super.c_str());
881 	else
882 		osprintf(os, "    : ptr(nullptr) {}\n\n");
883 	osprintf(os, "%s::%s(const %s &obj)\n", cppname, cppname, cppname);
884 	if (subclass)
885 		osprintf(os, "    : %s(obj)\n", super.c_str());
886 	else
887 		osprintf(os, "    : ptr(nullptr)\n");
888 	osprintf(os, "{\n");
889 	if (!subclass) {
890 		print_check_ptr_start("obj.ptr");
891 		osprintf(os, "  ptr = obj.copy();\n");
892 		if (clazz.has_persistent_callbacks())
893 			osprintf(os, "  copy_callbacks(obj);\n");
894 		print_check_ptr_end("ptr");
895 	}
896 	osprintf(os, "}\n");
897 }
898 
899 /* Print definition for "method",
900  * without any automatic type conversions.
901  *
902  * This method distinguishes three kinds of methods: member methods, static
903  * methods, and constructors.
904  *
905  * Member methods and static methods return a newly managed
906  * isl C++ object.
907  *
908  * Constructors create a new object from a given set of input parameters. They
909  * do not return a value, but instead update the pointer stored inside the
910  * newly created object.
911  *
912  * Unless checked C++ bindings are being generated,
913  * the inputs of the method are first checked for being valid isl objects and
914  * a copy of the associated isl::ctx is saved (if needed).
915  * If any failure occurs, either during the check for the inputs or
916  * during the isl function call, an exception is thrown.
917  * During the function call, isl is made not to print any error message
918  * because the error message is included in the exception.
919  */
print_method(const Method & method)920 void plain_cpp_generator::impl_printer::print_method(const Method &method)
921 {
922 	string methodname = method.fd->getName().str();
923 	int num_params = method.c_num_params();
924 
925 	osprintf(os, "\n");
926 	print_full_method_header(method);
927 	osprintf(os, "{\n");
928 	print_argument_validity_check(method);
929 	print_save_ctx(method);
930 	print_on_error_continue();
931 
932 	if (method.callback)
933 		print_callback_local(method.callback);
934 
935 	osprintf(os, "  auto res = %s", methodname.c_str());
936 
937 	Method::print_arg_list(os, 0, num_params, [&] (int i) {
938 		method.print_param_use(os, i);
939 	});
940 	osprintf(os, ";\n");
941 
942 	print_exceptional_execution_check(method);
943 	if (method.kind == Method::Kind::constructor) {
944 		osprintf(os, "  ptr = res;\n");
945 	} else {
946 		print_method_return(method);
947 	}
948 
949 	osprintf(os, "}\n");
950 }
951 
952 /* Convert argument of type "src" to "dst", with a name specified by "dst".
953  *
954  * If "src" is the same as "dst", then no argument conversion is needed.
955  *
956  * Otherwise, call the conversion function
957  * with as arguments the isl_ctx of the object and the argument name,
958  * or simply the argument name if the source type is an isl type.
959  * This means this isl_ctx should be available.
960  */
print_arg_conversion(ParmVarDecl * dst,ParmVarDecl * src)961 void plain_cpp_generator::impl_printer::print_arg_conversion(ParmVarDecl *dst,
962 	ParmVarDecl *src)
963 {
964 	std::string name = dst->getName().str();
965 	QualType type = dst->getOriginalType();
966 	string cpptype = generator.param2cpp(type);
967 
968 	if (dst == src)
969 		os << name;
970 	else if (is_isl_type(src->getOriginalType()))
971 		os << cpptype << "(" << name << ")";
972 	else
973 		os << cpptype << "(ctx(), " << name << ")";
974 }
975 
976 /* Print a definition for "method",
977  * where "this" or at least one of the argument types needs to be converted.
978  *
979  * "method" is assumed to be a member method.
980  *
981  * The generated method performs the required conversion(s) and
982  * calls the method generated without conversions.
983  *
984  * Perform a conversion from the argument in the method declaration
985  * (as specified by Method::get_param) to the argument of the C function,
986  * if needed.
987  * Such a conversion may require the isl_ctx to be available.
988  * In order to be able to use this isl_ctx, the current object needs
989  * to valid.  The validity of other arguments is checked
990  * by the called method.
991  */
print_method(const ConversionMethod & method)992 void plain_cpp_generator::impl_printer::print_method(
993 	const ConversionMethod &method)
994 {
995 	if (method.kind != Method::Kind::member_method)
996 		die("Automatic conversion currently only supported "
997 		    "for object methods");
998 
999 	osprintf(os, "\n");
1000 	print_full_method_header(method);
1001 	osprintf(os, "{\n");
1002 	print_check_ptr("ptr");
1003 	osprintf(os, "  return ");
1004 	method.print_call(os, generator.isl_namespace());
1005 	method.print_cpp_arg_list(os, [&] (int i) {
1006 		ParmVarDecl *param = method.fd->getParamDecl(i);
1007 
1008 		print_arg_conversion(param, method.get_param(i));
1009 	});
1010 	osprintf(os, ";\n");
1011 	osprintf(os, "}\n");
1012 }
1013 
1014 /* Print implementation of copy assignment operator.
1015  *
1016  * If the class has any persistent callbacks, then copy them
1017  * from the original object.
1018  */
print_copy_assignment()1019 void plain_cpp_generator::impl_printer::print_copy_assignment()
1020 {
1021 	const char *name = clazz.name.c_str();
1022 	const char *cppname = cppstring.c_str();
1023 
1024 	osprintf(os, "\n");
1025 	osprintf(os, "%s &%s::operator=(%s obj) {\n", cppname,
1026 		 cppname, cppname);
1027 	osprintf(os, "  std::swap(this->ptr, obj.ptr);\n", name);
1028 	if (clazz.has_persistent_callbacks())
1029 		osprintf(os, "  copy_callbacks(obj);\n");
1030 	osprintf(os, "  return *this;\n");
1031 	osprintf(os, "}\n");
1032 }
1033 
1034 /* Print implementation of destructor.
1035  *
1036  * No explicit destructor is needed for type based subclasses.
1037  */
print_destructor()1038 void plain_cpp_generator::impl_printer::print_destructor()
1039 {
1040 	const char *name = clazz.name.c_str();
1041 	const char *cppname = cppstring.c_str();
1042 
1043 	if (clazz.is_type_subclass())
1044 		return;
1045 
1046 	osprintf(os, "\n");
1047 	osprintf(os, "%s::~%s() {\n", cppname, cppname);
1048 	osprintf(os, "  if (ptr)\n");
1049 	osprintf(os, "    %s_free(ptr);\n", name);
1050 	osprintf(os, "}\n");
1051 }
1052 
1053 /* Print a check that the persistent callback corresponding to "fd"
1054  * is not set, throwing an exception (or printing an error message
1055  * and returning nullptr) if it is set.
1056  */
print_check_no_persistent_callback(ostream & os,const isl_class & clazz,FunctionDecl * fd)1057 void plain_cpp_generator::print_check_no_persistent_callback(ostream &os,
1058 	const isl_class &clazz, FunctionDecl *fd)
1059 {
1060 	string callback_name = clazz.persistent_callback_name(fd);
1061 
1062 	osprintf(os, "  if (%s_data)\n", callback_name.c_str());
1063 	print_invalid(os, 4, "cannot release object with persistent callbacks",
1064 			    "return nullptr");
1065 }
1066 
1067 /* Print implementation of ptr() functions.
1068  * Since type based subclasses share the pointer with their superclass,
1069  * they can also reuse these functions from the superclass.
1070  *
1071  * If an object has persistent callbacks set, then the underlying
1072  * C object pointer cannot be released because it references data
1073  * in the C++ object.
1074  */
print_ptr()1075 void plain_cpp_generator::impl_printer::print_ptr()
1076 {
1077 	const char *name = clazz.name.c_str();
1078 	const char *cppname = cppstring.c_str();
1079 	set<FunctionDecl *>::const_iterator in;
1080 	const set<FunctionDecl *> &callbacks = clazz.persistent_callbacks;
1081 
1082 	if (clazz.is_type_subclass())
1083 		return;
1084 
1085 	osprintf(os, "\n");
1086 	osprintf(os, "__isl_give %s *%s::copy() const & {\n", name, cppname);
1087 	osprintf(os, "  return %s_copy(ptr);\n", name);
1088 	osprintf(os, "}\n\n");
1089 	osprintf(os, "__isl_keep %s *%s::get() const {\n", name, cppname);
1090 	osprintf(os, "  return ptr;\n");
1091 	osprintf(os, "}\n\n");
1092 	osprintf(os, "__isl_give %s *%s::release() {\n", name, cppname);
1093 	for (in = callbacks.begin(); in != callbacks.end(); ++in)
1094 		generator.print_check_no_persistent_callback(os, clazz, *in);
1095 	osprintf(os, "  %s *tmp = ptr;\n", name);
1096 	osprintf(os, "  ptr = nullptr;\n");
1097 	osprintf(os, "  return tmp;\n");
1098 	osprintf(os, "}\n\n");
1099 	osprintf(os, "bool %s::is_null() const {\n", cppname);
1100 	osprintf(os, "  return ptr == nullptr;\n");
1101 	osprintf(os, "}\n");
1102 }
1103 
1104 /* Print implementations for the "as" and "isa" methods, if the printed class
1105  * is a superclass with a type function.
1106  *
1107  * "isa" checks whether an object is of a given subclass type.
1108  * "isa_type" does the same, but gets passed the value of the type field
1109  * of the subclass as a function argument and the type of this field
1110  * as a template argument.
1111  * "as" casts an object to a given subclass type, erroring out
1112  * if the object is not of the given type.
1113  *
1114  * If the input is an invalid object, then these methods raise
1115  * an exception.
1116  * If checked bindings are being generated,
1117  * then an invalid boolean or object is returned instead.
1118  */
print_downcast()1119 void plain_cpp_generator::impl_printer::print_downcast()
1120 {
1121 	const char *cppname = cppstring.c_str();
1122 
1123 	if (!clazz.fn_type)
1124 		return;
1125 
1126 	osprintf(os, "\n");
1127 	osprintf(os, "template <typename T, typename>\n");
1128 	osprintf(os, "%s %s::isa_type(T subtype) const\n",
1129 		generator.isl_bool2cpp().c_str(), cppname);
1130 	osprintf(os, "{\n");
1131 	osprintf(os, "  if (is_null())\n");
1132 	if (generator.checked)
1133 		osprintf(os, "    return boolean();\n");
1134 	else
1135 		print_throw_NULL_input(os);
1136 	osprintf(os, "  return %s(get()) == subtype;\n",
1137 		clazz.fn_type->getNameAsString().c_str());
1138 	osprintf(os, "}\n");
1139 
1140 	osprintf(os, "template <class T>\n");
1141 	osprintf(os, "%s %s::isa() const\n",
1142 		generator.isl_bool2cpp().c_str(), cppname);
1143 	osprintf(os, "{\n");
1144 	osprintf(os, "  return isa_type<decltype(T::type)>(T::type);\n");
1145 	osprintf(os, "}\n");
1146 
1147 	osprintf(os, "template <class T>\n");
1148 	osprintf(os, "T %s::as() const\n", cppname);
1149 	osprintf(os, "{\n");
1150 	if (generator.checked)
1151 		osprintf(os, " if (isa<T>().is_false())\n");
1152 	else
1153 		osprintf(os, " if (!isa<T>())\n");
1154 	generator.print_invalid(os, 4, "not an object of the requested subtype",
1155 		    "return T()");
1156 	osprintf(os, "  return T(copy());\n");
1157 	osprintf(os, "}\n");
1158 }
1159 
1160 /* Print the implementation of the ctx method.
1161  */
print_ctx()1162 void plain_cpp_generator::impl_printer::print_ctx()
1163 {
1164 	const char *name = clazz.name.c_str();
1165 	const char *cppname = cppstring.c_str();
1166 	std::string ns = generator.isl_namespace();
1167 
1168 	osprintf(os, "\n");
1169 	osprintf(os, "%sctx %s::ctx() const {\n", ns.c_str(), cppname);
1170 	osprintf(os, "  return %sctx(%s_get_ctx(ptr));\n", ns.c_str(), name);
1171 	osprintf(os, "}\n");
1172 }
1173 
1174 /* Print the implementations of the methods needed for the persistent callbacks
1175  * of the class.
1176  */
print_persistent_callbacks()1177 void plain_cpp_generator::impl_printer::print_persistent_callbacks()
1178 {
1179 	const char *cppname = cppstring.c_str();
1180 	string classname = type2cpp(clazz);
1181 
1182 	if (!clazz.has_persistent_callbacks())
1183 		return;
1184 
1185 	osprintf(os, "\n");
1186 	osprintf(os, "%s &%s::copy_callbacks(const %s &obj)\n",
1187 		cppname, classname.c_str(), cppname);
1188 	osprintf(os, "{\n");
1189 	for (const auto &callback : clazz.persistent_callbacks) {
1190 		string callback_name = clazz.persistent_callback_name(callback);
1191 
1192 		osprintf(os, "  %s_data = obj.%s_data;\n",
1193 			callback_name.c_str(), callback_name.c_str());
1194 	}
1195 	osprintf(os, "  return *this;\n");
1196 	osprintf(os, "}\n");
1197 
1198 	for (const auto &callback : clazz.persistent_callbacks)
1199 		print_set_persistent_callback(Method(clazz, callback));
1200 }
1201 
1202 /* Print a definition for the "get" method "fd" in class "clazz",
1203  * using a name that includes the "get_" prefix, to "os".
1204  *
1205  * This definition simply calls the variant without the "get_" prefix and
1206  * returns its result.
1207  * Note that static methods are not considered to be "get" methods.
1208  */
print_get_method(FunctionDecl * fd)1209 void plain_cpp_generator::impl_printer::print_get_method(FunctionDecl *fd)
1210 {
1211 	string get_name = clazz.base_method_name(fd);
1212 	string name = clazz.method_name(fd);
1213 	int num_params = fd->getNumParams();
1214 
1215 	osprintf(os, "\n");
1216 	print_full_method_header(Method(clazz, fd, get_name));
1217 	osprintf(os, "{\n");
1218 	osprintf(os, "  return %s(", name.c_str());
1219 	for (int i = 1; i < num_params; ++i) {
1220 		ParmVarDecl *param = fd->getParamDecl(i);
1221 
1222 		if (i != 1)
1223 			osprintf(os, ", ");
1224 		osprintf(os, "%s", param->getName().str().c_str());
1225 	}
1226 	osprintf(os, ");\n");
1227 	osprintf(os, "}\n");
1228 }
1229 
1230 /* Print code that checks that all isl object arguments to "method" are valid
1231  * (not NULL) and throws an exception if they are not.
1232  *
1233  * If checked bindings are being generated,
1234  * then no such check is performed.
1235  */
print_argument_validity_check(const Method & method)1236 void plain_cpp_generator::impl_printer::print_argument_validity_check(
1237 	const Method &method)
1238 {
1239 	int n;
1240 	bool first = true;
1241 
1242 	if (generator.checked)
1243 		return;
1244 
1245 	n = method.num_params();
1246 	for (int i = 0; i < n; ++i) {
1247 		bool is_this;
1248 		ParmVarDecl *param = method.fd->getParamDecl(i);
1249 		string name = param->getName().str();
1250 		const char *name_str = name.c_str();
1251 		QualType type = param->getOriginalType();
1252 
1253 		is_this = i == 0 && method.kind == Method::Kind::member_method;
1254 		if (!is_this && (is_isl_ctx(type) || !is_isl_type(type)))
1255 			continue;
1256 
1257 		if (first)
1258 			osprintf(os, "  if (");
1259 		else
1260 			osprintf(os, " || ");
1261 
1262 		if (is_this)
1263 			osprintf(os, "!ptr");
1264 		else
1265 			osprintf(os, "%s.is_null()", name_str);
1266 
1267 		first = false;
1268 	}
1269 	if (first)
1270 		return;
1271 	osprintf(os, ")\n");
1272 	print_throw_NULL_input(os);
1273 }
1274 
1275 /* Print code for saving a copy of the isl::ctx available at the start
1276  * of the method "method" in a "saved_ctx" variable,
1277  * for use in exception handling.
1278  *
1279  * If checked bindings are being generated,
1280  * then the "saved_ctx" variable is not needed.
1281  * If "method" is a member function, then obtain the isl_ctx from
1282  * the "this" object.
1283  * If the first argument of the method is an isl::ctx, then use that one.
1284  * Otherwise, save a copy of the isl::ctx associated to the first argument
1285  * of isl object type.
1286  */
print_save_ctx(const Method & method)1287 void plain_cpp_generator::impl_printer::print_save_ctx(const Method &method)
1288 {
1289 	int n;
1290 	ParmVarDecl *param = method.fd->getParamDecl(0);
1291 	QualType type = param->getOriginalType();
1292 
1293 	if (generator.checked)
1294 		return;
1295 	if (method.kind == Method::Kind::member_method) {
1296 		osprintf(os, "  auto saved_ctx = ctx();\n");
1297 		return;
1298 	}
1299 	if (is_isl_ctx(type)) {
1300 		std::string name;
1301 
1302 		name = param->getName().str();
1303 		osprintf(os, "  auto saved_ctx = %s;\n", name.c_str());
1304 		return;
1305 	}
1306 	n = method.num_params();
1307 	for (int i = 0; i < n; ++i) {
1308 		ParmVarDecl *param = method.fd->getParamDecl(i);
1309 		QualType type = param->getOriginalType();
1310 
1311 		if (!is_isl_type(type))
1312 			continue;
1313 		osprintf(os, "  auto saved_ctx = %s.ctx();\n",
1314 			param->getName().str().c_str());
1315 		return;
1316 	}
1317 }
1318 
1319 /* Print code to make isl not print an error message when an error occurs
1320  * within the current scope (if exceptions are available),
1321  * since the error message will be included in the exception.
1322  * If exceptions are not available, then exception::on_error
1323  * is set to ISL_ON_ERROR_ABORT and isl is therefore made to abort instead.
1324  *
1325  * If checked bindings are being generated,
1326  * then leave it to the user to decide what isl should do on error.
1327  * Otherwise, assume that a valid isl::ctx is available
1328  * in the "saved_ctx" variable,
1329  * e.g., through a prior call to print_save_ctx.
1330  */
print_on_error_continue()1331 void plain_cpp_generator::impl_printer::print_on_error_continue()
1332 {
1333 	if (generator.checked)
1334 		return;
1335 	osprintf(os, "  options_scoped_set_on_error saved_on_error(saved_ctx, "
1336 		     "exception::on_error);\n");
1337 }
1338 
1339 /* Print code to "os" that checks whether any of the persistent callbacks
1340  * of the class of "method" is set and if it failed with an exception.
1341  * If so, the "eptr" in the corresponding data structure contains the exception
1342  * that was caught and that needs to be rethrown.
1343  * This field is cleared because the callback and its data may get reused.
1344  *
1345  * The check only needs to be generated for member methods since
1346  * an object is needed for any of the persistent callbacks to be set.
1347  */
print_persistent_callback_exceptional_execution_check(ostream & os,const Method & method)1348 static void print_persistent_callback_exceptional_execution_check(ostream &os,
1349 	const Method &method)
1350 {
1351 	if (method.kind != Method::Kind::member_method)
1352 		return;
1353 
1354 	for (const auto &pcb : method.clazz.persistent_callbacks) {
1355 		auto callback_name = method.clazz.persistent_callback_name(pcb);
1356 
1357 		osprintf(os, "  if (%s_data && %s_data->eptr) {\n",
1358 			callback_name.c_str(), callback_name.c_str());
1359 		osprintf(os, "    std::exception_ptr eptr = %s_data->eptr;\n",
1360 			callback_name.c_str());
1361 		osprintf(os, "    %s_data->eptr = nullptr;\n",
1362 			callback_name.c_str());
1363 		osprintf(os, "    std::rethrow_exception(eptr);\n");
1364 		osprintf(os, "  }\n");
1365 	}
1366 }
1367 
1368 /* Print code that checks whether the execution of the core of "method"
1369  * was successful.
1370  *
1371  * If checked bindings are being generated,
1372  * then no checks are performed.
1373  *
1374  * Otherwise, first check if any of the callbacks failed with
1375  * an exception.  If so, the "eptr" in the corresponding data structure
1376  * contains the exception that was caught and that needs to be rethrown.
1377  * Then check if the function call failed in any other way and throw
1378  * the appropriate exception.
1379  * In particular, if the return type is isl_stat, isl_bool or isl_size,
1380  * then a negative value indicates a failure.  If the return type
1381  * is an isl type, then a NULL value indicates a failure.
1382  * Assume print_save_ctx has made sure that a valid isl::ctx
1383  * is available in the "ctx" variable.
1384  */
print_exceptional_execution_check(const Method & method)1385 void plain_cpp_generator::impl_printer::print_exceptional_execution_check(
1386 	const Method &method)
1387 {
1388 	bool check_null, check_neg;
1389 	QualType return_type = method.fd->getReturnType();
1390 
1391 	if (generator.checked)
1392 		return;
1393 
1394 	print_persistent_callback_exceptional_execution_check(os, method);
1395 
1396 	if (method.callback) {
1397 		std::string name;
1398 
1399 		name = method.callback->getName().str();
1400 		osprintf(os, "  if (%s_data.eptr)\n", name.c_str());
1401 		osprintf(os, "    std::rethrow_exception(%s_data.eptr);\n",
1402 			name.c_str());
1403 	}
1404 
1405 	check_neg = is_isl_neg_error(return_type);
1406 	check_null = is_isl_type(return_type);
1407 	if (!check_null && !check_neg)
1408 		return;
1409 
1410 	if (check_neg)
1411 		osprintf(os, "  if (res < 0)\n");
1412 	else
1413 		osprintf(os, "  if (!res)\n");
1414 	print_throw_last_error(os);
1415 }
1416 
1417 /* Return a pointer to the appropriate type printer,
1418  * i.e., the regular type printer or the checked type printer
1419  * depending on the setting of this->checked.
1420  */
type_printer()1421 std::unique_ptr<cpp_type_printer> plain_cpp_generator::type_printer()
1422 {
1423 	cpp_type_printer *printer;
1424 
1425 	if (checked)
1426 		printer = new checked_cpp_type_printer();
1427 	else
1428 		printer = new cpp_type_printer();
1429 
1430 	return std::unique_ptr<cpp_type_printer>(printer);
1431 }
1432 
1433 /* Return the C++ return type of the method "method".
1434  *
1435  * Use the appropriate type printer.
1436  */
get_return_type(const Method & method)1437 std::string plain_cpp_generator::get_return_type(const Method &method)
1438 {
1439 	return type_printer()->return_type(method);
1440 }
1441 
1442 /* Given a method "method" for setting a persistent callback of its class,
1443  * print the implementations of the methods needed for that callback.
1444  *
1445  * In particular, print
1446  * - the implementation of a static inline method
1447  *   for use as the C callback function
1448  * - the definition of a private method for setting the callback function
1449  * - the public method for constructing a new object with the callback set.
1450  */
print_set_persistent_callback(const Method & method)1451 void plain_cpp_generator::impl_printer::print_set_persistent_callback(
1452 	const Method &method)
1453 {
1454 	string fullname = method.fd->getName().str();
1455 	ParmVarDecl *param = persistent_callback_arg(method.fd);
1456 	string pname;
1457 	string callback_name = clazz.persistent_callback_name(method.fd);
1458 
1459 	osprintf(os, "\n");
1460 	print_persistent_callback_prototype(method.fd);
1461 	osprintf(os, "\n");
1462 	osprintf(os, "{\n");
1463 	print_callback_body(2, param, callback_name);
1464 	osprintf(os, "}\n\n");
1465 
1466 	pname = param->getName().str();
1467 	print_persistent_callback_setter_prototype(method.fd);
1468 	osprintf(os, "\n");
1469 	osprintf(os, "{\n");
1470 	print_check_ptr_start("ptr");
1471 	osprintf(os, "  %s_data = std::make_shared<struct %s_data>();\n",
1472 		callback_name.c_str(), callback_name.c_str());
1473 	osprintf(os, "  %s_data->func = %s;\n",
1474 		callback_name.c_str(), pname.c_str());
1475 	osprintf(os, "  ptr = %s(ptr, &%s, %s_data.get());\n",
1476 		fullname.c_str(), callback_name.c_str(), callback_name.c_str());
1477 	print_check_ptr_end("ptr");
1478 	osprintf(os, "}\n\n");
1479 
1480 	print_full_method_header(method);
1481 	osprintf(os, "{\n");
1482 	osprintf(os, "  auto copy = *this;\n");
1483 	osprintf(os, "  copy.set_%s_data(%s);\n",
1484 		callback_name.c_str(), pname.c_str());
1485 	osprintf(os, "  return copy;\n");
1486 	osprintf(os, "}\n");
1487 }
1488 
1489 /* Print the return statement of the C++ method "method".
1490  *
1491  * The result of the corresponding isl function is returned as a new
1492  * object if the underlying isl function returns an isl_* ptr, as a bool
1493  * if the isl function returns an isl_bool, as void if the isl functions
1494  * returns an isl_stat,
1495  * as std::string if the isl function returns 'const char *', and as
1496  * unmodified return value otherwise.
1497  * If checked C++ bindings are being generated,
1498  * then an isl_bool return type is transformed into a boolean and
1499  * an isl_stat into a stat since no exceptions can be generated
1500  * on negative results from the isl function.
1501  * If the method returns a new instance of the same object type and
1502  * if the class has any persistent callbacks, then the data
1503  * for these callbacks are copied from the original to the new object.
1504  * If "clazz" is a subclass that is based on a type function and
1505  * if the return type corresponds to the superclass data type,
1506  * then it is replaced by the subclass data type.
1507  */
print_method_return(const Method & method)1508 void plain_cpp_generator::impl_printer::print_method_return(
1509 	const Method &method)
1510 {
1511 	QualType return_type = method.fd->getReturnType();
1512 	string rettype_str = generator.get_return_type(method);
1513 	bool returns_super = method.is_subclass_mutator();
1514 
1515 	if (is_isl_type(return_type) ||
1516 		    (generator.checked && is_isl_neg_error(return_type))) {
1517 		osprintf(os, "  return manage(res)");
1518 		if (is_mutator(clazz, method.fd) &&
1519 		    clazz.has_persistent_callbacks())
1520 			osprintf(os, ".copy_callbacks(*this)");
1521 		if (returns_super)
1522 			osprintf(os, ".as<%s>()", rettype_str.c_str());
1523 		osprintf(os, ";\n");
1524 	} else if (is_isl_stat(return_type)) {
1525 		osprintf(os, "  return;\n");
1526 	} else if (is_string(return_type)) {
1527 		osprintf(os, "  std::string tmp(res);\n");
1528 		if (gives(method.fd))
1529 			osprintf(os, "  free(res);\n");
1530 		osprintf(os, "  return tmp;\n");
1531 	} else {
1532 		osprintf(os, "  return res;\n");
1533 	}
1534 }
1535 
1536 /* Print the header for "method", including the terminating semicolon
1537  * in case of a declaration and a newline.
1538  *
1539  * Use the appropriate type printer to print argument and return types.
1540  */
print_full_method_header(const Method & method)1541 void plain_cpp_generator::plain_printer::print_full_method_header(
1542 	const Method &method)
1543 {
1544 	auto type_printer = generator.type_printer();
1545 
1546 	print_method_header(method, *type_printer);
1547 
1548 	if (declarations)
1549 		osprintf(os, ";");
1550 	osprintf(os, "\n");
1551 }
1552 
1553 /* Generate the list of argument types for a callback function of
1554  * type "type".  If "cpp" is set, then generate the C++ type list, otherwise
1555  * the C type list.
1556  *
1557  * Use the appropriate type printer.
1558  * For the plain C++ interface, the argument position is irrelevant,
1559  * so simply pass in -1.
1560  */
generate_callback_args(QualType type,bool cpp)1561 string plain_cpp_generator::generate_callback_args(QualType type, bool cpp)
1562 {
1563 	return type_printer()->generate_callback_args(-1, type, cpp);
1564 }
1565 
1566 /* Generate the full cpp type of a callback function of type "type".
1567  *
1568  * Use the appropriate type printer.
1569  * For the plain C++ interface, the argument position is irrelevant,
1570  * so simply pass in -1.
1571  */
generate_callback_type(QualType type)1572 string plain_cpp_generator::generate_callback_type(QualType type)
1573 {
1574 	return type_printer()->generate_callback_type(-1, type);
1575 }
1576 
1577 /* Print the call to the C++ callback function "call",
1578  * with the given indentation, wrapped
1579  * for use inside the lambda function that is used as the C callback function,
1580  * in the case where checked C++ bindings are being generated.
1581  *
1582  * In particular, print
1583  *
1584  *        auto ret = @call@;
1585  *        return ret.release();
1586  */
print_wrapped_call_checked(int indent,const string & call)1587 void plain_cpp_generator::impl_printer::print_wrapped_call_checked(int indent,
1588 	const string &call)
1589 {
1590 	osprintf(os, indent, "auto ret = %s;\n", call.c_str());
1591 	osprintf(os, indent, "return ret.release();\n");
1592 }
1593 
1594 /* Print the call to the C++ callback function "call",
1595  * with the given indentation and with return type "rtype", wrapped
1596  * for use inside the lambda function that is used as the C callback function.
1597  *
1598  * In particular, print
1599  *
1600  *        ISL_CPP_TRY {
1601  *          @call@;
1602  *          return isl_stat_ok;
1603  *        } ISL_CPP_CATCH_ALL {
1604  *          data->eptr = std::current_exception();
1605  *          return isl_stat_error;
1606  *        }
1607  * or
1608  *        ISL_CPP_TRY {
1609  *          auto ret = @call@;
1610  *          return ret ? isl_bool_true : isl_bool_false;
1611  *        } ISL_CPP_CATCH_ALL {
1612  *          data->eptr = std::current_exception();
1613  *          return isl_bool_error;
1614  *        }
1615  * or
1616  *        ISL_CPP_TRY {
1617  *          auto ret = @call@;
1618  *          return ret.release();
1619  *        } ISL_CPP_CATCH_ALL {
1620  *          data->eptr = std::current_exception();
1621  *          return NULL;
1622  *        }
1623  *
1624  * depending on the return type.
1625  *
1626  * where ISL_CPP_TRY is defined to "try" and ISL_CPP_CATCH_ALL to "catch (...)"
1627  * (if exceptions are available).
1628  *
1629  * If checked C++ bindings are being generated, then
1630  * the call is wrapped differently.
1631  */
print_wrapped_call(int indent,const string & call,QualType rtype)1632 void plain_cpp_generator::impl_printer::print_wrapped_call(int indent,
1633 	const string &call, QualType rtype)
1634 {
1635 	if (generator.checked)
1636 		return print_wrapped_call_checked(indent, call);
1637 
1638 	osprintf(os, indent, "ISL_CPP_TRY {\n");
1639 	if (is_isl_stat(rtype))
1640 		osprintf(os, indent, "  %s;\n", call.c_str());
1641 	else
1642 		osprintf(os, indent, "  auto ret = %s;\n", call.c_str());
1643 	if (is_isl_stat(rtype))
1644 		osprintf(os, indent, "  return isl_stat_ok;\n");
1645 	else if (is_isl_bool(rtype))
1646 		osprintf(os, indent,
1647 			"  return ret ? isl_bool_true : isl_bool_false;\n");
1648 	else
1649 		osprintf(os, indent, "  return ret.release();\n");
1650 	osprintf(os, indent, "} ISL_CPP_CATCH_ALL {\n");
1651 	osprintf(os, indent, "  data->eptr = std::current_exception();\n");
1652 	if (is_isl_stat(rtype))
1653 		osprintf(os, indent, "  return isl_stat_error;\n");
1654 	else if (is_isl_bool(rtype))
1655 		osprintf(os, indent, "  return isl_bool_error;\n");
1656 	else
1657 		osprintf(os, indent, "  return NULL;\n");
1658 	osprintf(os, indent, "}\n");
1659 }
1660 
1661 /* Print the declaration for a "prefix"_data data structure
1662  * that can be used for passing to a C callback function
1663  * containing a copy of the C++ callback function "param",
1664  * along with an std::exception_ptr that is used to store any
1665  * exceptions thrown in the C++ callback.
1666  *
1667  * If the C callback is of the form
1668  *
1669  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
1670  *
1671  * then the following declaration is printed:
1672  *
1673  *      struct <prefix>_data {
1674  *        std::function<stat(map)> func;
1675  *        std::exception_ptr eptr;
1676  *      }
1677  *
1678  * (without a newline or a semicolon).
1679  *
1680  * The std::exception_ptr object is not added to "prefix"_data
1681  * if checked C++ bindings are being generated.
1682  */
print_callback_data_decl(ParmVarDecl * param,const string & prefix)1683 void plain_cpp_generator::plain_printer::print_callback_data_decl(
1684 	ParmVarDecl *param,
1685 	const string &prefix)
1686 {
1687 	string cpp_args;
1688 
1689 	cpp_args = generator.generate_callback_type(param->getType());
1690 
1691 	osprintf(os, "  struct %s_data {\n", prefix.c_str());
1692 	osprintf(os, "    %s func;\n", cpp_args.c_str());
1693 	if (!generator.checked)
1694 		osprintf(os, "    std::exception_ptr eptr;\n");
1695 	osprintf(os, "  }");
1696 }
1697 
1698 /* Given a group of methods with the same name,
1699  * should extra methods be added that take as arguments
1700  * those types that can be converted to the original argument type
1701  * through a unary constructor?
1702  *
1703  * Note that even if this method returns true,
1704  * the extra methods are only printed by the caller
1705  * if exactly one of the methods in the group was originally defined
1706  * in the printed class.
1707  * Signal that they should be printed if the group contains
1708  * both methods originally defined in the printed class and
1709  * methods that have been copied from an ancestor
1710  * by checking whether there are at least two methods in the group.
1711  */
want_descendent_overloads(const function_set & methods)1712 bool plain_cpp_generator::plain_printer::want_descendent_overloads(
1713 	const function_set &methods)
1714 {
1715 	return methods.size() > 1;
1716 }
1717 
1718 /* Print the body of C function callback with the given indentation
1719  * that can be use as an argument to "param" for marshalling
1720  * the corresponding C++ callback.
1721  * The data structure that contains the C++ callback is of type
1722  * "prefix"_data.
1723  *
1724  * For a callback of the form
1725  *
1726  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
1727  *
1728  * the following code is generated:
1729  *
1730  *        auto *data = static_cast<struct <prefix>_data *>(arg_1);
1731  *        ISL_CPP_TRY {
1732  *          stat ret = (data->func)(manage(arg_0));
1733  *          return isl_stat_ok;
1734  *        } ISL_CPP_CATCH_ALL {
1735  *          data->eptr = std::current_exception();
1736  *          return isl_stat_error;
1737  *        }
1738  *
1739  * If checked C++ bindings are being generated, then
1740  * generate the following code:
1741  *
1742  *        auto *data = static_cast<struct <prefix>_data *>(arg_1);
1743  *        stat ret = (data->func)(manage(arg_0));
1744  *        return isl_stat(ret);
1745  */
print_callback_body(int indent,ParmVarDecl * param,const string & prefix)1746 void plain_cpp_generator::impl_printer::print_callback_body(int indent,
1747 	ParmVarDecl *param, const string &prefix)
1748 {
1749 	QualType ptype, rtype;
1750 	string call, last_idx;
1751 	const FunctionProtoType *callback;
1752 	int num_params;
1753 
1754 	ptype = param->getType();
1755 
1756 	callback = extract_prototype(ptype);
1757 	rtype = callback->getReturnType();
1758 	num_params = callback->getNumArgs();
1759 
1760 	last_idx = ::to_string(num_params - 1);
1761 
1762 	call = "(data->func)(";
1763 	for (long i = 0; i < num_params - 1; i++) {
1764 		if (!generator.callback_takes_argument(param, i))
1765 			call += "manage_copy";
1766 		else
1767 			call += "manage";
1768 		call += "(arg_" + ::to_string(i) + ")";
1769 		if (i != num_params - 2)
1770 			call += ", ";
1771 	}
1772 	call += ")";
1773 
1774 	osprintf(os, indent,
1775 		 "auto *data = static_cast<struct %s_data *>(arg_%s);\n",
1776 		 prefix.c_str(), last_idx.c_str());
1777 	print_wrapped_call(indent, call, rtype);
1778 }
1779 
1780 /* Print the local variables that are needed for a callback argument,
1781  * in particular, print a lambda function that wraps the callback and
1782  * a pointer to the actual C++ callback function.
1783  *
1784  * For a callback of the form
1785  *
1786  *      isl_stat (*fn)(__isl_take isl_map *map, void *user)
1787  *
1788  * the following lambda function is generated:
1789  *
1790  *      auto fn_lambda = [](isl_map *arg_0, void *arg_1) -> isl_stat {
1791  *        auto *data = static_cast<struct fn_data *>(arg_1);
1792  *        try {
1793  *          stat ret = (data->func)(manage(arg_0));
1794  *          return isl_stat_ok;
1795  *        } catch (...) {
1796  *          data->eptr = std::current_exception();
1797  *          return isl_stat_error;
1798  *        }
1799  *      };
1800  *
1801  * A copy of the std::function C++ callback function is stored in
1802  * a fn_data data structure for passing to the C callback function,
1803  * along with an std::exception_ptr that is used to store any
1804  * exceptions thrown in the C++ callback.
1805  *
1806  *      struct fn_data {
1807  *        std::function<stat(map)> func;
1808  *        std::exception_ptr eptr;
1809  *      } fn_data = { fn };
1810  *
1811  * This std::function object represents the actual user
1812  * callback function together with the locally captured state at the caller.
1813  *
1814  * The lambda function is expected to be used as a C callback function
1815  * where the lambda itself is provided as the function pointer and
1816  * where the user void pointer is a pointer to fn_data.
1817  * The std::function object is extracted from the pointer to fn_data
1818  * inside the lambda function.
1819  *
1820  * The std::exception_ptr object is not added to fn_data
1821  * if checked C++ bindings are being generated.
1822  * The body of the generated lambda function then is as follows:
1823  *
1824  *        stat ret = (data->func)(manage(arg_0));
1825  *        return isl_stat(ret);
1826  *
1827  * If the C callback does not take its arguments, then
1828  * manage_copy is used instead of manage.
1829  */
print_callback_local(ParmVarDecl * param)1830 void plain_cpp_generator::impl_printer::print_callback_local(ParmVarDecl *param)
1831 {
1832 	string pname;
1833 	QualType ptype, rtype;
1834 	string c_args, cpp_args, rettype;
1835 	const FunctionProtoType *callback;
1836 
1837 	pname = param->getName().str();
1838 	ptype = param->getType();
1839 
1840 	c_args = generator.generate_callback_args(ptype, false);
1841 
1842 	callback = extract_prototype(ptype);
1843 	rtype = callback->getReturnType();
1844 	rettype = rtype.getAsString();
1845 
1846 	print_callback_data_decl(param, pname);
1847 	osprintf(os, " %s_data = { %s };\n", pname.c_str(), pname.c_str());
1848 	osprintf(os, "  auto %s_lambda = [](%s) -> %s {\n",
1849 		 pname.c_str(), c_args.c_str(), rettype.c_str());
1850 	print_callback_body(4, param, pname);
1851 	osprintf(os, "  };\n");
1852 }
1853 
1854 /* Return the C++ counterpart to the isl_bool type.
1855  *
1856  * For the checked C++ bindings this is "boolean".
1857  */
isl_bool() const1858 std::string checked_cpp_type_printer::isl_bool() const
1859 {
1860 	return "boolean";
1861 }
1862 
1863 /* Return the C++ counterpart to the isl_bool type.
1864  *
1865  * Use the appropriate type printer.
1866  */
isl_bool2cpp()1867 string plain_cpp_generator::isl_bool2cpp()
1868 {
1869 	return type_printer()->isl_bool();
1870 }
1871 
1872 /* Return the C++ counterpart to the isl_stat type.
1873  *
1874  * For the checked C++ bindings this is "stat".
1875  */
isl_stat() const1876 string checked_cpp_type_printer::isl_stat() const
1877 {
1878 	return "stat";
1879 }
1880 
1881 /* Return the C++ counterpart to the isl_size type.
1882  *
1883  * For the checked C++ bindings this is "class size".
1884  */
isl_size() const1885 string checked_cpp_type_printer::isl_size() const
1886 {
1887 	return "class size";
1888 }
1889 
1890 /* Return the namespace of the generated C++ bindings.
1891  *
1892  * For the checked C++ bindings this is "isl::checked::".
1893  */
isl_namespace() const1894 std::string checked_cpp_type_printer::isl_namespace() const
1895 {
1896 	return "isl::checked::";
1897 }
1898 
1899 /* Return the namespace of the generated C++ bindings.
1900  *
1901  * Use the appropriate type printer.
1902  */
isl_namespace()1903 string plain_cpp_generator::isl_namespace()
1904 {
1905 	return type_printer()->isl_namespace();
1906 }
1907 
1908 /* Translate parameter or return type "type" to its C++ name counterpart.
1909  *
1910  * Use the appropriate type printer.
1911  * For the plain C++ interface, the argument position is irrelevant,
1912  * so simply pass in -1.
1913  */
param2cpp(QualType type)1914 string plain_cpp_generator::param2cpp(QualType type)
1915 {
1916 	return type_printer()->param(-1, type);
1917 }
1918