]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_function.c
import 12.2.13 release
[ceph.git] / ceph / src / civetweb / src / third_party / duktape-1.5.2 / src-separate / duk_bi_function.c
diff --git a/ceph/src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_function.c b/ceph/src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_function.c
new file mode 100644 (file)
index 0000000..2596a4a
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ *  Function built-ins
+ */
+
+#include "duk_internal.h"
+
+DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
+       duk_hthread *thr = (duk_hthread *) ctx;
+       duk_hstring *h_sourcecode;
+       duk_idx_t nargs;
+       duk_idx_t i;
+       duk_small_uint_t comp_flags;
+       duk_hcompiledfunction *func;
+       duk_hobject *outer_lex_env;
+       duk_hobject *outer_var_env;
+
+       /* normal and constructor calls have identical semantics */
+
+       nargs = duk_get_top(ctx);
+       for (i = 0; i < nargs; i++) {
+               duk_to_string(ctx, i);
+       }
+
+       if (nargs == 0) {
+               duk_push_string(ctx, "");
+               duk_push_string(ctx, "");
+       } else if (nargs == 1) {
+               /* XXX: cover this with the generic >1 case? */
+               duk_push_string(ctx, "");
+       } else {
+               duk_insert(ctx, 0);   /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
+               duk_push_string(ctx, ",");
+               duk_insert(ctx, 1);
+               duk_join(ctx, nargs - 1);
+       }
+
+       /* [ body formals ], formals is comma separated list that needs to be parsed */
+
+       DUK_ASSERT_TOP(ctx, 2);
+
+       /* XXX: this placeholder is not always correct, but use for now.
+        * It will fail in corner cases; see test-dev-func-cons-args.js.
+        */
+       duk_push_string(ctx, "function(");
+       duk_dup(ctx, 1);
+       duk_push_string(ctx, "){");
+       duk_dup(ctx, 0);
+       duk_push_string(ctx, "}");
+       duk_concat(ctx, 5);
+
+       /* [ body formals source ] */
+
+       DUK_ASSERT_TOP(ctx, 3);
+
+       /* strictness is not inherited, intentional */
+       comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR;
+
+       duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE);  /* XXX: copy from caller? */  /* XXX: ignored now */
+       h_sourcecode = duk_require_hstring(ctx, -2);
+       duk_js_compile(thr,
+                      (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
+                      (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
+                      comp_flags);
+       func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
+       DUK_ASSERT(func != NULL);
+       DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
+
+       /* [ body formals source template ] */
+
+       /* only outer_lex_env matters, as functions always get a new
+        * variable declaration environment.
+        */
+
+       outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
+       outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
+
+       duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 1 /*add_auto_proto*/);
+
+       /* [ body formals source template closure ] */
+
+       return 1;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) {
+       /* ignore arguments, return undefined (E5 Section 15.3.4) */
+       DUK_UNREF(ctx);
+       return 0;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
+       duk_tval *tv;
+
+       /*
+        *  E5 Section 15.3.4.2 places few requirements on the output of
+        *  this function:
+        *
+        *    - The result is an implementation dependent representation
+        *      of the function; in particular
+        *
+        *    - The result must follow the syntax of a FunctionDeclaration.
+        *      In particular, the function must have a name (even in the
+        *      case of an anonymous function or a function with an empty
+        *      name).
+        *
+        *    - Note in particular that the output does NOT need to compile
+        *      into anything useful.
+        */
+
+
+       /* XXX: faster internal way to get this */
+       duk_push_this(ctx);
+       tv = duk_get_tval(ctx, -1);
+       DUK_ASSERT(tv != NULL);
+
+       if (DUK_TVAL_IS_OBJECT(tv)) {
+               duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv);
+               const char *func_name;
+
+               /* Function name: missing/undefined is mapped to empty string,
+                * otherwise coerce to string.
+                */
+               /* XXX: currently no handling for non-allowed identifier characters,
+                * e.g. a '{' in the function name.
+                */
+               duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
+               if (duk_is_undefined(ctx, -1)) {
+                       func_name = "";
+               } else {
+                       func_name = duk_to_string(ctx, -1);
+                       DUK_ASSERT(func_name != NULL);
+               }
+
+               /* Indicate function type in the function body using a dummy
+                * directive.
+                */
+               if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj)) {
+                       duk_push_sprintf(ctx, "function %s() {\"ecmascript\"}", (const char *) func_name);
+               } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
+                       duk_push_sprintf(ctx, "function %s() {\"native\"}", (const char *) func_name);
+               } else if (DUK_HOBJECT_HAS_BOUND(obj)) {
+                       duk_push_sprintf(ctx, "function %s() {\"bound\"}", (const char *) func_name);
+               } else {
+                       goto type_error;
+               }
+       } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
+               duk_push_lightfunc_tostring(ctx, tv);
+       } else {
+               goto type_error;
+       }
+
+       return 1;
+
+ type_error:
+       return DUK_RET_TYPE_ERROR;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) {
+       duk_idx_t len;
+       duk_idx_t i;
+
+       DUK_ASSERT_TOP(ctx, 2);  /* not a vararg function */
+
+       duk_push_this(ctx);
+       if (!duk_is_callable(ctx, -1)) {
+               DUK_DDD(DUK_DDDPRINT("func is not callable"));
+               goto type_error;
+       }
+       duk_insert(ctx, 0);
+       DUK_ASSERT_TOP(ctx, 3);
+
+       DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT",
+                            (duk_tval *) duk_get_tval(ctx, 0),
+                            (duk_tval *) duk_get_tval(ctx, 1),
+                            (duk_tval *) duk_get_tval(ctx, 2)));
+
+       /* [ func thisArg argArray ] */
+
+       if (duk_is_null_or_undefined(ctx, 2)) {
+               DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args"));
+               len = 0;
+       } else if (!duk_is_object(ctx, 2)) {
+               goto type_error;
+       } else {
+               DUK_DDD(DUK_DDDPRINT("argArray is an object"));
+
+               /* XXX: make this an internal helper */
+               duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH);
+               len = (duk_idx_t) duk_to_uint32(ctx, -1);  /* ToUint32() coercion required */
+               duk_pop(ctx);
+
+               duk_require_stack(ctx, len);
+
+               DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len));
+               for (i = 0; i < len; i++) {
+                       duk_get_prop_index(ctx, 2, i);
+               }
+       }
+       duk_remove(ctx, 2);
+       DUK_ASSERT_TOP(ctx, 2 + len);
+
+       /* [ func thisArg arg1 ... argN ] */
+
+       DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld",
+                            (duk_tval *) duk_get_tval(ctx, 0),
+                            (duk_tval *) duk_get_tval(ctx, 1),
+                            (long) len));
+       duk_call_method(ctx, len);
+       return 1;
+
+ type_error:
+       return DUK_RET_TYPE_ERROR;
+}
+
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) {
+       duk_idx_t nargs;
+
+       /* Step 1 is not necessary because duk_call_method() will take
+        * care of it.
+        */
+
+       /* vararg function, thisArg needs special handling */
+       nargs = duk_get_top(ctx);  /* = 1 + arg count */
+       if (nargs == 0) {
+               duk_push_undefined(ctx);
+               nargs++;
+       }
+       DUK_ASSERT(nargs >= 1);
+
+       /* [ thisArg arg1 ... argN ] */
+
+       duk_push_this(ctx);  /* 'func' in the algorithm */
+       duk_insert(ctx, 0);
+
+       /* [ func thisArg arg1 ... argN ] */
+
+       DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld",
+                            (duk_tval *) duk_get_tval(ctx, 0),
+                            (duk_tval *) duk_get_tval(ctx, 1),
+                            (long) (nargs - 1),
+                            (long) duk_get_top(ctx)));
+       duk_call_method(ctx, nargs - 1);
+       return 1;
+}
+
+/* XXX: the implementation now assumes "chained" bound functions,
+ * whereas "collapsed" bound functions (where there is ever only
+ * one bound function which directly points to a non-bound, final
+ * function) would require a "collapsing" implementation which
+ * merges argument lists etc here.
+ */
+DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) {
+       duk_hobject *h_bound;
+       duk_hobject *h_target;
+       duk_idx_t nargs;
+       duk_idx_t i;
+
+       /* vararg function, careful arg handling (e.g. thisArg may not be present) */
+       nargs = duk_get_top(ctx);  /* = 1 + arg count */
+       if (nargs == 0) {
+               duk_push_undefined(ctx);
+               nargs++;
+       }
+       DUK_ASSERT(nargs >= 1);
+
+       duk_push_this(ctx);
+       if (!duk_is_callable(ctx, -1)) {
+               DUK_DDD(DUK_DDDPRINT("func is not callable"));
+               goto type_error;
+       }
+
+       /* [ thisArg arg1 ... argN func ]  (thisArg+args == nargs total) */
+       DUK_ASSERT_TOP(ctx, nargs + 1);
+
+       /* create bound function object */
+       duk_push_object_helper(ctx,
+                              DUK_HOBJECT_FLAG_EXTENSIBLE |
+                              DUK_HOBJECT_FLAG_BOUND |
+                              DUK_HOBJECT_FLAG_CONSTRUCTABLE |
+                              DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
+                              DUK_BIDX_FUNCTION_PROTOTYPE);
+       h_bound = duk_get_hobject(ctx, -1);
+       DUK_ASSERT(h_bound != NULL);
+
+       /* [ thisArg arg1 ... argN func boundFunc ] */
+       duk_dup(ctx, -2);  /* func */
+       duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
+
+       duk_dup(ctx, 0);   /* thisArg */
+       duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
+
+       duk_push_array(ctx);
+
+       /* [ thisArg arg1 ... argN func boundFunc argArray ] */
+
+       for (i = 0; i < nargs - 1; i++) {
+               duk_dup(ctx, 1 + i);
+               duk_put_prop_index(ctx, -2, i);
+       }
+       duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);
+
+       /* [ thisArg arg1 ... argN func boundFunc ] */
+
+       /* bound function 'length' property is interesting */
+       h_target = duk_get_hobject(ctx, -2);
+       if (h_target == NULL ||  /* lightfunc */
+           DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
+               /* For lightfuncs, simply read the virtual property. */
+               duk_int_t tmp;
+               duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH);
+               tmp = duk_to_int(ctx, -1) - (nargs - 1);  /* step 15.a */
+               duk_pop(ctx);
+               duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
+       } else {
+               duk_push_int(ctx, 0);
+       }
+       duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);  /* attrs in E5 Section 15.3.5.1 */
+
+       /* caller and arguments must use the same thrower, [[ThrowTypeError]] */
+       duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
+       duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
+
+       /* these non-standard properties are copied for convenience */
+       /* XXX: 'copy properties' API call? */
+       duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
+       duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC);
+       duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME);
+       duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
+
+       /* The 'strict' flag is copied to get the special [[Get]] of E5.1
+        * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
+        * function.  Not sure if this is correct, because the specification
+        * is a bit ambiguous on this point but it would make sense.
+        */
+       if (h_target == NULL) {
+               /* Lightfuncs are always strict. */
+               DUK_HOBJECT_SET_STRICT(h_bound);
+       } else if (DUK_HOBJECT_HAS_STRICT(h_target)) {
+               DUK_HOBJECT_SET_STRICT(h_bound);
+       }
+       DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
+
+       return 1;
+
+ type_error:
+       return DUK_RET_TYPE_ERROR;
+}