| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 #pragma once | 
|  | 2 | 
|  | 3 #include <cstdio> | 
|  | 4 #include <cstdlib> | 
|  | 5 #include <cstring> | 
|  | 6 #include <exception> | 
|  | 7 #include <map> | 
|  | 8 #include <string> | 
|  | 9 #include <type_traits> | 
|  | 10 #include <utility> | 
|  | 11 #include <vector> | 
|  | 12 | 
|  | 13 #include <emscripten.h> | 
|  | 14 | 
|  | 15 #include "String.h" | 
|  | 16 #include "intrusive_ptr.h" | 
|  | 17 | 
|  | 18 typedef void* TYPEID; | 
|  | 19 | 
|  | 20 enum class TypeCategory | 
|  | 21 { | 
|  | 22   UNKNOWN, | 
|  | 23   VOID, | 
|  | 24   INT, | 
|  | 25   DEPENDENT_STRING, | 
|  | 26   OWNED_STRING, | 
|  | 27   STRING_REF, | 
|  | 28   CLASS_PTR | 
|  | 29 }; | 
|  | 30 | 
|  | 31 template<typename T> | 
|  | 32 struct TypeInfo | 
|  | 33 { | 
|  | 34   static char c; | 
|  | 35   constexpr operator TYPEID() const | 
|  | 36   { | 
|  | 37     return &c; | 
|  | 38   } | 
|  | 39 | 
|  | 40   constexpr operator TypeCategory() const | 
|  | 41   { | 
|  | 42     if (std::is_void<T>()) | 
|  | 43       return TypeCategory::VOID; | 
|  | 44 | 
|  | 45     if (std::is_integral<T>() || std::is_enum<T>()) | 
|  | 46       return TypeCategory::INT; | 
|  | 47 | 
|  | 48     if (std::is_same<DependentString,T>() || std::is_same<const DependentString,
     T>()) | 
|  | 49       return TypeCategory::DEPENDENT_STRING; | 
|  | 50 | 
|  | 51     if (std::is_same<OwnedString,T>() || std::is_same<const OwnedString,T>()) | 
|  | 52       return TypeCategory::OWNED_STRING; | 
|  | 53 | 
|  | 54     if (std::is_same<String&,T>() || std::is_same<const String&,T>() || | 
|  | 55       std::is_same<DependentString&,T>()) | 
|  | 56     { | 
|  | 57       return TypeCategory::STRING_REF; | 
|  | 58     } | 
|  | 59 | 
|  | 60     if (std::is_pointer<T>() && std::is_class<typename std::remove_pointer<T>::t
     ype>()) | 
|  | 61       return TypeCategory::CLASS_PTR; | 
|  | 62 | 
|  | 63     return TypeCategory::UNKNOWN; | 
|  | 64   } | 
|  | 65 | 
|  | 66   TYPEID pointer_type() const | 
|  | 67   { | 
|  | 68     if (std::is_pointer<T>()) | 
|  | 69       return TypeInfo<typename std::remove_pointer<T>::type>(); | 
|  | 70     else | 
|  | 71       return nullptr; | 
|  | 72   } | 
|  | 73 }; | 
|  | 74 | 
|  | 75 template<typename T> | 
|  | 76 char TypeInfo<T>::c; | 
|  | 77 | 
|  | 78 struct FunctionInfo | 
|  | 79 { | 
|  | 80   TypeCategory returnType; | 
|  | 81   TYPEID pointerType; | 
|  | 82   std::vector<TypeCategory> args; | 
|  | 83   bool instance_function; | 
|  | 84   int effectiveArgs; | 
|  | 85   TypeCategory effectiveReturnType; | 
|  | 86   char name[1024]; | 
|  | 87 | 
|  | 88   FunctionInfo() | 
|  | 89   { | 
|  | 90     name[0] = 0; | 
|  | 91   } | 
|  | 92 | 
|  | 93   FunctionInfo(TypeCategory returnType, TYPEID pointerType, | 
|  | 94       std::initializer_list<TypeCategory> argTypes, bool instance_function, | 
|  | 95       void* function) | 
|  | 96       : returnType(returnType), pointerType(pointerType), | 
|  | 97         instance_function(instance_function) | 
|  | 98   { | 
|  | 99     name[0] = 0; | 
|  | 100     if (!*reinterpret_cast<int*>(function)) | 
|  | 101       return; | 
|  | 102 | 
|  | 103     for (auto it = argTypes.begin(); it != argTypes.end(); ++it) | 
|  | 104     { | 
|  | 105       if (*it != TypeCategory::INT && *it != TypeCategory::STRING_REF && | 
|  | 106           *it != TypeCategory::CLASS_PTR) | 
|  | 107       { | 
|  | 108         throw std::runtime_error("Unexpected function argument type"); | 
|  | 109       } | 
|  | 110       args.push_back(*it); | 
|  | 111     } | 
|  | 112 | 
|  | 113     if (returnType != TypeCategory::VOID && returnType != TypeCategory::INT && | 
|  | 114         returnType != TypeCategory::DEPENDENT_STRING && | 
|  | 115         returnType != TypeCategory::OWNED_STRING && | 
|  | 116         returnType != TypeCategory::CLASS_PTR) | 
|  | 117     { | 
|  | 118       throw std::runtime_error("Unexpected function return type"); | 
|  | 119     } | 
|  | 120 | 
|  | 121     effectiveArgs = args.size(); | 
|  | 122     effectiveReturnType = returnType; | 
|  | 123     if (instance_function) | 
|  | 124       effectiveArgs++; | 
|  | 125 | 
|  | 126     if (returnType == TypeCategory::DEPENDENT_STRING || | 
|  | 127         returnType == TypeCategory::OWNED_STRING) | 
|  | 128     { | 
|  | 129       effectiveArgs++; | 
|  | 130       effectiveReturnType = TypeCategory::VOID; | 
|  | 131     } | 
|  | 132 | 
|  | 133     get_function_name(function, effectiveArgs, | 
|  | 134         effectiveReturnType == TypeCategory::VOID); | 
|  | 135   } | 
|  | 136 | 
|  | 137   template<typename ReturnType, typename... Args> | 
|  | 138   FunctionInfo(ReturnType (*function)(Args...)) | 
|  | 139       : FunctionInfo(TypeInfo<ReturnType>(), | 
|  | 140         TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, false, | 
|  | 141         &function) | 
|  | 142   { | 
|  | 143   } | 
|  | 144 | 
|  | 145   template<typename ClassType, typename ReturnType, typename... Args> | 
|  | 146   FunctionInfo(ReturnType (ClassType::*function)(Args...)) | 
|  | 147       : FunctionInfo(TypeInfo<ReturnType>(), | 
|  | 148         TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, | 
|  | 149         &function) | 
|  | 150   { | 
|  | 151   } | 
|  | 152 | 
|  | 153   template<typename ClassType, typename ReturnType, typename... Args> | 
|  | 154   FunctionInfo(ReturnType (ClassType::*function)(Args...) const) | 
|  | 155       : FunctionInfo(TypeInfo<ReturnType>(), | 
|  | 156         TypeInfo<ReturnType>().pointer_type(), { TypeInfo<Args>()... }, true, | 
|  | 157         &function) | 
|  | 158   { | 
|  | 159   } | 
|  | 160 | 
|  | 161   bool empty() const | 
|  | 162   { | 
|  | 163     return name[0] == 0; | 
|  | 164   } | 
|  | 165 | 
|  | 166   void get_function_name(void* ptr, int numArgs, bool voidResult) | 
|  | 167   { | 
|  | 168     // This is a hack, C++ won't let us get the mangled function name. JavaScrip
     t | 
|  | 169     // is more dynamic so we pass the pointer to our function there. With that | 
|  | 170     // and the function signature we can call the function - with intentionally | 
|  | 171     // invalid parameters so that we will cause a segmentation fault (pointers | 
|  | 172     // cannot be negative). Sometimes the function we are calling will also be | 
|  | 173     // missing from the build. The result is the same: abort() is called. By | 
|  | 174     // replacing abort() we get access to the call stack and search it for the | 
|  | 175     // name of our function. | 
|  | 176 | 
|  | 177     EM_ASM_ARGS({ | 
|  | 178       var signature = $3 ? "v" : "i"; | 
|  | 179       var args = []; | 
|  | 180       for (var i = 0; i < $2; i++) | 
|  | 181       { | 
|  | 182         signature += "i"; | 
|  | 183         args.push(-10000); | 
|  | 184       } | 
|  | 185 | 
|  | 186       var oldPrintErr = Module.printErr; | 
|  | 187       var oldAbort = abort; | 
|  | 188       Module.printErr = function(){}; | 
|  | 189       abort = function() | 
|  | 190       { | 
|  | 191         var stack = []; | 
|  | 192         for (var f = arguments.callee.caller; f; f = f.caller) | 
|  | 193         { | 
|  | 194           if (f.name) | 
|  | 195           { | 
|  | 196             if (f.name.indexOf("dynCall") == 0) | 
|  | 197               break; | 
|  | 198             else | 
|  | 199               stack.push(f.name); | 
|  | 200           } | 
|  | 201         } | 
|  | 202 | 
|  | 203         result = stack[stack.length - 1]; | 
|  | 204         if (result && result.indexOf("__wrapper") >= 0) | 
|  | 205           result = stack[stack.length - 2]; | 
|  | 206         throw result; | 
|  | 207       }; | 
|  | 208 | 
|  | 209       try | 
|  | 210       { | 
|  | 211         Runtime.dynCall(signature, HEAP32[$1 >> 2], args); | 
|  | 212       } | 
|  | 213       catch(e) | 
|  | 214       { | 
|  | 215         Module.stringToAscii(e, $0); | 
|  | 216       } | 
|  | 217       finally | 
|  | 218       { | 
|  | 219         Module.printErr = oldPrintErr; | 
|  | 220         abort = oldAbort; | 
|  | 221       } | 
|  | 222     }, name, ptr, numArgs, voidResult); | 
|  | 223   } | 
|  | 224 }; | 
|  | 225 | 
|  | 226 class NoBaseClass | 
|  | 227 { | 
|  | 228 }; | 
|  | 229 | 
|  | 230 struct PropertyInfo | 
|  | 231 { | 
|  | 232   std::string name; | 
|  | 233   FunctionInfo getter; | 
|  | 234   FunctionInfo setter; | 
|  | 235   std::string jsValue; | 
|  | 236 }; | 
|  | 237 | 
|  | 238 struct MethodInfo | 
|  | 239 { | 
|  | 240   std::string name; | 
|  | 241   FunctionInfo call; | 
|  | 242 }; | 
|  | 243 | 
|  | 244 struct DifferentiatorInfo | 
|  | 245 { | 
|  | 246   FunctionInfo call; | 
|  | 247   std::vector<std::pair<int,std::string>> mapping; | 
|  | 248 }; | 
|  | 249 | 
|  | 250 struct ClassInfo | 
|  | 251 { | 
|  | 252   ClassInfo* baseClass; | 
|  | 253   std::string name; | 
|  | 254   std::vector<PropertyInfo> properties; | 
|  | 255   std::vector<MethodInfo> methods; | 
|  | 256   std::vector<FunctionInfo> initializers; | 
|  | 257   DifferentiatorInfo subclass_differentiator; | 
|  | 258 }; | 
|  | 259 | 
|  | 260 std::map<TYPEID,ClassInfo> classes; | 
|  | 261 | 
|  | 262 void register_class(const char* name, TYPEID classID, TYPEID baseClassID) | 
|  | 263 { | 
|  | 264   auto it = classes.find(classID); | 
|  | 265   if (it != classes.end()) | 
|  | 266     throw std::runtime_error(std::string("Duplicate definition for class ") + na
     me); | 
|  | 267 | 
|  | 268   ClassInfo* baseClass = nullptr; | 
|  | 269   if (baseClassID != TypeInfo<NoBaseClass>()) | 
|  | 270   { | 
|  | 271     it = classes.find(baseClassID); | 
|  | 272     if (it == classes.end()) | 
|  | 273       throw std::runtime_error(std::string("Unknown base class defined for class
      ") + name); | 
|  | 274     baseClass = &(it->second); | 
|  | 275   } | 
|  | 276 | 
|  | 277   ClassInfo classInfo; | 
|  | 278   classInfo.baseClass = baseClass; | 
|  | 279   classInfo.name = name; | 
|  | 280   classes[classID] = classInfo; | 
|  | 281 } | 
|  | 282 | 
|  | 283 void register_property(TYPEID classID, const char* name, | 
|  | 284     const FunctionInfo& getter, const FunctionInfo& setter, | 
|  | 285     const char* jsValue = "") | 
|  | 286 { | 
|  | 287   auto it = classes.find(classID); | 
|  | 288   if (it == classes.end()) | 
|  | 289     throw std::runtime_error(std::string("Property defined on unknown class: ") 
     + name); | 
|  | 290 | 
|  | 291   PropertyInfo propertyInfo; | 
|  | 292   propertyInfo.name = name; | 
|  | 293   propertyInfo.getter = getter; | 
|  | 294   propertyInfo.setter = setter; | 
|  | 295   propertyInfo.jsValue = jsValue; | 
|  | 296   it->second.properties.push_back(propertyInfo); | 
|  | 297 } | 
|  | 298 | 
|  | 299 void register_method(TYPEID classID, const char* name, | 
|  | 300     const FunctionInfo& call) | 
|  | 301 { | 
|  | 302   auto it = classes.find(classID); | 
|  | 303   if (it == classes.end()) | 
|  | 304     throw std::runtime_error(std::string("Method defined on unknown class: ") + 
     name); | 
|  | 305 | 
|  | 306   MethodInfo methodInfo; | 
|  | 307   methodInfo.name = name; | 
|  | 308   methodInfo.call = call; | 
|  | 309   it->second.methods.push_back(methodInfo); | 
|  | 310 } | 
|  | 311 | 
|  | 312 void register_initializer(TYPEID classID, const FunctionInfo& call) | 
|  | 313 { | 
|  | 314   auto it = classes.find(classID); | 
|  | 315   if (it == classes.end()) | 
|  | 316     throw std::runtime_error("Initializer defined on unknown class"); | 
|  | 317 | 
|  | 318   it->second.initializers.push_back(call); | 
|  | 319 } | 
|  | 320 | 
|  | 321 void register_differentiator(TYPEID classID, const FunctionInfo& call, | 
|  | 322     std::vector<std::pair<int,std::string>>& mapping) | 
|  | 323 { | 
|  | 324   auto it = classes.find(classID); | 
|  | 325   if (it == classes.end()) | 
|  | 326     throw std::runtime_error("Subclass differentiator defined on unknown class")
     ; | 
|  | 327 | 
|  | 328   if (!it->second.subclass_differentiator.call.empty()) | 
|  | 329     throw std::runtime_error("More than one subclass differentiator defined for 
     class " + it->second.name); | 
|  | 330 | 
|  | 331   DifferentiatorInfo differentiatorInfo; | 
|  | 332   differentiatorInfo.call = call; | 
|  | 333   differentiatorInfo.mapping = mapping; | 
|  | 334   it->second.subclass_differentiator = differentiatorInfo; | 
|  | 335 } | 
|  | 336 | 
|  | 337 const std::string generateCall(const FunctionInfo& call, | 
|  | 338     std::vector<std::string>& params) | 
|  | 339 { | 
|  | 340   if (call.returnType == TypeCategory::DEPENDENT_STRING || | 
|  | 341       call.returnType == TypeCategory::OWNED_STRING) | 
|  | 342   { | 
|  | 343     params.insert(params.begin(), "string"); | 
|  | 344   } | 
|  | 345 | 
|  | 346   std::string call_str(call.name); | 
|  | 347   call_str += "("; | 
|  | 348   for (int i = 0; i < params.size(); i++) | 
|  | 349   { | 
|  | 350     if (i > 0) | 
|  | 351       call_str += ", "; | 
|  | 352     call_str += params[i]; | 
|  | 353   } | 
|  | 354   call_str += ")"; | 
|  | 355 | 
|  | 356   if (call.returnType == TypeCategory::VOID) | 
|  | 357     return "  " + call_str + ";\n"; | 
|  | 358   else if (call.returnType == TypeCategory::INT) | 
|  | 359     return "  var result = " + call_str + ";\n"; | 
|  | 360   else if (call.returnType == TypeCategory::DEPENDENT_STRING || | 
|  | 361       call.returnType == TypeCategory::OWNED_STRING) | 
|  | 362   { | 
|  | 363     std::string result; | 
|  | 364     result += "  var string = createString();\n"; | 
|  | 365     result += "  " + call_str + ";\n"; | 
|  | 366     result += "  var result = getStringData(string);\n"; | 
|  | 367     if (call.returnType == TypeCategory::OWNED_STRING) | 
|  | 368       result += "  Module._DestroyString(string);\n"; | 
|  | 369     return result; | 
|  | 370   } | 
|  | 371   else if (call.returnType == TypeCategory::CLASS_PTR) | 
|  | 372   { | 
|  | 373     std::string result; | 
|  | 374     result += "  var result = " + call_str + ";\n"; | 
|  | 375     result += "  if (result)\n"; | 
|  | 376     result += "  {\n"; | 
|  | 377     result += "    Module._AddRef(result);\n"; | 
|  | 378 | 
|  | 379     auto it = classes.find(call.pointerType); | 
|  | 380     if (it == classes.end()) | 
|  | 381       throw std::runtime_error("Function " + std::string(call.name) + " returns 
     pointer to unknown class"); | 
|  | 382 | 
|  | 383     const ClassInfo& cls = it->second; | 
|  | 384     if (cls.subclass_differentiator.call.empty()) | 
|  | 385       result += "    result = " + cls.name + "(result);\n"; | 
|  | 386     else | 
|  | 387     { | 
|  | 388       result += "    var type = " + | 
|  | 389           std::string(cls.subclass_differentiator.call.name) + "(result);\n"; | 
|  | 390       result += "    if (type in " + cls.name + "_mapping)\n"; | 
|  | 391       result += "      result = new (exports[" + cls.name + "_mapping[type]])(re
     sult);\n"; | 
|  | 392       result += "    else\n"; | 
|  | 393       result += "      throw new Error('Unexpected " + cls.name + " type: ' + ty
     pe);\n"; | 
|  | 394     } | 
|  | 395 | 
|  | 396     result += "  }\n"; | 
|  | 397     return result; | 
|  | 398   } | 
|  | 399   else | 
|  | 400     throw std::runtime_error("Unexpected return type for " + std::string(call.na
     me)); | 
|  | 401 } | 
|  | 402 | 
|  | 403 const std::string wrapCall(const FunctionInfo& call) | 
|  | 404 { | 
|  | 405   char buffer[20]; | 
|  | 406   bool hasStringArgs = false; | 
|  | 407   std::vector<std::string> params; | 
|  | 408   std::string prefix = "function("; | 
|  | 409   for (int i = 0; i < call.args.size(); i++) | 
|  | 410   { | 
|  | 411     sprintf(buffer, "arg%i", i); | 
|  | 412     if (i > 0) | 
|  | 413       prefix += ", "; | 
|  | 414     prefix += buffer; | 
|  | 415 | 
|  | 416 | 
|  | 417     if (call.args[i] == TypeCategory::STRING_REF) | 
|  | 418     { | 
|  | 419       hasStringArgs = true; | 
|  | 420       params.push_back(std::string("createString(") + buffer + ")"); | 
|  | 421     } | 
|  | 422     else | 
|  | 423       params.push_back(buffer); | 
|  | 424   } | 
|  | 425   prefix += ")\n{\n"; | 
|  | 426 | 
|  | 427   std::string suffix = "}"; | 
|  | 428   if (call.returnType != TypeCategory::VOID) | 
|  | 429     suffix = "  return result;\n" + suffix; | 
|  | 430 | 
|  | 431   if (call.returnType == TypeCategory::DEPENDENT_STRING || | 
|  | 432       call.returnType == TypeCategory::OWNED_STRING || hasStringArgs) | 
|  | 433   { | 
|  | 434     prefix += "  var sp = Runtime.stackSave();\n"; | 
|  | 435     suffix = "  Runtime.stackRestore(sp);\n" + suffix; | 
|  | 436   } | 
|  | 437 | 
|  | 438   if (call.instance_function) | 
|  | 439     params.insert(params.begin(), "this._pointer"); | 
|  | 440 | 
|  | 441   return prefix + generateCall(call, params) + suffix; | 
|  | 442 } | 
|  | 443 | 
|  | 444 const std::string generatePropertyDescriptor(const PropertyInfo& property) | 
|  | 445 { | 
|  | 446   if (!property.jsValue.empty()) | 
|  | 447     return "value: " + property.jsValue; | 
|  | 448 | 
|  | 449   std::string result("get: " + wrapCall(property.getter)); | 
|  | 450   if (!property.setter.empty()) | 
|  | 451     result += ", set: " + wrapCall(property.setter); | 
|  | 452   return result; | 
|  | 453 } | 
|  | 454 | 
|  | 455 void printHelpers() | 
|  | 456 { | 
|  | 457   printf("var sizeofString = %i\n", sizeof(String)); | 
|  | 458 | 
|  | 459   puts(R"( | 
|  | 460 function copyString(str, buffer) | 
|  | 461 { | 
|  | 462   var length = str.length; | 
|  | 463   for (var i = 0, pointer = (buffer >> 1); i < length; i++, pointer++) | 
|  | 464     HEAP16[pointer] = str.charCodeAt(i); | 
|  | 465   return length; | 
|  | 466 } | 
|  | 467 | 
|  | 468 function createString(str) | 
|  | 469 { | 
|  | 470   var length = 0; | 
|  | 471   var buffer = 0; | 
|  | 472   if (str) | 
|  | 473   { | 
|  | 474     buffer = Runtime.stackAlloc(str.length * 2); | 
|  | 475     length = copyString(str, buffer); | 
|  | 476   } | 
|  | 477 | 
|  | 478   var result = Module.Runtime.stackAlloc(sizeofString); | 
|  | 479   Module._InitString(result, buffer, length); | 
|  | 480   return result; | 
|  | 481 } | 
|  | 482 | 
|  | 483 function getStringData(str) | 
|  | 484 { | 
|  | 485   var length = Module._GetStringLength(str); | 
|  | 486   var pointer = Module._GetStringData(str) >> 1; | 
|  | 487   return String.fromCharCode.apply(String, HEAP16.slice(pointer, pointer + lengt
     h)); | 
|  | 488 } | 
|  | 489 | 
|  | 490 function createClass(superclass) | 
|  | 491 { | 
|  | 492   var result = function(pointer) | 
|  | 493   { | 
|  | 494     this._pointer = pointer; | 
|  | 495   }; | 
|  | 496   if (superclass) | 
|  | 497     result.prototype = Object.create(superclass.prototype); | 
|  | 498   result.prototype.delete = function() | 
|  | 499   { | 
|  | 500     Module._ReleaseRef(this._pointer); | 
|  | 501   }; | 
|  | 502   return result; | 
|  | 503 })"); | 
|  | 504 } | 
|  | 505 | 
|  | 506 void printClass(ClassInfo& cls) | 
|  | 507 { | 
|  | 508   DifferentiatorInfo differentiator = cls.subclass_differentiator; | 
|  | 509   if (!differentiator.call.empty()) | 
|  | 510   { | 
|  | 511     printf("var %s_mapping = \n", cls.name.c_str()); | 
|  | 512     puts("{"); | 
|  | 513     for (auto it = differentiator.mapping.begin(); it != differentiator.mapping.
     end(); ++it) | 
|  | 514       printf("  %i: '%s',\n", it->first, it->second.c_str()); | 
|  | 515     puts("};"); | 
|  | 516   } | 
|  | 517 | 
|  | 518   printf("exports.%s = createClass(%s);\n", cls.name.c_str(), | 
|  | 519       (cls.baseClass ? ("exports." + cls.baseClass->name).c_str() : "")); | 
|  | 520 | 
|  | 521   for (auto it = cls.properties.begin(); it != cls.properties.end(); ++it) | 
|  | 522   { | 
|  | 523     printf("Object.defineProperty(exports.%s.prototype, '%s', {%s});\n", | 
|  | 524         cls.name.c_str(), it->name.c_str(), | 
|  | 525         generatePropertyDescriptor(*it).c_str()); | 
|  | 526   } | 
|  | 527 | 
|  | 528   for (auto it = cls.methods.begin(); it != cls.methods.end(); ++it) | 
|  | 529   { | 
|  | 530     std::string obj("exports." + cls.name); | 
|  | 531     if (it->call.instance_function) | 
|  | 532       obj += ".prototype"; | 
|  | 533     printf("%s.%s = %s;\n", obj.c_str(), it->name.c_str(), | 
|  | 534         wrapCall(it->call).c_str()); | 
|  | 535   } | 
|  | 536 | 
|  | 537   for (auto it = cls.initializers.begin(); it != cls.initializers.end(); ++it) | 
|  | 538     printf("%s()\n", it->name); | 
|  | 539 } | 
|  | 540 | 
|  | 541 void printBindings() | 
|  | 542 { | 
|  | 543   printHelpers(); | 
|  | 544 | 
|  | 545   for (auto it = classes.begin(); it != classes.end(); ++it) | 
|  | 546     printClass(it->second); | 
|  | 547 } | 
|  | 548 | 
|  | 549 #if defined(PRINT_BINDINGS) | 
|  | 550   // Bindings generation step: collect bindings information and print | 
|  | 551   // corresponding JS code. | 
|  | 552   #define EMSCRIPTEN_BINDINGS \ | 
|  | 553       static struct BindingsInitializer {\ | 
|  | 554           BindingsInitializer();\ | 
|  | 555           BindingsInitializer(bool dummy)\ | 
|  | 556           {\ | 
|  | 557             try\ | 
|  | 558             {\ | 
|  | 559               BindingsInitializer();\ | 
|  | 560               printBindings();\ | 
|  | 561             }\ | 
|  | 562             catch (const std::exception& e)\ | 
|  | 563             {\ | 
|  | 564               EM_ASM_ARGS(\ | 
|  | 565                 console.error("Error occurred generating JavaScript bindings: " 
     +\ | 
|  | 566                     Module.AsciiToString($0)), e.what()\ | 
|  | 567               );\ | 
|  | 568               abort();\ | 
|  | 569             }\ | 
|  | 570           }\ | 
|  | 571       } BindingsInitializer_instance(true);\ | 
|  | 572       BindingsInitializer::BindingsInitializer() | 
|  | 573 #else | 
|  | 574   // Actual compilation step: ignore bindings information but define some | 
|  | 575   // exported helper functions necessary for the bindings. | 
|  | 576   #define EMSCRIPTEN_BINDINGS \ | 
|  | 577       extern "C"\ | 
|  | 578       {\ | 
|  | 579         void EMSCRIPTEN_KEEPALIVE InitString(DependentString* str,\ | 
|  | 580             String::value_type* data, String::size_type len)\ | 
|  | 581         {\ | 
|  | 582           /* String is already allocated on stack, we merely need to call*/\ | 
|  | 583           /* constructor.*/\ | 
|  | 584           new (str) DependentString(data, len);\ | 
|  | 585         }\ | 
|  | 586         void EMSCRIPTEN_KEEPALIVE DestroyString(OwnedString* str)\ | 
|  | 587         {\ | 
|  | 588           /* Stack memory will be freed automatically, we need to call*/\ | 
|  | 589           /* destructor explicitly however.*/\ | 
|  | 590           str->~OwnedString();\ | 
|  | 591         }\ | 
|  | 592         String::size_type EMSCRIPTEN_KEEPALIVE GetStringLength(\ | 
|  | 593             const String& str)\ | 
|  | 594         {\ | 
|  | 595           return str.length();\ | 
|  | 596         }\ | 
|  | 597         const String::value_type* EMSCRIPTEN_KEEPALIVE GetStringData(\ | 
|  | 598             const String& str)\ | 
|  | 599         {\ | 
|  | 600           return str.data();\ | 
|  | 601         }\ | 
|  | 602         void EMSCRIPTEN_KEEPALIVE AddRef(ref_counted* ptr)\ | 
|  | 603         {\ | 
|  | 604           ptr->AddRef();\ | 
|  | 605         }\ | 
|  | 606         void EMSCRIPTEN_KEEPALIVE ReleaseRef(ref_counted* ptr)\ | 
|  | 607         {\ | 
|  | 608           ptr->ReleaseRef();\ | 
|  | 609         }\ | 
|  | 610       }\ | 
|  | 611       void BindingsInitializer_dummy() | 
|  | 612 #endif | 
|  | 613 | 
|  | 614 template<typename ClassType, typename BaseClass = NoBaseClass, | 
|  | 615     typename std::enable_if<std::is_base_of<ref_counted, ClassType>::value>::typ
     e* = nullptr> | 
|  | 616 class class_ | 
|  | 617 { | 
|  | 618 public: | 
|  | 619   class_(const char* name) | 
|  | 620   { | 
|  | 621     register_class(name, TypeInfo<ClassType>(), TypeInfo<BaseClass>()); | 
|  | 622   } | 
|  | 623 | 
|  | 624   template<typename FieldType> | 
|  | 625   const class_& property(const char* name, | 
|  | 626       FieldType (ClassType::*getter)() const, | 
|  | 627       void (ClassType::*setter)(FieldType) = 0) const | 
|  | 628   { | 
|  | 629     register_property(TypeInfo<ClassType>(), name, getter, setter); | 
|  | 630     return *this; | 
|  | 631   } | 
|  | 632 | 
|  | 633   const class_& class_property(const char* name, | 
|  | 634       const char* jsValue) const | 
|  | 635   { | 
|  | 636     register_property(TypeInfo<ClassType>(), name, FunctionInfo(), | 
|  | 637         FunctionInfo(), jsValue); | 
|  | 638     return *this; | 
|  | 639   } | 
|  | 640 | 
|  | 641   template<typename ReturnType, typename... Args> | 
|  | 642   const class_& function(const char* name, ReturnType (ClassType::*method)(Args.
     ..)) const | 
|  | 643   { | 
|  | 644     register_method(TypeInfo<ClassType>(), name, method); | 
|  | 645     return *this; | 
|  | 646   } | 
|  | 647 | 
|  | 648   template<typename ReturnType, typename... Args> | 
|  | 649   const class_& function(const char* name, ReturnType (ClassType::*method)(Args.
     ..) const) const | 
|  | 650   { | 
|  | 651     register_method(TypeInfo<ClassType>(), name, method); | 
|  | 652     return *this; | 
|  | 653   } | 
|  | 654 | 
|  | 655   template<typename ReturnType, typename... Args> | 
|  | 656   const class_& class_function(const char* name, ReturnType (*method)(Args...)) 
     const | 
|  | 657   { | 
|  | 658     register_method(TypeInfo<ClassType>(), name, method); | 
|  | 659     return *this; | 
|  | 660   } | 
|  | 661 | 
|  | 662   const class_& class_initializer(void (*function)()) const | 
|  | 663   { | 
|  | 664     register_initializer(TypeInfo<ClassType>(), function); | 
|  | 665     return *this; | 
|  | 666   } | 
|  | 667 | 
|  | 668   template<typename ReturnType, | 
|  | 669       typename std::enable_if<std::is_convertible<ReturnType, int>::value>::type
     * = nullptr> | 
|  | 670   const class_& subclass_differentiator(ReturnType (*function)(ClassType*), | 
|  | 671       std::initializer_list<std::pair<ReturnType,const char*>> list) const | 
|  | 672   { | 
|  | 673     std::vector<std::pair<int,std::string>> mapping; | 
|  | 674     for (auto it = list.begin(); it != list.end(); ++it) | 
|  | 675       mapping.push_back(std::pair<int,std::string>(it->first, it->second)); | 
|  | 676 | 
|  | 677     register_differentiator(TypeInfo<ClassType>(), function, mapping); | 
|  | 678     return *this; | 
|  | 679   } | 
|  | 680 }; | 
| OLD | NEW | 
|---|