aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChad Austin <chad@imvu.com>2013-03-20 20:15:36 -0700
committerJukka Jylänki <jujjyl@gmail.com>2013-04-12 14:26:32 +0300
commite10ede1e07ee85d9d99bd34eb4ec8a62ae972616 (patch)
tree4bad80cb9e227d265333b979d5e938221c117cf1
parent0a6f5476f19792164e122c27ffca83baa69c1ca3 (diff)
Add sensible error messages when working with classes that depend on unbound types.
-rwxr-xr-xsrc/embind/embind.js172
-rwxr-xr-xsystem/lib/embind/bind.cpp37
2 files changed, 128 insertions, 81 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js
index c27c49b2..ddfc4d43 100755
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -3,6 +3,7 @@
/*global FUNCTION_TABLE, HEAP32, HEAPU8*/
/*global Pointer_stringify*/
/*global __emval_register, _emval_handle_array, __emval_decref*/
+/*global ___getTypeName*/
var InternalError = Module.InternalError = extendError(Error, 'InternalError');
var BindingError = Module.BindingError = extendError(Error, 'BindingError');
@@ -45,6 +46,13 @@ function exposePublicSymbol(name, value) {
Module[name] = value;
}
+function replacePublicSymbol(name, value) {
+ if (!Module.hasOwnProperty(name)) {
+ throwInternalError('Replacing nonexistant public symbol');
+ }
+ Module[name] = value;
+}
+
// from https://github.com/imvu/imvujs/blob/master/src/error.js
function extendError(baseErrorType, errorName) {
var errorClass = createNamedFunction(errorName, function(message) {
@@ -165,7 +173,10 @@ function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverter
}
function getTypeName(type) {
- return Module._embind_getTypeName(type);
+ var ptr = ___getTypeName(type);
+ var rv = Pointer_stringify(ptr);
+ _free(ptr);
+ return rv;
}
function heap32VectorToArray(count, firstElement) {
@@ -317,16 +328,12 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker,
name = Pointer_stringify(name);
rawInvoker = FUNCTION_TABLE[rawInvoker];
- var invoker = function() {
- throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes);
- };
-
exposePublicSymbol(name, function() {
- return invoker.apply(this, arguments);
+ throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes);
});
whenDependentTypesAreResolved([], argTypes, function(argTypes) {
- invoker = makeInvoker(name, argCount, argTypes, rawInvoker, fn);
+ replacePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn));
return [];
});
}
@@ -800,6 +807,11 @@ function __embind_register_class(
downcast = FUNCTION_TABLE[downcast];
var legalFunctionName = makeLegalFunctionName(name);
+ exposePublicSymbol(legalFunctionName, function() {
+ // this code cannot run if baseClassRawType is zero
+ throwUnboundTypeError('Cannot construct ' + name + ' due to unbound types', [baseClassRawType]);
+ });
+
whenDependentTypesAreResolved(
[rawType, rawPointerType, rawConstPointerType],
baseClassRawType ? [baseClassRawType] : [],
@@ -868,7 +880,7 @@ function __embind_register_class(
constPointerType: constPointerConverter
};
- exposePublicSymbol(legalFunctionName, constructor);
+ replacePublicSymbol(legalFunctionName, constructor);
return [referenceConverter, pointerConverter, constPointerConverter];
}
@@ -885,26 +897,33 @@ function __embind_register_class_constructor(
var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
invoker = FUNCTION_TABLE[invoker];
- whenDependentTypesAreResolved([], [rawClassType].concat(rawArgTypes), function(argTypes) {
- var classType = argTypes[0];
- argTypes = argTypes.slice(1);
+ whenDependentTypesAreResolved([], [rawClassType], function(classType) {
+ classType = classType[0];
var humanName = 'constructor ' + classType.name;
- classType.registeredClass.constructor_body = function() {
- if (arguments.length !== argCount - 1) {
- throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1));
- }
- var destructors = [];
- var args = new Array(argCount);
- args[0] = rawConstructor;
- for (var i = 1; i < argCount; ++i) {
- args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]);
- }
-
- var ptr = invoker.apply(null, args);
- runDestructors(destructors);
- return argTypes[0].fromWireType(ptr);
+ classType.registeredClass.constructor_body = function() {
+ throwUnboundTypeError('Cannot construct ' + classType.name + ' due to unbound types', rawArgTypes);
};
+
+ whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) {
+ classType.registeredClass.constructor_body = function() {
+ if (arguments.length !== argCount - 1) {
+ throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1));
+ }
+ var destructors = [];
+ var args = new Array(argCount);
+ args[0] = rawConstructor;
+ for (var i = 1; i < argCount; ++i) {
+ args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]);
+ }
+
+ var ptr = invoker.apply(null, args);
+ runDestructors(destructors);
+
+ return argTypes[0].fromWireType(ptr);
+ };
+ return [];
+ });
return [];
});
}
@@ -961,32 +980,39 @@ function __embind_register_class_function(
rawInvoker = FUNCTION_TABLE[rawInvoker];
memberFunction = copyMemberPointer(memberFunction, memberFunctionSize);
- whenDependentTypesAreResolved([], [rawClassType].concat(rawArgTypes), function(argTypes) {
- var classType = argTypes[0];
- argTypes = argTypes.slice(1);
+ whenDependentTypesAreResolved([], [rawClassType], function(classType) {
+ classType = classType[0];
var humanName = classType.name + '.' + methodName;
+
classType.registeredClass.instancePrototype[methodName] = function() {
- if (arguments.length !== argCount - 1) {
- throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1));
- }
+ throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes);
+ };
- var ptr = validateThis(this, classType, humanName);
- if (!isConst && this.$$.ptrType.isConst) {
- throwBindingError('Cannot call non-const method ' + humanName + ' on const reference');
- }
+ whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) {
+ classType.registeredClass.instancePrototype[methodName] = function() {
+ if (arguments.length !== argCount - 1) {
+ throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1));
+ }
- var destructors = [];
- var args = new Array(argCount + 1);
- args[0] = ptr;
- args[1] = memberFunction;
- for (var i = 1; i < argCount; ++i) {
- args[i + 1] = argTypes[i].toWireType(destructors, arguments[i - 1]);
- }
- var rv = rawInvoker.apply(null, args);
- rv = argTypes[0].fromWireType(rv);
- runDestructors(destructors);
- return rv;
- };
+ var ptr = validateThis(this, classType, humanName);
+ if (!isConst && this.$$.ptrType.isConst) {
+ throwBindingError('Cannot call non-const method ' + humanName + ' on const reference');
+ }
+
+ var destructors = [];
+ var args = new Array(argCount + 1);
+ args[0] = ptr;
+ args[1] = memberFunction;
+ for (var i = 1; i < argCount; ++i) {
+ args[i + 1] = argTypes[i].toWireType(destructors, arguments[i - 1]);
+ }
+ var rv = rawInvoker.apply(null, args);
+ rv = argTypes[0].fromWireType(rv);
+ runDestructors(destructors);
+ return rv;
+ };
+ return [];
+ });
return [];
});
}
@@ -999,13 +1025,21 @@ function __embind_register_class_class_function(
rawInvoker,
fn
) {
- var classType = requireRegisteredType(rawClassType, 'class');
var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
methodName = Pointer_stringify(methodName);
rawInvoker = FUNCTION_TABLE[rawInvoker];
- whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) {
+ whenDependentTypesAreResolved([], [rawClassType], function(classType) {
+ classType = classType[0];
var humanName = classType.name + '.' + methodName;
- classType.registeredClass.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn);
+
+ classType.registeredClass.constructor[methodName] = function() {
+ throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes);
+ };
+
+ whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) {
+ classType.registeredClass.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn);
+ return [];
+ });
return [];
});
}
@@ -1023,23 +1057,39 @@ function __embind_register_class_property(
getter = FUNCTION_TABLE[getter];
setter = FUNCTION_TABLE[setter];
memberPointer = copyMemberPointer(memberPointer, memberPointerSize);
- whenDependentTypesAreResolved([], [rawClassType, rawFieldType], function(converters) {
- var classType = converters[0];
- var fieldType = converters[1];
+ whenDependentTypesAreResolved([], [rawClassType], function(classType) {
+ classType = classType[0];
var humanName = classType.name + '.' + fieldName;
+
Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, {
get: function() {
- var ptr = validateThis(this, classType, humanName + ' getter');
- return fieldType.fromWireType(getter(ptr, memberPointer));
+ throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]);
},
- set: function(v) {
- var ptr = validateThis(this, classType, humanName + ' setter');
- var destructors = [];
- setter(ptr, memberPointer, fieldType.toWireType(destructors, v));
- runDestructors(destructors);
+ set: function() {
+ throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]);
},
- enumerable: true
+ enumerable: true,
+ configurable: true
+ });
+
+ whenDependentTypesAreResolved([], [rawFieldType], function(fieldType) {
+ fieldType = fieldType[0];
+ Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, {
+ get: function() {
+ var ptr = validateThis(this, classType, humanName + ' getter');
+ return fieldType.fromWireType(getter(ptr, memberPointer));
+ },
+ set: function(v) {
+ var ptr = validateThis(this, classType, humanName + ' setter');
+ var destructors = [];
+ setter(ptr, memberPointer, fieldType.toWireType(destructors, v));
+ runDestructors(destructors);
+ },
+ enumerable: true
+ });
+ return [];
});
+
return [];
});
}
diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp
index a75ba96a..a5c878f5 100755
--- a/system/lib/embind/bind.cpp
+++ b/system/lib/embind/bind.cpp
@@ -8,25 +8,24 @@
using namespace emscripten;
-static std::string _embind_getTypeName(intptr_t ti_raw) {
- auto ti = reinterpret_cast<const std::type_info*>(ti_raw);
- int stat;
- char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat);
- if (stat == 0) {
- std::string rv(demangled);
- free(demangled);
- return rv;
- }
+extern "C" {
+ const char* EMSCRIPTEN_KEEPALIVE __getTypeName(const std::type_info* ti) {
+ int stat;
+ char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat);
+ if (stat == 0 && demangled) {
+ return demangled;
+ }
- switch (stat) {
- case -1:
- return "<allocation failure>";
- case -2:
- return "<invalid C++ symbol>";
- case -3:
- return "<invalid argument>";
- default:
- return "<unknown error>";
+ switch (stat) {
+ case -1:
+ return strdup("<allocation failure>");
+ case -2:
+ return strdup("<invalid C++ symbol>");
+ case -3:
+ return strdup("<invalid argument>");
+ default:
+ return strdup("<unknown error>");
+ }
}
}
@@ -60,6 +59,4 @@ EMSCRIPTEN_BINDINGS(native_and_builtin_types) {
_embind_register_cstring(TypeID<std::string>::get(), "std::string");
_embind_register_emval(TypeID<val>::get(), "emscripten::val");
-
- function("_embind_getTypeName", &_embind_getTypeName);
}