Add sensible error messages when working with classes that depend on unbound types.
This commit is contained in:
Родитель
0a6f5476f1
Коммит
e10ede1e07
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче