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 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,10 +897,15 @@ 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() {
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));
@ -907,6 +924,8 @@ function __embind_register_class_constructor(
};
return [];
});
return [];
});
}
function downcastPointer(ptr, ptrClass, desiredClass) {
@ -961,10 +980,15 @@ 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() {
throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes);
};
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));
@ -989,6 +1013,8 @@ function __embind_register_class_function(
};
return [];
});
return [];
});
}
function __embind_register_class_class_function(
@ -999,15 +1025,23 @@ 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] = 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 [];
});
}
function __embind_register_class_property(
@ -1023,10 +1057,23 @@ 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() {
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, {
get: function() {
var ptr = validateThis(this, classType, humanName + ' getter');
@ -1042,6 +1089,9 @@ function __embind_register_class_property(
});
return [];
});
return [];
});
}
var char_0 = '0'.charCodeAt(0);

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

@ -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);
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) {
std::string rv(demangled);
free(demangled);
return rv;
if (stat == 0 && demangled) {
return demangled;
}
switch (stat) {
case -1:
return "<allocation failure>";
return strdup("<allocation failure>");
case -2:
return "<invalid C++ symbol>";
return strdup("<invalid C++ symbol>");
case -3:
return "<invalid argument>";
return strdup("<invalid argument>");
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_emval(TypeID<val>::get(), "emscripten::val");
function("_embind_getTypeName", &_embind_getTypeName);
}