Javascript, Octave, R - Improve exceptions for %catches

and exception specifications for native types.

Now the raised exception contains the string value as the exception
message instead of just the C/C++ type of the exception.

R exceptions were completely swallowed beforehand
This commit is contained in:
William S Fulton 2022-09-17 16:06:44 +01:00
commit 00190c484f
8 changed files with 35 additions and 17 deletions

View file

@ -7,6 +7,11 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.1.0 (in progress) Version 4.1.0 (in progress)
=========================== ===========================
2022-09-17: wsfulton
[Javascript, Octave, R] Improve exceptions for %catches and exception
specifications for native types. String exception messages are shown as
the exception message instead of just the type of the exception.
2022-09-17: wsfulton 2022-09-17: wsfulton
Add missing typecheck typemaps for std::auto_ptr and std::unique_ptr to Add missing typecheck typemaps for std::auto_ptr and std::unique_ptr to
fix overloading when using these types. fix overloading when using these types.

View file

@ -10,7 +10,7 @@ try{
if(error == -1) { if(error == -1) {
console.log("t.unknown() didn't throw"); console.log("t.unknown() didn't throw");
} else { } else {
console.log("successfully caught throw in Test::unknown()."); console.log("successfully caught throw in Test::unknown() :" + error);
} }
} }
@ -22,7 +22,7 @@ catch(error){
if(error == -1) { if(error == -1) {
console.log("t.simple() did not throw"); console.log("t.simple() did not throw");
} else { } else {
console.log("successfully caught throw in Test::simple()."); console.log("successfully caught throw in Test::simple() :" + error);
} }
} }
@ -33,7 +33,7 @@ try{
if(error == -1) { if(error == -1) {
console.log("t.message() did not throw"); console.log("t.message() did not throw");
} else { } else {
console.log("successfully caught throw in Test::message()."); console.log("successfully caught throw in Test::message() :" + error);
} }
} }
@ -45,7 +45,7 @@ catch(error){
if(error == -1) { if(error == -1) {
console.log("t.hosed() did not throw"); console.log("t.hosed() did not throw");
} else { } else {
console.log("successfully caught throw in Test::hosed()."); console.log("successfully caught throw in Test::hosed() :" + error + " " + error.code + " " + error.msg);
} }
} }
@ -58,7 +58,7 @@ for (var i=1; i<4; i++) {
if(error == -1) { if(error == -1) {
console.log("t.multi(" + i + ") did not throw"); console.log("t.multi(" + i + ") did not throw");
} else { } else {
console.log("successfully caught throw in Test::multi()."); console.log("successfully caught throw in Test::multi() :" + error);
} }
} }
} }

View file

@ -7,23 +7,27 @@
#define SWIG_exception(code, msg) do { SWIG_JSC_exception(context, exception, code, msg); SWIG_fail; } while (0) #define SWIG_exception(code, msg) do { SWIG_JSC_exception(context, exception, code, msg); SWIG_fail; } while (0)
#define SWIG_fail goto fail #define SWIG_fail goto fail
SWIGRUNTIME void SWIG_Javascript_Raise(JSContextRef context, JSValueRef *exception, const char* type) { SWIGRUNTIME void SWIG_Javascript_Raise_ValueRef(JSContextRef context, JSValueRef *exception, JSValueRef valRef) {
JSStringRef message = JSStringCreateWithUTF8CString(type);
JSValueRef error_arguments[1]; JSValueRef error_arguments[1];
JSObjectRef exception_object; JSObjectRef exception_object;
JSValueRef exception_value;
exception_value = JSValueMakeString(context, message);
/* Converting the result to an object will let JavascriptCore add /* Converting the result to an object will let JavascriptCore add
"sourceURL" (file) and "line" (number) and "message" to the exception, "sourceURL" (file) and "line" (number) and "message" to the exception,
instead of just returning a raw string. This is extremely important for debugging your errors. instead of just returning a raw string. This is extremely important for debugging your errors.
Using JSObjectMakeError is better than JSValueToObject because the latter only populates Using JSObjectMakeError is better than JSValueToObject because the latter only populates
"sourceURL" and "line", but not "message" or any others I don't know about. "sourceURL" and "line", but not "message" or any others I don't know about.
*/ */
error_arguments[0] = exception_value; error_arguments[0] = valRef;
exception_object = JSObjectMakeError(context, 1, error_arguments, NULL); exception_object = JSObjectMakeError(context, 1, error_arguments, NULL);
/* Return the exception_object */ /* Return the exception_object */
*exception = exception_object; *exception = exception_object;
}
SWIGRUNTIME void SWIG_Javascript_Raise(JSContextRef context, JSValueRef *exception, const char* msg) {
JSStringRef message = JSStringCreateWithUTF8CString(msg);
JSValueRef exception_value = JSValueMakeString(context, message);
SWIG_Javascript_Raise_ValueRef(context, exception, exception_value);
JSStringRelease(message); JSStringRelease(message);
} }

