1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
/*
* Compilation and evaluation
*/
#include "duk_internal.h"
typedef struct duk__compile_raw_args duk__compile_raw_args;
struct duk__compile_raw_args {
duk_size_t src_length; /* should be first on 64-bit platforms */
const duk_uint8_t *src_buffer;
duk_uint_t flags;
};
/* Eval is just a wrapper now. */
DUK_EXTERNAL duk_int_t duk_eval_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
duk_int_t rc;
DUK_ASSERT_API_ENTRY(thr);
/* Note: strictness is *not* inherited from the current Duktape/C.
* This would be confusing because the current strictness state
* depends on whether we're running inside a Duktape/C activation
* (= strict mode) or outside of any activation (= non-strict mode).
* See tests/api/test-eval-strictness.c for more discussion.
*/
/* [ ... source? filename? ] (depends on flags) */
rc = duk_compile_raw(thr,
src_buffer,
src_length,
flags | DUK_COMPILE_EVAL); /* may be safe, or non-safe depending on flags */
/* [ ... closure/error ] */
if (rc != DUK_EXEC_SUCCESS) {
rc = DUK_EXEC_ERROR;
goto got_rc;
}
duk_push_global_object(thr); /* explicit 'this' binding, see GH-164 */
if (flags & DUK_COMPILE_SAFE) {
rc = duk_pcall_method(thr, 0);
} else {
duk_call_method(thr, 0);
rc = DUK_EXEC_SUCCESS;
}
/* [ ... result/error ] */
got_rc:
if (flags & DUK_COMPILE_NORESULT) {
duk_pop(thr);
}
return rc;
}
/* Helper which can be called both directly and with duk_safe_call(). */
DUK_LOCAL duk_ret_t duk__do_compile(duk_hthread *thr, void *udata) {
duk__compile_raw_args *comp_args;
duk_uint_t flags;
duk_hcompfunc *h_templ;
DUK_CTX_ASSERT_VALID(thr);
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(thr, (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(thr, -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_WO_NORETURN(return 0;);
}
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);
if (flags & DUK_COMPILE_FUNCTION) {
flags |= DUK_COMPILE_EVAL | DUK_COMPILE_FUNCEXPR;
}
/* [ ... source? filename ] */
duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, flags);
/* [ ... source? func_template ] */
if (flags & DUK_COMPILE_NOSOURCE) {
;
} else {
duk_remove_m2(thr);
}
/* [ ... func_template ] */
h_templ = (duk_hcompfunc *) duk_known_hobject(thr, -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(thr); /* -> [ ... closure ] */
/* [ ... closure ] */
return 1;
}
DUK_EXTERNAL duk_int_t duk_compile_raw(duk_hthread *thr, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
duk__compile_raw_args comp_args_alloc;
duk__compile_raw_args *comp_args = &comp_args_alloc;
DUK_ASSERT_API_ENTRY(thr);
if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) {
/* String length is computed here to avoid multiple evaluation
* of a macro argument in the calling side.
*/
src_length = DUK_STRLEN(src_buffer);
}
comp_args->src_buffer = (const duk_uint8_t *) src_buffer;
comp_args->src_length = src_length;
comp_args->flags = flags;
/* [ ... source? filename? ] (depends on flags) */
if (flags & DUK_COMPILE_SAFE) {
duk_int_t rc;
duk_int_t nargs;
duk_int_t nrets = 1;
/* Arguments can be: [ source? filename? &comp_args] so that
* nargs is 1 to 3. Call site encodes the correct nargs count
* directly into flags.
*/
nargs = flags & 0x07;
DUK_ASSERT(nargs == ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) + ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1));
rc = duk_safe_call(thr, duk__do_compile, (void *) comp_args, nargs, nrets);
/* [ ... closure ] */
return rc;
}
(void) duk__do_compile(thr, (void *) comp_args);
/* [ ... closure ] */
return DUK_EXEC_SUCCESS;
}
|