blob: 6fb3194dadd77cecc5d7ec995d0b38bbc3b64fa9 [file] [log] [blame]
/*
* Example of how to use DUK_USE_CPP_EXCEPTIONS to support automatic
* variables (e.g. destructor calls) in Duktape/C functions.
*
* Compile with -DDUK_OPT_CPP_EXCEPTIONS:
*
* $ g++ -otest -DDUK_OPT_CPP_EXCEPTIONS -I<duktape_dist>/src/ \
* <duktape_dist>/src/duktape.c cpp_exceptions.cpp -lm
*
* or ensure duk_config.h has DUK_USE_CPP_EXCEPTIONS enabled using
* genconfig. When executed you should see something like:
*
* $ ./test
* my_class instance created
* my_class instance destroyed <== destructor gets called
* --> rc=1 (SyntaxError: parse error (line 1))
* [...]
*
* Duktape uses a custom exception class (duk_internal_exception) which
* doesn't inherit from any base class, so that catching any base classes
* in user code won't accidentally catch exceptions thrown by Duktape.
*/
#if !defined(__cplusplus)
#error compile using a c++ compiler
#endif
#include <stdio.h>
#include <exception>
#include "duktape.h"
#if defined(__cplusplus) && (__cplusplus >= 201103L)
#define NOEXCEPT noexcept
#else
#define NOEXCEPT throw()
#endif
/*
* Example class with a destructor
*/
class my_class {
public:
my_class();
~my_class();
};
my_class::my_class() {
printf("my_class instance created\n");
}
my_class::~my_class() {
printf("my_class instance destroyed\n");
}
/*
* SyntaxError caused by eval exits Duktape/C function but destructors
* are executed.
*/
duk_ret_t test1(duk_context *ctx) {
my_class myclass;
duk_eval_string(ctx, "aiee=");
return 0;
}
/*
* You can use C++ exceptions inside Duktape/C functions for your own
* purposes but you should catch them before they propagate to Duktape.
*/
duk_ret_t test2(duk_context *ctx) {
my_class myclass;
try {
throw 123;
} catch (int myvalue) {
printf("Caught: %d\n", myvalue);
}
return 0;
}
/*
* If you let your own C++ exceptions propagate out of a Duktape/C function
* it will be caught by Duktape and considered a programming error. Duktape
* will catch the exception and convert it to a Duktape error.
*
* This may be allowed in a later version once all the implications have been
* worked out.
*/
duk_ret_t test3(duk_context *ctx) {
my_class myclass;
throw 123; /* ERROR: exception propagated to Duktape */
return 0;
}
/*
* Same as above, but if the exception inherits from std::exception, it's
* "what()" will be included in the error message.
*/
class my_exception : public std::exception {
virtual const char *what() const NOEXCEPT {
return "my_exception";
}
};
duk_ret_t test4(duk_context *ctx) {
my_class myclass;
my_exception myexc;
throw myexc; /* ERROR: exception propagated to Duktape */
return 0;
}
/*
* Same as above, but if the exception inherits from std::exception with
* a NULL what(). Duktape will describe the error as 'unknown' if so.
*/
class my_exception2 : public std::exception {
virtual const char *what() const NOEXCEPT {
return NULL;
}
};
duk_ret_t test5(duk_context *ctx) {
my_class myclass;
my_exception2 myexc;
throw myexc; /* ERROR: exception propagated to Duktape */
return 0;
}
int main(int argc, char *argv[]) {
duk_context *ctx = duk_create_heap_default();
duk_int_t rc;
(void) argc; (void) argv; /* suppress warning */
printf("*** test1 - duk_pcall()\n");
duk_push_c_function(ctx, test1, 0);
rc = duk_pcall(ctx, 0);
printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
duk_pop(ctx);
printf("\n");
printf("*** test1 - duk_safe_call()\n");
rc = duk_safe_call(ctx, test1, 0, 1);
printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
duk_pop(ctx);
printf("\n");
printf("*** test1 - ecmascript try-catch\n");
duk_push_c_function(ctx, test1, 0);
duk_put_global_string(ctx, "test1");
duk_eval_string_noresult(ctx,
"try {\n"
" test1();\n"
"} catch (e) {\n"
" print(e.stack || e);\n"
"}\n");
printf("\n");
printf("*** test2 - duk_pcall()\n");
duk_push_c_function(ctx, test2, 0);
rc = duk_pcall(ctx, 0);
printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
duk_pop(ctx);
printf("\n");
printf("*** test2 - duk_safe_call()\n");
rc = duk_safe_call(ctx, test2, 0, 1);
printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
duk_pop(ctx);
printf("\n");
printf("*** test2 - ecmascript try-catch\n");
duk_push_c_function(ctx, test2, 0);
duk_put_global_string(ctx, "test2");
duk_eval_string_noresult(ctx,
"try {\n"
" test2();\n"
"} catch (e) {\n"
" print(e.stack || e);\n"
"}\n");
printf("\n");
printf("*** test3 - duk_pcall()\n");
duk_push_c_function(ctx, test3, 0);
rc = duk_pcall(ctx, 0);
printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
duk_pop(ctx);
printf("\n");
printf("*** test3 - duk_safe_call()\n");
rc = duk_safe_call(ctx, test3, 0, 1);
printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
duk_pop(ctx);
printf("\n");
printf("*** test3 - ecmascript try-catch\n");
duk_push_c_function(ctx, test3, 0);
duk_put_global_string(ctx, "test3");
duk_eval_string_noresult(ctx,
"try {\n"
" test3();\n"
"} catch (e) {\n"
" print(e.stack || e);\n"
"}\n");
printf("\n");
printf("*** test4 - duk_pcall()\n");
duk_push_c_function(ctx, test4, 0);
rc = duk_pcall(ctx, 0);
printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
duk_pop(ctx);
printf("\n");
printf("*** test4 - duk_safe_call()\n");
rc = duk_safe_call(ctx, test4, 0, 1);
printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
duk_pop(ctx);
printf("\n");
printf("*** test4 - ecmascript try-catch\n");
duk_push_c_function(ctx, test4, 0);
duk_put_global_string(ctx, "test4");
duk_eval_string_noresult(ctx,
"try {\n"
" test4();\n"
"} catch (e) {\n"
" print(e.stack || e);\n"
"}\n");
printf("\n");
printf("*** test5 - duk_pcall()\n");
duk_push_c_function(ctx, test5, 0);
rc = duk_pcall(ctx, 0);
printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
duk_pop(ctx);
printf("\n");
printf("*** test5 - duk_safe_call()\n");
rc = duk_safe_call(ctx, test5, 0, 1);
printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
duk_pop(ctx);
printf("\n");
printf("*** test5 - ecmascript try-catch\n");
duk_push_c_function(ctx, test5, 0);
duk_put_global_string(ctx, "test5");
duk_eval_string_noresult(ctx,
"try {\n"
" test5();\n"
"} catch (e) {\n"
" print(e.stack || e);\n"
"}\n");
printf("\n");
printf("*** done\n");
duk_destroy_heap(ctx);
return 0;
}