]> git.proxmox.com Git - ceph.git/blob - ceph/src/civetweb/src/third_party/duktape-1.3.0/src-separate/duk_bi_function.c
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / civetweb / src / third_party / duktape-1.3.0 / src-separate / duk_bi_function.c
1 /*
2 * Function built-ins
3 */
4
5 #include "duk_internal.h"
6
7 DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
8 duk_hthread *thr = (duk_hthread *) ctx;
9 duk_hstring *h_sourcecode;
10 duk_idx_t nargs;
11 duk_idx_t i;
12 duk_small_uint_t comp_flags;
13 duk_hcompiledfunction *func;
14 duk_hobject *outer_lex_env;
15 duk_hobject *outer_var_env;
16
17 /* normal and constructor calls have identical semantics */
18
19 nargs = duk_get_top(ctx);
20 for (i = 0; i < nargs; i++) {
21 duk_to_string(ctx, i);
22 }
23
24 if (nargs == 0) {
25 duk_push_string(ctx, "");
26 duk_push_string(ctx, "");
27 } else if (nargs == 1) {
28 /* XXX: cover this with the generic >1 case? */
29 duk_push_string(ctx, "");
30 } else {
31 duk_insert(ctx, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
32 duk_push_string(ctx, ",");
33 duk_insert(ctx, 1);
34 duk_join(ctx, nargs - 1);
35 }
36
37 /* [ body formals ], formals is comma separated list that needs to be parsed */
38
39 DUK_ASSERT_TOP(ctx, 2);
40
41 /* XXX: this placeholder is not always correct, but use for now.
42 * It will fail in corner cases; see test-dev-func-cons-args.js.
43 */
44 duk_push_string(ctx, "function(");
45 duk_dup(ctx, 1);
46 duk_push_string(ctx, "){");
47 duk_dup(ctx, 0);
48 duk_push_string(ctx, "}");
49 duk_concat(ctx, 5);
50
51 /* [ body formals source ] */
52
53 DUK_ASSERT_TOP(ctx, 3);
54
55 /* strictness is not inherited, intentional */
56 comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR;
57
58 duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
59 h_sourcecode = duk_require_hstring(ctx, -2);
60 duk_js_compile(thr,
61 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
62 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
63 comp_flags);
64 func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
65 DUK_ASSERT(func != NULL);
66 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
67
68 /* [ body formals source template ] */
69
70 /* only outer_lex_env matters, as functions always get a new
71 * variable declaration environment.
72 */
73
74 outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
75 outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
76
77 duk_js_push_closure(thr, func, outer_var_env, outer_lex_env);
78
79 /* [ body formals source template closure ] */
80
81 return 1;
82 }
83
84 DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) {
85 /* ignore arguments, return undefined (E5 Section 15.3.4) */
86 DUK_UNREF(ctx);
87 return 0;
88 }
89
90 DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
91 duk_tval *tv;
92
93 /*
94 * E5 Section 15.3.4.2 places few requirements on the output of
95 * this function:
96 *
97 * - The result is an implementation dependent representation
98 * of the function; in particular
99 *
100 * - The result must follow the syntax of a FunctionDeclaration.
101 * In particular, the function must have a name (even in the
102 * case of an anonymous function or a function with an empty
103 * name).
104 *
105 * - Note in particular that the output does NOT need to compile
106 * into anything useful.
107 */
108
109
110 /* XXX: faster internal way to get this */
111 duk_push_this(ctx);
112 tv = duk_get_tval(ctx, -1);
113 DUK_ASSERT(tv != NULL);
114
115 if (DUK_TVAL_IS_OBJECT(tv)) {
116 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv);
117 const char *func_name = DUK_STR_ANON;
118
119 /* XXX: rework, it would be nice to avoid C formatting functions to
120 * ensure there are no Unicode issues.
121 */
122
123 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
124 if (!duk_is_undefined(ctx, -1)) {
125 func_name = duk_to_string(ctx, -1);
126 DUK_ASSERT(func_name != NULL);
127
128 if (func_name[0] == (char) 0) {
129 func_name = DUK_STR_ANON;
130 }
131 }
132
133 if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj)) {
134 /* XXX: actual source, if available */
135 duk_push_sprintf(ctx, "function %s() {/* ecmascript */}", (const char *) func_name);
136 } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
137 duk_push_sprintf(ctx, "function %s() {/* native */}", (const char *) func_name);
138 } else if (DUK_HOBJECT_HAS_BOUND(obj)) {
139 duk_push_sprintf(ctx, "function %s() {/* bound */}", (const char *) func_name);
140 } else {
141 goto type_error;
142 }
143 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
144 duk_push_lightfunc_tostring(ctx, tv);
145 } else {
146 goto type_error;
147 }
148
149 return 1;
150
151 type_error:
152 return DUK_RET_TYPE_ERROR;
153 }
154
155 DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) {
156 duk_idx_t len;
157 duk_idx_t i;
158
159 DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */
160
161 duk_push_this(ctx);
162 if (!duk_is_callable(ctx, -1)) {
163 DUK_DDD(DUK_DDDPRINT("func is not callable"));
164 goto type_error;
165 }
166 duk_insert(ctx, 0);
167 DUK_ASSERT_TOP(ctx, 3);
168
169 DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT",
170 (duk_tval *) duk_get_tval(ctx, 0),
171 (duk_tval *) duk_get_tval(ctx, 1),
172 (duk_tval *) duk_get_tval(ctx, 2)));
173
174 /* [ func thisArg argArray ] */
175
176 if (duk_is_null_or_undefined(ctx, 2)) {
177 DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args"));
178 len = 0;
179 } else if (!duk_is_object(ctx, 2)) {
180 goto type_error;
181 } else {
182 DUK_DDD(DUK_DDDPRINT("argArray is an object"));
183
184 /* XXX: make this an internal helper */
185 duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH);
186 len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */
187 duk_pop(ctx);
188
189 duk_require_stack(ctx, len);
190
191 DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len));
192 for (i = 0; i < len; i++) {
193 duk_get_prop_index(ctx, 2, i);
194 }
195 }
196 duk_remove(ctx, 2);
197 DUK_ASSERT_TOP(ctx, 2 + len);
198
199 /* [ func thisArg arg1 ... argN ] */
200
201 DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld",
202 (duk_tval *) duk_get_tval(ctx, 0),
203 (duk_tval *) duk_get_tval(ctx, 1),
204 (long) len));
205 duk_call_method(ctx, len);
206 return 1;
207
208 type_error:
209 return DUK_RET_TYPE_ERROR;
210 }
211
212 DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) {
213 duk_idx_t nargs;
214
215 /* Step 1 is not necessary because duk_call_method() will take
216 * care of it.
217 */
218
219 /* vararg function, thisArg needs special handling */
220 nargs = duk_get_top(ctx); /* = 1 + arg count */
221 if (nargs == 0) {
222 duk_push_undefined(ctx);
223 nargs++;
224 }
225 DUK_ASSERT(nargs >= 1);
226
227 /* [ thisArg arg1 ... argN ] */
228
229 duk_push_this(ctx); /* 'func' in the algorithm */
230 duk_insert(ctx, 0);
231
232 /* [ func thisArg arg1 ... argN ] */
233
234 DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld",
235 (duk_tval *) duk_get_tval(ctx, 0),
236 (duk_tval *) duk_get_tval(ctx, 1),
237 (long) (nargs - 1),
238 (long) duk_get_top(ctx)));
239 duk_call_method(ctx, nargs - 1);
240 return 1;
241 }
242
243 /* XXX: the implementation now assumes "chained" bound functions,
244 * whereas "collapsed" bound functions (where there is ever only
245 * one bound function which directly points to a non-bound, final
246 * function) would require a "collapsing" implementation which
247 * merges argument lists etc here.
248 */
249 DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) {
250 duk_hobject *h_bound;
251 duk_hobject *h_target;
252 duk_idx_t nargs;
253 duk_idx_t i;
254
255 /* vararg function, careful arg handling (e.g. thisArg may not be present) */
256 nargs = duk_get_top(ctx); /* = 1 + arg count */
257 if (nargs == 0) {
258 duk_push_undefined(ctx);
259 nargs++;
260 }
261 DUK_ASSERT(nargs >= 1);
262
263 duk_push_this(ctx);
264 if (!duk_is_callable(ctx, -1)) {
265 DUK_DDD(DUK_DDDPRINT("func is not callable"));
266 goto type_error;
267 }
268
269 /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */
270 DUK_ASSERT_TOP(ctx, nargs + 1);
271
272 /* create bound function object */
273 duk_push_object_helper(ctx,
274 DUK_HOBJECT_FLAG_EXTENSIBLE |
275 DUK_HOBJECT_FLAG_BOUND |
276 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
277 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
278 DUK_BIDX_FUNCTION_PROTOTYPE);
279 h_bound = duk_get_hobject(ctx, -1);
280 DUK_ASSERT(h_bound != NULL);
281
282 /* [ thisArg arg1 ... argN func boundFunc ] */
283 duk_dup(ctx, -2); /* func */
284 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
285
286 duk_dup(ctx, 0); /* thisArg */
287 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
288
289 duk_push_array(ctx);
290
291 /* [ thisArg arg1 ... argN func boundFunc argArray ] */
292
293 for (i = 0; i < nargs - 1; i++) {
294 duk_dup(ctx, 1 + i);
295 duk_put_prop_index(ctx, -2, i);
296 }
297 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);
298
299 /* [ thisArg arg1 ... argN func boundFunc ] */
300
301 /* bound function 'length' property is interesting */
302 h_target = duk_get_hobject(ctx, -2);
303 if (h_target == NULL || /* lightfunc */
304 DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
305 /* For lightfuncs, simply read the virtual property. */
306 duk_int_t tmp;
307 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH);
308 tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */
309 duk_pop(ctx);
310 duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
311 } else {
312 duk_push_int(ctx, 0);
313 }
314 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); /* attrs in E5 Section 15.3.5.1 */
315
316 /* caller and arguments must use the same thrower, [[ThrowTypeError]] */
317 duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
318 duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
319
320 /* these non-standard properties are copied for convenience */
321 /* XXX: 'copy properties' API call? */
322 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
323 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC);
324 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME);
325 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
326
327 /* The 'strict' flag is copied to get the special [[Get]] of E5.1
328 * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
329 * function. Not sure if this is correct, because the specification
330 * is a bit ambiguous on this point but it would make sense.
331 */
332 if (h_target == NULL) {
333 /* Lightfuncs are always strict. */
334 DUK_HOBJECT_SET_STRICT(h_bound);
335 } else if (DUK_HOBJECT_HAS_STRICT(h_target)) {
336 DUK_HOBJECT_SET_STRICT(h_bound);
337 }
338 DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
339
340 return 1;
341
342 type_error:
343 return DUK_RET_TYPE_ERROR;
344 }