]> git.proxmox.com Git - ceph.git/blame - ceph/src/civetweb/src/third_party/duktape-1.3.0/src-separate/duk_bi_error.c
bump version to 12.2.12-pve1
[ceph.git] / ceph / src / civetweb / src / third_party / duktape-1.3.0 / src-separate / duk_bi_error.c
CommitLineData
7c673cae
FG
1/*
2 * Error built-ins
3 */
4
5#include "duk_internal.h"
6
7DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
8 /* Behavior for constructor and non-constructor call is
9 * the same except for augmenting the created error. When
10 * called as a constructor, the caller (duk_new()) will handle
11 * augmentation; when called as normal function, we need to do
12 * it here.
13 */
14
15 duk_hthread *thr = (duk_hthread *) ctx;
16 duk_small_int_t bidx_prototype = duk_get_current_magic(ctx);
17
18 /* same for both error and each subclass like TypeError */
19 duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
20 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
21
22 DUK_UNREF(thr);
23
24 duk_push_object_helper(ctx, flags_and_class, bidx_prototype);
25
26 /* If message is undefined, the own property 'message' is not set at
27 * all to save property space. An empty message is inherited anyway.
28 */
29 if (!duk_is_undefined(ctx, 0)) {
30 duk_to_string(ctx, 0);
31 duk_dup(ctx, 0); /* [ message error message ] */
32 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
33 }
34
35 /* Augment the error if called as a normal function. __FILE__ and __LINE__
36 * are not desirable in this case.
37 */
38
39#ifdef DUK_USE_AUGMENT_ERROR_CREATE
40 if (!duk_is_constructor_call(ctx)) {
41 duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
42 }
43#endif
44
45 return 1;
46}
47
48DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
49 /* XXX: optimize with more direct internal access */
50
51 duk_push_this(ctx);
52 (void) duk_require_hobject_or_lfunc_coerce(ctx, -1);
53
54 /* [ ... this ] */
55
56 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
57 if (duk_is_undefined(ctx, -1)) {
58 duk_pop(ctx);
59 duk_push_string(ctx, "Error");
60 } else {
61 duk_to_string(ctx, -1);
62 }
63
64 /* [ ... this name ] */
65
66 /* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by
67 * accident or are they actually needed? The first ToString()
68 * could conceivably return 'undefined'.
69 */
70 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
71 if (duk_is_undefined(ctx, -1)) {
72 duk_pop(ctx);
73 duk_push_string(ctx, "");
74 } else {
75 duk_to_string(ctx, -1);
76 }
77
78 /* [ ... this name message ] */
79
80 if (duk_get_length(ctx, -2) == 0) {
81 /* name is empty -> return message */
82 return 1;
83 }
84 if (duk_get_length(ctx, -1) == 0) {
85 /* message is empty -> return name */
86 duk_pop(ctx);
87 return 1;
88 }
89 duk_push_string(ctx, ": ");
90 duk_insert(ctx, -2); /* ... name ': ' message */
91 duk_concat(ctx, 3);
92
93 return 1;
94}
95
96#ifdef DUK_USE_TRACEBACKS
97
98/*
99 * Traceback handling
100 *
101 * The unified helper decodes the traceback and produces various requested
102 * outputs. It should be optimized for size, and may leave garbage on stack,
103 * only the topmost return value matters. For instance, traceback separator
104 * and decoded strings are pushed even when looking for filename only.
105 *
106 * NOTE: although _Tracedata is an internal property, user code can currently
107 * write to the array (or replace it with something other than an array).
108 * The code below must tolerate arbitrary _Tracedata. It can throw errors
109 * etc, but cannot cause a segfault or memory unsafe behavior.
110 */
111
112/* constants arbitrary, chosen for small loads */
113#define DUK__OUTPUT_TYPE_TRACEBACK (-1)
114#define DUK__OUTPUT_TYPE_FILENAME 0
115#define DUK__OUTPUT_TYPE_LINENUMBER 1
116
117DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
118 duk_hthread *thr = (duk_hthread *) ctx;
119 duk_idx_t idx_td;
120 duk_small_int_t i; /* traceback depth fits into 16 bits */
121 duk_small_int_t t; /* stack type fits into 16 bits */
122 const char *str_tailcalled = " tailcalled";
123 const char *str_strict = " strict";
124 const char *str_construct = " construct";
125 const char *str_prevyield = " preventsyield";
126 const char *str_directeval = " directeval";
127 const char *str_empty = "";
128
129 DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */
130
131 duk_push_this(ctx);
132 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TRACEDATA);
133 idx_td = duk_get_top_index(ctx);
134
135 duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_TAB);
136 duk_push_this(ctx);
137
138 /* [ ... this tracedata sep this ] */
139
140 /* XXX: skip null filename? */
141
142 if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) {
143 /* Current tracedata contains 2 entries per callstack entry. */
144 for (i = 0; ; i += 2) {
145 duk_int_t pc;
146 duk_int_t line;
147 duk_int_t flags;
148 duk_double_t d;
149 const char *funcname;
150 const char *filename;
151 duk_hobject *h_func;
152 duk_hstring *h_name;
153
154 duk_require_stack(ctx, 5);
155 duk_get_prop_index(ctx, idx_td, i);
156 duk_get_prop_index(ctx, idx_td, i + 1);
157 d = duk_to_number(ctx, -1);
158 pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32);
159 flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
160 t = (duk_small_int_t) duk_get_type(ctx, -2);
161
162 if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
163 /*
164 * Ecmascript/native function call or lightfunc call
165 */
166
167 /* [ ... v1(func) v2(pc+flags) ] */
168
169 h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */
170
171 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
172 duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME);
173
174#if defined(DUK_USE_PC2LINE)
175 line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc);
176#else
177 line = 0;
178#endif
179
180 /* [ ... v1 v2 name filename ] */
181
182 if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
183 return 1;
184 } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
185 duk_push_int(ctx, line);
186 return 1;
187 }
188
189 h_name = duk_get_hstring(ctx, -2); /* may be NULL */
190 funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
191 "anon" : (const char *) DUK_HSTRING_GET_DATA(h_name);
192 filename = duk_get_string(ctx, -1);
193 filename = filename ? filename : "";
194 DUK_ASSERT(funcname != NULL);
195 DUK_ASSERT(filename != NULL);
196
197 if (h_func == NULL) {
198 duk_push_sprintf(ctx, "%s light%s%s%s%s%s",
199 (const char *) funcname,
200 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
201 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcalled : str_empty),
202 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
203 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
204 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
205 } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h_func)) {
206 duk_push_sprintf(ctx, "%s %s native%s%s%s%s%s",
207 (const char *) funcname,
208 (const char *) filename,
209 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
210 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcalled : str_empty),
211 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
212 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
213 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
214 } else {
215 duk_push_sprintf(ctx, "%s %s:%ld%s%s%s%s%s",
216 (const char *) funcname,
217 (const char *) filename,
218 (long) line,
219 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
220 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcalled : str_empty),
221 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
222 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
223 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
224 }
225 duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
226 duk_pop_n(ctx, 3); /* -> [ ... str ] */
227 } else if (t == DUK_TYPE_STRING) {
228 /*
229 * __FILE__ / __LINE__ entry, here 'pc' is line number directly.
230 * Sometimes __FILE__ / __LINE__ is reported as the source for
231 * the error (fileName, lineNumber), sometimes not.
232 */
233
234 /* [ ... v1(filename) v2(line+flags) ] */
235
236 if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
237 if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
238 duk_pop(ctx);
239 return 1;
240 } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
241 duk_push_int(ctx, pc);
242 return 1;
243 }
244 }
245
246 duk_push_sprintf(ctx, "%s:%ld",
247 (const char *) duk_get_string(ctx, -2), (long) pc);
248 duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
249 duk_pop(ctx); /* -> [ ... str ] */
250 } else {
251 /* unknown, ignore */
252 duk_pop_2(ctx);
253 break;
254 }
255 }
256
257 if (i >= DUK_USE_TRACEBACK_DEPTH * 2) {
258 /* Possibly truncated; there is no explicit truncation
259 * marker so this is the best we can do.
260 */
261
262 duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS);
263 }
264 }
265
266 /* [ ... this tracedata sep this str1 ... strN ] */
267
268 if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) {
269 return 0;
270 } else {
271 /* The 'this' after 'sep' will get ToString() coerced by
272 * duk_join() automatically. We don't want to do that
273 * coercion when providing .fileName or .lineNumber (GH-254).
274 */
275 duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/);
276 return 1;
277 }
278}
279
280/* XXX: output type could be encoded into native function 'magic' value to
281 * save space.
282 */
283
284DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
285 return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
286}
287
288DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
289 return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
290}
291
292DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
293 return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
294}
295
296#undef DUK__OUTPUT_TYPE_TRACEBACK
297#undef DUK__OUTPUT_TYPE_FILENAME
298#undef DUK__OUTPUT_TYPE_LINENUMBER
299
300#else /* DUK_USE_TRACEBACKS */
301
302/*
303 * Traceback handling when tracebacks disabled.
304 *
305 * The fileName / lineNumber stubs are now necessary because built-in
306 * data will include the accessor properties in Error.prototype. If those
307 * are removed for builds without tracebacks, these can also be removed.
308 * 'stack' should still be present and produce a ToString() equivalent:
309 * this is useful for user code which prints a stacktrace and expects to
310 * see something useful. A normal stacktrace also begins with a ToString()
311 * of the error so this makes sense.
312 */
313
314DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
315 /* XXX: remove this native function and map 'stack' accessor
316 * to the toString() implementation directly.
317 */
318 return duk_bi_error_prototype_to_string(ctx);
319}
320
321DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
322 DUK_UNREF(ctx);
323 return 0;
324}
325
326DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
327 DUK_UNREF(ctx);
328 return 0;
329}
330
331#endif /* DUK_USE_TRACEBACKS */
332
333DUK_INTERNAL duk_ret_t duk_bi_error_prototype_nop_setter(duk_context *ctx) {
334 /* Attempt to write 'stack', 'fileName', 'lineNumber' is a silent no-op.
335 * User can use Object.defineProperty() to override this behavior.
336 */
337 DUK_ASSERT_TOP(ctx, 1); /* fixed arg count */
338 DUK_UNREF(ctx);
339 return 0;
340}