| LEFT | RIGHT | 
|---|
| 1 /* | 1 /* | 
| 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
| 3  * Copyright (C) 2006-2017 eyeo GmbH | 3  * Copyright (C) 2006-present eyeo GmbH | 
| 4  * | 4  * | 
| 5  * Adblock Plus is free software: you can redistribute it and/or modify | 5  * Adblock Plus is free software: you can redistribute it and/or modify | 
| 6  * it under the terms of the GNU General Public License version 3 as | 6  * it under the terms of the GNU General Public License version 3 as | 
| 7  * published by the Free Software Foundation. | 7  * published by the Free Software Foundation. | 
| 8  * | 8  * | 
| 9  * Adblock Plus is distributed in the hope that it will be useful, | 9  * Adblock Plus is distributed in the hope that it will be useful, | 
| 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 12  * GNU General Public License for more details. | 12  * GNU General Public License for more details. | 
| 13  * | 13  * | 
| 14  * You should have received a copy of the GNU General Public License | 14  * You should have received a copy of the GNU General Public License | 
| 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
| 16  */ | 16  */ | 
| 17 | 17 | 
| 18 #include <cstdio> | 18 #include <cstdio> | 
| 19 | 19 | 
| 20 #include "generator.h" | 20 #include "generator.h" | 
| 21 #include "library.h" | 21 #include "library.h" | 
| 22 | 22 | 
| 23 namespace | 23 namespace | 
| 24 { | 24 { | 
| 25   std::vector<bindings_internal::ClassInfo> classes; | 25   std::vector<bindings_internal::ClassInfo> classes; | 
| 26   std::vector<bindings_internal::NamespaceInfo> namespaces; |  | 
| 27 |  | 
| 28   void printProperties(const bindings_internal::Properties& properties) |  | 
| 29   { |  | 
| 30     for (const auto& property : properties) |  | 
| 31     { |  | 
| 32       if (property.jsValue.empty()) |  | 
| 33       { |  | 
| 34         printf("get %s%s,\n", property.name.c_str(), |  | 
| 35                wrapCall(property.getter, false).c_str()); |  | 
| 36         if (!property.setter.empty()) |  | 
| 37         { |  | 
| 38           printf("set %s%s,\n", property.name.c_str(), |  | 
| 39                  wrapCall(property.setter, false).c_str()); |  | 
| 40         } |  | 
| 41       } |  | 
| 42       else |  | 
| 43         printf("%s: %s,\n", property.name.c_str(), property.jsValue.c_str()); |  | 
| 44     } |  | 
| 45   } |  | 
| 46 |  | 
| 47   void printMethods(const bindings_internal::Methods& methods, |  | 
| 48                     bool instanceOnly = true) |  | 
| 49   { |  | 
| 50     for (const auto& method : methods) |  | 
| 51       if (!instanceOnly || method.call.instance_function) |  | 
| 52         printf("%s: %s,\n", method.name.c_str(), wrapCall(method.call).c_str()); |  | 
| 53   } |  | 
| 54 } | 26 } | 
| 55 | 27 | 
| 56 namespace bindings_internal | 28 namespace bindings_internal | 
| 57 { | 29 { | 
| 58   FunctionInfo::FunctionInfo() | 30   FunctionInfo::FunctionInfo() | 
| 59   { | 31   { | 
| 60   } | 32   } | 
| 61 | 33 | 
| 62   FunctionInfo::FunctionInfo(TypeCategory returnType, TYPEID pointerType, | 34   FunctionInfo::FunctionInfo(TypeCategory returnType, TYPEID pointerType, | 
| 63       std::initializer_list<TypeCategory> argTypes, bool instance_function, | 35       std::initializer_list<TypeCategory> argTypes, bool instance_function, | 
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 149 | 121 | 
| 150   ClassInfo* find_class(TYPEID classID) | 122   ClassInfo* find_class(TYPEID classID) | 
| 151   { | 123   { | 
| 152     for (auto& classInfo : classes) | 124     for (auto& classInfo : classes) | 
| 153       if (classInfo.id == classID) | 125       if (classInfo.id == classID) | 
| 154         return &classInfo; | 126         return &classInfo; | 
| 155     return nullptr; | 127     return nullptr; | 
| 156   } | 128   } | 
| 157 | 129 | 
| 158   void register_class(const char* name, TYPEID classID, TYPEID baseClassID, | 130   void register_class(const char* name, TYPEID classID, TYPEID baseClassID, | 
| 159                       ptrdiff_t ref_counted_offset) | 131                       ptrdiff_t ref_counted_offset, | 
|  | 132                       const FunctionInfo& instanceGetter) | 
| 160   { | 133   { | 
| 161     if (find_class(classID)) | 134     if (find_class(classID)) | 
| 162       throw std::runtime_error(std::string("Duplicate definition for class ") + 
     name); | 135       throw std::runtime_error(std::string("Duplicate definition for class ") + 
     name); | 
| 163 | 136 | 
| 164     if (baseClassID != TypeInfo<NoBaseClass>() && !find_class(baseClassID)) | 137     if (baseClassID != TypeInfo<NoBaseClass>() && !find_class(baseClassID)) | 
| 165       throw std::runtime_error(std::string("Unknown base class defined for class
      ") + name); | 138       throw std::runtime_error(std::string("Unknown base class defined for class
      ") + name); | 
| 166 | 139 | 
| 167     ClassInfo classInfo; | 140     ClassInfo classInfo; | 
| 168     classInfo.id = classID; | 141     classInfo.id = classID; | 
| 169     classInfo.baseClass = baseClassID; | 142     classInfo.baseClass = baseClassID; | 
| 170     classInfo.name = name; | 143     classInfo.name = name; | 
| 171     classInfo.subclass_differentiator.offset = SIZE_MAX; | 144     classInfo.subclass_differentiator.offset = SIZE_MAX; | 
| 172     classInfo.ref_counted_offset = ref_counted_offset; | 145     classInfo.ref_counted_offset = ref_counted_offset; | 
|  | 146     classInfo.instanceGetter = instanceGetter; | 
| 173     classes.push_back(classInfo); | 147     classes.push_back(classInfo); | 
| 174   } | 148   } | 
| 175 | 149 | 
| 176   void register_property(TYPEID classID, const char* name, | 150   void register_property(TYPEID classID, const char* name, | 
| 177       const FunctionInfo& getter, const FunctionInfo& setter, | 151       const FunctionInfo& getter, const FunctionInfo& setter, | 
| 178       const char* jsValue) | 152       const char* jsValue) | 
| 179   { | 153   { | 
| 180     ClassInfo* classInfo = find_class(classID); | 154     ClassInfo* classInfo = find_class(classID); | 
| 181     if (!classInfo) | 155     if (!classInfo) | 
| 182       throw std::runtime_error(std::string("Property defined on unknown class: "
     ) + name); | 156       throw std::runtime_error(std::string("Property defined on unknown class: "
     ) + name); | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 209     if (!classInfo) | 183     if (!classInfo) | 
| 210       throw std::runtime_error("Subclass differentiator defined on unknown class
     "); | 184       throw std::runtime_error("Subclass differentiator defined on unknown class
     "); | 
| 211 | 185 | 
| 212     if (classInfo->subclass_differentiator.offset != SIZE_MAX) | 186     if (classInfo->subclass_differentiator.offset != SIZE_MAX) | 
| 213       throw std::runtime_error("More than one subclass differentiator defined fo
     r class " + classInfo->name); | 187       throw std::runtime_error("More than one subclass differentiator defined fo
     r class " + classInfo->name); | 
| 214 | 188 | 
| 215     DifferentiatorInfo differentiatorInfo; | 189     DifferentiatorInfo differentiatorInfo; | 
| 216     differentiatorInfo.offset = offset; | 190     differentiatorInfo.offset = offset; | 
| 217     differentiatorInfo.mapping = mapping; | 191     differentiatorInfo.mapping = mapping; | 
| 218     classInfo->subclass_differentiator = differentiatorInfo; | 192     classInfo->subclass_differentiator = differentiatorInfo; | 
| 219   } |  | 
| 220 |  | 
| 221   NamespaceInfo* find_namespace(const char* namespaceName) |  | 
| 222   { |  | 
| 223     for (auto& namespaceInfo : namespaces) |  | 
| 224       if (namespaceInfo.name == namespaceName) |  | 
| 225         return &namespaceInfo; |  | 
| 226     return nullptr; |  | 
| 227   } |  | 
| 228 |  | 
| 229   void register_namespace(const char* name) |  | 
| 230   { |  | 
| 231     if (find_namespace(name)) |  | 
| 232       throw std::runtime_error(std::string("Duplicate definition for namespace "
     ) + name); |  | 
| 233 |  | 
| 234     NamespaceInfo namespaceInfo; |  | 
| 235     namespaceInfo.name = name; |  | 
| 236     namespaces.push_back(namespaceInfo); |  | 
| 237   } |  | 
| 238 |  | 
| 239   void register_namespace_property(const char* namespaceName, const char* name, |  | 
| 240       const FunctionInfo& getter, const FunctionInfo& setter) |  | 
| 241   { |  | 
| 242     NamespaceInfo* namespaceInfo = find_namespace(namespaceName); |  | 
| 243     if (!namespaceInfo) |  | 
| 244       throw std::runtime_error(std::string("Property defined on unknown namespac
     e: ") + name); |  | 
| 245 |  | 
| 246     PropertyInfo propertyInfo; |  | 
| 247     propertyInfo.name = name; |  | 
| 248     propertyInfo.getter = getter; |  | 
| 249     propertyInfo.setter = setter; |  | 
| 250     namespaceInfo->properties.push_back(propertyInfo); |  | 
| 251   } |  | 
| 252 |  | 
| 253   void register_namespace_method(const char* namespaceName, const char* name, |  | 
| 254       const FunctionInfo& call) |  | 
| 255   { |  | 
| 256     NamespaceInfo* namespaceInfo = find_namespace(namespaceName); |  | 
| 257     if (!namespaceInfo) |  | 
| 258       throw std::runtime_error(std::string("Method defined on unknown namespace:
      ") + name); |  | 
| 259 |  | 
| 260     MethodInfo methodInfo; |  | 
| 261     methodInfo.name = name; |  | 
| 262     methodInfo.call = call; |  | 
| 263     namespaceInfo->methods.push_back(methodInfo); |  | 
| 264   } | 193   } | 
| 265 | 194 | 
| 266   std::string generateCall(const FunctionInfo& call, | 195   std::string generateCall(const FunctionInfo& call, | 
| 267       std::vector<std::string>& params) | 196       std::vector<std::string>& params) | 
| 268   { | 197   { | 
| 269     if (call.returnType == TypeCategory::DEPENDENT_STRING || | 198     if (call.returnType == TypeCategory::DEPENDENT_STRING || | 
| 270         call.returnType == TypeCategory::OWNED_STRING) | 199         call.returnType == TypeCategory::OWNED_STRING) | 
| 271     { | 200     { | 
| 272       params.insert(params.begin(), "string"); | 201       params.insert(params.begin(), "string"); | 
| 273     } | 202     } | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
| 293       case TypeCategory::INT64: | 222       case TypeCategory::INT64: | 
| 294         return "  var result = Runtime.makeBigInt(" + call_str + ", " + | 223         return "  var result = Runtime.makeBigInt(" + call_str + ", " + | 
| 295                                                   "Runtime.getTempRet0(), " + | 224                                                   "Runtime.getTempRet0(), " + | 
| 296                                                   "true);\n"; | 225                                                   "true);\n"; | 
| 297       case TypeCategory::DEPENDENT_STRING: | 226       case TypeCategory::DEPENDENT_STRING: | 
| 298       { | 227       { | 
| 299         std::string result; | 228         std::string result; | 
| 300         result += "  var string = createString();\n"; | 229         result += "  var string = createString();\n"; | 
| 301         result += "  " + call_str + ";\n"; | 230         result += "  " + call_str + ";\n"; | 
| 302         result += "  var result = readString(string);\n"; | 231         result += "  var result = readString(string);\n"; | 
|  | 232         // We don't call a destructor here because we know that dependent | 
|  | 233         // strings don't need to clean up. | 
| 303         return result; | 234         return result; | 
| 304       } | 235       } | 
| 305       case TypeCategory::OWNED_STRING: | 236       case TypeCategory::OWNED_STRING: | 
| 306       { | 237       { | 
| 307         std::string result; | 238         std::string result; | 
| 308         result += "  var string = createOwnedString();\n"; | 239         result += "  var string = createOwnedString();\n"; | 
| 309         result += "  " + call_str + ";\n"; | 240         result += "  " + call_str + ";\n"; | 
| 310         result += "  var result = readString(string);\n"; | 241         result += "  var result = readString(string);\n"; | 
| 311         result += "  Module._DestroyString(string);\n"; | 242         result += "  Module._DestroyString(string);\n"; | 
| 312         return result; | 243         return result; | 
| 313       } | 244       } | 
| 314       case TypeCategory::STRING_REF: | 245       case TypeCategory::STRING_REF: | 
| 315         return "  var result = readString(" + call_str + ");\n"; | 246         return "  var result = readString(" + call_str + ");\n"; | 
| 316       case TypeCategory::CLASS_PTR: | 247       case TypeCategory::CLASS_PTR: | 
| 317       { | 248       { | 
| 318         std::string result; | 249         std::string result; | 
| 319         result += "  var result = " + call_str + ";\n"; | 250         result += "  var result = " + call_str + ";\n"; | 
| 320         result += "  if (result)\n"; | 251         result += "  if (result)\n"; | 
| 321         result += "  {\n"; |  | 
| 322 | 252 | 
| 323         const ClassInfo* cls = find_class(call.pointerType); | 253         const ClassInfo* cls = find_class(call.pointerType); | 
| 324         if (!cls) | 254         if (!cls) | 
| 325           throw std::runtime_error("Function " + call.name + " returns pointer t
     o unknown class"); | 255           throw std::runtime_error("Function " + call.name + " returns pointer t
     o unknown class"); | 
| 326 | 256 | 
| 327         auto offset = cls->subclass_differentiator.offset; | 257         auto offset = cls->subclass_differentiator.offset; | 
| 328         if (offset == SIZE_MAX) | 258         if (offset == SIZE_MAX) | 
| 329           result += "    result = exports." + cls->name + "(result);\n"; | 259           result += "    result = exports." + cls->name + "(result);\n"; | 
| 330         else | 260         else | 
| 331           result += "    result = exports." + cls->name + ".fromPointer(result);
     \n"; | 261           result += "    result = exports." + cls->name + ".fromPointer(result);
     \n"; | 
| 332 | 262 | 
| 333         result += "  }\n"; |  | 
| 334         result += "  else\n"; | 263         result += "  else\n"; | 
| 335         result += "    result = null;\n"; | 264         result += "    result = null;\n"; | 
| 336         return result; | 265         return result; | 
| 337       } | 266       } | 
| 338       default: | 267       default: | 
| 339         throw std::runtime_error("Unexpected return type for " + call.name); | 268         throw std::runtime_error("Unexpected return type for " + call.name); | 
| 340     } | 269     } | 
| 341   } | 270   } | 
| 342 | 271 | 
| 343   std::string wrapCall(const FunctionInfo& call, bool isFunction) | 272   std::string wrapCall(const FunctionInfo& call, bool isFunction, | 
|  | 273       const FunctionInfo& instanceGetter) | 
| 344   { | 274   { | 
| 345     bool hasStringArgs = false; | 275     bool hasStringArgs = false; | 
| 346     std::vector<std::string> params; | 276     std::vector<std::string> params; | 
| 347     std::string prefix; | 277     std::string prefix; | 
| 348 | 278 | 
| 349     if (isFunction) | 279     if (isFunction) | 
| 350       prefix += "function"; | 280       prefix += "function"; | 
| 351     prefix += "("; | 281     prefix += "("; | 
| 352     for (int i = 0; i < call.args.size(); i++) | 282     for (int i = 0; i < call.args.size(); i++) | 
| 353     { | 283     { | 
| (...skipping 25 matching lines...) Expand all  Loading... | 
| 379       suffix = "  return result;\n" + suffix; | 309       suffix = "  return result;\n" + suffix; | 
| 380 | 310 | 
| 381     if (call.returnType == TypeCategory::DEPENDENT_STRING || | 311     if (call.returnType == TypeCategory::DEPENDENT_STRING || | 
| 382         call.returnType == TypeCategory::OWNED_STRING || hasStringArgs) | 312         call.returnType == TypeCategory::OWNED_STRING || hasStringArgs) | 
| 383     { | 313     { | 
| 384       prefix += "  var sp = Runtime.stackSave();\n"; | 314       prefix += "  var sp = Runtime.stackSave();\n"; | 
| 385       suffix = "  Runtime.stackRestore(sp);\n" + suffix; | 315       suffix = "  Runtime.stackRestore(sp);\n" + suffix; | 
| 386     } | 316     } | 
| 387 | 317 | 
| 388     if (call.instance_function) | 318     if (call.instance_function) | 
| 389       params.insert(params.begin(), "this._pointer"); | 319     { | 
|  | 320       if (instanceGetter.empty()) | 
|  | 321         params.insert(params.begin(), "this._pointer"); | 
|  | 322       else | 
|  | 323         params.insert(params.begin(), instanceGetter.name + "()"); | 
|  | 324     } | 
| 390 | 325 | 
| 391     return prefix + generateCall(call, params) + suffix; | 326     return prefix + generateCall(call, params) + suffix; | 
| 392   } | 327   } | 
| 393 | 328 | 
| 394   void printHelpers() | 329   void printHelpers() | 
| 395   { | 330   { | 
| 396     printf("var sizeofString = %i;\n", sizeof(String)); | 331     printf("var sizeofString = %i;\n", sizeof(String)); | 
| 397 | 332 | 
| 398     puts(R"( | 333     puts(R"( | 
| 399       function copyString(str, buffer) | 334       function copyString(str, buffer) | 
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 446           Module._ReleaseRef(this._pointer + ref_counted_offset); | 381           Module._ReleaseRef(this._pointer + ref_counted_offset); | 
| 447         }; | 382         }; | 
| 448         return result; | 383         return result; | 
| 449       } | 384       } | 
| 450     )"); | 385     )"); | 
| 451   } | 386   } | 
| 452 | 387 | 
| 453   void printClass(const ClassInfo& cls) | 388   void printClass(const ClassInfo& cls) | 
| 454   { | 389   { | 
| 455     // Begin class definition | 390     // Begin class definition | 
| 456     ClassInfo* baseClass = find_class(cls.baseClass); | 391     bool singleton = !cls.instanceGetter.empty(); | 
| 457     printf("exports.%s = createClass(%s, %i, {\n", cls.name.c_str(), | 392     if (singleton) | 
| 458         (baseClass ? ("exports." + baseClass->name).c_str() : "null"), | 393       printf("exports.%s = {\n", cls.name.c_str()); | 
| 459         cls.ref_counted_offset); | 394     else | 
|  | 395     { | 
|  | 396       ClassInfo* baseClass = find_class(cls.baseClass); | 
|  | 397       printf("exports.%s = createClass(%s, %i, {\n", cls.name.c_str(), | 
|  | 398           (baseClass ? ("exports." + baseClass->name).c_str() : "null"), | 
|  | 399           cls.ref_counted_offset); | 
|  | 400     } | 
| 460 | 401 | 
| 461     // Print prototype members | 402     // Print prototype members | 
| 462     printProperties(cls.properties); | 403     for (const auto& property : cls.properties) | 
| 463     printMethods(cls.methods); | 404     { | 
|  | 405       if (property.jsValue.empty()) | 
|  | 406       { | 
|  | 407         printf("get %s%s,\n", property.name.c_str(), | 
|  | 408                wrapCall(property.getter, false, cls.instanceGetter).c_str()); | 
|  | 409         if (!property.setter.empty()) | 
|  | 410         { | 
|  | 411           printf("set %s%s,\n", property.name.c_str(), | 
|  | 412                  wrapCall(property.setter, false, cls.instanceGetter).c_str()); | 
|  | 413         } | 
|  | 414       } | 
|  | 415       else | 
|  | 416         printf("%s: %s,\n", property.name.c_str(), property.jsValue.c_str()); | 
|  | 417     } | 
|  | 418 | 
|  | 419     for (const auto& method : cls.methods) | 
|  | 420     { | 
|  | 421       if (method.call.instance_function) | 
|  | 422       { | 
|  | 423         printf("%s: %s,\n", | 
|  | 424             method.name.c_str(), | 
|  | 425             wrapCall(method.call, true, cls.instanceGetter).c_str()); | 
|  | 426       } | 
|  | 427     } | 
| 464 | 428 | 
| 465     // End class definition | 429     // End class definition | 
| 466     printf("});\n"); | 430     if (singleton) | 
|  | 431       printf("};\n"); | 
|  | 432     else | 
|  | 433       printf("});\n"); | 
| 467 | 434 | 
| 468     // Print static members | 435     // Print static members | 
| 469     DifferentiatorInfo differentiator = cls.subclass_differentiator; | 436     DifferentiatorInfo differentiator = cls.subclass_differentiator; | 
| 470     if (differentiator.offset != SIZE_MAX) | 437     if (differentiator.offset != SIZE_MAX) | 
| 471     { | 438     { | 
| 472       printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str()); | 439       printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str()); | 
| 473       puts("{"); | 440       puts("{"); | 
| 474       printf("  var type = HEAP32[ptr + %i >> 2];\n", differentiator.offset); | 441       printf("  var type = HEAP32[ptr + %i >> 2];\n", differentiator.offset); | 
| 475       printf("  if (type in %s_mapping)\n", cls.name.c_str()); | 442       printf("  if (type in %s_mapping)\n", cls.name.c_str()); | 
| 476       printf("    return new %s_mapping[type](ptr);\n", cls.name.c_str()); | 443       printf("    return new %s_mapping[type](ptr);\n", cls.name.c_str()); | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
| 500       DifferentiatorInfo differentiator = cls.subclass_differentiator; | 467       DifferentiatorInfo differentiator = cls.subclass_differentiator; | 
| 501       if (differentiator.offset == SIZE_MAX) | 468       if (differentiator.offset == SIZE_MAX) | 
| 502         return; | 469         return; | 
| 503 | 470 | 
| 504       printf("var %s_mapping = \n", cls.name.c_str()); | 471       printf("var %s_mapping = \n", cls.name.c_str()); | 
| 505       puts("{"); | 472       puts("{"); | 
| 506       for (const auto& item : differentiator.mapping) | 473       for (const auto& item : differentiator.mapping) | 
| 507         printf("  %i: exports.%s,\n", item.first, item.second.c_str()); | 474         printf("  %i: exports.%s,\n", item.first, item.second.c_str()); | 
| 508       puts("};"); | 475       puts("};"); | 
| 509   } | 476   } | 
| 510 |  | 
| 511   void printNamespace(const NamespaceInfo& namespaceInfo) |  | 
| 512   { |  | 
| 513     printf("exports.%s = {\n", namespaceInfo.name.c_str()); |  | 
| 514     printProperties(namespaceInfo.properties); |  | 
| 515     printMethods(namespaceInfo.methods, false); |  | 
| 516     puts("};"); |  | 
| 517   } |  | 
| 518 } | 477 } | 
| 519 | 478 | 
| 520 void printBindings() | 479 void printBindings() | 
| 521 { | 480 { | 
| 522   bindings_internal::printHelpers(); | 481   bindings_internal::printHelpers(); | 
| 523 | 482 | 
| 524   for (const auto& cls : classes) | 483   for (const auto& cls : classes) | 
| 525     bindings_internal::printClass(cls); | 484     bindings_internal::printClass(cls); | 
| 526   for (const auto& cls : classes) | 485   for (const auto& cls : classes) | 
| 527     bindings_internal::printClassMapping(cls); | 486     bindings_internal::printClassMapping(cls); | 
| 528   for (const auto& namespace_ : namespaces) |  | 
| 529     bindings_internal::printNamespace(namespace_); |  | 
| 530 } | 487 } | 
| LEFT | RIGHT | 
|---|