7 #include <fmt/ostream.h> 9 #include <clang/AST/CXXInheritance.h> 15 return std::regex_replace(input, std::regex(
"\\s*,\\s*"),
" V8TOOLKIT_COMMA ");
25 cerr << fmt::format(
"In update_wrapped_class_for_type {} in wrapped class {}", qual_type.getAsString(), wrapped_class.
class_name) << endl;
27 if (
print_logging) cerr <<
"Went from " << qual_type.getAsString();
28 qual_type = qual_type.getLocalUnqualifiedType();
32 while(!qual_type->getPointeeType().isNull()) {
33 qual_type = qual_type->getPointeeType();
35 qual_type = qual_type.getLocalUnqualifiedType();
37 if (
print_logging) cerr <<
" to " << qual_type.getAsString() << endl;
38 auto base_type_record_decl = qual_type->getAsCXXRecordDecl();
42 if (
auto function_type = dyn_cast<FunctionType>(&*qual_type)) {
43 cerr <<
"IS A FUNCTION TYPE!!!!" << endl;
46 if (
auto function_prototype = dyn_cast<FunctionProtoType>(function_type)) {
47 cerr <<
"IS A FUNCTION PROTOTYPE" << endl;
49 cerr <<
"Recursing on return type" << endl;
52 for (
auto param : function_prototype->param_types()) {
54 cerr <<
"Recursing on param type" << endl;
58 cerr <<
"IS NOT A FUNCTION PROTOTYPE" << endl;
62 cerr <<
"is not a FUNCTION TYPE" << endl;
67 if (base_type_record_decl ==
nullptr) {
73 if (
print_logging) cerr << &wrapped_class <<
"Got include string for " << qual_type.getAsString() <<
": " << actual_include_string << endl;
84 cerr << fmt::format(
"{} now has {} include files having added {}", wrapped_class.
name_alias, wrapped_class.
include_files.size(), actual_include_string) << endl;
87 if (dyn_cast<ClassTemplateSpecializationDecl>(base_type_record_decl)) {
88 if (
print_logging) cerr <<
"##!#!#!#!# Oh shit, it's a template type " << qual_type.getAsString() << endl;
90 auto template_specialization_decl = dyn_cast<ClassTemplateSpecializationDecl>(base_type_record_decl);
93 auto & template_arg_list = template_specialization_decl->getTemplateArgs();
94 for (decltype(template_arg_list.size()) i = 0; i < template_arg_list.size(); i++) {
95 auto & arg = template_arg_list[i];
98 if (arg.getKind() != clang::TemplateArgument::Type) {
101 auto template_arg_qual_type = arg.getAsType();
102 if (template_arg_qual_type.isNull()) {
106 if (
print_logging) cerr <<
"Recursing on templated type " << template_arg_qual_type.getAsString() << endl;
110 if (
print_logging) cerr <<
"Not a template specializaiton type " << qual_type.getAsString() << endl;
119 auto &attrs = decl->getAttrs();
122 auto name = decl->getNameAsString();
124 bool found_export_specifier =
false;
126 for (
auto attr : attrs) {
127 if (dyn_cast<AnnotateAttr>(attr)) {
128 auto attribute_attr = dyn_cast<AnnotateAttr>(attr);
129 auto annotation_string = attribute_attr->getAnnotation().str();
132 if (found_export_specifier) {
data_error(fmt::format(
"Found more than one export specifier on {}", name));}
135 found_export_specifier =
true;
136 }
else if (annotation_string ==
"v8toolkit_generate_bindings_some") {
137 if (found_export_specifier) {
data_error(fmt::format(
"Found more than one export specifier on {}", name));}
139 found_export_specifier =
true;
140 }
else if (annotation_string ==
"v8toolkit_generate_bindings_except") {
141 if (found_export_specifier) {
data_error(fmt::format(
"Found more than one export specifier on {}", name).c_str());}
143 found_export_specifier =
true;
145 if (found_export_specifier) {
data_error(fmt::format(
"Found more than one export specifier on {}", name).c_str());}
147 found_export_specifier =
true;
153 if (
const CXXRecordDecl * record_decl = dyn_cast<CXXRecordDecl>(decl)) {
154 for (
auto & base : record_decl->bases()) {
155 auto type = base.getType();
156 auto base_decl = type->getAsCXXRecordDecl();
159 if (base_name ==
"class v8toolkit::WrappedClassBase") {
160 cerr <<
"FOUND WRAPPED CLASS BASE -- EXPORT_ALL" << endl;
161 if (found_export_specifier) {
data_error(fmt::format(
"Found more than one export specifier on {}", name).c_str());}
163 found_export_specifier =
true;
175 if (decl ==
nullptr) {
176 llvm::report_fatal_error(
"null type decl to get_canonical_name_for_decl");
178 return decl->getTypeForDecl()->getCanonicalTypeInternal().getAsString();
203 cerr <<
"DATA ERROR: " << error << endl;
204 data_errors.push_back(error);
209 cerr <<
"DATA WARNING: " << warning << endl;
210 data_warnings.push_back(warning);
214 auto type = qual_type.getNonReferenceType();
215 while(!type->getPointeeType().isNull()) {
216 type = type->getPointeeType();
229 int declaration_count_this_file = 1;
231 vector<WrappedClass*> classes_for_this_file;
233 set<WrappedClass *> already_wrapped_classes;
235 vector<vector<WrappedClass *>> classes_per_file;
244 bool found_match =
true;
245 while (found_match) {
251 if (!wrapped_class->should_be_wrapped()) {
256 cerr << fmt::format(
"considering dumping class: {}", wrapped_class->class_name) << endl;
259 if (!wrapped_class->ready_for_wrapping(already_wrapped_classes)) {
260 std::cerr << fmt::format(
"Skipping {}", wrapped_class->class_name) << std::endl;
263 already_wrapped_classes.insert(wrapped_class);
266 std::cerr << fmt::format(
"writing class {} to file with declaration_count = {}", wrapped_class->name_alias, wrapped_class->declaration_count) << std::endl;
269 auto space_available = declaration_count_this_file == 0 ||
270 declaration_count_this_file + wrapped_class->declaration_count <
273 if (!space_available) {
276 std::cerr << fmt::format(
"Out of space in file, rotating") << std::endl;
277 classes_per_file.emplace_back(classes_for_this_file);
280 classes_for_this_file.clear();
281 declaration_count_this_file = 0;
285 classes_for_this_file.push_back(wrapped_class);
286 wrapped_class->dumped =
true;
287 declaration_count_this_file += wrapped_class->declaration_count;
295 if (!classes_for_this_file.empty()) {
296 classes_per_file.emplace_back(classes_for_this_file);
300 cerr << fmt::format(
"Could not wrap all classes - wrapped {} out of {}",
304 int total_file_count = classes_per_file.size();
305 for (
int i = 0; i < total_file_count; i++) {
306 write_classes(i + 1, classes_per_file[i], i == total_file_count - 1);
328 cerr <<
"Classes used that were not wrapped:" << endl;
330 if (!wrapped_class->dumped) {
continue; }
331 for (
auto used_class : wrapped_class->used_classes) {
332 if (!used_class->dumped) {
333 cerr << fmt::format(
"{} uses unwrapped type: {}", wrapped_class->name_alias, used_class->name_alias) << endl;
346 js_stub.open(filename, ios::out);
348 throw std::exception();
356 if (wrapped_class->should_be_wrapped() && !wrapped_class->bidirectional) {
357 js_stub << wrapped_class->generate_js_stub();
367 cerr <<
"Generating bidirectional classes..." << endl;
372 wrapped_class_iterator++) {
373 auto wrapped_class = *wrapped_class_iterator;
376 if (!wrapped_class->bidirectional) {
381 cerr << fmt::format(
"Building bidirectional class {}", wrapped_class->name_alias) << endl;
383 assert(wrapped_class->base_types.size() == 1);
384 auto base_type = *wrapped_class->base_types.begin();
387 ofstream bidirectional_file(regex_replace(wrapped_class->my_include, std::regex(
"[<>\"]"),
""));
389 bidirectional_file << endl <<
"#pragma once\n\n";
394 for (
auto & include : wrapped_class->get_base_type_includes()) {
398 std::cerr << fmt::format(
"for bidirectional {}, adding base type include {}", wrapped_class->name_alias, include) << std::endl;
399 bidirectional_file <<
"#include " << include <<
"\n";
403 for (
auto & include : wrapped_class->include_files) {
407 bidirectional_file <<
"#include " << include <<
"\n";
409 bidirectional_file << endl;
411 std::cerr << fmt::format(
"done with includes, building class and constructor") << std::endl;
412 bidirectional_file << fmt::format(
413 "class JS{} : public {}, public v8toolkit::JSWrapper<{}> {{\npublic:",
414 base_type->name_alias, base_type->name_alias, base_type->name_alias) << endl;
416 std::cerr << fmt::format(
"cc1") << std::endl;
418 << fmt::format(
" JS{}(v8::Local<v8::Context> context, v8::Local<v8::Object> object,",
419 base_type->name_alias) << endl;
420 std::cerr << fmt::format(
"cc2") << std::endl;
421 bidirectional_file << fmt::format(
" v8::Local<v8::FunctionTemplate> created_by") << endl;
422 std::cerr << fmt::format(
"cc3") << std::endl;
423 std::cerr << fmt::format(
"dealing with bidirectional constructor at {} for class {}", (
void*)base_type->bidirectional_constructor,base_type->name_alias) << std::endl;
424 if (base_type->bidirectional_constructor ==
nullptr) {
425 llvm::report_fatal_error(fmt::format(
"bidirectional constructor: {} for class {}",
426 (
void*)base_type->bidirectional_constructor,
427 base_type->name_alias));
429 ClassFunction bidirectional_constructor(*base_type, base_type->bidirectional_constructor);
430 std::cerr << fmt::format(
"cc3.1") << std::endl;
431 int param_position = 1;
432 for (
auto & parameter : bidirectional_constructor.
parameters) {
433 std::cerr << fmt::format(
"cc3.in_loop top") << std::endl;
434 bidirectional_file << fmt::format(
", {} var{}", parameter.type.name, param_position++);
435 std::cerr << fmt::format(
"cc3.in_loop bottom") << std::endl;
439 std::cerr << fmt::format(
"cc4") << std::endl;
440 bidirectional_file << fmt::format(
") :") << endl;
444 std::cerr << fmt::format(
"cc5") << std::endl;
445 bidirectional_file << fmt::format(
" {}({}),", base_type->name_alias,
join(variable_names)) << endl;
446 bidirectional_file << fmt::format(
" v8toolkit::JSWrapper<{}>(context, object, created_by) {{}}", base_type->name_alias) << endl;
447 bidirectional_file << endl;
449 cerr << fmt::format(
"bidirectional class has {} methods, looking for virtual ones", base_type->get_member_functions().size()) << endl;
454 auto * current_inheritance_class = base_type;
455 set<string> js_access_virtual_methods_added;
457 cerr << fmt::format(
"building virtual method list for {}", wrapped_class->name_alias);
458 while(current_inheritance_class) {
459 cerr << fmt::format(
" ** Inheritance hierarchy class: {} with {} base types", current_inheritance_class->name_alias, current_inheritance_class->base_types.size()) << endl;
461 for (
auto & method : current_inheritance_class->get_member_functions()) {
462 if (!method->is_virtual) {
465 auto added_method = js_access_virtual_methods_added.find(method->get_signature_string());
468 if (added_method != js_access_virtual_methods_added.end()) {
472 js_access_virtual_methods_added.insert(method->get_signature_string());
475 auto bidirectional_virtual_method = method->method_decl;
476 auto num_params = bidirectional_virtual_method->getNumParams();
480 stringstream js_access_virtual_method_string;
483 js_access_virtual_method_string <<
" JS_ACCESS_" << num_params
484 << (bidirectional_virtual_method->isConst() ?
"_CONST(" :
"(");
489 js_access_virtual_method_string << bidirectional_virtual_method->getName().str();
491 if (num_params > 0) {
494 bidirectional_virtual_method);
495 vector<string> type_names;
496 for (
auto &type : types) {
500 js_access_virtual_method_string <<
join(type_names,
", ",
true);
505 js_access_virtual_method_string <<
");\n";
508 if (js_access_virtual_methods_added.count(js_access_virtual_method_string.str())) {
511 js_access_virtual_methods_added.insert(js_access_virtual_method_string.str());
512 bidirectional_file << js_access_virtual_method_string.str();
518 current_inheritance_class = *current_inheritance_class->base_types.begin();
572 bidirectional_file << endl <<
"};" << endl << endl;
576 bidirectional_file.close();
630 cerr << fmt::format(
"Class template instantiations") << endl;
631 vector<pair<string, int>> insts;
633 insts.push_back({class_template->name, class_template->instantiations});
635 std::sort(insts.begin(), insts.end(), [](
auto & a,
auto & b){
636 return a.second < b.second;
641 for (
auto & pair : insts) {
642 total += pair.second;
647 cerr << pair.first <<
": " << pair.second << endl;;
651 cerr <<
"Total of " << total <<
" instantiations" << endl;
656 insts.push_back({function_template->name, function_template->instantiations});
658 std::sort(insts.begin(), insts.end(), [](
auto & a,
auto & b){
659 return a.second < b.second;
662 for (
auto & pair : insts) {
663 total += pair.second;
668 cerr << pair.first <<
": " << pair.second << endl;;
674 cerr <<
"Total of " << total <<
" instantiations" << endl;
int matched_classes_returned
set< WrappedClass * > used_classes
#define V8TOOLKIT_ALL_STRING
static WrappedClass & get_or_insert_wrapped_class(const CXXRecordDecl *decl, CompilerInstance &compiler_instance, FOUND_METHOD found_method)
string name_alias
this is the possibly shortened javascript name of the type - not necessarily valid in generated c++ ...
vector< ParameterInfo > parameters
void data_error(const string &error)
QualType get_plain_type(QualType qual_type)
void update_wrapped_class_for_type(WrappedClass &wrapped_class, QualType qual_type)
vector< QualType > get_method_param_qual_types(CompilerInstance &compiler_instance, const CXXMethodDecl *method, string const &annotation)
string make_macro_safe_comma(string const &input)
static vector< WrappedClass * > wrapped_classes
#define TEMPLATED_CLASS_PRINT_THRESHOLD
set< string > include_files
std::string get_include_for_type_decl(CompilerInstance &compiler_instance, const TypeDecl *type_decl)
int MAX_DECLARATIONS_PER_FILE
vector< unique_ptr< FunctionTemplate > > function_templates
std::string js_api_header
vector< string > data_errors
void write_classes(int file_count, vector< WrappedClass * > &classes, bool last_one)
vector< string > generate_variable_names(vector< QualType > qual_types, bool with_std_move)
vector< std::unique_ptr< ClassTemplate > > class_templates
void generate_bidirectional_classes(CompilerInstance &compiler_instance)
void data_warning(const string &warning)
EXPORT_TYPE get_export_type(const NamedDecl *decl, EXPORT_TYPE previous)
#define V8TOOLKIT_NONE_STRING
#define TEMPLATED_FUNCTION_PRINT_THRESHOLD
void generate_javascript_stub(std::string const &filename)
vector< string > data_warnings
std::string get_canonical_name_for_decl(const TypeDecl *decl)
std::string join(const T &source, const std::string &between=", ", bool leading_between=false)
CompilerInstance & compiler_instance
bool has_wrapped_class(const CXXRecordDecl *decl)