2 * Global object built-ins
5 #include "duk_internal.h"
8 * Encoding/decoding helpers
11 /* XXX: Could add fast path (for each transform callback) with direct byte
12 * lookups (no shifting) and no explicit check for x < 0x80 before table
16 /* Macros for creating and checking bitmasks for character encoding.
17 * Bit number is a bit counterintuitive, but minimizes code size.
19 #define DUK__MKBITS(a,b,c,d,e,f,g,h) ((duk_uint8_t) ( \
20 ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \
21 ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \
23 #define DUK__CHECK_BITMASK(table,cp) ((table)[(cp) >> 3] & (1 << ((cp) & 0x07)))
25 /* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */
26 DUK_LOCAL
const duk_uint8_t duk__encode_uriunescaped_table
[16] = {
27 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
28 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
29 DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x20-0x2f */
30 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
31 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
32 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
33 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
34 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
37 /* E5.1 Section 15.1.3.4: uriUnescaped */
38 DUK_LOCAL
const duk_uint8_t duk__encode_uricomponent_unescaped_table
[16] = {
39 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
40 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
41 DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1), DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0), /* 0x20-0x2f */
42 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
43 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
44 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
45 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
46 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
49 /* E5.1 Section 15.1.3.1: uriReserved + '#' */
50 DUK_LOCAL
const duk_uint8_t duk__decode_uri_reserved_table
[16] = {
51 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
52 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
53 DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0), DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1), /* 0x20-0x2f */
54 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
55 DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
56 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
57 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
58 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
61 /* E5.1 Section 15.1.3.2: empty */
62 DUK_LOCAL
const duk_uint8_t duk__decode_uri_component_reserved_table
[16] = {
63 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
64 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
65 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x20-0x2f */
66 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
67 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
68 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
69 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
70 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
73 #ifdef DUK_USE_SECTION_B
74 /* E5.1 Section B.2.2, step 7. */
75 DUK_LOCAL
const duk_uint8_t duk__escape_unescaped_table
[16] = {
76 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
77 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
78 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1), /* 0x20-0x2f */
79 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
80 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
81 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
82 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
83 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0) /* 0x70-0x7f */
85 #endif /* DUK_USE_SECTION_B */
94 const duk_uint8_t
*p_start
;
95 const duk_uint8_t
*p_end
;
96 } duk__transform_context
;
98 typedef void (*duk__transform_callback
)(duk__transform_context
*tfm_ctx
, void *udata
, duk_codepoint_t cp
);
100 /* XXX: refactor and share with other code */
101 DUK_LOCAL duk_small_int_t
duk__decode_hex_escape(const duk_uint8_t
*p
, duk_small_int_t n
) {
103 duk_small_int_t t
= 0;
107 ch
= (duk_small_int_t
) duk_hex_dectab
[*p
++];
108 if (DUK_LIKELY(ch
>= 0)) {
118 DUK_LOCAL
int duk__transform_helper(duk_context
*ctx
, duk__transform_callback callback
, void *udata
) {
119 duk_hthread
*thr
= (duk_hthread
*) ctx
;
120 duk__transform_context tfm_ctx_alloc
;
121 duk__transform_context
*tfm_ctx
= &tfm_ctx_alloc
;
126 tfm_ctx
->h_str
= duk_to_hstring(ctx
, 0);
127 DUK_ASSERT(tfm_ctx
->h_str
!= NULL
);
129 DUK_BW_INIT_PUSHBUF(thr
, &tfm_ctx
->bw
, DUK_HSTRING_GET_BYTELEN(tfm_ctx
->h_str
)); /* initial size guess */
131 tfm_ctx
->p_start
= DUK_HSTRING_GET_DATA(tfm_ctx
->h_str
);
132 tfm_ctx
->p_end
= tfm_ctx
->p_start
+ DUK_HSTRING_GET_BYTELEN(tfm_ctx
->h_str
);
133 tfm_ctx
->p
= tfm_ctx
->p_start
;
135 while (tfm_ctx
->p
< tfm_ctx
->p_end
) {
136 cp
= (duk_codepoint_t
) duk_unicode_decode_xutf8_checked(thr
, &tfm_ctx
->p
, tfm_ctx
->p_start
, tfm_ctx
->p_end
);
137 callback(tfm_ctx
, udata
, cp
);
140 DUK_BW_COMPACT(thr
, &tfm_ctx
->bw
);
142 duk_to_string(ctx
, -1);
146 DUK_LOCAL
void duk__transform_callback_encode_uri(duk__transform_context
*tfm_ctx
, void *udata
, duk_codepoint_t cp
) {
147 duk_uint8_t xutf8_buf
[DUK_UNICODE_MAX_XUTF8_LENGTH
];
149 duk_codepoint_t cp1
, cp2
;
150 duk_small_int_t i
, t
;
151 const duk_uint8_t
*unescaped_table
= (duk_uint8_t
*) udata
;
153 /* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes.
154 * Codepoint range is restricted so this is a slightly too large
155 * but doesn't matter.
157 DUK_BW_ENSURE(tfm_ctx
->thr
, &tfm_ctx
->bw
, 3 * DUK_UNICODE_MAX_XUTF8_LENGTH
);
161 } else if ((cp
< 0x80L
) && DUK__CHECK_BITMASK(unescaped_table
, cp
)) {
162 DUK_BW_WRITE_RAW_U8(tfm_ctx
->thr
, &tfm_ctx
->bw
, (duk_uint8_t
) cp
);
164 } else if (cp
>= 0xdc00L
&& cp
<= 0xdfffL
) {
166 } else if (cp
>= 0xd800L
&& cp
<= 0xdbffL
) {
167 /* Needs lookahead */
168 if (duk_unicode_decode_xutf8(tfm_ctx
->thr
, &tfm_ctx
->p
, tfm_ctx
->p_start
, tfm_ctx
->p_end
, (duk_ucodepoint_t
*) &cp2
) == 0) {
171 if (!(cp2
>= 0xdc00L
&& cp2
<= 0xdfffL
)) {
175 cp
= ((cp1
- 0xd800L
) << 10) + (cp2
- 0xdc00L
) + 0x10000L
;
176 } else if (cp
> 0x10ffffL
) {
177 /* Although we can allow non-BMP characters (they'll decode
178 * back into surrogate pairs), we don't allow extended UTF-8
179 * characters; they would encode to URIs which won't decode
180 * back because of strict UTF-8 checks in URI decoding.
181 * (However, we could just as well allow them here.)
185 /* Non-BMP characters within valid UTF-8 range: encode as is.
186 * They'll decode back into surrogate pairs if the escaped
192 len
= duk_unicode_encode_xutf8((duk_ucodepoint_t
) cp
, xutf8_buf
);
193 for (i
= 0; i
< len
; i
++) {
194 t
= (int) xutf8_buf
[i
];
195 DUK_BW_WRITE_RAW_U8_3(tfm_ctx
->thr
,
198 (duk_uint8_t
) duk_uc_nybbles
[t
>> 4],
199 (duk_uint8_t
) duk_uc_nybbles
[t
& 0x0f]);
205 DUK_ERROR(tfm_ctx
->thr
, DUK_ERR_URI_ERROR
, "invalid input");
208 DUK_LOCAL
void duk__transform_callback_decode_uri(duk__transform_context
*tfm_ctx
, void *udata
, duk_codepoint_t cp
) {
209 const duk_uint8_t
*reserved_table
= (duk_uint8_t
*) udata
;
210 duk_small_uint_t utf8_blen
;
211 duk_codepoint_t min_cp
;
212 duk_small_int_t t
; /* must be signed */
215 /* Maximum write size: XUTF8 path writes max DUK_UNICODE_MAX_XUTF8_LENGTH,
216 * percent escape path writes max two times CESU-8 encoded BMP length.
218 DUK_BW_ENSURE(tfm_ctx
->thr
,
220 (DUK_UNICODE_MAX_XUTF8_LENGTH
>= 2 * DUK_UNICODE_MAX_CESU8_BMP_LENGTH
?
221 DUK_UNICODE_MAX_XUTF8_LENGTH
: DUK_UNICODE_MAX_CESU8_BMP_LENGTH
));
223 if (cp
== (duk_codepoint_t
) '%') {
224 const duk_uint8_t
*p
= tfm_ctx
->p
;
225 duk_size_t left
= (duk_size_t
) (tfm_ctx
->p_end
- p
); /* bytes left */
227 DUK_DDD(DUK_DDDPRINT("percent encoding, left=%ld", (long) left
));
233 t
= duk__decode_hex_escape(p
, 2);
234 DUK_DDD(DUK_DDDPRINT("first byte: %ld", (long) t
));
240 if (DUK__CHECK_BITMASK(reserved_table
, t
)) {
241 /* decode '%xx' to '%xx' if decoded char in reserved set */
242 DUK_ASSERT(tfm_ctx
->p
- 1 >= tfm_ctx
->p_start
);
243 DUK_BW_WRITE_RAW_U8_3(tfm_ctx
->thr
,
249 DUK_BW_WRITE_RAW_U8(tfm_ctx
->thr
, &tfm_ctx
->bw
, (duk_uint8_t
) t
);
255 /* Decode UTF-8 codepoint from a sequence of hex escapes. The
256 * first byte of the sequence has been decoded to 't'.
258 * Note that UTF-8 validation must be strict according to the
259 * specification: E5.1 Section 15.1.3, decode algorithm step
260 * 4.d.vii.8. URIError from non-shortest encodings is also
261 * specifically noted in the spec.
264 DUK_ASSERT(t
>= 0x80);
266 /* continuation byte */
268 } else if (t
< 0xe0) {
269 /* 110x xxxx; 2 bytes */
273 } else if (t
< 0xf0) {
274 /* 1110 xxxx; 3 bytes */
278 } else if (t
< 0xf8) {
279 /* 1111 0xxx; 4 bytes */
284 /* extended utf-8 not allowed for URIs */
288 if (left
< utf8_blen
* 3 - 1) {
289 /* '%xx%xx...%xx', p points to char after first '%' */
294 for (i
= 1; i
< utf8_blen
; i
++) {
295 /* p points to digit part ('%xy', p points to 'x') */
296 t
= duk__decode_hex_escape(p
, 2);
297 DUK_DDD(DUK_DDDPRINT("i=%ld utf8_blen=%ld cp=%ld t=0x%02lx",
298 (long) i
, (long) utf8_blen
, (long) cp
, (unsigned long) t
));
302 if ((t
& 0xc0) != 0x80) {
305 cp
= (cp
<< 6) + (t
& 0x3f);
308 p
--; /* p overshoots */
311 DUK_DDD(DUK_DDDPRINT("final cp=%ld, min_cp=%ld", (long) cp
, (long) min_cp
));
313 if (cp
< min_cp
|| cp
> 0x10ffffL
|| (cp
>= 0xd800L
&& cp
<= 0xdfffL
)) {
317 /* The E5.1 algorithm checks whether or not a decoded codepoint
318 * is below 0x80 and perhaps may be in the "reserved" set.
319 * This seems pointless because the single byte UTF-8 case is
320 * handled separately, and non-shortest encodings are rejected.
321 * So, 'cp' cannot be below 0x80 here, and thus cannot be in
325 /* utf-8 validation ensures these */
326 DUK_ASSERT(cp
>= 0x80L
&& cp
<= 0x10ffffL
);
328 if (cp
>= 0x10000L
) {
330 DUK_ASSERT(cp
< 0x100000L
);
332 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx
->thr
, &tfm_ctx
->bw
, ((cp
>> 10) + 0xd800L
));
333 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx
->thr
, &tfm_ctx
->bw
, ((cp
& 0x03ffUL
) + 0xdc00L
));
335 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx
->thr
, &tfm_ctx
->bw
, cp
);
338 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx
->thr
, &tfm_ctx
->bw
, cp
);
343 DUK_ERROR(tfm_ctx
->thr
, DUK_ERR_URI_ERROR
, "invalid input");
346 #ifdef DUK_USE_SECTION_B
347 DUK_LOCAL
void duk__transform_callback_escape(duk__transform_context
*tfm_ctx
, void *udata
, duk_codepoint_t cp
) {
350 DUK_BW_ENSURE(tfm_ctx
->thr
, &tfm_ctx
->bw
, 6);
354 } else if ((cp
< 0x80L
) && DUK__CHECK_BITMASK(duk__escape_unescaped_table
, cp
)) {
355 DUK_BW_WRITE_RAW_U8(tfm_ctx
->thr
, &tfm_ctx
->bw
, (duk_uint8_t
) cp
);
356 } else if (cp
< 0x100L
) {
357 DUK_BW_WRITE_RAW_U8_3(tfm_ctx
->thr
,
359 (duk_uint8_t
) DUK_ASC_PERCENT
,
360 (duk_uint8_t
) duk_uc_nybbles
[cp
>> 4],
361 (duk_uint8_t
) duk_uc_nybbles
[cp
& 0x0f]);
362 } else if (cp
< 0x10000L
) {
363 DUK_BW_WRITE_RAW_U8_6(tfm_ctx
->thr
,
365 (duk_uint8_t
) DUK_ASC_PERCENT
,
366 (duk_uint8_t
) DUK_ASC_LC_U
,
367 (duk_uint8_t
) duk_uc_nybbles
[cp
>> 12],
368 (duk_uint8_t
) duk_uc_nybbles
[(cp
>> 8) & 0x0f],
369 (duk_uint8_t
) duk_uc_nybbles
[(cp
>> 4) & 0x0f],
370 (duk_uint8_t
) duk_uc_nybbles
[cp
& 0x0f]);
372 /* Characters outside BMP cannot be escape()'d. We could
373 * encode them as surrogate pairs (for codepoints inside
374 * valid UTF-8 range, but not extended UTF-8). Because
375 * escape() and unescape() are legacy functions, we don't.
383 DUK_ERROR(tfm_ctx
->thr
, DUK_ERR_TYPE_ERROR
, "invalid input");
386 DUK_LOCAL
void duk__transform_callback_unescape(duk__transform_context
*tfm_ctx
, void *udata
, duk_codepoint_t cp
) {
391 if (cp
== (duk_codepoint_t
) '%') {
392 const duk_uint8_t
*p
= tfm_ctx
->p
;
393 duk_size_t left
= (duk_size_t
) (tfm_ctx
->p_end
- p
); /* bytes left */
395 if (left
>= 5 && p
[0] == 'u' &&
396 ((t
= duk__decode_hex_escape(p
+ 1, 4)) >= 0)) {
397 cp
= (duk_codepoint_t
) t
;
399 } else if (left
>= 2 &&
400 ((t
= duk__decode_hex_escape(p
, 2)) >= 0)) {
401 cp
= (duk_codepoint_t
) t
;
406 DUK_BW_WRITE_ENSURE_XUTF8(tfm_ctx
->thr
, &tfm_ctx
->bw
, cp
);
408 #endif /* DUK_USE_SECTION_B */
413 * Eval needs to handle both a "direct eval" and an "indirect eval".
414 * Direct eval handling needs access to the caller's activation so that its
415 * lexical environment can be accessed. A direct eval is only possible from
416 * Ecmascript code; an indirect eval call is possible also from C code.
417 * When an indirect eval call is made from C code, there may not be a
418 * calling activation at all which needs careful handling.
421 DUK_INTERNAL duk_ret_t
duk_bi_global_object_eval(duk_context
*ctx
) {
422 duk_hthread
*thr
= (duk_hthread
*) ctx
;
424 duk_activation
*act_caller
;
425 duk_activation
*act_eval
;
427 duk_hcompiledfunction
*func
;
428 duk_hobject
*outer_lex_env
;
429 duk_hobject
*outer_var_env
;
430 duk_bool_t this_to_global
= 1;
431 duk_small_uint_t comp_flags
;
433 DUK_ASSERT_TOP(ctx
, 1);
434 DUK_ASSERT(thr
->callstack_top
>= 1); /* at least this function exists */
435 DUK_ASSERT(((thr
->callstack
+ thr
->callstack_top
- 1)->flags
& DUK_ACT_FLAG_DIRECT_EVAL
) == 0 || /* indirect eval */
436 (thr
->callstack_top
>= 2)); /* if direct eval, calling activation must exist */
439 * callstack_top - 1 --> this function
440 * callstack_top - 2 --> caller (may not exist)
442 * If called directly from C, callstack_top might be 1. If calling
443 * activation doesn't exist, call must be indirect.
446 h
= duk_get_hstring(ctx
, 0);
448 return 1; /* return arg as-is */
453 comp_flags
= DUK_JS_COMPILE_FLAG_EVAL
;
454 act_eval
= thr
->callstack
+ thr
->callstack_top
- 1; /* this function */
455 if (thr
->callstack_top
>= 2) {
456 /* Have a calling activation, check for direct eval (otherwise
457 * assume indirect eval.
459 act_caller
= thr
->callstack
+ thr
->callstack_top
- 2; /* caller */
460 if ((act_caller
->flags
& DUK_ACT_FLAG_STRICT
) &&
461 (act_eval
->flags
& DUK_ACT_FLAG_DIRECT_EVAL
)) {
462 /* Only direct eval inherits strictness from calling code
463 * (E5.1 Section 10.1.1).
465 comp_flags
|= DUK_JS_COMPILE_FLAG_STRICT
;
468 DUK_ASSERT((act_eval
->flags
& DUK_ACT_FLAG_DIRECT_EVAL
) == 0);
470 act_caller
= NULL
; /* avoid dereference after potential callstack realloc */
473 duk_push_hstring_stridx(ctx
, DUK_STRIDX_INPUT
); /* XXX: copy from caller? */
475 (const duk_uint8_t
*) DUK_HSTRING_GET_DATA(h
),
476 (duk_size_t
) DUK_HSTRING_GET_BYTELEN(h
),
478 func
= (duk_hcompiledfunction
*) duk_get_hobject(ctx
, -1);
479 DUK_ASSERT(func
!= NULL
);
480 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject
*) func
));
482 /* [ source template ] */
484 /* E5 Section 10.4.2 */
485 DUK_ASSERT(thr
->callstack_top
>= 1);
486 act
= thr
->callstack
+ thr
->callstack_top
- 1; /* this function */
487 if (act
->flags
& DUK_ACT_FLAG_DIRECT_EVAL
) {
488 DUK_ASSERT(thr
->callstack_top
>= 2);
489 act
= thr
->callstack
+ thr
->callstack_top
- 2; /* caller */
490 if (act
->lex_env
== NULL
) {
491 DUK_ASSERT(act
->var_env
== NULL
);
492 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
494 /* this may have side effects, so re-lookup act */
495 duk_js_init_activation_environment_records_delayed(thr
, act
);
496 act
= thr
->callstack
+ thr
->callstack_top
- 2;
498 DUK_ASSERT(act
->lex_env
!= NULL
);
499 DUK_ASSERT(act
->var_env
!= NULL
);
503 if (DUK_HOBJECT_HAS_STRICT((duk_hobject
*) func
)) {
504 duk_hobject
*new_env
;
505 duk_hobject
*act_lex_env
;
507 DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> "
508 "var_env and lex_env to a fresh env, "
509 "this_binding to caller's this_binding"));
511 act
= thr
->callstack
+ thr
->callstack_top
- 2; /* caller */
512 act_lex_env
= act
->lex_env
;
513 act
= NULL
; /* invalidated */
515 (void) duk_push_object_helper_proto(ctx
,
516 DUK_HOBJECT_FLAG_EXTENSIBLE
|
517 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV
),
519 new_env
= duk_require_hobject(ctx
, -1);
520 DUK_ASSERT(new_env
!= NULL
);
521 DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO",
522 (duk_heaphdr
*) new_env
));
524 outer_lex_env
= new_env
;
525 outer_var_env
= new_env
;
527 duk_insert(ctx
, 0); /* stash to bottom of value stack to keep new_env reachable */
529 /* compiler's responsibility */
530 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject
*) func
));
532 DUK_DDD(DUK_DDDPRINT("direct eval call to a non-strict function -> "
533 "var_env and lex_env to caller's envs, "
534 "this_binding to caller's this_binding"));
536 outer_lex_env
= act
->lex_env
;
537 outer_var_env
= act
->var_env
;
539 /* compiler's responsibility */
540 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject
*) func
));
543 DUK_DDD(DUK_DDDPRINT("indirect eval call -> var_env and lex_env to "
544 "global object, this_binding to global object"));
547 outer_lex_env
= thr
->builtins
[DUK_BIDX_GLOBAL_ENV
];
548 outer_var_env
= thr
->builtins
[DUK_BIDX_GLOBAL_ENV
];
552 duk_js_push_closure(thr
, func
, outer_var_env
, outer_lex_env
);
554 /* [ source template closure ] */
556 if (this_to_global
) {
557 DUK_ASSERT(thr
->builtins
[DUK_BIDX_GLOBAL
] != NULL
);
558 duk_push_hobject_bidx(ctx
, DUK_BIDX_GLOBAL
);
561 DUK_ASSERT(thr
->callstack_top
>= 2);
562 act
= thr
->callstack
+ thr
->callstack_top
- 2; /* caller */
563 tv
= thr
->valstack
+ act
->idx_bottom
- 1; /* this is just beneath bottom */
564 DUK_ASSERT(tv
>= thr
->valstack
);
565 duk_push_tval(ctx
, tv
);
568 DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
569 (duk_heaphdr
*) outer_lex_env
,
570 (duk_heaphdr
*) outer_var_env
,
571 (duk_tval
*) duk_get_tval(ctx
, -1)));
573 /* [ source template closure this ] */
575 duk_call_method(ctx
, 0);
577 /* [ source template result ] */
583 * Parsing of ints and floats
586 DUK_INTERNAL duk_ret_t
duk_bi_global_object_parse_int(duk_context
*ctx
) {
587 duk_bool_t strip_prefix
;
589 duk_small_uint_t s2n_flags
;
591 DUK_ASSERT_TOP(ctx
, 2);
592 duk_to_string(ctx
, 0);
595 radix
= duk_to_int32(ctx
, 1);
597 if (radix
< 2 || radix
> 36) {
600 /* For octal, setting strip_prefix=0 is not necessary, as zero
601 * is tolerated anyway:
603 * parseInt('123', 8) === parseInt('0123', 8) with or without strip_prefix
604 * parseInt('123', 16) === parseInt('0x123', 16) requires strip_prefix = 1
613 s2n_flags
= DUK_S2N_FLAG_TRIM_WHITE
|
614 DUK_S2N_FLAG_ALLOW_GARBAGE
|
615 DUK_S2N_FLAG_ALLOW_PLUS
|
616 DUK_S2N_FLAG_ALLOW_MINUS
|
617 DUK_S2N_FLAG_ALLOW_LEADING_ZERO
|
618 #ifdef DUK_USE_OCTAL_SUPPORT
619 (strip_prefix
? (DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT
| DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT
) : 0)
621 (strip_prefix
? DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT
: 0)
626 duk_numconv_parse(ctx
, radix
, s2n_flags
);
634 DUK_INTERNAL duk_ret_t
duk_bi_global_object_parse_float(duk_context
*ctx
) {
635 duk_small_uint_t s2n_flags
;
638 DUK_ASSERT_TOP(ctx
, 1);
639 duk_to_string(ctx
, 0);
643 /* XXX: check flags */
644 s2n_flags
= DUK_S2N_FLAG_TRIM_WHITE
|
645 DUK_S2N_FLAG_ALLOW_EXP
|
646 DUK_S2N_FLAG_ALLOW_GARBAGE
|
647 DUK_S2N_FLAG_ALLOW_PLUS
|
648 DUK_S2N_FLAG_ALLOW_MINUS
|
649 DUK_S2N_FLAG_ALLOW_INF
|
650 DUK_S2N_FLAG_ALLOW_FRAC
|
651 DUK_S2N_FLAG_ALLOW_NAKED_FRAC
|
652 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC
|
653 DUK_S2N_FLAG_ALLOW_LEADING_ZERO
;
655 duk_numconv_parse(ctx
, radix
, s2n_flags
);
663 DUK_INTERNAL duk_ret_t
duk_bi_global_object_is_nan(duk_context
*ctx
) {
664 duk_double_t d
= duk_to_number(ctx
, 0);
665 duk_push_boolean(ctx
, DUK_ISNAN(d
));
669 DUK_INTERNAL duk_ret_t
duk_bi_global_object_is_finite(duk_context
*ctx
) {
670 duk_double_t d
= duk_to_number(ctx
, 0);
671 duk_push_boolean(ctx
, DUK_ISFINITE(d
));
679 DUK_INTERNAL duk_ret_t
duk_bi_global_object_decode_uri(duk_context
*ctx
) {
680 return duk__transform_helper(ctx
, duk__transform_callback_decode_uri
, (void *) duk__decode_uri_reserved_table
);
683 DUK_INTERNAL duk_ret_t
duk_bi_global_object_decode_uri_component(duk_context
*ctx
) {
684 return duk__transform_helper(ctx
, duk__transform_callback_decode_uri
, (void *) duk__decode_uri_component_reserved_table
);
687 DUK_INTERNAL duk_ret_t
duk_bi_global_object_encode_uri(duk_context
*ctx
) {
688 return duk__transform_helper(ctx
, duk__transform_callback_encode_uri
, (void *) duk__encode_uriunescaped_table
);
691 DUK_INTERNAL duk_ret_t
duk_bi_global_object_encode_uri_component(duk_context
*ctx
) {
692 return duk__transform_helper(ctx
, duk__transform_callback_encode_uri
, (void *) duk__encode_uricomponent_unescaped_table
);
695 #ifdef DUK_USE_SECTION_B
696 DUK_INTERNAL duk_ret_t
duk_bi_global_object_escape(duk_context
*ctx
) {
697 return duk__transform_helper(ctx
, duk__transform_callback_escape
, (void *) NULL
);
700 DUK_INTERNAL duk_ret_t
duk_bi_global_object_unescape(duk_context
*ctx
) {
701 return duk__transform_helper(ctx
, duk__transform_callback_unescape
, (void *) NULL
);
703 #else /* DUK_USE_SECTION_B */
704 DUK_INTERNAL duk_ret_t
duk_bi_global_object_escape(duk_context
*ctx
) {
706 return DUK_RET_UNSUPPORTED_ERROR
;
709 DUK_INTERNAL duk_ret_t
duk_bi_global_object_unescape(duk_context
*ctx
) {
711 return DUK_RET_UNSUPPORTED_ERROR
;
713 #endif /* DUK_USE_SECTION_B */
715 #if defined(DUK_USE_BROWSER_LIKE) && (defined(DUK_USE_FILE_IO) || defined(DUK_USE_DEBUGGER_SUPPORT))
716 DUK_INTERNAL duk_ret_t
duk_bi_global_object_print_helper(duk_context
*ctx
) {
717 duk_hthread
*thr
= (duk_hthread
*) ctx
;
720 const duk_uint8_t
*buf
;
722 const char nl
= (const char) DUK_ASC_LF
;
723 #ifndef DUK_USE_PREFER_SIZE
724 duk_uint8_t buf_stack
[256];
726 #ifdef DUK_USE_FILE_IO
730 magic
= duk_get_current_magic(ctx
);
733 nargs
= duk_get_top(ctx
);
735 /* If argument count is 1 and first argument is a buffer, write the buffer
736 * as raw data into the file without a newline; this allows exact control
737 * over stdout/stderr without an additional entrypoint (useful for now).
739 * Otherwise current print/alert semantics are to ToString() coerce
740 * arguments, join them with a single space, and append a newline.
743 if (nargs
== 1 && duk_is_buffer(ctx
, 0)) {
744 buf
= (const duk_uint8_t
*) duk_get_buffer(ctx
, 0, &sz_buf
);
745 DUK_ASSERT(buf
!= NULL
);
746 } else if (nargs
> 0) {
747 #ifdef DUK_USE_PREFER_SIZE
748 /* Compact but lots of churn. */
749 duk_push_hstring_stridx(thr
, DUK_STRIDX_SPACE
);
751 duk_join(ctx
, nargs
);
752 duk_push_string(thr
, "\n");
754 buf
= (const duk_uint8_t
*) duk_get_lstring(ctx
, -1, &sz_buf
);
755 DUK_ASSERT(buf
!= NULL
);
756 #else /* DUK_USE_PREFER_SIZE */
757 /* Higher footprint, less churn. */
760 const duk_uint8_t
*p_str
;
763 sz_buf
= (duk_size_t
) nargs
; /* spaces (nargs - 1) + newline */
764 for (i
= 0; i
< nargs
; i
++) {
765 (void) duk_to_lstring(ctx
, i
, &sz_str
);
769 if (sz_buf
<= sizeof(buf_stack
)) {
770 buf
= (const duk_uint8_t
*) buf_stack
;
772 buf
= (const duk_uint8_t
*) duk_push_fixed_buffer(ctx
, sz_buf
);
773 DUK_ASSERT(buf
!= NULL
);
776 p
= (duk_uint8_t
*) buf
;
777 for (i
= 0; i
< nargs
; i
++) {
778 p_str
= (const duk_uint8_t
*) duk_get_lstring(ctx
, i
, &sz_str
);
779 DUK_ASSERT(p_str
!= NULL
);
780 DUK_MEMCPY((void *) p
, (const void *) p_str
, sz_str
);
782 *p
++ = (duk_uint8_t
) (i
== nargs
- 1 ? DUK_ASC_LF
: DUK_ASC_SPACE
);
784 DUK_ASSERT((const duk_uint8_t
*) p
== buf
+ sz_total
);
785 #endif /* DUK_USE_PREFER_SIZE */
787 buf
= (const duk_uint8_t
*) &nl
;
791 /* 'buf' contains the string to write, 'sz_buf' contains the length
792 * (which may be zero).
794 DUK_ASSERT(buf
!= NULL
);
800 #ifdef DUK_USE_FILE_IO
801 f_out
= (magic
? DUK_STDERR
: DUK_STDOUT
);
802 DUK_FWRITE((const void *) buf
, 1, (size_t) sz_buf
, f_out
);
806 #if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_PRINTALERT)
807 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr
->heap
)) {
808 duk_debug_write_notify(thr
, magic
? DUK_DBG_CMD_ALERT
: DUK_DBG_CMD_PRINT
);
809 duk_debug_write_string(thr
, (const char *) buf
, sz_buf
);
810 duk_debug_write_eom(thr
);
815 #elif defined(DUK_USE_BROWSER_LIKE) /* print provider */
816 DUK_INTERNAL duk_ret_t
duk_bi_global_object_print_helper(duk_context
*ctx
) {
820 #else /* print provider */
821 DUK_INTERNAL duk_ret_t
duk_bi_global_object_print_helper(duk_context
*ctx
) {
823 return DUK_RET_UNSUPPORTED_ERROR
;
825 #endif /* print provider */
828 * CommonJS require() and modules support
831 #if defined(DUK_USE_COMMONJS_MODULES)
832 DUK_LOCAL
void duk__bi_global_resolve_module_id(duk_context
*ctx
, const char *req_id
, const char *mod_id
) {
833 duk_hthread
*thr
= (duk_hthread
*) ctx
;
834 duk_size_t mod_id_len
;
835 duk_size_t req_id_len
;
836 duk_uint8_t buf_in
[DUK_BI_COMMONJS_MODULE_ID_LIMIT
];
837 duk_uint8_t buf_out
[DUK_BI_COMMONJS_MODULE_ID_LIMIT
];
841 DUK_ASSERT(req_id
!= NULL
);
842 /* mod_id may be NULL */
843 DUK_ASSERT(sizeof(buf_out
) >= sizeof(buf_in
)); /* bound checking requires this */
846 * A few notes on the algorithm:
848 * - Terms are not allowed to begin with a period unless the term
849 * is either '.' or '..'. This simplifies implementation (and
850 * is within CommonJS modules specification).
852 * - There are few output bound checks here. This is on purpose:
853 * we check the input length and rely on the output never being
854 * longer than the input, so we cannot run out of output space.
856 * - Non-ASCII characters are processed as individual bytes and
857 * need no special treatment. However, U+0000 terminates the
858 * algorithm; this is not an issue because U+0000 is not a
859 * desirable term character anyway.
863 * Set up the resolution input which is the requested ID directly
864 * (if absolute or no current module path) or with current module
865 * ID prepended (if relative and current module path exists).
867 * Suppose current module is 'foo/bar' and relative path is './quux'.
868 * The 'bar' component must be replaced so the initial input here is
869 * 'foo/bar/.././quux'.
872 req_id_len
= DUK_STRLEN(req_id
);
873 if (mod_id
!= NULL
&& req_id
[0] == '.') {
874 mod_id_len
= DUK_STRLEN(mod_id
);
875 if (mod_id_len
+ 4 + req_id_len
+ 1 >= sizeof(buf_in
)) {
876 DUK_DD(DUK_DDPRINT("resolve error: current and requested module ID don't fit into resolve input buffer"));
879 (void) DUK_SNPRINTF((char *) buf_in
, sizeof(buf_in
), "%s/../%s", (const char *) mod_id
, (const char *) req_id
);
881 if (req_id_len
+ 1 >= sizeof(buf_in
)) {
882 DUK_DD(DUK_DDPRINT("resolve error: requested module ID doesn't fit into resolve input buffer"));
885 (void) DUK_SNPRINTF((char *) buf_in
, sizeof(buf_in
), "%s", (const char *) req_id
);
887 buf_in
[sizeof(buf_in
) - 1] = (duk_uint8_t
) 0;
889 DUK_DDD(DUK_DDDPRINT("input module id: '%s'", (const char *) buf_in
));
892 * Resolution loop. At the top of the loop we're expecting a valid
893 * term: '.', '..', or a non-empty identifier not starting with a period.
901 /* Here 'p' always points to the start of a term. */
902 DUK_DDD(DUK_DDDPRINT("resolve loop top: p -> '%s', q=%p, buf_out=%p",
903 (const char *) p
, (void *) q
, (void *) buf_out
));
906 if (DUK_UNLIKELY(c
== 0)) {
907 DUK_DD(DUK_DDPRINT("resolve error: requested ID must end with a non-empty term"));
909 } else if (DUK_UNLIKELY(c
== '.')) {
912 /* Term was '.' and is eaten entirely (including dup slashes). */
913 goto eat_dup_slashes
;
915 if (c
== '.' && *p
== '/') {
916 /* Term was '..', backtrack resolved name by one component.
917 * q[-1] = previous slash (or beyond start of buffer)
918 * q[-2] = last char of previous component (or beyond start of buffer)
920 p
++; /* eat (first) input slash */
921 DUK_ASSERT(q
>= buf_out
);
923 DUK_DD(DUK_DDPRINT("resolve error: term was '..' but nothing to backtrack"));
926 DUK_ASSERT(*(q
- 1) == '/');
927 q
--; /* backtrack to last output slash */
929 /* Backtrack to previous slash or start of buffer. */
930 DUK_ASSERT(q
>= buf_out
);
934 if (*(q
- 1) == '/') {
939 goto eat_dup_slashes
;
941 DUK_DD(DUK_DDPRINT("resolve error: term begins with '.' but is not '.' or '..' (not allowed now)"));
943 } else if (DUK_UNLIKELY(c
== '/')) {
944 /* e.g. require('/foo'), empty terms not allowed */
945 DUK_DD(DUK_DDPRINT("resolve error: empty term (not allowed now)"));
949 /* Copy term name until end or '/'. */
952 if (DUK_UNLIKELY(c
== 0)) {
954 } else if (DUK_UNLIKELY(c
== '/')) {
958 /* write on next loop */
965 /* eat dup slashes */
967 if (DUK_LIKELY(c
!= '/')) {
975 duk_push_lstring(ctx
, (const char *) buf_out
, (size_t) (q
- buf_out
));
979 DUK_ERROR(thr
, DUK_ERR_TYPE_ERROR
, "cannot resolve module id: %s", (const char *) req_id
);
981 #endif /* DUK_USE_COMMONJS_MODULES */
983 #if defined(DUK_USE_COMMONJS_MODULES)
984 DUK_INTERNAL duk_ret_t
duk_bi_global_object_require(duk_context
*ctx
) {
985 const char *str_req_id
; /* requested identifier */
986 const char *str_mod_id
; /* require.id of current module */
989 /* NOTE: we try to minimize code size by avoiding unnecessary pops,
990 * so the stack looks a bit cluttered in this function. DUK_ASSERT_TOP()
991 * assertions are used to ensure stack configuration is correct at each
996 * Resolve module identifier into canonical absolute form.
999 str_req_id
= duk_require_string(ctx
, 0);
1000 duk_push_current_function(ctx
);
1001 duk_get_prop_stridx(ctx
, -1, DUK_STRIDX_ID
);
1002 str_mod_id
= duk_get_string(ctx
, 2); /* ignore non-strings */
1003 DUK_DDD(DUK_DDDPRINT("resolve module id: requested=%!T, currentmodule=%!T",
1004 (duk_tval
*) duk_get_tval(ctx
, 0),
1005 (duk_tval
*) duk_get_tval(ctx
, 2)));
1006 duk__bi_global_resolve_module_id(ctx
, str_req_id
, str_mod_id
);
1009 DUK_DDD(DUK_DDDPRINT("resolved module id: requested=%!T, currentmodule=%!T, result=%!T",
1010 (duk_tval
*) duk_get_tval(ctx
, 0),
1011 (duk_tval
*) duk_get_tval(ctx
, 2),
1012 (duk_tval
*) duk_get_tval(ctx
, 3)));
1014 /* [ requested_id require require.id resolved_id ] */
1015 DUK_ASSERT_TOP(ctx
, 4);
1018 * Cached module check.
1020 * If module has been loaded or its loading has already begun without
1021 * finishing, return the same cached value ('exports'). The value is
1022 * registered when module load starts so that circular references can
1023 * be supported to some extent.
1026 /* [ requested_id require require.id resolved_id ] */
1027 DUK_ASSERT_TOP(ctx
, 4);
1029 duk_push_hobject_bidx(ctx
, DUK_BIDX_DUKTAPE
);
1030 duk_get_prop_stridx(ctx
, 4, DUK_STRIDX_MOD_LOADED
); /* Duktape.modLoaded */
1031 (void) duk_require_hobject(ctx
, 5);
1033 /* [ requested_id require require.id resolved_id Duktape Duktape.modLoaded ] */
1034 DUK_ASSERT_TOP(ctx
, 6);
1037 if (duk_get_prop(ctx
, 5)) {
1038 /* [ requested_id require require.id resolved_id Duktape Duktape.modLoaded Duktape.modLoaded[id] ] */
1039 DUK_DD(DUK_DDPRINT("module already loaded: %!T",
1040 (duk_tval
*) duk_get_tval(ctx
, 3)));
1041 duk_get_prop_stridx(ctx
, -1, DUK_STRIDX_EXPORTS
); /* return module.exports */
1045 /* [ requested_id require require.id resolved_id Duktape Duktape.modLoaded undefined ] */
1046 DUK_ASSERT_TOP(ctx
, 7);
1049 * Module not loaded (and loading not started previously).
1051 * Create a new require() function with 'id' set to resolved ID
1052 * of module being loaded. Also create 'exports' and 'module'
1053 * tables but don't register exports to the loaded table yet.
1054 * We don't want to do that unless the user module search callbacks
1055 * succeeds in finding the module.
1058 DUK_DD(DUK_DDPRINT("module not yet loaded: %!T",
1059 (duk_tval
*) duk_get_tval(ctx
, 3)));
1061 /* Fresh require: require.id is left configurable (but not writable)
1062 * so that is not easy to accidentally tweak it, but it can still be
1063 * done with Object.defineProperty().
1065 * XXX: require.id could also be just made non-configurable, as there
1066 * is no practical reason to touch it.
1068 duk_push_c_function(ctx
, duk_bi_global_object_require
, 1 /*nargs*/);
1070 duk_xdef_prop_stridx(ctx
, 7, DUK_STRIDX_ID
, DUK_PROPDESC_FLAGS_C
); /* a fresh require() with require.id = resolved target module id */
1073 * - module.exports: initial exports table (may be replaced by user)
1074 * - module.id is non-writable and non-configurable, as the CommonJS
1075 * spec suggests this if possible.
1077 duk_push_object(ctx
); /* exports */
1078 duk_push_object(ctx
); /* module */
1080 duk_xdef_prop_stridx(ctx
, 9, DUK_STRIDX_EXPORTS
, DUK_PROPDESC_FLAGS_WC
); /* module.exports = exports */
1081 duk_dup(ctx
, 3); /* resolved id: require(id) must return this same module */
1082 duk_xdef_prop_stridx(ctx
, 9, DUK_STRIDX_ID
, DUK_PROPDESC_FLAGS_NONE
); /* module.id = resolved_id */
1083 duk_compact(ctx
, 9); /* module table remains registered to modLoaded, minimize its size */
1085 /* [ requested_id require require.id resolved_id Duktape Duktape.modLoaded undefined fresh_require exports module ] */
1086 DUK_ASSERT_TOP(ctx
, 10);
1088 /* Register the module table early to modLoaded[] so that we can
1089 * support circular references even in modSearch(). If an error
1090 * is thrown, we'll delete the reference.
1094 duk_put_prop(ctx
, 5); /* Duktape.modLoaded[resolved_id] = module */
1097 * Call user provided module search function and build the wrapped
1098 * module source code (if necessary). The module search function
1099 * can be used to implement pure Ecmacsript, pure C, and mixed
1100 * Ecmascript/C modules.
1102 * The module search function can operate on the exports table directly
1103 * (e.g. DLL code can register values to it). It can also return a
1104 * string which is interpreted as module source code (if a non-string
1105 * is returned the module is assumed to be a pure C one). If a module
1106 * cannot be found, an error must be thrown by the user callback.
1108 * Because Duktape.modLoaded[] already contains the module being
1109 * loaded, circular references for C modules should also work
1110 * (although expected to be quite rare).
1113 duk_push_string(ctx
, "(function(require,exports,module){");
1115 /* Duktape.modSearch(resolved_id, fresh_require, exports, module). */
1116 duk_get_prop_stridx(ctx
, 4, DUK_STRIDX_MOD_SEARCH
); /* Duktape.modSearch */
1120 duk_dup(ctx
, 9); /* [ ... Duktape.modSearch resolved_id fresh_require exports module ] */
1121 pcall_rc
= duk_pcall(ctx
, 4 /*nargs*/); /* -> [ ... source ] */
1122 DUK_ASSERT_TOP(ctx
, 12);
1124 if (pcall_rc
!= DUK_EXEC_SUCCESS
) {
1125 /* Delete entry in Duktape.modLoaded[] and rethrow. */
1126 goto delete_rethrow
;
1129 /* If user callback did not return source code, module loading
1130 * is finished (user callback initialized exports table directly).
1132 if (!duk_is_string(ctx
, 11)) {
1133 /* User callback did not return source code, so module loading
1134 * is finished: just update modLoaded with final module.exports
1137 goto return_exports
;
1140 /* Finish the wrapped module source. Force resolved module ID as the
1141 * fileName so it gets set for functions defined within a module. This
1142 * also ensures loggers created within the module get the module ID as
1143 * their default logger name.
1145 duk_push_string(ctx
, "})");
1147 duk_dup(ctx
, 3); /* resolved module ID for fileName */
1148 duk_eval_raw(ctx
, NULL
, 0, DUK_COMPILE_EVAL
);
1150 /* XXX: The module wrapper function is currently anonymous and is shown
1151 * in stack traces. It would be nice to force it to match the module
1152 * name (perhaps just the cleaned up last term). At the moment 'name'
1153 * is write protected so we can't change it directly. Note that we must
1154 * not introduce an actual name binding into the function scope (which
1155 * is usually the case with a named function) because it would affect
1156 * the scope seen by the module and shadow accesses to globals of the
1161 * Call the wrapped module function.
1163 * Use a protected call so that we can update Duktape.modLoaded[resolved_id]
1164 * even if the module throws an error.
1167 /* [ requested_id require require.id resolved_id Duktape Duktape.modLoaded undefined fresh_require exports module mod_func ] */
1168 DUK_ASSERT_TOP(ctx
, 11);
1170 duk_dup(ctx
, 8); /* exports (this binding) */
1171 duk_dup(ctx
, 7); /* fresh require (argument) */
1172 duk_get_prop_stridx(ctx
, 9, DUK_STRIDX_EXPORTS
); /* relookup exports from module.exports in case it was changed by modSearch */
1173 duk_dup(ctx
, 9); /* module (argument) */
1175 /* [ requested_id require require.id resolved_id Duktape Duktape.modLoaded undefined fresh_require exports module mod_func exports fresh_require exports module ] */
1176 DUK_ASSERT_TOP(ctx
, 15);
1178 pcall_rc
= duk_pcall_method(ctx
, 3 /*nargs*/);
1179 if (pcall_rc
!= DUK_EXEC_SUCCESS
) {
1180 /* Module loading failed. Node.js will forget the module
1181 * registration so that another require() will try to load
1182 * the module again. Mimic that behavior.
1184 goto delete_rethrow
;
1187 /* [ requested_id require require.id resolved_id Duktape Duktape.modLoaded undefined fresh_require exports module result(ignored) ] */
1188 DUK_ASSERT_TOP(ctx
, 11);
1193 duk_get_prop_stridx(ctx
, 9, DUK_STRIDX_EXPORTS
);
1194 return 1; /* return module.exports */
1198 duk_del_prop(ctx
, 5); /* delete Duktape.modLoaded[resolved_id] */
1199 duk_throw(ctx
); /* rethrow original error */
1200 return 0; /* not reachable */
1203 DUK_INTERNAL duk_ret_t
duk_bi_global_object_require(duk_context
*ctx
) {
1205 return DUK_RET_UNSUPPORTED_ERROR
;
1207 #endif /* DUK_USE_COMMONJS_MODULES */