1 /*
2 * Example of how to use DUK_USE_CPP_EXCEPTIONS to support automatic
3 * variables (e.g. destructor calls) in Duktape/C functions.
4 *
5 * Compile with -DDUK_OPT_CPP_EXCEPTIONS:
6 *
7 * $ g++ -otest -DDUK_OPT_CPP_EXCEPTIONS -I<duktape_dist>/src/ \
8 * <duktape_dist>/src/duktape.c cpp_exceptions.cpp -lm
9 *
10 * or ensure duk_config.h has DUK_USE_CPP_EXCEPTIONS enabled using
11 * genconfig. When executed you should see something like:
12 *
13 * $ ./test
14 * my_class instance created
15 * my_class instance destroyed <== destructor gets called
16 * --> rc=1 (SyntaxError: parse error (line 1))
17 * [...]
18 *
19 * Duktape uses a custom exception class (duk_internal_exception) which
20 * doesn't inherit from any base class, so that catching any base classes
21 * in user code won't accidentally catch exceptions thrown by Duktape.
22 */
23
24 #if !defined(__cplusplus)
25 #error compile using a c++ compiler
26 #endif
27
28 #include <stdio.h>
29 #include <exception>
30 #include "duktape.h"
31
32 #if defined(__cplusplus) && (__cplusplus >= 201103L)
33 #define NOEXCEPT noexcept
34 #else
35 #define NOEXCEPT throw()
36 #endif
37
38 /*
39 * Example class with a destructor
40 */
41
42 class my_class {
43 public:
44 my_class();
45 ~my_class();
46 };
47
my_class()48 my_class::my_class() {
49 printf("my_class instance created\n");
50 }
51
~my_class()52 my_class::~my_class() {
53 printf("my_class instance destroyed\n");
54 }
55
56 /*
57 * SyntaxError caused by eval exits Duktape/C function but destructors
58 * are executed.
59 */
60
test1(duk_context * ctx)61 duk_ret_t test1(duk_context *ctx) {
62 my_class myclass;
63
64 duk_eval_string(ctx, "aiee=");
65
66 return 0;
67 }
68
69 /*
70 * You can use C++ exceptions inside Duktape/C functions for your own
71 * purposes but you should catch them before they propagate to Duktape.
72 */
73
test2(duk_context * ctx)74 duk_ret_t test2(duk_context *ctx) {
75 my_class myclass;
76
77 try {
78 throw 123;
79 } catch (int myvalue) {
80 printf("Caught: %d\n", myvalue);
81 }
82
83 return 0;
84 }
85
86 /*
87 * If you let your own C++ exceptions propagate out of a Duktape/C function
88 * it will be caught by Duktape and considered a programming error. Duktape
89 * will catch the exception and convert it to a Duktape error.
90 *
91 * This may be allowed in a later version once all the implications have been
92 * worked out.
93 */
94
test3(duk_context * ctx)95 duk_ret_t test3(duk_context *ctx) {
96 my_class myclass;
97
98 throw 123; /* ERROR: exception propagated to Duktape */
99
100 return 0;
101 }
102
103 /*
104 * Same as above, but if the exception inherits from std::exception, it's
105 * "what()" will be included in the error message.
106 */
107
108 class my_exception : public std::exception {
what() const109 virtual const char *what() const NOEXCEPT {
110 return "my_exception";
111 }
112 };
113
test4(duk_context * ctx)114 duk_ret_t test4(duk_context *ctx) {
115 my_class myclass;
116 my_exception myexc;
117
118 throw myexc; /* ERROR: exception propagated to Duktape */
119
120 return 0;
121 }
122
123 /*
124 * Same as above, but if the exception inherits from std::exception with
125 * a NULL what(). Duktape will describe the error as 'unknown' if so.
126 */
127
128 class my_exception2 : public std::exception {
what() const129 virtual const char *what() const NOEXCEPT {
130 return NULL;
131 }
132 };
133
test5(duk_context * ctx)134 duk_ret_t test5(duk_context *ctx) {
135 my_class myclass;
136 my_exception2 myexc;
137
138 throw myexc; /* ERROR: exception propagated to Duktape */
139
140 return 0;
141 }
142
main(int argc,char * argv[])143 int main(int argc, char *argv[]) {
144 duk_context *ctx = duk_create_heap_default();
145 duk_int_t rc;
146
147 (void) argc; (void) argv; /* suppress warning */
148
149 printf("*** test1 - duk_pcall()\n");
150 duk_push_c_function(ctx, test1, 0);
151 rc = duk_pcall(ctx, 0);
152 printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
153 duk_pop(ctx);
154 printf("\n");
155
156 printf("*** test1 - duk_safe_call()\n");
157 rc = duk_safe_call(ctx, test1, 0, 1);
158 printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
159 duk_pop(ctx);
160 printf("\n");
161
162 printf("*** test1 - ecmascript try-catch\n");
163 duk_push_c_function(ctx, test1, 0);
164 duk_put_global_string(ctx, "test1");
165 duk_eval_string_noresult(ctx,
166 "try {\n"
167 " test1();\n"
168 "} catch (e) {\n"
169 " print(e.stack || e);\n"
170 "}\n");
171 printf("\n");
172
173 printf("*** test2 - duk_pcall()\n");
174 duk_push_c_function(ctx, test2, 0);
175 rc = duk_pcall(ctx, 0);
176 printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
177 duk_pop(ctx);
178 printf("\n");
179
180 printf("*** test2 - duk_safe_call()\n");
181 rc = duk_safe_call(ctx, test2, 0, 1);
182 printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
183 duk_pop(ctx);
184 printf("\n");
185
186 printf("*** test2 - ecmascript try-catch\n");
187 duk_push_c_function(ctx, test2, 0);
188 duk_put_global_string(ctx, "test2");
189 duk_eval_string_noresult(ctx,
190 "try {\n"
191 " test2();\n"
192 "} catch (e) {\n"
193 " print(e.stack || e);\n"
194 "}\n");
195 printf("\n");
196
197 printf("*** test3 - duk_pcall()\n");
198 duk_push_c_function(ctx, test3, 0);
199 rc = duk_pcall(ctx, 0);
200 printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
201 duk_pop(ctx);
202 printf("\n");
203
204 printf("*** test3 - duk_safe_call()\n");
205 rc = duk_safe_call(ctx, test3, 0, 1);
206 printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
207 duk_pop(ctx);
208 printf("\n");
209
210 printf("*** test3 - ecmascript try-catch\n");
211 duk_push_c_function(ctx, test3, 0);
212 duk_put_global_string(ctx, "test3");
213 duk_eval_string_noresult(ctx,
214 "try {\n"
215 " test3();\n"
216 "} catch (e) {\n"
217 " print(e.stack || e);\n"
218 "}\n");
219 printf("\n");
220
221 printf("*** test4 - duk_pcall()\n");
222 duk_push_c_function(ctx, test4, 0);
223 rc = duk_pcall(ctx, 0);
224 printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
225 duk_pop(ctx);
226 printf("\n");
227
228 printf("*** test4 - duk_safe_call()\n");
229 rc = duk_safe_call(ctx, test4, 0, 1);
230 printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
231 duk_pop(ctx);
232 printf("\n");
233
234 printf("*** test4 - ecmascript try-catch\n");
235 duk_push_c_function(ctx, test4, 0);
236 duk_put_global_string(ctx, "test4");
237 duk_eval_string_noresult(ctx,
238 "try {\n"
239 " test4();\n"
240 "} catch (e) {\n"
241 " print(e.stack || e);\n"
242 "}\n");
243 printf("\n");
244
245 printf("*** test5 - duk_pcall()\n");
246 duk_push_c_function(ctx, test5, 0);
247 rc = duk_pcall(ctx, 0);
248 printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
249 duk_pop(ctx);
250 printf("\n");
251
252 printf("*** test5 - duk_safe_call()\n");
253 rc = duk_safe_call(ctx, test5, 0, 1);
254 printf("--> rc=%ld (%s)\n", (long) rc, duk_safe_to_string(ctx, -1));
255 duk_pop(ctx);
256 printf("\n");
257
258 printf("*** test5 - ecmascript try-catch\n");
259 duk_push_c_function(ctx, test5, 0);
260 duk_put_global_string(ctx, "test5");
261 duk_eval_string_noresult(ctx,
262 "try {\n"
263 " test5();\n"
264 "} catch (e) {\n"
265 " print(e.stack || e);\n"
266 "}\n");
267 printf("\n");
268
269 printf("*** done\n");
270
271 duk_destroy_heap(ctx);
272
273 return 0;
274 }
275