5 #include "duk_internal.h"
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
;
12 duk_small_uint_t comp_flags
;
13 duk_hcompiledfunction
*func
;
14 duk_hobject
*outer_lex_env
;
15 duk_hobject
*outer_var_env
;
17 /* normal and constructor calls have identical semantics */
19 nargs
= duk_get_top(ctx
);
20 for (i
= 0; i
< nargs
; i
++) {
21 duk_to_string(ctx
, i
);
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
, "");
31 duk_insert(ctx
, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
32 duk_push_string(ctx
, ",");
34 duk_join(ctx
, nargs
- 1);
37 /* [ body formals ], formals is comma separated list that needs to be parsed */
39 DUK_ASSERT_TOP(ctx
, 2);
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.
44 duk_push_string(ctx
, "function(");
46 duk_push_string(ctx
, "){");
48 duk_push_string(ctx
, "}");
51 /* [ body formals source ] */
53 DUK_ASSERT_TOP(ctx
, 3);
55 /* strictness is not inherited, intentional */
56 comp_flags
= DUK_JS_COMPILE_FLAG_FUNCEXPR
;
58 duk_push_hstring_stridx(ctx
, DUK_STRIDX_COMPILE
); /* XXX: copy from caller? */ /* XXX: ignored now */
59 h_sourcecode
= duk_require_hstring(ctx
, -2);
61 (const duk_uint8_t
*) DUK_HSTRING_GET_DATA(h_sourcecode
),
62 (duk_size_t
) DUK_HSTRING_GET_BYTELEN(h_sourcecode
),
64 func
= (duk_hcompiledfunction
*) duk_get_hobject(ctx
, -1);
65 DUK_ASSERT(func
!= NULL
);
66 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject
*) func
));
68 /* [ body formals source template ] */
70 /* only outer_lex_env matters, as functions always get a new
71 * variable declaration environment.
74 outer_lex_env
= thr
->builtins
[DUK_BIDX_GLOBAL_ENV
];
75 outer_var_env
= thr
->builtins
[DUK_BIDX_GLOBAL_ENV
];
77 duk_js_push_closure(thr
, func
, outer_var_env
, outer_lex_env
);
79 /* [ body formals source template closure ] */
84 DUK_INTERNAL duk_ret_t
duk_bi_function_prototype(duk_context
*ctx
) {
85 /* ignore arguments, return undefined (E5 Section 15.3.4) */
90 DUK_INTERNAL duk_ret_t
duk_bi_function_prototype_to_string(duk_context
*ctx
) {
94 * E5 Section 15.3.4.2 places few requirements on the output of
97 * - The result is an implementation dependent representation
98 * of the function; in particular
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
105 * - Note in particular that the output does NOT need to compile
106 * into anything useful.
110 /* XXX: faster internal way to get this */
112 tv
= duk_get_tval(ctx
, -1);
113 DUK_ASSERT(tv
!= NULL
);
115 if (DUK_TVAL_IS_OBJECT(tv
)) {
116 duk_hobject
*obj
= DUK_TVAL_GET_OBJECT(tv
);
117 const char *func_name
= DUK_STR_ANON
;
119 /* XXX: rework, it would be nice to avoid C formatting functions to
120 * ensure there are no Unicode issues.
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
);
128 if (func_name
[0] == (char) 0) {
129 func_name
= DUK_STR_ANON
;
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
);
143 } else if (DUK_TVAL_IS_LIGHTFUNC(tv
)) {
144 duk_push_lightfunc_tostring(ctx
, tv
);
152 return DUK_RET_TYPE_ERROR
;
155 DUK_INTERNAL duk_ret_t
duk_bi_function_prototype_apply(duk_context
*ctx
) {
159 DUK_ASSERT_TOP(ctx
, 2); /* not a vararg function */
162 if (!duk_is_callable(ctx
, -1)) {
163 DUK_DDD(DUK_DDDPRINT("func is not callable"));
167 DUK_ASSERT_TOP(ctx
, 3);
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)));
174 /* [ func thisArg argArray ] */
176 if (duk_is_null_or_undefined(ctx
, 2)) {
177 DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args"));
179 } else if (!duk_is_object(ctx
, 2)) {
182 DUK_DDD(DUK_DDDPRINT("argArray is an object"));
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 */
189 duk_require_stack(ctx
, len
);
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
);
197 DUK_ASSERT_TOP(ctx
, 2 + len
);
199 /* [ func thisArg arg1 ... argN ] */
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),
205 duk_call_method(ctx
, len
);
209 return DUK_RET_TYPE_ERROR
;
212 DUK_INTERNAL duk_ret_t
duk_bi_function_prototype_call(duk_context
*ctx
) {
215 /* Step 1 is not necessary because duk_call_method() will take
219 /* vararg function, thisArg needs special handling */
220 nargs
= duk_get_top(ctx
); /* = 1 + arg count */
222 duk_push_undefined(ctx
);
225 DUK_ASSERT(nargs
>= 1);
227 /* [ thisArg arg1 ... argN ] */
229 duk_push_this(ctx
); /* 'func' in the algorithm */
232 /* [ func thisArg arg1 ... argN ] */
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),
238 (long) duk_get_top(ctx
)));
239 duk_call_method(ctx
, nargs
- 1);
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.
249 DUK_INTERNAL duk_ret_t
duk_bi_function_prototype_bind(duk_context
*ctx
) {
250 duk_hobject
*h_bound
;
251 duk_hobject
*h_target
;
255 /* vararg function, careful arg handling (e.g. thisArg may not be present) */
256 nargs
= duk_get_top(ctx
); /* = 1 + arg count */
258 duk_push_undefined(ctx
);
261 DUK_ASSERT(nargs
>= 1);
264 if (!duk_is_callable(ctx
, -1)) {
265 DUK_DDD(DUK_DDDPRINT("func is not callable"));
269 /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */
270 DUK_ASSERT_TOP(ctx
, nargs
+ 1);
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
);
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
);
286 duk_dup(ctx
, 0); /* thisArg */
287 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_INT_THIS
, DUK_PROPDESC_FLAGS_NONE
);
291 /* [ thisArg arg1 ... argN func boundFunc argArray ] */
293 for (i
= 0; i
< nargs
- 1; i
++) {
295 duk_put_prop_index(ctx
, -2, i
);
297 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_INT_ARGS
, DUK_PROPDESC_FLAGS_NONE
);
299 /* [ thisArg arg1 ... argN func boundFunc ] */
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. */
307 duk_get_prop_stridx(ctx
, -2, DUK_STRIDX_LENGTH
);
308 tmp
= duk_to_int(ctx
, -1) - (nargs
- 1); /* step 15.a */
310 duk_push_int(ctx
, (tmp
< 0 ? 0 : tmp
));
312 duk_push_int(ctx
, 0);
314 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_LENGTH
, DUK_PROPDESC_FLAGS_NONE
); /* attrs in E5 Section 15.3.5.1 */
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
);
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
);
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.
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
);
338 DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval
*) duk_get_tval(ctx
, -1)));
343 return DUK_RET_TYPE_ERROR
;