diff --git a/CHANGES.current b/CHANGES.current index 3731b7561..bb96c581f 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,14 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-09-17: wsfulton + [Go, Guile, Racket, Scilab] Add throws typemaps for std::string so that thrown + string exception messages can be seen. + +2022-09-17: wsfulton + [Racket] Add throws typemaps for char * so that thrown string exception + messages can be seen from Racket. + 2022-09-17: wsfulton [Javascript, Octave, R] Improve exceptions for %catches and exception specifications for native types. String exception messages are shown as diff --git a/Examples/test-suite/catches_strings.i b/Examples/test-suite/catches_strings.i index 843246e23..818a62285 100644 --- a/Examples/test-suite/catches_strings.i +++ b/Examples/test-suite/catches_strings.i @@ -3,11 +3,15 @@ %include %catches(const char *) StringsThrower::charstring; +%catches(std::string) StringsThrower::stdstring; %inline %{ struct StringsThrower { static void charstring() { throw "charstring message"; } + static void stdstring() { + throw std::string("stdstring message"); + } }; %} diff --git a/Examples/test-suite/csharp/catches_strings_runme.cs b/Examples/test-suite/csharp/catches_strings_runme.cs index 6eb159141..e2e336443 100644 --- a/Examples/test-suite/csharp/catches_strings_runme.cs +++ b/Examples/test-suite/csharp/catches_strings_runme.cs @@ -16,5 +16,17 @@ public class catches_strings_runme { if (!exception_thrown) throw new ApplicationException("Should have thrown an exception"); } + { + bool exception_thrown = false; + try { + StringsThrower.stdstring(); + } catch (ApplicationException e) { + if (!e.Message.Contains("stdstring message")) + throw new ApplicationException("incorrect exception message:" + e); + exception_thrown = true; + } + if (!exception_thrown) + throw new ApplicationException("Should have thrown an exception"); + } } } diff --git a/Examples/test-suite/d/catches_strings_runme.1.d b/Examples/test-suite/d/catches_strings_runme.1.d index d42035100..89108355b 100644 --- a/Examples/test-suite/d/catches_strings_runme.1.d +++ b/Examples/test-suite/d/catches_strings_runme.1.d @@ -17,4 +17,16 @@ void main() { if (!exception_thrown) throw new Exception("Should have thrown an exception"); } + { + bool exception_thrown = false; + try { + StringsThrower.stdstring(); + } catch (Exception e) { + if (!canFind(e.msg, "stdstring message")) + throw new Exception("incorrect exception message:" ~ e.msg); + exception_thrown = true; + } + if (!exception_thrown) + throw new Exception("Should have thrown an exception"); + } } diff --git a/Examples/test-suite/d/catches_strings_runme.2.d b/Examples/test-suite/d/catches_strings_runme.2.d index d42035100..89108355b 100644 --- a/Examples/test-suite/d/catches_strings_runme.2.d +++ b/Examples/test-suite/d/catches_strings_runme.2.d @@ -17,4 +17,16 @@ void main() { if (!exception_thrown) throw new Exception("Should have thrown an exception"); } + { + bool exception_thrown = false; + try { + StringsThrower.stdstring(); + } catch (Exception e) { + if (!canFind(e.msg, "stdstring message")) + throw new Exception("incorrect exception message:" ~ e.msg); + exception_thrown = true; + } + if (!exception_thrown) + throw new Exception("Should have thrown an exception"); + } } diff --git a/Examples/test-suite/go/catches_strings_runme.go b/Examples/test-suite/go/catches_strings_runme.go index 6f0be2c9b..b31565c24 100644 --- a/Examples/test-suite/go/catches_strings_runme.go +++ b/Examples/test-suite/go/catches_strings_runme.go @@ -4,14 +4,29 @@ import "strings" import . "swigtests/catches_strings" func main() { - exception_thrown := false - func() { - defer func() { - exception_thrown = strings.Index(recover().(string), "charstring message") == 0 + { + exception_thrown := false + func() { + defer func() { + exception_thrown = strings.Index(recover().(string), "charstring message") == 0 + }() + StringsThrowerCharstring() }() - StringsThrowerCharstring() - }() - if !exception_thrown { - panic(0) + if !exception_thrown { + panic(0) + } + } + + { + exception_thrown := false + func() { + defer func() { + exception_thrown = strings.Index(recover().(string), "stdstring message") == 0 + }() + StringsThrowerStdstring() + }() + if !exception_thrown { + panic(0) + } } } diff --git a/Examples/test-suite/java/catches_strings_runme.java b/Examples/test-suite/java/catches_strings_runme.java index 0029327d4..75e0cf043 100644 --- a/Examples/test-suite/java/catches_strings_runme.java +++ b/Examples/test-suite/java/catches_strings_runme.java @@ -24,5 +24,18 @@ public class catches_strings_runme { if (!exception_thrown) throw new RuntimeException("Should have thrown an exception"); } + + { + boolean exception_thrown = false; + try { + StringsThrower.stdstring(); + } catch (RuntimeException e) { + if (!e.getMessage().contains("stdstring message")) + throw new RuntimeException("incorrect exception message"); + exception_thrown = true; + } + if (!exception_thrown) + throw new RuntimeException("Should have thrown an exception"); + } } } diff --git a/Examples/test-suite/javascript/catches_strings_runme.js b/Examples/test-suite/javascript/catches_strings_runme.js index be37c8710..c99e9a05f 100644 --- a/Examples/test-suite/javascript/catches_strings_runme.js +++ b/Examples/test-suite/javascript/catches_strings_runme.js @@ -4,12 +4,20 @@ exception_thrown = false; try { catches_strings.StringsThrower.charstring(); } catch (e) { - console.log(typeof(e)) - console.log(e.constructor.name) - console.log(typeof(e.message)) if (!e.message.includes("charstring message")) throw new Error("incorrect exception message " + e.message); exception_thrown = true; } if (!exception_thrown) throw new Error("Should have thrown an exception"); + +exception_thrown = false; +try { + catches_strings.StringsThrower.stdstring(); +} catch (e) { + if (!e.message.includes("stdstring message")) + throw new Error("incorrect exception message " + e.message); + exception_thrown = true; +} +if (!exception_thrown) + throw new Error("Should have thrown an exception"); diff --git a/Examples/test-suite/lua/catches_strings_runme.lua b/Examples/test-suite/lua/catches_strings_runme.lua index b23609f11..b0dbaee0e 100644 --- a/Examples/test-suite/lua/catches_strings_runme.lua +++ b/Examples/test-suite/lua/catches_strings_runme.lua @@ -8,3 +8,6 @@ setmetatable(env, {__index=function (t,i) error("undefined global variable `"..i s, msg = pcall(function() catches_strings.StringsThrower.charstring() end) assert(s == false and msg:find("charstring message", 1, true)) + +s, msg = pcall(function() catches_strings.StringsThrower.stdstring() end) +assert(s == false and msg:find("stdstring message", 1, true)) diff --git a/Examples/test-suite/mzscheme/catches_strings_runme.scm b/Examples/test-suite/mzscheme/catches_strings_runme.scm index 43d313de0..745a7cf0a 100644 --- a/Examples/test-suite/mzscheme/catches_strings_runme.scm +++ b/Examples/test-suite/mzscheme/catches_strings_runme.scm @@ -8,4 +8,11 @@ (unless (string-contains? exception_thrown "charstring message") (error (format "incorrect exception message: ~a" exception_thrown))) +(define exception_thrown "no exception thrown for kin") +(with-handlers ([exn:fail? (lambda (exn) + (set! exception_thrown (exn-message exn)))]) + (StringsThrower-stdstring)) +(unless (string-contains? exception_thrown "stdstring message") + (error (format "incorrect exception message: ~a" exception_thrown))) + (exit 0) diff --git a/Examples/test-suite/ocaml/catches_strings_runme.ml b/Examples/test-suite/ocaml/catches_strings_runme.ml index 610f23bd9..901aed0ec 100644 --- a/Examples/test-suite/ocaml/catches_strings_runme.ml +++ b/Examples/test-suite/ocaml/catches_strings_runme.ml @@ -6,3 +6,9 @@ let _ = ignore (_StringsThrower_charstring (C_void)); assert false with Failure s -> assert (s = "charstring message") + +let _ = + try + ignore (_StringsThrower_stdstring (C_void)); assert false + with Failure s -> + assert (s = "stdstring message") diff --git a/Examples/test-suite/octave/catches_strings_runme.m b/Examples/test-suite/octave/catches_strings_runme.m index 75ff6c10b..7e323cc13 100644 --- a/Examples/test-suite/octave/catches_strings_runme.m +++ b/Examples/test-suite/octave/catches_strings_runme.m @@ -17,3 +17,16 @@ end_try_catch if (!exception_thrown) error("Should have thrown an exception"); endif + +exception_thrown = false; +try + StringsThrower.stdstring(); +catch e + if (isempty(strfind(e.message, "stdstring message"))) + error("incorrect exception message: %s", e.message) + endif + exception_thrown = true; +end_try_catch +if (!exception_thrown) + error("Should have thrown an exception"); +endif diff --git a/Examples/test-suite/perl5/catches_strings_runme.pl b/Examples/test-suite/perl5/catches_strings_runme.pl index a35095f02..742b5bcab 100644 --- a/Examples/test-suite/perl5/catches_strings_runme.pl +++ b/Examples/test-suite/perl5/catches_strings_runme.pl @@ -1,6 +1,6 @@ use strict; use warnings; -use Test::More tests => 3; +use Test::More tests => 4; BEGIN { use_ok('catches_strings') } require_ok('catches_strings'); @@ -8,3 +8,8 @@ eval { catches_strings::StringsThrower::charstring(); }; like($@, qr/\bcharstring message/, "Should have thrown an exception"); + +eval { + catches_strings::StringsThrower::stdstring(); +}; +like($@, qr/\bstdstring message/, "Should have thrown an exception"); diff --git a/Examples/test-suite/php/catches_strings_runme.php b/Examples/test-suite/php/catches_strings_runme.php index ef945f0b5..f727ea26a 100644 --- a/Examples/test-suite/php/catches_strings_runme.php +++ b/Examples/test-suite/php/catches_strings_runme.php @@ -11,4 +11,13 @@ try { } check::equal($exception_thrown, true, "Should have thrown an exception"); +$exception_thrown = false; +try { + StringsThrower::stdstring(); +} catch (Exception $e) { + check::str_contains($e->getMessage(), "stdstring message", "incorrect exception message: {$e->getMessage()}"); + $exception_thrown = true; +} +check::equal($exception_thrown, true, "Should have thrown an exception"); + check::done(); diff --git a/Examples/test-suite/python/catches_strings_runme.py b/Examples/test-suite/python/catches_strings_runme.py index 16ad6b056..95b55a264 100644 --- a/Examples/test-suite/python/catches_strings_runme.py +++ b/Examples/test-suite/python/catches_strings_runme.py @@ -9,3 +9,13 @@ except RuntimeError as e: exception_thrown = True if not exception_thrown: raise RuntimeError("Should have thrown an exception") + +exception_thrown = False +try: + StringsThrower.stdstring() +except RuntimeError as e: + if "stdstring message" not in str(e): + raise RuntimeError("incorrect exception message:" + str(e)) + exception_thrown = True +if not exception_thrown: + raise RuntimeError("Should have thrown an exception") diff --git a/Examples/test-suite/r/catches_strings_runme.R b/Examples/test-suite/r/catches_strings_runme.R index 2eb4f3c83..db6783d91 100644 --- a/Examples/test-suite/r/catches_strings_runme.R +++ b/Examples/test-suite/r/catches_strings_runme.R @@ -13,3 +13,12 @@ tryCatch({ } ) unittest(exception_thrown, TRUE) + +exception_thrown = FALSE +tryCatch({ + StringsThrower_stdstring() +}, error = function(e) { + exception_thrown <<- grepl(e$message, "stdstring message", fixed=TRUE) +} +) +unittest(exception_thrown, TRUE) diff --git a/Examples/test-suite/ruby/catches_strings_runme.rb b/Examples/test-suite/ruby/catches_strings_runme.rb index 5af873ef7..fb7466765 100644 --- a/Examples/test-suite/ruby/catches_strings_runme.rb +++ b/Examples/test-suite/ruby/catches_strings_runme.rb @@ -16,3 +16,16 @@ end if (!exception_thrown) raise RuntimeError, "Should have thrown an exception" end + +exception_thrown = false +begin + Catches_strings::StringsThrower.stdstring() +rescue RuntimeError => e + if (!e.to_s.include? "stdstring message") + raise RuntimeError, "incorrect exception message: #{e.to_s}" + end + exception_thrown = true +end +if (!exception_thrown) + raise RuntimeError, "Should have thrown an exception" +end diff --git a/Examples/test-suite/schemerunme/catches_strings.scm b/Examples/test-suite/schemerunme/catches_strings.scm index 5be2d2345..8a83db07c 100644 --- a/Examples/test-suite/schemerunme/catches_strings.scm +++ b/Examples/test-suite/schemerunme/catches_strings.scm @@ -2,4 +2,8 @@ (StringsThrower-charstring)) ; TODO: check the exception message +(expect-throw 'swig-exception + (StringsThrower-stdstring)) +; TODO: check the exception message + (exit 0) diff --git a/Examples/test-suite/scilab/catches_strings_runme.sci b/Examples/test-suite/scilab/catches_strings_runme.sci index 4c6718a49..f9226c728 100644 --- a/Examples/test-suite/scilab/catches_strings_runme.sci +++ b/Examples/test-suite/scilab/catches_strings_runme.sci @@ -7,4 +7,11 @@ if (strstr(lasterror(), "charstring message") == '') exit(1) end +ierr = execstr("StringsThrower_stdstring()", 'errcatch'); +checkequal(ierr, 20000, "wrong/no exception thrown") +if (strstr(lasterror(), "stdstring message") == '') + printf("Should have thrown an exception") + exit(1) +end + exec("swigtest.quit", -1); diff --git a/Examples/test-suite/tcl/catches_strings_runme.tcl b/Examples/test-suite/tcl/catches_strings_runme.tcl index 1ada351e6..e60b660d7 100644 --- a/Examples/test-suite/tcl/catches_strings_runme.tcl +++ b/Examples/test-suite/tcl/catches_strings_runme.tcl @@ -16,3 +16,16 @@ if [ catch { if {!$exception_thrown} { error "Should have thrown an exception" } + +set exception_thrown 0 +if [ catch { + StringsThrower_stdstring +} e ] { + if {[string first "stdstring message" $e] == -1} { + error "incorrect exception message: $e" + } + set exception_thrown 1 +} +if {!$exception_thrown} { + error "Should have thrown an exception" +} diff --git a/Lib/go/std_string.i b/Lib/go/std_string.i index 3abf04cae..35b4a5e46 100644 --- a/Lib/go/std_string.i +++ b/Lib/go/std_string.i @@ -52,6 +52,9 @@ class string; %typemap(godirectorin,fragment="CopyString") string %{ $result = swigCopyString($input) %} +%typemap(throws) string +%{ _swig_gopanic($1.c_str()); %} + %typemap(in) const string & %{ $*1_ltype $1_str($input.p, $input.n); @@ -88,6 +91,9 @@ class string; %typemap(godirectorin,fragment="CopyString") const string & %{ $result = swigCopyString($input) %} +%typemap(throws) const string & +%{ _swig_gopanic($1.c_str()); %} + %typemap(gotype) string * "*string" diff --git a/Lib/guile/std_string.i b/Lib/guile/std_string.i index fbd27547f..c49bfcb07 100644 --- a/Lib/guile/std_string.i +++ b/Lib/guile/std_string.i @@ -83,4 +83,13 @@ namespace std { $result = SWIG_str02scm($1.c_str()); } + %typemap(throws) string { + scm_throw(scm_from_locale_symbol((char *) "swig-exception"), + scm_list_n(SWIG_str02scm($1.c_str()), SCM_UNDEFINED)); + } + + %typemap(throws) const string & { + scm_throw(scm_from_locale_symbol((char *) "swig-exception"), + scm_list_n(SWIG_str02scm($1.c_str()), SCM_UNDEFINED)); + } } diff --git a/Lib/mzscheme/std_string.i b/Lib/mzscheme/std_string.i index b19e8567a..70673eadf 100644 --- a/Lib/mzscheme/std_string.i +++ b/Lib/mzscheme/std_string.i @@ -52,6 +52,13 @@ namespace std { $result = scheme_make_string($1->c_str()); } + %typemap(throws) string { + scheme_signal_error("%s: %s", FUNC_NAME, $1.c_str()); + } + + %typemap(throws) const string & { + scheme_signal_error("%s: %s", FUNC_NAME, $1.c_str()); + } } diff --git a/Lib/scilab/std_string.i b/Lib/scilab/std_string.i index 71ac6d2f4..8736c2a28 100644 --- a/Lib/scilab/std_string.i +++ b/Lib/scilab/std_string.i @@ -37,3 +37,11 @@ SWIG_From_dec(std::string)(std::string pstValue) { } %include + +%typemap(throws, noblock=1) std::string { + SWIG_Scilab_Raise_Ex($1.c_str(), "$type", $&descriptor); +} + +%typemap(throws, noblock=1) const std::string & { + SWIG_Scilab_Raise_Ex($1.c_str(), "$type", $descriptor); +}