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;
}
Example #2
0
/* Helper which can be called both directly and with duk_safe_call(). */
DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx, void *udata) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk__compile_raw_args *comp_args;
	duk_uint_t flags;
	duk_small_uint_t comp_flags;
	duk_hcompfunc *h_templ;

	DUK_ASSERT_CTX_VALID(ctx);
	DUK_ASSERT(udata != NULL);

	/* Note: strictness is not inherited from the current Duktape/C
	 * context.  Otherwise it would not be possible to compile
	 * non-strict code inside a Duktape/C activation (which is
	 * always strict now).  See tests/api/test-eval-strictness.c
	 * for discussion.
	 */

	/* [ ... source? filename? ] (depends on flags) */

	comp_args = (duk__compile_raw_args *) udata;
	flags = comp_args->flags;

	if (flags & DUK_COMPILE_NOFILENAME) {
		/* Automatic filename: 'eval' or 'input'. */
		duk_push_hstring_stridx(ctx, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
	}

	/* [ ... source? filename ] */

	if (!comp_args->src_buffer) {
		duk_hstring *h_sourcecode;

		h_sourcecode = duk_get_hstring(ctx, -2);
		if ((flags & DUK_COMPILE_NOSOURCE) ||  /* args incorrect */
		    (h_sourcecode == NULL)) {          /* e.g. duk_push_string_file_raw() pushed undefined */
			DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE);
		}
		DUK_ASSERT(h_sourcecode != NULL);
		comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
		comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode);
	}
	DUK_ASSERT(comp_args->src_buffer != NULL);

	/* XXX: unnecessary translation of flags */
	comp_flags = 0;
	if (flags & DUK_COMPILE_EVAL) {
		comp_flags |= DUK_JS_COMPILE_FLAG_EVAL;
	}
	if (flags & DUK_COMPILE_FUNCTION) {
		comp_flags |= DUK_JS_COMPILE_FLAG_EVAL |
		              DUK_JS_COMPILE_FLAG_FUNCEXPR;
	}
	if (flags & DUK_COMPILE_STRICT) {
		comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
	}

	/* [ ... source? filename ] */

	duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags);

	/* [ ... source? func_template ] */

	if (flags & DUK_COMPILE_NOSOURCE) {
		;
	} else {
		duk_remove_m2(ctx);
	}

	/* [ ... func_template ] */

	h_templ = (duk_hcompfunc *) duk_known_hobject(ctx, -1);
	duk_js_push_closure(thr,
	                   h_templ,
	                   thr->builtins[DUK_BIDX_GLOBAL_ENV],
	                   thr->builtins[DUK_BIDX_GLOBAL_ENV],
	                   1 /*add_auto_proto*/);
	duk_remove_m2(ctx);   /* -> [ ... closure ] */

	/* [ ... closure ] */

	return 1;
}
Example #3
0
/* Helper which can be called both directly and with duk_safe_call(). */
DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk__compile_raw_args *comp_args;
	duk_uint_t flags;
	duk_small_uint_t comp_flags;
	duk_hcompiledfunction *h_templ;

	/* Note: strictness is not inherited from the current Duktape/C
	 * context.  Otherwise it would not be possible to compile
	 * non-strict code inside a Duktape/C activation (which is
	 * always strict now).  See api-testcases/test-eval-strictness.c
	 * for discussion.
	 */

	/* [ ... source? filename &comp_args ] (depends on flags) */

	comp_args = (duk__compile_raw_args *) duk_require_pointer(ctx, -1);
	flags = comp_args->flags;
	duk_pop(ctx);

	/* [ ... source? filename ] */

	if (!comp_args->src_buffer) {
		duk_hstring *h_sourcecode;

		h_sourcecode = duk_get_hstring(ctx, -2);
		if ((flags & DUK_COMPILE_NOSOURCE) ||  /* args incorrect */
		    (h_sourcecode == NULL)) {          /* e.g. duk_push_file_string_raw() pushed undefined */
			/* XXX: when this error is caused by a nonexistent
			 * file given to duk_peval_file() or similar, the
			 * error message is not the best possible.
			 */
			DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_NO_SOURCECODE);
		}
		DUK_ASSERT(h_sourcecode != NULL);
		comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
		comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode);
	}
	DUK_ASSERT(comp_args->src_buffer != NULL);

	/* XXX: unnecessary translation of flags */
	comp_flags = 0;
	if (flags & DUK_COMPILE_EVAL) {
		comp_flags |= DUK_JS_COMPILE_FLAG_EVAL;
	}
	if (flags & DUK_COMPILE_FUNCTION) {
		comp_flags |= DUK_JS_COMPILE_FLAG_EVAL |
		              DUK_JS_COMPILE_FLAG_FUNCEXPR;
	}
	if (flags & DUK_COMPILE_STRICT) {
		comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
	}

	/* [ ... source? filename ] */

	duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags);

	/* [ ... source? func_template ] */

	if (flags & DUK_COMPILE_NOSOURCE) {
		;
	} else {
		duk_remove(ctx, -2);
	}

	/* [ ... func_template ] */

	h_templ = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
	DUK_ASSERT(h_templ != NULL);
	duk_js_push_closure(thr,
	                   h_templ,
	                   thr->builtins[DUK_BIDX_GLOBAL_ENV],
	                   thr->builtins[DUK_BIDX_GLOBAL_ENV]);
	duk_remove(ctx, -2);   /* -> [ ... closure ] */

	/* [ ... closure ] */

	return 1;
}
Example #4
0
int duk_bi_function_constructor(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;
	int num_args;
	int i;
	int comp_flags;
	duk_hcompiledfunction *func;
	duk_hobject *outer_lex_env;
	duk_hobject *outer_var_env;

	/* normal and constructor calls have identical semantics */

	num_args = duk_get_top(ctx);

	for (i = 0; i < num_args; i++) {
		duk_to_string(ctx, i);
	}

	if (num_args == 0) {
		duk_push_string(ctx, "");
		duk_push_string(ctx, "");
	} else if (num_args == 1) {
		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, num_args - 1);
	}

	/* [ body formals ], formals is comma separated list that needs to be parsed */

	DUK_ASSERT_TOP(ctx, 2);

	/* FIXME: 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);

	DUK_ASSERT_TOP(ctx, 3);

	/* FIXME: uses internal API */

	/* strictness is not inherited, intentional */
	comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR;

	duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE);  /* XXX: copy from caller? */
	duk_js_compile(thr, comp_flags);
	func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
	DUK_ASSERT(func != NULL);
	DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));

	/* 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);

	return 1;
}