| Index: compiled/bindings/generator.cpp | 
| =================================================================== | 
| --- a/compiled/bindings/generator.cpp | 
| +++ b/compiled/bindings/generator.cpp | 
| @@ -19,16 +19,44 @@ | 
|  | 
| #include <emscripten.h> | 
|  | 
| #include "generator.h" | 
|  | 
| namespace | 
| { | 
| std::vector<bindings_internal::ClassInfo> classes; | 
| +  std::vector<bindings_internal::NamespaceInfo> namespaces; | 
| + | 
| +  void printProperties(const bindings_internal::PropertyList& properties) | 
| +  { | 
| +    for (const auto& property : properties) | 
| +    { | 
| +      if (property.jsValue.empty()) | 
| +      { | 
| +        printf("get %s%s,\n", property.name.c_str(), | 
| +               wrapCall(property.getter, false).c_str()); | 
| +        if (!property.setter.empty()) | 
| +        { | 
| +          printf("set %s%s,\n", property.name.c_str(), | 
| +                 wrapCall(property.setter, false).c_str()); | 
| +        } | 
| +      } | 
| +      else | 
| +        printf("%s: %s,\n", property.name.c_str(), property.jsValue.c_str()); | 
| +    } | 
| +  } | 
| + | 
| +  void printMethods(const bindings_internal::MethodList& methods, | 
| +                    bool instanceOnly = true) | 
| +  { | 
| +    for (const auto& method : methods) | 
| +      if (!instanceOnly || method.call.instance_function) | 
| +        printf("%s: %s,\n", method.name.c_str(), wrapCall(method.call).c_str()); | 
| +  } | 
| } | 
|  | 
| namespace bindings_internal | 
| { | 
| FunctionInfo::FunctionInfo() | 
| { | 
| name[0] = '\0'; | 
| } | 
| @@ -250,16 +278,61 @@ namespace bindings_internal | 
| throw std::runtime_error("More than one subclass differentiator defined for class " + classInfo->name); | 
|  | 
| DifferentiatorInfo differentiatorInfo; | 
| differentiatorInfo.offset = offset; | 
| differentiatorInfo.mapping = mapping; | 
| classInfo->subclass_differentiator = differentiatorInfo; | 
| } | 
|  | 
| +  NamespaceInfo* find_namespace(const char* namespaceName) | 
| +  { | 
| +    for (auto& namespaceInfo : namespaces) | 
| +      if (namespaceInfo.name == namespaceName) | 
| +        return &namespaceInfo; | 
| +    return nullptr; | 
| +  } | 
| + | 
| +  void register_namespace(const char* name) | 
| +  { | 
| +    if (find_namespace(name)) | 
| +      throw std::runtime_error(std::string("Duplicate definition for namespace ") + name); | 
| + | 
| +    NamespaceInfo namespaceInfo; | 
| +    namespaceInfo.name = name; | 
| +    namespaces.push_back(namespaceInfo); | 
| +  } | 
| + | 
| +  void register_namespace_property(const char* namespaceName, const char* name, | 
| +      const FunctionInfo& getter, const FunctionInfo& setter) | 
| +  { | 
| +    NamespaceInfo* namespaceInfo = find_namespace(namespaceName); | 
| +    if (!namespaceInfo) | 
| +      throw std::runtime_error(std::string("Property defined on unknown namespace: ") + name); | 
| + | 
| +    PropertyInfo propertyInfo; | 
| +    propertyInfo.name = name; | 
| +    propertyInfo.getter = getter; | 
| +    propertyInfo.setter = setter; | 
| +    namespaceInfo->properties.push_back(propertyInfo); | 
| +  } | 
| + | 
| +  void register_namespace_method(const char* namespaceName, const char* name, | 
| +      const FunctionInfo& call) | 
| +  { | 
| +    NamespaceInfo* namespaceInfo = find_namespace(namespaceName); | 
| +    if (!namespaceInfo) | 
| +      throw std::runtime_error(std::string("Method defined on unknown namespace: ") + name); | 
| + | 
| +    MethodInfo methodInfo; | 
| +    methodInfo.name = name; | 
| +    methodInfo.call = call; | 
| +    namespaceInfo->methods.push_back(methodInfo); | 
| +  } | 
| + | 
| std::string generateCall(const FunctionInfo& call, | 
| std::vector<std::string>& params) | 
| { | 
| if (call.returnType == TypeCategory::DEPENDENT_STRING || | 
| call.returnType == TypeCategory::OWNED_STRING) | 
| { | 
| params.insert(params.begin(), "string"); | 
| } | 
| @@ -343,17 +416,17 @@ namespace bindings_internal | 
| prefix += argName; | 
|  | 
| if (call.args[i] == TypeCategory::STRING_REF) | 
| { | 
| hasStringArgs = true; | 
| params.push_back(std::string("createString(") + argName + ")"); | 
| } | 
| else if (call.args[i] == TypeCategory::CLASS_PTR) | 
| -        params.push_back(argName + "._pointer"); | 
| +        params.push_back(argName + " ? " + argName + "._pointer : 0"); | 
| else if (call.args[i] == TypeCategory::INT64) | 
| { | 
| // 64-bit integers are passed as two integer parameters | 
| params.push_back(argName + " >>> 0"); | 
| params.push_back(argName + " / 0x100000000 >>> 0"); | 
| } | 
| else | 
| params.push_back(argName); | 
| @@ -427,50 +500,29 @@ namespace bindings_internal | 
| return result; | 
| } | 
| )"); | 
| } | 
|  | 
| void printClass(const ClassInfo& cls) | 
| { | 
| // Begin class definition | 
| - | 
| ClassInfo* baseClass = find_class(cls.baseClass); | 
| printf("exports.%s = createClass(%s, %i, {\n", cls.name.c_str(), | 
| (baseClass ? ("exports." + baseClass->name).c_str() : "null"), | 
| cls.ref_counted_offset); | 
|  | 
| // Print prototype members | 
| - | 
| -    for (const auto& property : cls.properties) | 
| -    { | 
| -      if (property.jsValue.empty()) | 
| -      { | 
| -        printf("get %s%s,\n", property.name.c_str(), | 
| -               wrapCall(property.getter, false).c_str()); | 
| -        if (!property.setter.empty()) | 
| -        { | 
| -          printf("set %s%s,\n", property.name.c_str(), | 
| -                 wrapCall(property.setter, false).c_str()); | 
| -        } | 
| -      } | 
| -      else | 
| -        printf("%s: %s,\n", property.name.c_str(), property.jsValue.c_str()); | 
| -    } | 
| - | 
| -    for (const auto& method : cls.methods) | 
| -      if (method.call.instance_function) | 
| -        printf("%s: %s,\n", method.name.c_str(), wrapCall(method.call).c_str()); | 
| +    printProperties(cls.properties); | 
| +    printMethods(cls.methods); | 
|  | 
| // End class definition | 
| - | 
| printf("});\n"); | 
|  | 
| // Print static members | 
| - | 
| DifferentiatorInfo differentiator = cls.subclass_differentiator; | 
| if (differentiator.offset != SIZE_MAX) | 
| { | 
| printf("var %s_mapping = \n", cls.name.c_str()); | 
| puts("{"); | 
| for (const auto& item : differentiator.mapping) | 
| printf("  %i: '%s',\n", item.first, item.second.c_str()); | 
| puts("};"); | 
| @@ -495,17 +547,27 @@ namespace bindings_internal | 
| { | 
| if (!method.call.instance_function) | 
| { | 
| printf("exports.%s.%s = %s;\n", cls.name.c_str(), method.name.c_str(), | 
| wrapCall(method.call).c_str()); | 
| } | 
| } | 
| } | 
| + | 
| +  void printNamespace(const NamespaceInfo& namespaceInfo) | 
| +  { | 
| +    printf("exports.%s = {\n", namespaceInfo.name.c_str()); | 
| +    printProperties(namespaceInfo.properties); | 
| +    printMethods(namespaceInfo.methods, false); | 
| +    puts("};"); | 
| +  } | 
| } | 
|  | 
| void printBindings() | 
| { | 
| bindings_internal::printHelpers(); | 
|  | 
| for (const auto& item : classes) | 
| bindings_internal::printClass(item); | 
| +  for (const auto& item : namespaces) | 
| +    bindings_internal::printNamespace(item); | 
| } | 
|  |