]>
Commit | Line | Data |
---|---|---|
37b3c998 TL |
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 | ||
48 | my_class::my_class() { | |
49 | printf("my_class instance created\n"); | |
50 | } | |
51 | ||
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 | ||
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 | ||
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 | ||
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 { | |
109 | virtual const char *what() const NOEXCEPT { | |
110 | return "my_exception"; | |
111 | } | |
112 | }; | |
113 | ||
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 { | |
129 | virtual const char *what() const NOEXCEPT { | |
130 | return NULL; | |
131 | } | |
132 | }; | |
133 | ||
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 | ||
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 | } |