View file

@ -41,7 +41,7 @@
#define SWIG_SetConstant(name, obj) #define SWIG_SetConstant(name, obj)
/* raise */ /* raise */
#define SWIG_Raise(obj, type, desc) SWIG_Javascript_Raise(context, exception, type) #define SWIG_Raise(obj, type, desc) SWIG_Javascript_Raise_ValueRef(context, exception, obj)
%insert("runtime") %{ %insert("runtime") %{
#define SWIG_JSC_FROM_DECL_ARGS(arg1) (JSContextRef context, arg1) #define SWIG_JSC_FROM_DECL_ARGS(arg1) (JSContextRef context, arg1)

View file

@ -96,6 +96,11 @@ SWIGINTERN void SWIG_V8_Raise(const char *msg) {
SWIGV8_THROW_EXCEPTION(v8::Exception::Error(SWIGV8_STRING_NEW(msg))); SWIGV8_THROW_EXCEPTION(v8::Exception::Error(SWIGV8_STRING_NEW(msg)));
} }
SWIGINTERN void SWIG_V8_Raise(SWIGV8_VALUE obj, const char *msg) {
SWIGV8_THROW_EXCEPTION(obj);
}
/* /*
Note: There are two contexts for handling errors. Note: There are two contexts for handling errors.
A static V8ErrorHandler is used in not overloaded methods. A static V8ErrorHandler is used in not overloaded methods.

View file

@ -37,7 +37,7 @@
#define SWIG_SetConstant(name, obj) #define SWIG_SetConstant(name, obj)
/* raise */ /* raise */
#define SWIG_Raise(obj, type, desc) SWIG_V8_Raise(type) #define SWIG_Raise(obj, type, desc) SWIG_V8_Raise(obj, type)
/* Include the unified typemap library */ /* Include the unified typemap library */
%include <typemaps/swigtypemaps.swg> %include <typemaps/swigtypemaps.swg>

View file

@ -32,7 +32,7 @@
#define SWIG_SetConstant(name, obj) SWIG_Octave_SetConstant(module_ns,name,obj) #define SWIG_SetConstant(name, obj) SWIG_Octave_SetConstant(module_ns,name,obj)
// raise // raise
#define SWIG_Octave_Raise(OBJ, TYPE, DESC) error("C++ side threw an exception of type " TYPE) #define SWIG_Octave_Raise(OBJ, TYPE, DESC) error(OBJ.is_string() ? OBJ.string_value().c_str() : "C++ side threw an exception of type " TYPE)
#define SWIG_Raise(obj, type, desc) SWIG_Octave_Raise(obj, type, desc) #define SWIG_Raise(obj, type, desc) SWIG_Octave_Raise(obj, type, desc)
// Include the unified typemap library // Include the unified typemap library

View file

@ -26,9 +26,13 @@ SWIGEXPORT void SWIG_init(void) {
assign(name, _obj); assign(name, _obj);
%end_block %enddef %end_block %enddef
%define %raise(obj,type,desc) %runtime %{
return R_NilValue; void SWIG_R_Raise(SEXP obj, const char *msg) {
%enddef Rf_error(Rf_isString(obj) ? STRING_VALUE(obj) : msg);
}
%}
#define %raise(OBJ, TYPE, DESC) SWIG_R_Raise(OBJ, "C/C++ exception of type " TYPE); return R_NilValue
%insert("sinit") "srun.swg" %insert("sinit") "srun.swg"