Add sensible error messages when working with classes that depend on unbound types.

This commit is contained in:
Chad Austin 2013-03-20 20:15:36 -07:00 коммит произвёл Jukka Jylänki
Родитель 0a6f5476f1
Коммит e10ede1e07
2 изменённых файлов: 129 добавлений и 82 удалений

Просмотреть файл

@ -3,6 +3,7 @@
/*global FUNCTION_TABLE, HEAP32, HEAPU8*/ /*global FUNCTION_TABLE, HEAP32, HEAPU8*/
/*global Pointer_stringify*/ /*global Pointer_stringify*/
/*global __emval_register, _emval_handle_array, __emval_decref*/ /*global __emval_register, _emval_handle_array, __emval_decref*/
/*global ___getTypeName*/
var InternalError = Module.InternalError = extendError(Error, 'InternalError'); var InternalError = Module.InternalError = extendError(Error, 'InternalError');
var BindingError = Module.BindingError = extendError(Error, 'BindingError'); var BindingError = Module.BindingError = extendError(Error, 'BindingError');
@ -45,6 +46,13 @@ function exposePublicSymbol(name, value) {
Module[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 // from https://github.com/imvu/imvujs/blob/master/src/error.js
function extendError(baseErrorType, errorName) { function extendError(baseErrorType, errorName) {
var errorClass = createNamedFunction(errorName, function(message) { var errorClass = createNamedFunction(errorName, function(message) {
@ -165,7 +173,10 @@ function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverter
} }
function getTypeName(type) { 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) { function heap32VectorToArray(count, firstElement) {
@ -317,16 +328,12 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker,
name = Pointer_stringify(name); name = Pointer_stringify(name);
rawInvoker = FUNCTION_TABLE[rawInvoker]; rawInvoker = FUNCTION_TABLE[rawInvoker];
var invoker = function() {
throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes);
};
exposePublicSymbol(name, function() { exposePublicSymbol(name, function() {
return invoker.apply(this, arguments); throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes);
}); });
whenDependentTypesAreResolved([], argTypes, function(argTypes) { whenDependentTypesAreResolved([], argTypes, function(argTypes) {
invoker = makeInvoker(name, argCount, argTypes, rawInvoker, fn); replacePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn));
return []; return [];
}); });
} }
@ -800,6 +807,11 @@ function __embind_register_class(
downcast = FUNCTION_TABLE[downcast]; downcast = FUNCTION_TABLE[downcast];
var legalFunctionName = makeLegalFunctionName(name); 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( whenDependentTypesAreResolved(
[rawType, rawPointerType, rawConstPointerType], [rawType, rawPointerType, rawConstPointerType],
baseClassRawType ? [baseClassRawType] : [], baseClassRawType ? [baseClassRawType] : [],
@ -868,7 +880,7 @@ function __embind_register_class(
constPointerType: constPointerConverter constPointerType: constPointerConverter
}; };
exposePublicSymbol(legalFunctionName, constructor); replacePublicSymbol(legalFunctionName, constructor);
return [referenceConverter, pointerConverter, constPointerConverter]; return [referenceConverter, pointerConverter, constPointerConverter];
} }
@ -885,10 +897,15 @@ function __embind_register_class_constructor(
var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
invoker = FUNCTION_TABLE[invoker]; invoker = FUNCTION_TABLE[invoker];
whenDependentTypesAreResolved([], [rawClassType].concat(rawArgTypes), function(argTypes) { whenDependentTypesAreResolved([], [rawClassType], function(classType) {
var classType = argTypes[0]; classType = classType[0];
argTypes = argTypes.slice(1);
var humanName = 'constructor ' + classType.name; var humanName = 'constructor ' + classType.name;
classType.registeredClass.constructor_body = function() {
throwUnboundTypeError('Cannot construct ' + classType.name + ' due to unbound types', rawArgTypes);
};
whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) {
classType.registeredClass.constructor_body = function() { classType.registeredClass.constructor_body = function() {
if (arguments.length !== argCount - 1) { if (arguments.length !== argCount - 1) {
throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1));
@ -907,6 +924,8 @@ function __embind_register_class_constructor(
}; };
return []; return [];
}); });
return [];
});
} }
function downcastPointer(ptr, ptrClass, desiredClass) { function downcastPointer(ptr, ptrClass, desiredClass) {
@ -961,10 +980,15 @@ function __embind_register_class_function(
rawInvoker = FUNCTION_TABLE[rawInvoker]; rawInvoker = FUNCTION_TABLE[rawInvoker];
memberFunction = copyMemberPointer(memberFunction, memberFunctionSize); memberFunction = copyMemberPointer(memberFunction, memberFunctionSize);
whenDependentTypesAreResolved([], [rawClassType].concat(rawArgTypes), function(argTypes) { whenDependentTypesAreResolved([], [rawClassType], function(classType) {
var classType = argTypes[0]; classType = classType[0];
argTypes = argTypes.slice(1);
var humanName = classType.name + '.' + methodName; var humanName = classType.name + '.' + methodName;
classType.registeredClass.instancePrototype[methodName] = function() {
throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes);
};
whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) {
classType.registeredClass.instancePrototype[methodName] = function() { classType.registeredClass.instancePrototype[methodName] = function() {
if (arguments.length !== argCount - 1) { if (arguments.length !== argCount - 1) {
throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1)); throwBindingError('emscripten binding method ' + humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1));
@ -989,6 +1013,8 @@ function __embind_register_class_function(
}; };
return []; return [];
}); });
return [];
});
} }
function __embind_register_class_class_function( function __embind_register_class_class_function(
@ -999,15 +1025,23 @@ function __embind_register_class_class_function(
rawInvoker, rawInvoker,
fn fn
) { ) {
var classType = requireRegisteredType(rawClassType, 'class');
var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
methodName = Pointer_stringify(methodName); methodName = Pointer_stringify(methodName);
rawInvoker = FUNCTION_TABLE[rawInvoker]; rawInvoker = FUNCTION_TABLE[rawInvoker];
whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { whenDependentTypesAreResolved([], [rawClassType], function(classType) {
classType = classType[0];
var humanName = classType.name + '.' + methodName; var humanName = classType.name + '.' + methodName;
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); classType.registeredClass.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn);
return []; return [];
}); });
return [];
});
} }
function __embind_register_class_property( function __embind_register_class_property(
@ -1023,10 +1057,23 @@ function __embind_register_class_property(
getter = FUNCTION_TABLE[getter]; getter = FUNCTION_TABLE[getter];
setter = FUNCTION_TABLE[setter]; setter = FUNCTION_TABLE[setter];
memberPointer = copyMemberPointer(memberPointer, memberPointerSize); memberPointer = copyMemberPointer(memberPointer, memberPointerSize);
whenDependentTypesAreResolved([], [rawClassType, rawFieldType], function(converters) { whenDependentTypesAreResolved([], [rawClassType], function(classType) {
var classType = converters[0]; classType = classType[0];
var fieldType = converters[1];
var humanName = classType.name + '.' + fieldName; var humanName = classType.name + '.' + fieldName;
Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, {
get: function() {
throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]);
},
set: function() {
throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]);
},
enumerable: true,
configurable: true
});
whenDependentTypesAreResolved([], [rawFieldType], function(fieldType) {
fieldType = fieldType[0];
Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, { Object.defineProperty(classType.registeredClass.instancePrototype, fieldName, {
get: function() { get: function() {
var ptr = validateThis(this, classType, humanName + ' getter'); var ptr = validateThis(this, classType, humanName + ' getter');
@ -1042,6 +1089,9 @@ function __embind_register_class_property(
}); });
return []; return [];
}); });
return [];
});
} }
var char_0 = '0'.charCodeAt(0); var char_0 = '0'.charCodeAt(0);

Просмотреть файл

@ -8,25 +8,24 @@
using namespace emscripten; using namespace emscripten;
static std::string _embind_getTypeName(intptr_t ti_raw) { extern "C" {
auto ti = reinterpret_cast<const std::type_info*>(ti_raw); const char* EMSCRIPTEN_KEEPALIVE __getTypeName(const std::type_info* ti) {
int stat; int stat;
char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat); char* demangled = abi::__cxa_demangle(ti->name(), NULL, NULL, &stat);
if (stat == 0) { if (stat == 0 && demangled) {
std::string rv(demangled); return demangled;
free(demangled);
return rv;
} }
switch (stat) { switch (stat) {
case -1: case -1:
return "<allocation failure>"; return strdup("<allocation failure>");
case -2: case -2:
return "<invalid C++ symbol>"; return strdup("<invalid C++ symbol>");
case -3: case -3:
return "<invalid argument>"; return strdup("<invalid argument>");
default: default:
return "<unknown error>"; 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_cstring(TypeID<std::string>::get(), "std::string");
_embind_register_emval(TypeID<val>::get(), "emscripten::val"); _embind_register_emval(TypeID<val>::get(), "emscripten::val");
function("_embind_getTypeName", &_embind_getTypeName);
} }