· 6 years ago · Oct 13, 2019, 03:30 AM
1
2V7_PRIVATE size_t
3get_regexp_flags_str(struct v7 *v7, struct v7_regexp *rp, char *buf) {
4 int re_flags = slre_get_flags(rp->compiled_regexp);
5 size_t n = 0;
6
7 (void) v7;
8 if (re_flags & SLRE_FLAG_G) buf[n++] = 'g';
9 if (re_flags & SLRE_FLAG_I) buf[n++] = 'i';
10 if (re_flags & SLRE_FLAG_M) buf[n++] = 'm';
11
12 assert(n <= _V7_REGEXP_MAX_FLAGS_LEN);
13
14 return n;
15}
16
17#else /* V7_ENABLE__RegExp */
18
19/*
20 * Dummy implementation when RegExp support is disabled: just return 0
21 */
22int v7_is_regexp(struct v7 *v7, val_t v) {
23 (void) v7;
24 (void) v;
25 return 0;
26}
27
28#endif /* V7_ENABLE__RegExp */
29#ifdef V7_MODULE_LINES
30#line 1 "v7/src/exceptions.c"
31#endif
32/*
33 * Copyright (c) 2014 Cesanta Software Limited
34 * All rights reserved
35 */
36
37/* Amalgamated: #include "common/str_util.h" */
38/* Amalgamated: #include "v7/src/internal.h" */
39/* Amalgamated: #include "v7/src/exceptions.h" */
40/* Amalgamated: #include "v7/src/array.h" */
41/* Amalgamated: #include "v7/src/core.h" */
42/* Amalgamated: #include "v7/src/eval.h" */
43/* Amalgamated: #include "v7/src/object.h" */
44
45enum v7_err v7_throw(struct v7 *v7, v7_val_t val) {
46 v7->vals.thrown_error = val;
47 v7->is_thrown = 1;
48 return V7_EXEC_EXCEPTION;
49}
50
51void v7_clear_thrown_value(struct v7 *v7) {
52 v7->vals.thrown_error = V7_UNDEFINED;
53 v7->is_thrown = 0;
54}
55
56enum v7_err v7_throwf(struct v7 *v7, const char *typ, const char *err_fmt,
57 ...) {
58 /* TODO(dfrank) : get rid of v7->error_msg, allocate mem right here */
59 enum v7_err rcode = V7_OK;
60 va_list ap;
61 val_t e = V7_UNDEFINED;
62 va_start(ap, err_fmt);
63 c_vsnprintf(v7->error_msg, sizeof(v7->error_msg), err_fmt, ap);
64 va_end(ap);
65
66 v7_own(v7, &e);
67 rcode = create_exception(v7, typ, v7->error_msg, &e);
68 if (rcode != V7_OK) {
69 goto clean;
70 }
71
72 rcode = v7_throw(v7, e);
73
74clean:
75 v7_disown(v7, &e);
76 return rcode;
77}
78
79enum v7_err v7_rethrow(struct v7 *v7) {
80 assert(v7->is_thrown);
81#ifdef NDEBUG
82 (void) v7;
83#endif
84 return V7_EXEC_EXCEPTION;
85}
86
87v7_val_t v7_get_thrown_value(struct v7 *v7, uint8_t *is_thrown) {
88 if (is_thrown != NULL) {
89 *is_thrown = v7->is_thrown;
90 }
91 return v7->vals.thrown_error;
92}
93
94/*
95 * Create an instance of the exception with type `typ` (see `TYPE_ERROR`,
96 * `SYNTAX_ERROR`, etc) and message `msg`.
97 */
98V7_PRIVATE enum v7_err create_exception(struct v7 *v7, const char *typ,
99 const char *msg, val_t *res) {
100 enum v7_err rcode = V7_OK;
101 uint8_t saved_creating_exception = v7->creating_exception;
102 val_t ctor_args = V7_UNDEFINED, ctor_func = V7_UNDEFINED;
103#if 0
104 assert(v7_is_undefined(v7->vals.thrown_error));
105#endif
106
107 *res = V7_UNDEFINED;
108
109 v7_own(v7, &ctor_args);
110 v7_own(v7, &ctor_func);
111
112 if (v7->creating_exception) {
113#ifndef NO_LIBC
114 fprintf(stderr, "Exception creation throws an exception %s: %s\n", typ,
115 msg);
116#endif
117 } else {
118 v7->creating_exception = 1;
119
120 /* Prepare arguments for the `Error` constructor */
121 ctor_args = v7_mk_dense_array(v7);
122 v7_array_set(v7, ctor_args, 0, v7_mk_string(v7, msg, strlen(msg), 1));
123
124 /* Get constructor for the given error `typ` */
125 ctor_func = v7_get(v7, v7->vals.global_object, typ, ~0);
126 if (v7_is_undefined(ctor_func)) {
127 fprintf(stderr, "cannot find exception %s\n", typ);
128 }
129
130 /* Create an error object, with prototype from constructor function */
131 *res = mk_object(v7, v7_get(v7, ctor_func, "prototype", 9));
132
133 /*
134 * Finally, call the error constructor, passing an error object as `this`
135 */
136 V7_TRY(b_apply(v7, ctor_func, *res, ctor_args, 0, NULL));
137 }
138
139clean:
140 v7->creating_exception = saved_creating_exception;
141
142 v7_disown(v7, &ctor_func);
143 v7_disown(v7, &ctor_args);
144
145 return rcode;
146}
147#ifdef V7_MODULE_LINES
148#line 1 "v7/src/conversion.c"
149#endif
150/*
151 * Copyright (c) 2014 Cesanta Software Limited
152 * All rights reserved
153 */
154
155/* Amalgamated: #include "common/cs_strtod.h" */
156/* Amalgamated: #include "common/str_util.h" */
157
158/* Amalgamated: #include "v7/src/internal.h" */
159/* Amalgamated: #include "v7/src/core.h" */
160/* Amalgamated: #include "v7/src/util.h" */
161/* Amalgamated: #include "v7/src/primitive.h" */
162/* Amalgamated: #include "v7/src/function.h" */
163/* Amalgamated: #include "v7/src/conversion.h" */
164/* Amalgamated: #include "v7/src/exceptions.h" */
165/* Amalgamated: #include "v7/src/eval.h" */
166/* Amalgamated: #include "v7/src/gc.h" */
167/* Amalgamated: #include "v7/src/array.h" */
168/* Amalgamated: #include "v7/src/object.h" */
169
170static void save_val(struct v7 *v7, const char *str, size_t str_len,
171 val_t *dst_v, char *dst, size_t dst_size, int wanted_len,
172 size_t *res_wanted_len) {
173 if (dst_v != NULL) {
174 *dst_v = v7_mk_string(v7, str, str_len, 1);
175 }
176
177 if (dst != NULL && dst_size > 0) {
178 size_t size = str_len + 1 /*null-term*/;
179 if (size > dst_size) {
180 size = dst_size;
181 }
182 memcpy(dst, str, size);
183
184 /* make sure we have null-term */
185 dst[dst_size - 1] = '\0';
186 }
187
188 if (res_wanted_len != NULL) {
189 *res_wanted_len = (wanted_len >= 0) ? (size_t) wanted_len : str_len;
190 }
191}
192
193WARN_UNUSED_RESULT
194V7_PRIVATE enum v7_err primitive_to_str(struct v7 *v7, val_t v, val_t *res,
195 char *buf, size_t buf_size,
196 size_t *res_len) {
197 enum v7_err rcode = V7_OK;
198 char tmp_buf[25];
199 double num;
200 size_t wanted_len;
201
202 assert(!v7_is_object(v));
203
204 memset(tmp_buf, 0x00, sizeof(tmp_buf));
205
206 v7_own(v7, &v);
207
208 switch (val_type(v7, v)) {
209 case V7_TYPE_STRING: {
210 /* if `res` provided, set it to source value */
211 if (res != NULL) {
212 *res = v;
213 }
214
215 /* if buf provided, copy string data there */
216 if (buf != NULL && buf_size > 0) {
217 size_t size;
218 const char *str = v7_get_string(v7, &v, &size);
219 size += 1 /*null-term*/;
220
221 if (size > buf_size) {
222 size = buf_size;
223 }
224
225 memcpy(buf, str, size);
226
227 /* make sure we have a null-term */
228 buf[buf_size - 1] = '\0';
229 }
230
231 if (res_len != NULL) {
232 v7_get_string(v7, &v, res_len);
233 }
234
235 goto clean;
236 }
237 case V7_TYPE_NULL:
238 strncpy(tmp_buf, "null", sizeof(tmp_buf) - 1);
239 save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
240 goto clean;
241 case V7_TYPE_UNDEFINED:
242 strncpy(tmp_buf, "undefined", sizeof(tmp_buf) - 1);
243 save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
244 goto clean;
245 case V7_TYPE_BOOLEAN:
246 if (v7_get_bool(v7, v)) {
247 strncpy(tmp_buf, "true", sizeof(tmp_buf) - 1);
248 save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
249 goto clean;
250 } else {
251 strncpy(tmp_buf, "false", sizeof(tmp_buf) - 1);
252 save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
253 goto clean;
254 }
255 case V7_TYPE_NUMBER:
256 if (v == V7_TAG_NAN) {
257 strncpy(tmp_buf, "NaN", sizeof(tmp_buf) - 1);
258 save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
259 goto clean;
260 }
261 num = v7_get_double(v7, v);
262 if (isinf(num)) {
263 if (num < 0.0) {
264 strncpy(tmp_buf, "-Infinity", sizeof(tmp_buf) - 1);
265 } else {
266 strncpy(tmp_buf, "Infinity", sizeof(tmp_buf) - 1);
267 }
268 save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
269 goto clean;
270 }
271 {
272 const char *fmt = num > 1e10 ? "%.21g" : "%.10g";
273 wanted_len = snprintf(tmp_buf, sizeof(tmp_buf), fmt, num);
274 save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, wanted_len,
275 res_len);
276 goto clean;
277 }
278 case V7_TYPE_CFUNCTION:
279#ifdef V7_UNIT_TEST
280 wanted_len = c_snprintf(tmp_buf, sizeof(tmp_buf), "cfunc_xxxxxx");
281 save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, wanted_len,
282 res_len);
283 goto clean;
284#else
285 wanted_len = c_snprintf(tmp_buf, sizeof(tmp_buf), "cfunc_%p", get_ptr(v));
286 save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, wanted_len,
287 res_len);
288 goto clean;
289#endif
290 case V7_TYPE_FOREIGN:
291 wanted_len = c_snprintf(tmp_buf, sizeof(tmp_buf), "[foreign_%p]",
292 v7_get_ptr(v7, v));
293 save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, wanted_len,
294 res_len);
295 goto clean;
296 default:
297 abort();
298 }
299
300clean:
301
302 v7_disown(v7, &v);
303 return rcode;
304}
305
306WARN_UNUSED_RESULT
307V7_PRIVATE enum v7_err primitive_to_number(struct v7 *v7, val_t v, val_t *res) {
308 enum v7_err rcode = V7_OK;
309
310 assert(!v7_is_object(v));
311
312 *res = v;
313
314 if (v7_is_number(*res)) {
315 goto clean;
316 }
317
318 if (v7_is_undefined(*res)) {
319 *res = V7_TAG_NAN;
320 goto clean;
321 }
322
323 if (v7_is_null(*res)) {
324 *res = v7_mk_number(v7, 0.0);
325 goto clean;
326 }
327
328 if (v7_is_boolean(*res)) {
329 *res = v7_mk_number(v7, !!v7_get_bool(v7, v));
330 goto clean;
331 }
332
333 if (is_cfunction_lite(*res)) {
334 *res = v7_mk_number(v7, 0.0);
335 goto clean;
336 }
337
338 if (v7_is_string(*res)) {
339 double d;
340 size_t n;
341 char *e, *s = (char *) v7_get_string(v7, res, &n);
342 if (n != 0) {
343 d = cs_strtod(s, &e);
344 if (e - n != s) {
345 d = NAN;
346 }
347 } else {
348 /* empty string: convert to 0 */
349 d = 0.0;
350 }
351 *res = v7_mk_number(v7, d);
352 goto clean;
353 }
354
355 assert(0);
356
357clean:
358 return rcode;
359}
360
361WARN_UNUSED_RESULT
362enum v7_err to_primitive(struct v7 *v7, val_t v, enum to_primitive_hint hint,
363 val_t *res) {
364 enum v7_err rcode = V7_OK;
365 enum v7_err (*p_func)(struct v7 *v7, val_t v, val_t *res);
366
367 v7_own(v7, &v);
368
369 *res = v;
370
371 /*
372 * If given value is an object, try to convert it to string by calling first
373 * preferred function (`toString()` or `valueOf()`, depending on the `hint`
374 * argument)
375 */
376 if (v7_is_object(*res)) {
377 /* Handle special case for Date object */
378 if (hint == V7_TO_PRIMITIVE_HINT_AUTO) {
379 hint = (v7_get_proto(v7, *res) == v7->vals.date_prototype)
380 ? V7_TO_PRIMITIVE_HINT_STRING
381 : V7_TO_PRIMITIVE_HINT_NUMBER;
382 }
383
384 p_func =
385 (hint == V7_TO_PRIMITIVE_HINT_NUMBER) ? obj_value_of : obj_to_string;
386 rcode = p_func(v7, *res, res);
387 if (rcode != V7_OK) {
388 goto clean;
389 }
390
391 /*
392 * If returned value is still an object, get original argument value
393 */
394 if (v7_is_object(*res)) {
395 *res = v;
396 }
397 }
398
399 /*
400 * If the value is still an object, try to call second function (`valueOf()`
401 * or `toString()`)
402 */
403 if (v7_is_object(*res)) {
404 p_func =
405 (hint == V7_TO_PRIMITIVE_HINT_NUMBER) ? obj_to_string : obj_value_of;
406 rcode = p_func(v7, *res, res);
407 if (rcode != V7_OK) {
408 goto clean;
409 }
410 }
411
412 /*
413 * If the value is still an object, then throw.
414 */
415 if (v7_is_object(*res)) {
416 rcode =
417 v7_throwf(v7, TYPE_ERROR, "Cannot convert object to primitive value");
418 goto clean;
419 }
420
421clean:
422 v7_disown(v7, &v);
423 return rcode;
424}
425
426WARN_UNUSED_RESULT
427V7_PRIVATE enum v7_err to_string(struct v7 *v7, val_t v, val_t *res, char *buf,
428 size_t buf_size, size_t *res_len) {
429 enum v7_err rcode = V7_OK;
430
431 v7_own(v7, &v);
432
433 /*
434 * Convert value to primitive if needed, calling `toString()` first
435 */
436 V7_TRY(to_primitive(v7, v, V7_TO_PRIMITIVE_HINT_STRING, &v));
437
438 /*
439 * Now, we're guaranteed to have a primitive here. Convert it to string.
440 */
441 V7_TRY(primitive_to_str(v7, v, res, buf, buf_size, res_len));
442
443clean:
444 v7_disown(v7, &v);
445 return rcode;
446}
447
448WARN_UNUSED_RESULT
449V7_PRIVATE enum v7_err to_number_v(struct v7 *v7, val_t v, val_t *res) {
450 enum v7_err rcode = V7_OK;
451
452 *res = v;
453
454 /*
455 * Convert value to primitive if needed, calling `valueOf()` first
456 */
457 rcode = to_primitive(v7, *res, V7_TO_PRIMITIVE_HINT_NUMBER, res);
458 if (rcode != V7_OK) {
459 goto clean;
460 }
461
462 /*
463 * Now, we're guaranteed to have a primitive here. Convert it to number.
464 */
465 rcode = primitive_to_number(v7, *res, res);
466 if (rcode != V7_OK) {
467 goto clean;
468 }
469
470clean:
471 return rcode;
472}
473
474WARN_UNUSED_RESULT
475V7_PRIVATE enum v7_err to_long(struct v7 *v7, val_t v, long default_value,
476 long *res) {
477 enum v7_err rcode = V7_OK;
478 double d;
479
480 /* if value is `undefined`, just return `default_value` */
481 if (v7_is_undefined(v)) {
482 *res = default_value;
483 goto clean;
484 }
485
486 /* Try to convert value to number */
487 rcode = to_number_v(v7, v, &v);
488 if (rcode != V7_OK) {
489 goto clean;
490 }
491
492 /*
493 * Conversion to number succeeded, so, convert it to long
494 */
495
496 d = v7_get_double(v7, v);
497 /* We want to return LONG_MAX if d is positive Inf, thus d < 0 check */
498 if (isnan(d) || (isinf(d) && d < 0)) {
499 *res = 0;
500 goto clean;
501 } else if (d > LONG_MAX) {
502 *res = LONG_MAX;
503 goto clean;
504 }
505 *res = (long) d;
506 goto clean;
507
508clean:
509 return rcode;
510}
511
512V7_PRIVATE enum v7_err obj_value_of(struct v7 *v7, val_t v, val_t *res) {
513 enum v7_err rcode = V7_OK;
514 val_t func_valueOf = V7_UNDEFINED;
515
516 v7_own(v7, &func_valueOf);
517 v7_own(v7, &v);
518
519 /*
520 * TODO(dfrank): use `assert(v7_is_object(v))` instead, like `obj_to_string()`
521 * does, and fix all callers to ensure it's an object before calling.
522 *
523 * Or, conversely, make `obj_to_string()` to accept objects.
524 */
525 if (!v7_is_object(v)) {
526 *res = v;
527 goto clean;
528 }
529
530 V7_TRY(v7_get_throwing(v7, v, "valueOf", 7, &func_valueOf));
531
532 if (v7_is_callable(v7, func_valueOf)) {
533 V7_TRY(b_apply(v7, func_valueOf, v, V7_UNDEFINED, 0, res));
534 }
535
536clean:
537 if (rcode != V7_OK) {
538 *res = v;
539 }
540
541 v7_disown(v7, &v);
542 v7_disown(v7, &func_valueOf);
543
544 return rcode;
545}
546
547/*
548 * Caller should ensure that `v` is an object
549 */
550WARN_UNUSED_RESULT
551V7_PRIVATE enum v7_err obj_to_string(struct v7 *v7, val_t v, val_t *res) {
552 enum v7_err rcode = V7_OK;
553 val_t to_string_func = V7_UNDEFINED;
554
555 /* Caller should ensure that `v` is an object */
556 assert(v7_is_object(v));
557
558 v7_own(v7, &to_string_func);
559 v7_own(v7, &v);
560
561 /*
562 * If `toString` is callable, then call it; otherwise, just return source
563 * value
564 */
565 V7_TRY(v7_get_throwing(v7, v, "toString", 8, &to_string_func));
566 if (v7_is_callable(v7, to_string_func)) {
567 V7_TRY(b_apply(v7, to_string_func, v, V7_UNDEFINED, 0, res));
568 } else {
569 *res = v;
570 }
571
572clean:
573 v7_disown(v7, &v);
574 v7_disown(v7, &to_string_func);
575
576 return rcode;
577}
578
579static const char *hex_digits = "0123456789abcdef";
580static char *append_hex(char *buf, char *limit, uint8_t c) {
581 if (buf < limit) *buf++ = 'u';
582 if (buf < limit) *buf++ = '0';
583 if (buf < limit) *buf++ = '0';
584 if (buf < limit) *buf++ = hex_digits[(int) ((c >> 4) % 0xf)];
585 if (buf < limit) *buf++ = hex_digits[(int) (c & 0xf)];
586 return buf;
587}
588
589/*
590 * Appends quoted s to buf. Any double quote contained in s will be escaped.
591 * Returns the number of characters that would have been added,
592 * like snprintf.
593 * If size is zero it doesn't output anything but keeps counting.
594 */
595static int snquote(char *buf, size_t size, const char *s, size_t len) {
596 char *limit = buf + size;
597 const char *end;
598 /*
599 * String single character escape sequence:
600 * http://www.ecma-international.org/ecma-262/6.0/index.html#table-34
601 *
602 * 0x8 -> \b
603 * 0x9 -> \t
604 * 0xa -> \n
605 * 0xb -> \v
606 * 0xc -> \f
607 * 0xd -> \r
608 */
609 const char *specials = "btnvfr";
610 size_t i = 0;
611
612 i++;
613 if (buf < limit) *buf++ = '"';
614
615 for (end = s + len; s < end; s++) {
616 if (*s == '"' || *s == '\\') {
617 i++;
618 if (buf < limit) *buf++ = '\\';
619 } else if (*s >= '\b' && *s <= '\r') {
620 i += 2;
621 if (buf < limit) *buf++ = '\\';
622 if (buf < limit) *buf++ = specials[*s - '\b'];
623 continue;
624 } else if ((unsigned char) *s < '\b' || (*s > '\r' && *s < ' ')) {
625 i += 6 /* \uXXXX */;
626 if (buf < limit) *buf++ = '\\';
627 buf = append_hex(buf, limit, (uint8_t) *s);
628 continue;
629 }
630 i++;
631 if (buf < limit) *buf++ = *s;
632 }
633
634 i++;
635 if (buf < limit) *buf++ = '"';
636
637 if (buf < limit) {
638 *buf = '\0';
639 } else if (size != 0) {
640 /*
641 * There is no room for the NULL char, but the size wasn't zero, so we can
642 * safely put NULL in the previous byte
643 */
644 *(buf - 1) = '\0';
645 }
646 return i;
647}
648
649/*
650 * Returns whether the value of given type should be skipped when generating
651 * JSON output
652 */
653static int should_skip_for_json(enum v7_type type) {
654 int ret;
655 switch (type) {
656 /* All permitted values */
657 case V7_TYPE_NULL:
658 case V7_TYPE_BOOLEAN:
659 case V7_TYPE_BOOLEAN_OBJECT:
660 case V7_TYPE_NUMBER:
661 case V7_TYPE_NUMBER_OBJECT:
662 case V7_TYPE_STRING:
663 case V7_TYPE_STRING_OBJECT:
664 case V7_TYPE_GENERIC_OBJECT:
665 case V7_TYPE_ARRAY_OBJECT:
666 case V7_TYPE_DATE_OBJECT:
667 case V7_TYPE_REGEXP_OBJECT:
668 case V7_TYPE_ERROR_OBJECT:
669 ret = 0;
670 break;
671 default:
672 ret = 1;
673 break;
674 }
675 return ret;
676}
677
678WARN_UNUSED_RESULT
679V7_PRIVATE enum v7_err to_json_or_debug(struct v7 *v7, val_t v, char *buf,
680 size_t size, size_t *res_len,
681 uint8_t is_debug) {
682 val_t el;
683 char *vp;
684 enum v7_err rcode = V7_OK;
685 size_t len = 0;
686 struct gc_tmp_frame tf = new_tmp_frame(v7);
687
688 tmp_stack_push(&tf, &v);
689 tmp_stack_push(&tf, &el);
690 /*
691 * TODO(dfrank) : also push all `v7_val_t`s that are declared below
692 */
693
694 if (size > 0) *buf = '\0';
695
696 if (!is_debug && should_skip_for_json(val_type(v7, v))) {
697 goto clean;
698 }
699
700 for (vp = v7->json_visited_stack.buf;
701 vp < v7->json_visited_stack.buf + v7->json_visited_stack.len;
702 vp += sizeof(val_t)) {
703 if (*(val_t *) vp == v) {
704 strncpy(buf, "[Circular]", size);
705 len = 10;
706 goto clean;
707 }
708 }
709
710 switch (val_type(v7, v)) {
711 case V7_TYPE_NULL:
712 case V7_TYPE_BOOLEAN:
713 case V7_TYPE_NUMBER:
714 case V7_TYPE_UNDEFINED:
715 case V7_TYPE_CFUNCTION:
716 case V7_TYPE_FOREIGN:
717 /* For those types, regular `primitive_to_str()` works */
718 V7_TRY(primitive_to_str(v7, v, NULL, buf, size, &len));
719 goto clean;
720
721 case V7_TYPE_STRING: {
722 /*
723 * For strings we can't just use `primitive_to_str()`, because we need
724 * quoted value
725 */
726 size_t n;
727 const char *str = v7_get_string(v7, &v, &n);
728 len = snquote(buf, size, str, n);
729 goto clean;
730 }
731
732 case V7_TYPE_DATE_OBJECT: {
733 v7_val_t func = V7_UNDEFINED, val = V7_UNDEFINED;
734 V7_TRY(v7_get_throwing(v7, v, "toString", 8, &func));
735#if V7_ENABLE__Date__toJSON
736 if (!is_debug) {
737 V7_TRY(v7_get_throwing(v7, v, "toJSON", 6, &func));
738 }
739#endif
740 V7_TRY(b_apply(v7, func, v, V7_UNDEFINED, 0, &val));
741 V7_TRY(to_json_or_debug(v7, val, buf, size, &len, is_debug));
742 goto clean;
743 }
744 case V7_TYPE_GENERIC_OBJECT:
745 case V7_TYPE_BOOLEAN_OBJECT:
746 case V7_TYPE_STRING_OBJECT:
747 case V7_TYPE_NUMBER_OBJECT:
748 case V7_TYPE_REGEXP_OBJECT:
749 case V7_TYPE_ERROR_OBJECT: {
750 /* TODO(imax): make it return the desired size of the buffer */
751 char *b = buf;
752 v7_val_t name = V7_UNDEFINED, val = V7_UNDEFINED;
753 v7_prop_attr_t attrs = 0;
754 const char *pname;
755 size_t nlen;
756 int ok = 0;
757 struct prop_iter_ctx ctx;
758 memset(&ctx, 0, sizeof(ctx));
759
760 mbuf_append(&v7->json_visited_stack, (char *) &v, sizeof(v));
761 b += c_snprintf(b, BUF_LEFT(size, b - buf), "{");
762 V7_TRY2(init_prop_iter_ctx(v7, v, 1 /*proxy-transparent*/, &ctx),
763 clean_iter);
764 while (1) {
765 size_t n;
766 const char *s;
767 V7_TRY2(next_prop(v7, &ctx, &name, &val, &attrs, &ok), clean_iter);
768 if (!ok) {
769 break;
770 } else if (attrs & (_V7_PROPERTY_HIDDEN | V7_PROPERTY_NON_ENUMERABLE)) {
771 continue;
772 }
773 pname = v7_get_string(v7, &name, &nlen);
774 V7_TRY(v7_get_throwing(v7, v, pname, nlen, &val));
775 if (!is_debug && should_skip_for_json(val_type(v7, val))) {
776 continue;
777 }
778 if (b - buf != 1) { /* Not the first property to be printed */
779 b += c_snprintf(b, BUF_LEFT(size, b - buf), ",");
780 }
781 s = v7_get_string(v7, &name, &n);
782 b += c_snprintf(b, BUF_LEFT(size, b - buf), "\"%.*s\":", (int) n, s);
783 {
784 size_t tmp = 0;
785 V7_TRY2(to_json_or_debug(v7, val, b, BUF_LEFT(size, b - buf), &tmp,
786 is_debug),
787 clean_iter);
788 b += tmp;
789 }
790 }
791 b += c_snprintf(b, BUF_LEFT(size, b - buf), "}");
792 v7->json_visited_stack.len -= sizeof(v);
793
794 clean_iter:
795 v7_destruct_prop_iter_ctx(v7, &ctx);
796
797 len = b - buf;
798 goto clean;
799 }
800 case V7_TYPE_ARRAY_OBJECT: {
801 int has;
802 char *b = buf;
803 size_t i, alen = v7_array_length(v7, v);
804 mbuf_append(&v7->json_visited_stack, (char *) &v, sizeof(v));
805 b += c_snprintf(b, BUF_LEFT(size, b - buf), "[");
806 for (i = 0; i < alen; i++) {
807 el = v7_array_get2(v7, v, i, &has);
808 if (has) {
809 size_t tmp = 0;
810 if (!is_debug && should_skip_for_json(val_type(v7, el))) {
811 b += c_snprintf(b, BUF_LEFT(size, b - buf), "null");
812 } else {
813 V7_TRY(to_json_or_debug(v7, el, b, BUF_LEFT(size, b - buf), &tmp,
814 is_debug));
815 }
816 b += tmp;
817 }
818 if (i != alen - 1) {
819 b += c_snprintf(b, BUF_LEFT(size, b - buf), ",");
820 }
821 }
822 b += c_snprintf(b, BUF_LEFT(size, b - buf), "]");
823 v7->json_visited_stack.len -= sizeof(v);
824 len = b - buf;
825 goto clean;
826 }
827 case V7_TYPE_CFUNCTION_OBJECT:
828 V7_TRY(obj_value_of(v7, v, &v));
829 len = c_snprintf(buf, size, "Function cfunc_%p", get_ptr(v));
830 goto clean;
831 case V7_TYPE_FUNCTION_OBJECT:
832 V7_TRY(to_string(v7, v, NULL, buf, size, &len));
833 goto clean;
834
835 case V7_TYPE_MAX_OBJECT_TYPE:
836 case V7_NUM_TYPES:
837 abort();
838 }
839
840 abort();
841
842 len = 0; /* for compilers that don't know about abort() */
843 goto clean;
844
845clean:
846 if (rcode != V7_OK) {
847 len = 0;
848 }
849 if (res_len != NULL) {
850 *res_len = len;
851 }
852 tmp_frame_cleanup(&tf);
853 return rcode;
854}
855
856WARN_UNUSED_RESULT
857V7_PRIVATE val_t to_boolean_v(struct v7 *v7, val_t v) {
858 size_t len;
859 int is_truthy;
860
861 is_truthy = ((v7_is_boolean(v) && v7_get_bool(v7, v)) ||
862 (v7_is_number(v) && v7_get_double(v7, v) != 0.0) ||
863 (v7_is_string(v) && v7_get_string(v7, &v, &len) && len > 0) ||
864 (v7_is_object(v))) &&
865 v != V7_TAG_NAN;
866
867 return v7_mk_boolean(v7, is_truthy);
868}
869
870/*
871 * v7_stringify allocates a new buffer if value representation doesn't fit into
872 * buf. Caller is responsible for freeing that buffer.
873 */
874char *v7_stringify(struct v7 *v7, val_t v, char *buf, size_t size,
875 enum v7_stringify_mode mode) {
876 enum v7_err rcode = V7_OK;
877 uint8_t saved_is_thrown = 0;
878 val_t saved_thrown = v7_get_thrown_value(v7, &saved_is_thrown);
879 char *ret = NULL;
880
881 rcode = v7_stringify_throwing(v7, v, buf, size, mode, &ret);
882 if (rcode != V7_OK) {
883 rcode = V7_OK;
884 if (saved_is_thrown) {
885 rcode = v7_throw(v7, saved_thrown);
886 } else {
887 v7_clear_thrown_value(v7);
888 }
889
890 buf[0] = '\0';
891 ret = buf;
892 }
893
894 return ret;
895}
896
897enum v7_err v7_stringify_throwing(struct v7 *v7, val_t v, char *buf,
898 size_t size, enum v7_stringify_mode mode,
899 char **res) {
900 enum v7_err rcode = V7_OK;
901 char *p = buf;
902 size_t len;
903
904 switch (mode) {
905 case V7_STRINGIFY_DEFAULT:
906 V7_TRY(to_string(v7, v, NULL, buf, size, &len));
907 break;
908
909 case V7_STRINGIFY_JSON:
910 V7_TRY(to_json_or_debug(v7, v, buf, size, &len, 0));
911 break;
912
913 case V7_STRINGIFY_DEBUG:
914 V7_TRY(to_json_or_debug(v7, v, buf, size, &len, 1));
915 break;
916 }
917
918 /* fit null terminating byte */
919 if (len >= size) {
920 /* Buffer is not large enough. Allocate a bigger one */
921 p = (char *) malloc(len + 1);
922 V7_TRY(v7_stringify_throwing(v7, v, p, len + 1, mode, res));
923 assert(*res == p);
924 goto clean;
925 } else {
926 *res = p;
927 goto clean;
928 }
929
930clean:
931 /*
932 * If we're going to throw, and we allocated a buffer, then free it.
933 * But if we don't throw, then the caller will free it.
934 */
935 if (rcode != V7_OK && p != buf) {
936 free(p);
937 }
938 return rcode;
939}
940
941int v7_is_truthy(struct v7 *v7, val_t v) {
942 return v7_get_bool(v7, to_boolean_v(v7, v));
943}
944#ifdef V7_MODULE_LINES
945#line 1 "v7/src/shdata.c"
946#endif
947/*
948 * Copyright (c) 2014 Cesanta Software Limited
949 * All rights reserved
950 */
951
952/* Amalgamated: #include "v7/src/internal.h" */
953/* Amalgamated: #include "v7/src/shdata.h" */
954
955#if !V7_DISABLE_FILENAMES && !V7_DISABLE_LINE_NUMBERS
956V7_PRIVATE struct shdata *shdata_create(const void *payload, size_t size) {
957 struct shdata *ret =
958 (struct shdata *) calloc(1, sizeof(struct shdata) + size);
959 shdata_retain(ret);
960 if (payload != NULL) {
961 memcpy((char *) shdata_get_payload(ret), (char *) payload, size);
962 }
963 return ret;
964}
965
966V7_PRIVATE struct shdata *shdata_create_from_string(const char *src) {
967 return shdata_create(src, strlen(src) + 1 /*null-term*/);
968}
969
970V7_PRIVATE void shdata_retain(struct shdata *p) {
971 p->refcnt++;
972 assert(p->refcnt > 0);
973}
974
975V7_PRIVATE void shdata_release(struct shdata *p) {
976 assert(p->refcnt > 0);
977 p->refcnt--;
978 if (p->refcnt == 0) {
979 free(p);
980 }
981}
982
983V7_PRIVATE void *shdata_get_payload(struct shdata *p) {
984 return (char *) p + sizeof(*p);
985}
986#endif
987#ifdef V7_MODULE_LINES
988#line 1 "v7/src/gc.c"
989#endif
990/*
991 * Copyright (c) 2014 Cesanta Software Limited
992 * All rights reserved
993 */
994
995/* Amalgamated: #include "v7/src/internal.h" */
996/* Amalgamated: #include "v7/src/bcode.h" */
997/* Amalgamated: #include "v7/src/varint.h" */
998/* Amalgamated: #include "v7/src/gc.h" */
999/* Amalgamated: #include "v7/src/freeze.h" */
1000/* Amalgamated: #include "v7/src/core.h" */
1001/* Amalgamated: #include "v7/src/function.h" */
1002/* Amalgamated: #include "v7/src/primitive.h" */
1003/* Amalgamated: #include "v7/src/object.h" */
1004/* Amalgamated: #include "v7/src/string.h" */
1005/* Amalgamated: #include "v7/src/util.h" */
1006/* Amalgamated: #include "v7/src/primitive.h" */
1007/* Amalgamated: #include "v7/src/heapusage.h" */
1008
1009#include <stdio.h>
1010
1011#ifdef V7_STACK_GUARD_MIN_SIZE
1012void *v7_sp_limit = NULL;
1013#endif
1014
1015void gc_mark_string(struct v7 *, val_t *);
1016
1017static struct gc_block *gc_new_block(struct gc_arena *a, size_t size);
1018static void gc_free_block(struct gc_block *b);
1019static void gc_mark_mbuf_pt(struct v7 *v7, const struct mbuf *mbuf);
1020static void gc_mark_mbuf_val(struct v7 *v7, const struct mbuf *mbuf);
1021static void gc_mark_vec_val(struct v7 *v7, const struct v7_vec *vec);
1022
1023V7_PRIVATE struct v7_generic_object *new_generic_object(struct v7 *v7) {
1024 return (struct v7_generic_object *) gc_alloc_cell(v7,
1025 &v7->generic_object_arena);
1026}
1027
1028V7_PRIVATE struct v7_property *new_property(struct v7 *v7) {
1029 return (struct v7_property *) gc_alloc_cell(v7, &v7->property_arena);
1030}
1031
1032V7_PRIVATE struct v7_js_function *new_function(struct v7 *v7) {
1033 return (struct v7_js_function *) gc_alloc_cell(v7, &v7->function_arena);
1034}
1035
1036V7_PRIVATE struct gc_tmp_frame new_tmp_frame(struct v7 *v7) {
1037 struct gc_tmp_frame frame;
1038 frame.v7 = v7;
1039 frame.pos = v7->tmp_stack.len;
1040 return frame;
1041}
1042
1043V7_PRIVATE void tmp_frame_cleanup(struct gc_tmp_frame *tf) {
1044 tf->v7->tmp_stack.len = tf->pos;
1045}
1046
1047/*
1048 * TODO(mkm): perhaps it's safer to keep val_t in the temporary
1049 * roots stack, instead of keeping val_t*, in order to be better
1050 * able to debug the relocating GC.
1051 */
1052V7_PRIVATE void tmp_stack_push(struct gc_tmp_frame *tf, val_t *vp) {
1053 mbuf_append(&tf->v7->tmp_stack, (char *) &vp, sizeof(val_t *));
1054}
1055
1056/* Initializes a new arena. */
1057V7_PRIVATE void gc_arena_init(struct gc_arena *a, size_t cell_size,
1058 size_t initial_size, size_t size_increment,
1059 const char *name) {
1060 assert(cell_size >= sizeof(uintptr_t));
1061
1062 memset(a, 0, sizeof(*a));
1063 a->cell_size = cell_size;
1064 a->name = name;
1065 a->size_increment = size_increment;
1066 a->blocks = gc_new_block(a, initial_size);
1067}
1068
1069V7_PRIVATE void gc_arena_destroy(struct v7 *v7, struct gc_arena *a) {
1070 struct gc_block *b;
1071
1072 if (a->blocks != NULL) {
1073 gc_sweep(v7, a, 0);
1074 for (b = a->blocks; b != NULL;) {
1075 struct gc_block *tmp;
1076 tmp = b;
1077 b = b->next;
1078 gc_free_block(tmp);
1079 }
1080 }
1081}
1082
1083static void gc_free_block(struct gc_block *b) {
1084 free(b->base);
1085 free(b);
1086}
1087
1088static struct gc_block *gc_new_block(struct gc_arena *a, size_t size) {
1089 struct gc_cell *cur;
1090 struct gc_block *b;
1091
1092 heapusage_dont_count(1);
1093 b = (struct gc_block *) calloc(1, sizeof(*b));
1094 heapusage_dont_count(0);
1095 if (b == NULL) abort();
1096
1097 b->size = size;
1098 heapusage_dont_count(1);
1099 b->base = (struct gc_cell *) calloc(a->cell_size, b->size);
1100 heapusage_dont_count(0);
1101 if (b->base == NULL) abort();
1102
1103 for (cur = GC_CELL_OP(a, b->base, +, 0);
1104 cur < GC_CELL_OP(a, b->base, +, b->size);
1105 cur = GC_CELL_OP(a, cur, +, 1)) {
1106 cur->head.link = a->free;
1107 a->free = cur;
1108 }
1109
1110 return b;
1111}
1112
1113V7_PRIVATE void *gc_alloc_cell(struct v7 *v7, struct gc_arena *a) {
1114#ifdef V7_MALLOC_GC
1115 struct gc_cell *r;
1116 maybe_gc(v7);
1117 heapusage_dont_count(1);
1118 r = (struct gc_cell *) calloc(1, a->cell_size);
1119 heapusage_dont_count(0);
1120 mbuf_append(&v7->malloc_trace, &r, sizeof(r));
1121 return r;
1122#else
1123 struct gc_cell *r;
1124 if (a->free == NULL) {
1125 if (!maybe_gc(v7)) {
1126 /* GC is inhibited, so, schedule invocation for later */
1127 v7->need_gc = 1;
1128 }
1129
1130 if (a->free == NULL) {
1131 struct gc_block *b = gc_new_block(a, a->size_increment);
1132 b->next = a->blocks;
1133 a->blocks = b;
1134 }
1135 }
1136 r = a->free;
1137
1138 UNMARK(r);
1139
1140 a->free = r->head.link;
1141
1142#if V7_ENABLE__Memory__stats
1143 a->allocations++;
1144 a->alive++;
1145#endif
1146
1147 /*
1148 * TODO(mkm): minor opt possible since most of the fields
1149 * are overwritten downstream, but not worth the yak shave time
1150 * when fields are added to GC-able structures */
1151 memset(r, 0, a->cell_size);
1152 return (void *) r;
1153#endif
1154}
1155
1156#ifdef V7_MALLOC_GC
1157/*
1158 * Scans trough the memory blocks registered in the malloc trace.
1159 * Free the unmarked ones and reset the mark on the rest.
1160 */
1161void gc_sweep_malloc(struct v7 *v7) {
1162 struct gc_cell **cur;
1163 for (cur = (struct gc_cell **) v7->malloc_trace.buf;
1164 cur < (struct gc_cell **) (v7->malloc_trace.buf + v7->malloc_trace.len);
1165 cur++) {
1166 if (*cur == NULL) continue;
1167
1168 if (MARKED(*cur)) {
1169 UNMARK(*cur);
1170 } else {
1171 free(*cur);
1172 /* TODO(mkm): compact malloc trace buffer */
1173 *cur = NULL;
1174 }
1175 }
1176}
1177#endif
1178
1179/*
1180 * Scans the arena and add all unmarked cells to the free list.
1181 *
1182 * Empty blocks get deallocated. The head of the free list will contais cells
1183 * from the last (oldest) block. Cells will thus be allocated in block order.
1184 */
1185void gc_sweep(struct v7 *v7, struct gc_arena *a, size_t start) {
1186 struct gc_block *b;
1187 struct gc_cell *cur;
1188 struct gc_block **prevp = &a->blocks;
1189#if V7_ENABLE__Memory__stats
1190 a->alive = 0;
1191#endif
1192
1193 /*
1194 * Before we sweep, we should mark all free cells in a way that is
1195 * distinguishable from marked used cells.
1196 */
1197 {
1198 struct gc_cell *next;
1199 for (cur = a->free; cur != NULL; cur = next) {
1200 next = cur->head.link;
1201 MARK_FREE(cur);
1202 }
1203 }
1204
1205 /*
1206 * We'll rebuild the whole `free` list, so initially we just reset it
1207 */
1208 a->free = NULL;
1209
1210 for (b = a->blocks; b != NULL;) {
1211 size_t freed_in_block = 0;
1212 /*
1213 * if it turns out that this block is 100% garbage
1214 * we can release the whole block, but the addition
1215 * of it's cells to the free list has to be undone.
1216 */
1217 struct gc_cell *prev_free = a->free;
1218
1219 for (cur = GC_CELL_OP(a, b->base, +, start);
1220 cur < GC_CELL_OP(a, b->base, +, b->size);
1221 cur = GC_CELL_OP(a, cur, +, 1)) {
1222 if (MARKED(cur)) {
1223 /* The cell is used and marked */
1224 UNMARK(cur);
1225#if V7_ENABLE__Memory__stats
1226 a->alive++;
1227#endif
1228 } else {
1229 /*
1230 * The cell is either:
1231 * - free
1232 * - garbage that's about to be freed
1233 */
1234
1235 if (MARKED_FREE(cur)) {
1236 /* The cell is free, so, just unmark it */
1237 UNMARK_FREE(cur);
1238 } else {
1239 /*
1240 * The cell is used and should be freed: call the destructor and
1241 * reset the memory
1242 */
1243 if (a->destructor != NULL) {
1244 a->destructor(v7, cur);
1245 }
1246 memset(cur, 0, a->cell_size);
1247 }
1248
1249 /* Add this cell to the `free` list */
1250 cur->head.link = a->free;
1251 a->free = cur;
1252 freed_in_block++;
1253#if V7_ENABLE__Memory__stats
1254 a->garbage++;
1255#endif
1256 }
1257 }
1258
1259 /*
1260 * don't free the initial block, which is at the tail
1261 * because it has a special size aimed at reducing waste
1262 * and simplifying initial startup. TODO(mkm): improve
1263 * */
1264 if (b->next != NULL && freed_in_block == b->size) {
1265 *prevp = b->next;
1266 gc_free_block(b);
1267 b = *prevp;
1268 a->free = prev_free;
1269 } else {
1270 prevp = &b->next;
1271 b = b->next;
1272 }
1273 }
1274}
1275
1276/*
1277 * dense arrays contain only one property pointing to an mbuf with array values.
1278 */
1279V7_PRIVATE void gc_mark_dense_array(struct v7 *v7,
1280 struct v7_generic_object *obj) {
1281 val_t v;
1282 struct mbuf *mbuf;
1283 val_t *vp;
1284
1285#if 0
1286 /* TODO(mkm): use this when dense array promotion is implemented */
1287 v = obj->properties->value;
1288#else
1289 v = v7_get(v7, v7_object_to_value(&obj->base), "", 0);
1290#endif
1291
1292 mbuf = (struct mbuf *) v7_get_ptr(v7, v);
1293
1294 /* function scope pointer is aliased to the object's prototype pointer */
1295 gc_mark(v7, v7_object_to_value(obj_prototype(v7, &obj->base)));
1296 MARK(obj);
1297
1298 if (mbuf == NULL) return;
1299 for (vp = (val_t *) mbuf->buf; (char *) vp < mbuf->buf + mbuf->len; vp++) {
1300 gc_mark(v7, *vp);
1301 gc_mark_string(v7, vp);
1302 }
1303 UNMARK(obj);
1304}
1305
1306V7_PRIVATE void gc_mark(struct v7 *v7, val_t v) {
1307 struct v7_object *obj_base;
1308 struct v7_property *prop;
1309 struct v7_property *next;
1310
1311 if (!v7_is_object(v)) {
1312 return;
1313 }
1314 obj_base = get_object_struct(v);
1315
1316 /*
1317 * we ignore objects that are not managed by V7 heap, such as frozen
1318 * objects, especially when on flash.
1319 */
1320 if (obj_base->attributes & V7_OBJ_OFF_HEAP) {
1321 return;
1322 }
1323
1324 /*
1325 * we treat all object like things like objects but they might be functions,
1326 * gc_gheck_val checks the appropriate arena per actual value type.
1327 */
1328 if (!gc_check_val(v7, v)) {
1329 abort();
1330 }
1331
1332 if (MARKED(obj_base)) return;
1333
1334#ifdef V7_FREEZE
1335 if (v7->freeze_file != NULL) {
1336 freeze_obj(v7, v7->freeze_file, v);
1337 }
1338#endif
1339
1340 if (obj_base->attributes & V7_OBJ_DENSE_ARRAY) {
1341 struct v7_generic_object *obj = get_generic_object_struct(v);
1342 gc_mark_dense_array(v7, obj);
1343 }
1344
1345 /* mark object itself, and its properties */
1346 for ((prop = obj_base->properties), MARK(obj_base); prop != NULL;
1347 prop = next) {
1348 if (prop->attributes & _V7_PROPERTY_OFF_HEAP) {
1349 break;
1350 }
1351
1352 if (!gc_check_ptr(&v7->property_arena, prop)) {
1353 abort();
1354 }
1355
1356#ifdef V7_FREEZE
1357 if (v7->freeze_file != NULL) {
1358 freeze_prop(v7, v7->freeze_file, prop);
1359 }
1360#endif
1361
1362 gc_mark_string(v7, &prop->value);
1363 gc_mark_string(v7, &prop->name);
1364 gc_mark(v7, prop->value);
1365
1366 next = prop->next;
1367 MARK(prop);
1368 }
1369
1370 /* mark object's prototype */
1371 gc_mark(v7, v7_get_proto(v7, v));
1372
1373 if (is_js_function(v)) {
1374 struct v7_js_function *func = get_js_function_struct(v);
1375
1376 /* mark function's scope */
1377 gc_mark(v7, v7_object_to_value(&func->scope->base));
1378
1379 if (func->bcode != NULL) {
1380 gc_mark_vec_val(v7, &func->bcode->lit);
1381 }
1382 }
1383}
1384
1385#if V7_ENABLE__Memory__stats
1386
1387V7_PRIVATE size_t gc_arena_size(struct gc_arena *a) {
1388 size_t size = 0;
1389 struct gc_block *b;
1390 for (b = a->blocks; b != NULL; b = b->next) {
1391 size += b->size;
1392 }
1393 return size;
1394}
1395
1396/*
1397 * TODO(dfrank): move to core
1398 */
1399int v7_heap_stat(struct v7 *v7, enum v7_heap_stat_what what) {
1400 switch (what) {
1401 case V7_HEAP_STAT_HEAP_SIZE:
1402 return gc_arena_size(&v7->generic_object_arena) *
1403 v7->generic_object_arena.cell_size +
1404 gc_arena_size(&v7->function_arena) * v7->function_arena.cell_size +
1405 gc_arena_size(&v7->property_arena) * v7->property_arena.cell_size;
1406 case V7_HEAP_STAT_HEAP_USED:
1407 return v7->generic_object_arena.alive *
1408 v7->generic_object_arena.cell_size +
1409 v7->function_arena.alive * v7->function_arena.cell_size +
1410 v7->property_arena.alive * v7->property_arena.cell_size;
1411 case V7_HEAP_STAT_STRING_HEAP_RESERVED:
1412 return v7->owned_strings.size;
1413 case V7_HEAP_STAT_STRING_HEAP_USED:
1414 return v7->owned_strings.len;
1415 case V7_HEAP_STAT_OBJ_HEAP_MAX:
1416 return gc_arena_size(&v7->generic_object_arena);
1417 case V7_HEAP_STAT_OBJ_HEAP_FREE:
1418 return gc_arena_size(&v7->generic_object_arena) -
1419 v7->generic_object_arena.alive;
1420 case V7_HEAP_STAT_OBJ_HEAP_CELL_SIZE:
1421 return v7->generic_object_arena.cell_size;
1422 case V7_HEAP_STAT_FUNC_HEAP_MAX:
1423 return gc_arena_size(&v7->function_arena);
1424 case V7_HEAP_STAT_FUNC_HEAP_FREE:
1425 return gc_arena_size(&v7->function_arena) - v7->function_arena.alive;
1426 case V7_HEAP_STAT_FUNC_HEAP_CELL_SIZE:
1427 return v7->function_arena.cell_size;
1428 case V7_HEAP_STAT_PROP_HEAP_MAX:
1429 return gc_arena_size(&v7->property_arena);
1430 case V7_HEAP_STAT_PROP_HEAP_FREE:
1431 return gc_arena_size(&v7->property_arena) - v7->property_arena.alive;
1432 case V7_HEAP_STAT_PROP_HEAP_CELL_SIZE:
1433 return v7->property_arena.cell_size;
1434 case V7_HEAP_STAT_FUNC_AST_SIZE:
1435 return v7->function_arena_ast_size;
1436 case V7_HEAP_STAT_BCODE_OPS_SIZE:
1437 return v7->bcode_ops_size;
1438 case V7_HEAP_STAT_BCODE_LIT_TOTAL_SIZE:
1439 return v7->bcode_lit_total_size;
1440 case V7_HEAP_STAT_BCODE_LIT_DESER_SIZE:
1441 return v7->bcode_lit_deser_size;
1442 case V7_HEAP_STAT_FUNC_OWNED:
1443 return v7->owned_values.len / sizeof(val_t *);
1444 case V7_HEAP_STAT_FUNC_OWNED_MAX:
1445 return v7->owned_values.size / sizeof(val_t *);
1446 }
1447
1448 return -1;
1449}
1450#endif
1451
1452V7_PRIVATE void gc_dump_arena_stats(const char *msg, struct gc_arena *a) {
1453 (void) msg;
1454 (void) a;
1455#ifndef NO_LIBC
1456#if V7_ENABLE__Memory__stats
1457 if (a->verbose) {
1458 fprintf(stderr, "%s: total allocations %lu, max %lu, alive %lu\n", msg,
1459 (long unsigned int) a->allocations,
1460 (long unsigned int) gc_arena_size(a), (long unsigned int) a->alive);
1461 }
1462#endif
1463#endif
1464}
1465
1466V7_PRIVATE uint64_t gc_string_val_to_offset(val_t v) {
1467 return (((uint64_t)(uintptr_t) get_ptr(v)) & ~V7_TAG_MASK)
1468#if !V7_DISABLE_STR_ALLOC_SEQ
1469 & 0xFFFFFFFF
1470#endif
1471 ;
1472}
1473
1474V7_PRIVATE val_t gc_string_val_from_offset(uint64_t s) {
1475 return s | V7_TAG_STRING_O;
1476}
1477
1478#if !V7_DISABLE_STR_ALLOC_SEQ
1479
1480static uint16_t next_asn(struct v7 *v7) {
1481 if (v7->gc_next_asn == 0xFFFF) {
1482 /* Wrap around explicitly. */
1483 v7->gc_next_asn = 0;
1484 return 0xFFFF;
1485 }
1486 return v7->gc_next_asn++;
1487}
1488
1489uint16_t gc_next_allocation_seqn(struct v7 *v7, const char *str, size_t len) {
1490 uint16_t asn = next_asn(v7);
1491 (void) str;
1492 (void) len;
1493#ifdef V7_GC_VERBOSE
1494 /*
1495 * ESP SDK printf cannot cope with null strings
1496 * as created by s_concat.
1497 */
1498 if (str == NULL) {
1499 fprintf(stderr, "GC ASN %d: <nil>\n", asn);
1500 } else {
1501 fprintf(stderr, "GC ASN %d: \"%.*s\"\n", asn, (int) len, str);
1502 }
1503#endif
1504#ifdef V7_GC_PANIC_ON_ASN
1505 if (asn == (V7_GC_PANIC_ON_ASN)) {
1506 abort();
1507 }
1508#endif
1509 return asn;
1510}
1511
1512int gc_is_valid_allocation_seqn(struct v7 *v7, uint16_t n) {
1513 /*
1514 * This functions attempts to handle integer wraparound in a naive way and
1515 * will give false positives when more than 65536 strings are allocated
1516 * between GC runs.
1517 */
1518 int r = (n >= v7->gc_min_asn && n < v7->gc_next_asn) ||
1519 (v7->gc_min_asn > v7->gc_next_asn &&
1520 (n >= v7->gc_min_asn || n < v7->gc_next_asn));
1521 if (!r) {
1522 fprintf(stderr, "GC ASN %d is not in [%d,%d)\n", n, v7->gc_min_asn,
1523 v7->gc_next_asn);
1524 }
1525 return r;
1526}
1527
1528void gc_check_valid_allocation_seqn(struct v7 *v7, uint16_t n) {
1529 if (!gc_is_valid_allocation_seqn(v7, n)) {
1530/*
1531 * TODO(dfrank) throw exception if V7_GC_ASN_PANIC is not defined.
1532 */
1533#if 0 && !defined(V7_GC_ASN_PANIC)
1534 throw_exception(v7, INTERNAL_ERROR, "Invalid ASN: %d", (int) n);
1535#else
1536 fprintf(stderr, "Invalid ASN: %d\n", (int) n);
1537 abort();
1538#endif
1539 }
1540}
1541
1542#endif /* V7_DISABLE_STR_ALLOC_SEQ */
1543
1544/* Mark a string value */
1545void gc_mark_string(struct v7 *v7, val_t *v) {
1546 val_t h, tmp = 0;
1547 char *s;
1548
1549 /* clang-format off */
1550
1551 /*
1552 * If a value points to an unmarked string we shall:
1553 * 1. save the first 6 bytes of the string
1554 * since we need to be able to distinguish real values from
1555 * the saved first 6 bytes of the string, we need to tag the chunk
1556 * as V7_TAG_STRING_C
1557 * 2. encode value's address (v) into the first 6 bytes of the string.
1558 * 3. put the saved 8 bytes (tag + chunk) back into the value.
1559 * 4. mark the string by putting '\1' in the NUL terminator of the previous
1560 * string chunk.
1561 *
1562 * If a value points to an already marked string we shall:
1563 * (0, <6 bytes of a pointer to a val_t>), hence we have to skip
1564 * the first byte. We tag the value pointer as a V7_TAG_FOREIGN
1565 * so that it won't be followed during recursive mark.
1566 *
1567 * ... the rest is the same
1568 *
1569 * Note: 64-bit pointers can be represented with 48-bits
1570 */
1571
1572 /* clang-format on */
1573
1574 if ((*v & V7_TAG_MASK) != V7_TAG_STRING_O) {
1575 return;
1576 }
1577
1578#ifdef V7_FREEZE
1579 if (v7->freeze_file != NULL) {
1580 return;
1581 }
1582#endif
1583
1584#ifdef V7_GC_VERBOSE
1585 {
1586 uint16_t asn = (*v >> 32) & 0xFFFF;
1587 size_t size;
1588 fprintf(stderr, "GC marking ASN %d: '%s'\n", asn,
1589 v7_get_string(v7, v, &size));
1590 }
1591#endif
1592
1593#if !V7_DISABLE_STR_ALLOC_SEQ
1594 gc_check_valid_allocation_seqn(v7, (*v >> 32) & 0xFFFF);
1595#endif
1596
1597 s = v7->owned_strings.buf + gc_string_val_to_offset(*v);
1598 assert(s < v7->owned_strings.buf + v7->owned_strings.len);
1599 if (s[-1] == '\0') {
1600 memcpy(&tmp, s, sizeof(tmp) - 2);
1601 tmp |= V7_TAG_STRING_C;
1602 } else {
1603 memcpy(&tmp, s, sizeof(tmp) - 2);
1604 tmp |= V7_TAG_FOREIGN;
1605 }
1606
1607 h = (val_t)(uintptr_t) v;
1608 s[-1] = 1;
1609 memcpy(s, &h, sizeof(h) - 2);
1610 memcpy(v, &tmp, sizeof(tmp));
1611}
1612
1613void gc_compact_strings(struct v7 *v7) {
1614 char *p = v7->owned_strings.buf + 1;
1615 uint64_t h, next, head = 1;
1616 int len, llen;
1617
1618#if !V7_DISABLE_STR_ALLOC_SEQ
1619 v7->gc_min_asn = v7->gc_next_asn;
1620#endif
1621 while (p < v7->owned_strings.buf + v7->owned_strings.len) {
1622 if (p[-1] == '\1') {
1623#if !V7_DISABLE_STR_ALLOC_SEQ
1624 /* Not using gc_next_allocation_seqn() as we don't have full string. */
1625 uint16_t asn = next_asn(v7);
1626#endif
1627 /* relocate and update ptrs */
1628 h = 0;
1629 memcpy(&h, p, sizeof(h) - 2);
1630
1631 /*
1632 * relocate pointers until we find the tail.
1633 * The tail is marked with V7_TAG_STRING_C,
1634 * while val_t link pointers are tagged with V7_TAG_FOREIGN
1635 */
1636 for (; (h & V7_TAG_MASK) != V7_TAG_STRING_C; h = next) {
1637 h &= ~V7_TAG_MASK;
1638 memcpy(&next, (char *) (uintptr_t) h, sizeof(h));
1639
1640 *(val_t *) (uintptr_t) h = gc_string_val_from_offset(head)
1641#if !V7_DISABLE_STR_ALLOC_SEQ
1642 | ((val_t) asn << 32)
1643#endif
1644 ;
1645 }
1646 h &= ~V7_TAG_MASK;
1647
1648 /*
1649 * the tail contains the first 6 bytes we stole from
1650 * the actual string.
1651 */
1652 len = decode_varint((unsigned char *) &h, &llen);
1653 len += llen + 1;
1654
1655 /*
1656 * restore the saved 6 bytes
1657 * TODO(mkm): think about endianness
1658 */
1659 memcpy(p, &h, sizeof(h) - 2);
1660
1661 /*
1662 * and relocate the string data by packing it to the left.
1663 */
1664 memmove(v7->owned_strings.buf + head, p, len);
1665 v7->owned_strings.buf[head - 1] = 0x0;
1666#if defined(V7_GC_VERBOSE) && !V7_DISABLE_STR_ALLOC_SEQ
1667 fprintf(stderr, "GC updated ASN %d: \"%.*s\"\n", asn, len - llen - 1,
1668 v7->owned_strings.buf + head + llen);
1669#endif
1670 p += len;
1671 head += len;
1672 } else {
1673 len = decode_varint((unsigned char *) p, &llen);
1674 len += llen + 1;
1675
1676 p += len;
1677 }
1678 }
1679
1680#if defined(V7_GC_VERBOSE) && !V7_DISABLE_STR_ALLOC_SEQ
1681 fprintf(stderr, "GC valid ASN range: [%d,%d)\n", v7->gc_min_asn,
1682 v7->gc_next_asn);
1683#endif
1684
1685 v7->owned_strings.len = head;
1686}
1687
1688void gc_dump_owned_strings(struct v7 *v7) {
1689 size_t i;
1690 for (i = 0; i < v7->owned_strings.len; i++) {
1691 if (isprint((unsigned char) v7->owned_strings.buf[i])) {
1692 fputc(v7->owned_strings.buf[i], stderr);
1693 } else {
1694 fputc('.', stderr);
1695 }
1696 }
1697 fputc('\n', stderr);
1698}
1699
1700/*
1701 * builting on gcc, tried out by redefining it.
1702 * Using null pointer as base can trigger undefined behavior, hence
1703 * a portable workaround that involves a valid yet dummy pointer.
1704 * It's meant to be used as a contant expression.
1705 */
1706#ifndef offsetof
1707#define offsetof(st, m) (((ptrdiff_t)(&((st *) 32)->m)) - 32)
1708#endif
1709
1710V7_PRIVATE void compute_need_gc(struct v7 *v7) {
1711 struct mbuf *m = &v7->owned_strings;
1712 if ((double) m->len / (double) m->size > 0.9) {
1713 v7->need_gc = 1;
1714 }
1715 /* TODO(mkm): check free heap */
1716}
1717
1718V7_PRIVATE int maybe_gc(struct v7 *v7) {
1719 if (!v7->inhibit_gc) {
1720 v7_gc(v7, 0);
1721 return 1;
1722 }
1723 return 0;
1724}
1725#if defined(V7_GC_VERBOSE)
1726static int gc_pass = 0;
1727#endif
1728
1729/*
1730 * mark an array of `val_t` values (*not pointers* to them)
1731 */
1732static void gc_mark_val_array(struct v7 *v7, val_t *vals, size_t len) {
1733 val_t *vp;
1734 for (vp = vals; vp < vals + len; vp++) {
1735 gc_mark(v7, *vp);
1736 gc_mark_string(v7, vp);
1737 }
1738}
1739
1740/*
1741 * mark an mbuf containing *pointers* to `val_t` values
1742 */
1743static void gc_mark_mbuf_pt(struct v7 *v7, const struct mbuf *mbuf) {
1744 val_t **vp;
1745 for (vp = (val_t **) mbuf->buf; (char *) vp < mbuf->buf + mbuf->len; vp++) {
1746 gc_mark(v7, **vp);
1747 gc_mark_string(v7, *vp);
1748 }
1749}
1750
1751/*
1752 * mark an mbuf containing `val_t` values (*not pointers* to them)
1753 */
1754static void gc_mark_mbuf_val(struct v7 *v7, const struct mbuf *mbuf) {
1755 gc_mark_val_array(v7, (val_t *) mbuf->buf, mbuf->len / sizeof(val_t));
1756}
1757
1758/*
1759 * mark a vector containing `val_t` values (*not pointers* to them)
1760 */
1761static void gc_mark_vec_val(struct v7 *v7, const struct v7_vec *vec) {
1762 gc_mark_val_array(v7, (val_t *) vec->p, vec->len / sizeof(val_t));
1763}
1764
1765/*
1766 * mark an mbuf containing foreign pointers to `struct bcode`
1767 */
1768static void gc_mark_mbuf_bcode_pt(struct v7 *v7, const struct mbuf *mbuf) {
1769 struct bcode **vp;
1770 for (vp = (struct bcode **) mbuf->buf; (char *) vp < mbuf->buf + mbuf->len;
1771 vp++) {
1772 gc_mark_vec_val(v7, &(*vp)->lit);
1773 }
1774}
1775
1776static void gc_mark_call_stack_private(
1777 struct v7 *v7, struct v7_call_frame_private *call_stack) {
1778 gc_mark_val_array(v7, (val_t *) &call_stack->vals,
1779 sizeof(call_stack->vals) / sizeof(val_t));
1780}
1781
1782static void gc_mark_call_stack_cfunc(struct v7 *v7,
1783 struct v7_call_frame_cfunc *call_stack) {
1784 gc_mark_val_array(v7, (val_t *) &call_stack->vals,
1785 sizeof(call_stack->vals) / sizeof(val_t));
1786}
1787
1788static void gc_mark_call_stack_bcode(struct v7 *v7,
1789 struct v7_call_frame_bcode *call_stack) {
1790 gc_mark_val_array(v7, (val_t *) &call_stack->vals,
1791 sizeof(call_stack->vals) / sizeof(val_t));
1792}
1793
1794/*
1795 * mark `struct v7_call_frame` and all its back-linked frames
1796 */
1797static void gc_mark_call_stack(struct v7 *v7,
1798 struct v7_call_frame_base *call_stack) {
1799 while (call_stack != NULL) {
1800 if (call_stack->type_mask & V7_CALL_FRAME_MASK_BCODE) {
1801 gc_mark_call_stack_bcode(v7, (struct v7_call_frame_bcode *) call_stack);
1802 }
1803
1804 if (call_stack->type_mask & V7_CALL_FRAME_MASK_PRIVATE) {
1805 gc_mark_call_stack_private(v7,
1806 (struct v7_call_frame_private *) call_stack);
1807 }
1808
1809 if (call_stack->type_mask & V7_CALL_FRAME_MASK_CFUNC) {
1810 gc_mark_call_stack_cfunc(v7, (struct v7_call_frame_cfunc *) call_stack);
1811 }
1812
1813 call_stack = call_stack->prev;
1814 }
1815}
1816
1817/* Perform garbage collection */
1818void v7_gc(struct v7 *v7, int full) {
1819#if V7_DISABLE_GC
1820 (void) v7;
1821 (void) full;
1822 return;
1823#else
1824
1825#if defined(V7_GC_VERBOSE)
1826 fprintf(stderr, "V7 GC pass %d\n", ++gc_pass);
1827#endif
1828
1829 gc_dump_arena_stats("Before GC objects", &v7->generic_object_arena);
1830 gc_dump_arena_stats("Before GC functions", &v7->function_arena);
1831 gc_dump_arena_stats("Before GC properties", &v7->property_arena);
1832
1833 gc_mark_call_stack(v7, v7->call_stack);
1834
1835 gc_mark_val_array(v7, (val_t *) &v7->vals, sizeof(v7->vals) / sizeof(val_t));
1836 /* mark all items on bcode stack */
1837 gc_mark_mbuf_val(v7, &v7->stack);
1838
1839 /* mark literals and names of all the active bcodes */
1840 gc_mark_mbuf_bcode_pt(v7, &v7->act_bcodes);
1841
1842 gc_mark_mbuf_pt(v7, &v7->tmp_stack);
1843 gc_mark_mbuf_pt(v7, &v7->owned_values);
1844
1845 gc_compact_strings(v7);
1846
1847#ifdef V7_MALLOC_GC
1848 gc_sweep_malloc(v7);
1849#else
1850 gc_sweep(v7, &v7->generic_object_arena, 0);
1851 gc_sweep(v7, &v7->function_arena, 0);
1852 gc_sweep(v7, &v7->property_arena, 0);
1853#endif
1854
1855 gc_dump_arena_stats("After GC objects", &v7->generic_object_arena);
1856 gc_dump_arena_stats("After GC functions", &v7->function_arena);
1857 gc_dump_arena_stats("After GC properties", &v7->property_arena);
1858
1859 if (full) {
1860 /*
1861 * In case of full GC, we also resize strings buffer, but we still leave
1862 * some extra space (at most, `_V7_STRING_BUF_RESERVE`) in order to avoid
1863 * frequent reallocations
1864 */
1865 size_t trimmed_size = v7->owned_strings.len + _V7_STRING_BUF_RESERVE;
1866 if (trimmed_size < v7->owned_strings.size) {
1867 heapusage_dont_count(1);
1868 mbuf_resize(&v7->owned_strings, trimmed_size);
1869 heapusage_dont_count(0);
1870 }
1871 }
1872#endif /* V7_DISABLE_GC */
1873}
1874
1875V7_PRIVATE int gc_check_val(struct v7 *v7, val_t v) {
1876 if (is_js_function(v)) {
1877 return gc_check_ptr(&v7->function_arena, get_js_function_struct(v));
1878 } else if (v7_is_object(v)) {
1879 return gc_check_ptr(&v7->generic_object_arena, get_object_struct(v));
1880 }
1881 return 1;
1882}
1883
1884V7_PRIVATE int gc_check_ptr(const struct gc_arena *a, const void *ptr) {
1885#ifdef V7_MALLOC_GC
1886 (void) a;
1887 (void) ptr;
1888 return 1;
1889#else
1890 const struct gc_cell *p = (const struct gc_cell *) ptr;
1891 struct gc_block *b;
1892 for (b = a->blocks; b != NULL; b = b->next) {
1893 if (p >= b->base && p < GC_CELL_OP(a, b->base, +, b->size)) {
1894 return 1;
1895 }
1896 }
1897 return 0;
1898#endif
1899}
1900#ifdef V7_MODULE_LINES
1901#line 1 "v7/src/freeze.c"
1902#endif
1903/*
1904 * Copyright (c) 2014 Cesanta Software Limited
1905 * All rights reserved
1906 */
1907
1908/* Amalgamated: #include "v7/src/core.h" */
1909/* Amalgamated: #include "v7/src/function.h" */
1910/* Amalgamated: #include "v7/src/util.h" */
1911/* Amalgamated: #include "v7/src/freeze.h" */
1912/* Amalgamated: #include "v7/src/bcode.h" */
1913/* Amalgamated: #include "v7/src/gc.h" */
1914/* Amalgamated: #include "common/base64.h" */
1915/* Amalgamated: #include "v7/src/object.h" */
1916
1917#include <stdio.h>
1918
1919#ifdef V7_FREEZE
1920
1921V7_PRIVATE void freeze(struct v7 *v7, char *filename) {
1922 size_t i;
1923
1924 v7->freeze_file = fopen(filename, "w");
1925 assert(v7->freeze_file != NULL);
1926
1927#ifndef V7_FREEZE_NOT_READONLY
1928 /*
1929 * We have to remove `global` from the global object since
1930 * when thawing global will actually be a new mutable object
1931 * living on the heap.
1932 */
1933 v7_del(v7, v7->vals.global_object, "global", 6);
1934#endif
1935
1936 for (i = 0; i < sizeof(v7->vals) / sizeof(val_t); i++) {
1937 val_t v = ((val_t *) &v7->vals)[i];
1938 fprintf(v7->freeze_file,
1939 "{\"type\":\"global\", \"idx\":%zu, \"value\":\"%p\"}\n", i,
1940 (void *) (v7_is_object(v) ? get_object_struct(v) : 0x0));
1941 }
1942
1943 /*
1944 * since v7->freeze_file is not NULL this will cause freeze_obj and
1945 * freeze_prop to be called for each reachable object and property.
1946 */
1947 v7_gc(v7, 1);
1948 assert(v7->stack.len == 0);
1949
1950 fclose(v7->freeze_file);
1951 v7->freeze_file = NULL;
1952}
1953
1954static char *freeze_vec(struct v7_vec *vec) {
1955 char *res = (char *) malloc(512 + vec->len);
1956 res[0] = '"';
1957 cs_base64_encode((const unsigned char *) vec->p, vec->len, &res[1]);
1958 strcat(res, "\"");
1959 return res;
1960}
1961
1962V7_PRIVATE void freeze_obj(struct v7 *v7, FILE *f, v7_val_t v) {
1963 struct v7_object *obj_base = get_object_struct(v);
1964 unsigned int attrs = V7_OBJ_OFF_HEAP;
1965
1966#ifndef V7_FREEZE_NOT_READONLY
1967 attrs |= V7_OBJ_NOT_EXTENSIBLE;
1968#endif
1969
1970 if (is_js_function(v)) {
1971 struct v7_js_function *func = get_js_function_struct(v);
1972 struct bcode *bcode = func->bcode;
1973 char *jops = freeze_vec(&bcode->ops);
1974 int i;
1975
1976 fprintf(f,
1977 "{\"type\":\"func\", \"addr\":\"%p\", \"props\":\"%p\", "
1978 "\"attrs\":%d, \"scope\":\"%p\", \"bcode\":\"%p\""
1979#if V7_ENABLE_ENTITY_IDS
1980 ", \"entity_id_base\":%d, \"entity_id_spec\":\"%d\" "
1981#endif
1982 "}\n",
1983 (void *) obj_base,
1984 (void *) ((uintptr_t) obj_base->properties & ~0x1),
1985 obj_base->attributes | attrs, (void *) func->scope, (void *) bcode
1986#if V7_ENABLE_ENTITY_IDS
1987 ,
1988 obj_base->entity_id_base, obj_base->entity_id_spec
1989#endif
1990 );
1991 fprintf(f,
1992 "{\"type\":\"bcode\", \"addr\":\"%p\", \"args_cnt\":%d, "
1993 "\"names_cnt\":%d, "
1994 "\"strict_mode\": %d, \"func_name_present\": %d, \"ops\":%s, "
1995 "\"lit\": [",
1996 (void *) bcode, bcode->args_cnt, bcode->names_cnt,
1997 bcode->strict_mode, bcode->func_name_present, jops);
1998
1999 for (i = 0; (size_t) i < bcode->lit.len / sizeof(val_t); i++) {
2000 val_t v = ((val_t *) bcode->lit.p)[i];
2001 const char *str;
2002
2003 if (((v & V7_TAG_MASK) == V7_TAG_STRING_O ||
2004 (v & V7_TAG_MASK) == V7_TAG_STRING_F) &&
2005 (str = v7_get_cstring(v7, &v)) != NULL) {
2006 fprintf(f, "{\"str\": \"%s\"}", str);
2007 } else {
2008 fprintf(f, "{\"val\": \"0x%" INT64_X_FMT "\"}", v);
2009 }
2010 if ((size_t) i != bcode->lit.len / sizeof(val_t) - 1) {
2011 fprintf(f, ",");
2012 }
2013 }
2014
2015 fprintf(f, "]}\n");
2016 free(jops);
2017 } else {
2018 struct v7_generic_object *gob = get_generic_object_struct(v);
2019 fprintf(f,
2020 "{\"type\":\"obj\", \"addr\":\"%p\", \"props\":\"%p\", "
2021 "\"attrs\":%d, \"proto\":\"%p\""
2022#if V7_ENABLE_ENTITY_IDS
2023 ", \"entity_id_base\":%d, \"entity_id_spec\":\"%d\" "
2024#endif
2025 "}\n",
2026 (void *) obj_base,
2027 (void *) ((uintptr_t) obj_base->properties & ~0x1),
2028 obj_base->attributes | attrs, (void *) gob->prototype
2029#if V7_ENABLE_ENTITY_IDS
2030 ,
2031 obj_base->entity_id_base, obj_base->entity_id_spec
2032#endif
2033 );
2034 }
2035}
2036
2037V7_PRIVATE void freeze_prop(struct v7 *v7, FILE *f, struct v7_property *prop) {
2038 unsigned int attrs = _V7_PROPERTY_OFF_HEAP;
2039#ifndef V7_FREEZE_NOT_READONLY
2040 attrs |= V7_PROPERTY_NON_WRITABLE | V7_PROPERTY_NON_CONFIGURABLE;
2041#endif
2042
2043 fprintf(f,
2044 "{\"type\":\"prop\","
2045 " \"addr\":\"%p\","
2046 " \"next\":\"%p\","
2047 " \"attrs\":%d,"
2048 " \"name\":\"0x%" INT64_X_FMT
2049 "\","
2050 " \"value_type\":%d,"
2051 " \"value\":\"0x%" INT64_X_FMT
2052 "\","
2053 " \"name_str\":\"%s\""
2054#if V7_ENABLE_ENTITY_IDS
2055 ", \"entity_id\":\"%d\""
2056#endif
2057 "}\n",
2058 (void *) prop, (void *) prop->next, prop->attributes | attrs,
2059 prop->name, val_type(v7, prop->value), prop->value,
2060 v7_get_cstring(v7, &prop->name)
2061#if V7_ENABLE_ENTITY_IDS
2062 ,
2063 prop->entity_id
2064#endif
2065 );
2066}
2067
2068#endif
2069#ifdef V7_MODULE_LINES
2070#line 1 "v7/src/parser.c"
2071#endif
2072/*
2073 * Copyright (c) 2014 Cesanta Software Limited
2074 * All rights reserved
2075 */
2076
2077/* Amalgamated: #include "common/coroutine.h" */
2078/* Amalgamated: #include "v7/src/internal.h" */
2079/* Amalgamated: #include "v7/src/parser.h" */
2080/* Amalgamated: #include "v7/src/tokenizer.h" */
2081/* Amalgamated: #include "v7/src/core.h" */
2082/* Amalgamated: #include "v7/src/exceptions.h" */
2083/* Amalgamated: #include "v7/src/ast.h" */
2084/* Amalgamated: #include "v7/src/primitive.h" */
2085/* Amalgamated: #include "v7/src/cyg_profile.h" */
2086
2087#if !defined(V7_NO_COMPILER)
2088
2089#define ACCEPT(t) (((v7)->cur_tok == (t)) ? next_tok((v7)), 1 : 0)
2090
2091#define EXPECT(t) \
2092 do { \
2093 if ((v7)->cur_tok != (t)) { \
2094 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR); \
2095 } \
2096 next_tok(v7); \
2097 } while (0)
2098
2099#define PARSE_WITH_OPT_ARG(tag, arg_tag, arg_parser, label) \
2100 do { \
2101 if (end_of_statement(v7) == V7_OK) { \
2102 add_node(v7, a, (tag)); \
2103 } else { \
2104 add_node(v7, a, (arg_tag)); \
2105 arg_parser(label); \
2106 } \
2107 } while (0)
2108
2109#define N (CR_ARG_RET_PT()->arg)
2110
2111/*
2112 * User functions
2113 * (as well as other in-function entry points)
2114 */
2115enum my_fid {
2116 fid_none = CR_FID__NONE,
2117
2118 /* parse_script function */
2119 fid_parse_script = CR_FID__USER,
2120 fid_p_script_1,
2121 fid_p_script_2,
2122 fid_p_script_3,
2123 fid_p_script_4,
2124
2125 /* parse_use_strict function */
2126 fid_parse_use_strict,
2127
2128 /* parse_body function */
2129 fid_parse_body,
2130 fid_p_body_1,
2131 fid_p_body_2,
2132
2133 /* parse_statement function */
2134 fid_parse_statement,
2135 fid_p_stat_1,
2136 fid_p_stat_2,
2137 fid_p_stat_3,
2138 fid_p_stat_4,
2139 fid_p_stat_5,
2140 fid_p_stat_6,
2141 fid_p_stat_7,
2142 fid_p_stat_8,
2143 fid_p_stat_9,
2144 fid_p_stat_10,
2145 fid_p_stat_11,
2146 fid_p_stat_12,
2147 fid_p_stat_13,
2148 fid_p_stat_14,
2149
2150 /* parse_expression function */
2151 fid_parse_expression,
2152 fid_p_expr_1,
2153
2154 /* parse_assign function */
2155 fid_parse_assign,
2156 fid_p_assign_1,
2157
2158 /* parse_binary function */
2159 fid_parse_binary,
2160 fid_p_binary_1,
2161 fid_p_binary_2,
2162 fid_p_binary_3,
2163 fid_p_binary_4,
2164 fid_p_binary_5,
2165 fid_p_binary_6,
2166
2167 /* parse_prefix function */
2168 fid_parse_prefix,
2169 fid_p_prefix_1,
2170
2171 /* parse_postfix function */
2172 fid_parse_postfix,
2173 fid_p_postfix_1,
2174
2175 /* parse_callexpr function */
2176 fid_parse_callexpr,
2177 fid_p_callexpr_1,
2178 fid_p_callexpr_2,
2179 fid_p_callexpr_3,
2180
2181 /* parse_newexpr function */
2182 fid_parse_newexpr,
2183 fid_p_newexpr_1,
2184 fid_p_newexpr_2,
2185 fid_p_newexpr_3,
2186 fid_p_newexpr_4,
2187
2188 /* parse_terminal function */
2189 fid_parse_terminal,
2190 fid_p_terminal_1,
2191 fid_p_terminal_2,
2192 fid_p_terminal_3,
2193 fid_p_terminal_4,
2194
2195 /* parse_block function */
2196 fid_parse_block,
2197 fid_p_block_1,
2198
2199 /* parse_if function */
2200 fid_parse_if,
2201 fid_p_if_1,
2202 fid_p_if_2,
2203 fid_p_if_3,
2204
2205 /* parse_while function */
2206 fid_parse_while,
2207 fid_p_while_1,
2208 fid_p_while_2,
2209
2210 /* parse_ident function */
2211 fid_parse_ident,
2212
2213 /* parse_ident_allow_reserved_words function */
2214 fid_parse_ident_allow_reserved_words,
2215 fid_p_ident_arw_1,
2216
2217 /* parse_funcdecl function */
2218 fid_parse_funcdecl,
2219 fid_p_funcdecl_1,
2220 fid_p_funcdecl_2,
2221 fid_p_funcdecl_3,
2222 fid_p_funcdecl_4,
2223 fid_p_funcdecl_5,
2224 fid_p_funcdecl_6,
2225 fid_p_funcdecl_7,
2226 fid_p_funcdecl_8,
2227 fid_p_funcdecl_9,
2228
2229 /* parse_arglist function */
2230 fid_parse_arglist,
2231 fid_p_arglist_1,
2232
2233 /* parse_member function */
2234 fid_parse_member,
2235 fid_p_member_1,
2236
2237 /* parse_memberexpr function */
2238 fid_parse_memberexpr,
2239 fid_p_memberexpr_1,
2240 fid_p_memberexpr_2,
2241
2242 /* parse_var function */
2243 fid_parse_var,
2244 fid_p_var_1,
2245
2246 /* parse_prop function */
2247 fid_parse_prop,
2248#if V7_ENABLE_JS_GETTERS
2249 fid_p_prop_1_getter,
2250#endif
2251 fid_p_prop_2,
2252#if V7_ENABLE_JS_SETTERS
2253 fid_p_prop_3_setter,
2254#endif
2255 fid_p_prop_4,
2256
2257 /* parse_dowhile function */
2258 fid_parse_dowhile,
2259 fid_p_dowhile_1,
2260 fid_p_dowhile_2,
2261
2262 /* parse_for function */
2263 fid_parse_for,
2264 fid_p_for_1,
2265 fid_p_for_2,
2266 fid_p_for_3,
2267 fid_p_for_4,
2268 fid_p_for_5,
2269 fid_p_for_6,
2270
2271 /* parse_try function */
2272 fid_parse_try,
2273 fid_p_try_1,
2274 fid_p_try_2,
2275 fid_p_try_3,
2276 fid_p_try_4,
2277
2278 /* parse_switch function */
2279 fid_parse_switch,
2280 fid_p_switch_1,
2281 fid_p_switch_2,
2282 fid_p_switch_3,
2283 fid_p_switch_4,
2284
2285 /* parse_with function */
2286 fid_parse_with,
2287 fid_p_with_1,
2288 fid_p_with_2,
2289
2290 MY_FID_CNT
2291};
2292
2293/*
2294 * User exception IDs. The first one should have value `CR_EXC_ID__USER`
2295 */
2296enum parser_exc_id {
2297 PARSER_EXC_ID__NONE = CR_EXC_ID__NONE,
2298 PARSER_EXC_ID__SYNTAX_ERROR = CR_EXC_ID__USER,
2299};
2300
2301/* structures with locals and args {{{ */
2302
2303/* parse_script {{{ */
2304
2305/* parse_script's arguments */
2306#if 0
2307typedef struct fid_parse_script_arg {
2308} fid_parse_script_arg_t;
2309#else
2310typedef cr_zero_size_type_t fid_parse_script_arg_t;
2311#endif
2312
2313/* parse_script's data on stack */
2314typedef struct fid_parse_script_locals {
2315#if 0
2316 struct fid_parse_script_arg arg;
2317#endif
2318
2319 ast_off_t start;
2320 ast_off_t outer_last_var_node;
2321 int saved_in_strict;
2322} fid_parse_script_locals_t;
2323
2324/* }}} */
2325
2326/* parse_use_strict {{{ */
2327/* parse_use_strict's arguments */
2328#if 0
2329typedef struct fid_parse_use_strict_arg {
2330} fid_parse_use_strict_arg_t;
2331#else
2332typedef cr_zero_size_type_t fid_parse_use_strict_arg_t;
2333#endif
2334
2335/* parse_use_strict's data on stack */
2336#if 0
2337typedef struct fid_parse_use_strict_locals {
2338 struct fid_parse_use_strict_arg arg;
2339} fid_parse_use_strict_locals_t;
2340#else
2341typedef cr_zero_size_type_t fid_parse_use_strict_locals_t;
2342#endif
2343
2344#define CALL_PARSE_USE_STRICT(_label) \
2345 do { \
2346 CR_CALL(fid_parse_use_strict, _label); \
2347 } while (0)
2348
2349/* }}} */
2350
2351/* parse_body {{{ */
2352/* parse_body's arguments */
2353typedef struct fid_parse_body_arg { enum v7_tok end; } fid_parse_body_arg_t;
2354
2355/* parse_body's data on stack */
2356typedef struct fid_parse_body_locals {
2357 struct fid_parse_body_arg arg;
2358
2359 ast_off_t start;
2360} fid_parse_body_locals_t;
2361
2362#define CALL_PARSE_BODY(_end, _label) \
2363 do { \
2364 N.fid_parse_body.end = (_end); \
2365 CR_CALL(fid_parse_body, _label); \
2366 } while (0)
2367/* }}} */
2368
2369/* parse_statement {{{ */
2370/* parse_statement's arguments */
2371#if 0
2372typedef struct fid_parse_statement_arg {
2373} fid_parse_statement_arg_t;
2374#else
2375typedef cr_zero_size_type_t fid_parse_statement_arg_t;
2376#endif
2377
2378/* parse_statement's data on stack */
2379#if 0
2380typedef struct fid_parse_statement_locals {
2381 struct fid_parse_statement_arg arg;
2382} fid_parse_statement_locals_t;
2383#else
2384typedef cr_zero_size_type_t fid_parse_statement_locals_t;
2385#endif
2386
2387#define CALL_PARSE_STATEMENT(_label) \
2388 do { \
2389 CR_CALL(fid_parse_statement, _label); \
2390 } while (0)
2391/* }}} */
2392
2393/* parse_expression {{{ */
2394/* parse_expression's arguments */
2395#if 0
2396typedef struct fid_parse_expression_arg {
2397} fid_parse_expression_arg_t;
2398#else
2399typedef cr_zero_size_type_t fid_parse_expression_arg_t;
2400#endif
2401
2402/* parse_expression's data on stack */
2403typedef struct fid_parse_expression_locals {
2404#if 0
2405 struct fid_parse_expression_arg arg;
2406#endif
2407
2408 ast_off_t pos;
2409 int group;
2410} fid_parse_expression_locals_t;
2411
2412#define CALL_PARSE_EXPRESSION(_label) \
2413 do { \
2414 CR_CALL(fid_parse_expression, _label); \
2415 } while (0)
2416/* }}} */
2417
2418/* parse_assign {{{ */
2419/* parse_assign's arguments */
2420#if 0
2421typedef struct fid_parse_assign_arg {
2422} fid_parse_assign_arg_t;
2423#else
2424typedef cr_zero_size_type_t fid_parse_assign_arg_t;
2425#endif
2426
2427/* parse_assign's data on stack */
2428#if 0
2429typedef struct fid_parse_assign_locals {
2430 struct fid_parse_assign_arg arg;
2431} fid_parse_assign_locals_t;
2432#else
2433typedef cr_zero_size_type_t fid_parse_assign_locals_t;
2434#endif
2435
2436#define CALL_PARSE_ASSIGN(_label) \
2437 do { \
2438 CR_CALL(fid_parse_assign, _label); \
2439 } while (0)
2440/* }}} */
2441
2442/* parse_binary {{{ */
2443/* parse_binary's arguments */
2444typedef struct fid_parse_binary_arg {
2445 ast_off_t pos;
2446 uint8_t min_level;
2447} fid_parse_binary_arg_t;
2448
2449/* parse_binary's data on stack */
2450typedef struct fid_parse_binary_locals {
2451 struct fid_parse_binary_arg arg;
2452
2453 uint8_t i;
2454 /* during iteration, it becomes negative, so should be signed */
2455 int8_t level;
2456 uint8_t /*enum v7_tok*/ tok;
2457 uint8_t /*enum ast_tag*/ ast;
2458 ast_off_t saved_mbuf_len;
2459} fid_parse_binary_locals_t;
2460
2461#define CALL_PARSE_BINARY(_level, _pos, _label) \
2462 do { \
2463 N.fid_parse_binary.min_level = (_level); \
2464 N.fid_parse_binary.pos = (_pos); \
2465 CR_CALL(fid_parse_binary, _label); \
2466 } while (0)
2467/* }}} */
2468
2469/* parse_prefix {{{ */
2470/* parse_prefix's arguments */
2471#if 0
2472typedef struct fid_parse_prefix_arg {
2473} fid_parse_prefix_arg_t;
2474#else
2475typedef cr_zero_size_type_t fid_parse_prefix_arg_t;
2476#endif
2477
2478/* parse_prefix's data on stack */
2479#if 0
2480typedef struct fid_parse_prefix_locals {
2481 struct fid_parse_prefix_arg arg;
2482} fid_parse_prefix_locals_t;
2483#else
2484typedef cr_zero_size_type_t fid_parse_prefix_locals_t;
2485#endif
2486
2487#define CALL_PARSE_PREFIX(_label) \
2488 do { \
2489 CR_CALL(fid_parse_prefix, _label); \
2490 } while (0)
2491/* }}} */
2492
2493/* parse_postfix {{{ */
2494/* parse_postfix's arguments */
2495#if 0
2496typedef struct fid_parse_postfix_arg {
2497} fid_parse_postfix_arg_t;
2498#else
2499typedef cr_zero_size_type_t fid_parse_postfix_arg_t;
2500#endif
2501
2502/* parse_postfix's data on stack */
2503typedef struct fid_parse_postfix_locals {
2504#if 0
2505 struct fid_parse_postfix_arg arg;
2506#endif
2507
2508 ast_off_t pos;
2509} fid_parse_postfix_locals_t;
2510
2511#define CALL_PARSE_POSTFIX(_label) \
2512 do { \
2513 CR_CALL(fid_parse_postfix, _label); \
2514 } while (0)
2515/* }}} */
2516
2517/* parse_callexpr {{{ */
2518/* parse_callexpr's arguments */
2519#if 0
2520typedef struct fid_parse_callexpr_arg {
2521} fid_parse_callexpr_arg_t;
2522#else
2523typedef cr_zero_size_type_t fid_parse_callexpr_arg_t;
2524#endif
2525
2526/* parse_callexpr's data on stack */
2527typedef struct fid_parse_callexpr_locals {
2528#if 0
2529 struct fid_parse_callexpr_arg arg;
2530#endif
2531
2532 ast_off_t pos;
2533} fid_parse_callexpr_locals_t;
2534
2535#define CALL_PARSE_CALLEXPR(_label) \
2536 do { \
2537 CR_CALL(fid_parse_callexpr, _label); \
2538 } while (0)
2539/* }}} */
2540
2541/* parse_newexpr {{{ */
2542/* parse_newexpr's arguments */
2543#if 0
2544typedef struct fid_parse_newexpr_arg {
2545} fid_parse_newexpr_arg_t;
2546#else
2547typedef cr_zero_size_type_t fid_parse_newexpr_arg_t;
2548#endif
2549
2550/* parse_newexpr's data on stack */
2551typedef struct fid_parse_newexpr_locals {
2552#if 0
2553 struct fid_parse_newexpr_arg arg;
2554#endif
2555
2556 ast_off_t start;
2557} fid_parse_newexpr_locals_t;
2558
2559#define CALL_PARSE_NEWEXPR(_label) \
2560 do { \
2561 CR_CALL(fid_parse_newexpr, _label); \
2562 } while (0)
2563/* }}} */
2564
2565/* parse_terminal {{{ */
2566/* parse_terminal's arguments */
2567#if 0
2568typedef struct fid_parse_terminal_arg {
2569} fid_parse_terminal_arg_t;
2570#else
2571typedef cr_zero_size_type_t fid_parse_terminal_arg_t;
2572#endif
2573
2574/* parse_terminal's data on stack */
2575typedef struct fid_parse_terminal_locals {
2576#if 0
2577 struct fid_parse_terminal_arg arg;
2578#endif
2579
2580 ast_off_t start;
2581} fid_parse_terminal_locals_t;
2582
2583#define CALL_PARSE_TERMINAL(_label) \
2584 do { \
2585 CR_CALL(fid_parse_terminal, _label); \
2586 } while (0)
2587/* }}} */
2588
2589/* parse_block {{{ */
2590/* parse_block's arguments */
2591#if 0
2592typedef struct fid_parse_block_arg {
2593} fid_parse_block_arg_t;
2594#else
2595typedef cr_zero_size_type_t fid_parse_block_arg_t;
2596#endif
2597
2598/* parse_block's data on stack */
2599#if 0
2600typedef struct fid_parse_block_locals {
2601 struct fid_parse_block_arg arg;
2602} fid_parse_block_locals_t;
2603#else
2604typedef cr_zero_size_type_t fid_parse_block_locals_t;
2605#endif
2606
2607#define CALL_PARSE_BLOCK(_label) \
2608 do { \
2609 CR_CALL(fid_parse_block, _label); \
2610 } while (0)
2611/* }}} */
2612
2613/* parse_if {{{ */
2614/* parse_if's arguments */
2615#if 0
2616typedef struct fid_parse_if_arg {
2617} fid_parse_if_arg_t;
2618#else
2619typedef cr_zero_size_type_t fid_parse_if_arg_t;
2620#endif
2621
2622/* parse_if's data on stack */
2623typedef struct fid_parse_if_locals {
2624#if 0
2625 struct fid_parse_if_arg arg;
2626#endif
2627
2628 ast_off_t start;
2629} fid_parse_if_locals_t;
2630
2631#define CALL_PARSE_IF(_label) \
2632 do { \
2633 CR_CALL(fid_parse_if, _label); \
2634 } while (0)
2635/* }}} */
2636
2637/* parse_while {{{ */
2638/* parse_while's arguments */
2639#if 0
2640typedef struct fid_parse_while_arg {
2641} fid_parse_while_arg_t;
2642#else
2643typedef cr_zero_size_type_t fid_parse_while_arg_t;
2644#endif
2645
2646/* parse_while's data on stack */
2647typedef struct fid_parse_while_locals {
2648#if 0
2649 struct fid_parse_while_arg arg;
2650#endif
2651
2652 ast_off_t start;
2653 uint8_t saved_in_loop;
2654} fid_parse_while_locals_t;
2655
2656#define CALL_PARSE_WHILE(_label) \
2657 do { \
2658 CR_CALL(fid_parse_while, _label); \
2659 } while (0)
2660/* }}} */
2661
2662/* parse_ident {{{ */
2663/* parse_ident's arguments */
2664#if 0
2665typedef struct fid_parse_ident_arg {
2666} fid_parse_ident_arg_t;
2667#else
2668typedef cr_zero_size_type_t fid_parse_ident_arg_t;
2669#endif
2670
2671/* parse_ident's data on stack */
2672#if 0
2673typedef struct fid_parse_ident_locals {
2674 struct fid_parse_ident_arg arg;
2675} fid_parse_ident_locals_t;
2676#else
2677typedef cr_zero_size_type_t fid_parse_ident_locals_t;
2678#endif
2679
2680#define CALL_PARSE_IDENT(_label) \
2681 do { \
2682 CR_CALL(fid_parse_ident, _label); \
2683 } while (0)
2684/* }}} */
2685
2686/* parse_ident_allow_reserved_words {{{ */
2687/* parse_ident_allow_reserved_words's arguments */
2688#if 0
2689typedef struct fid_parse_ident_allow_reserved_words_arg {
2690} fid_parse_ident_allow_reserved_words_arg_t;
2691#else
2692typedef cr_zero_size_type_t fid_parse_ident_allow_reserved_words_arg_t;
2693#endif
2694
2695/* parse_ident_allow_reserved_words's data on stack */
2696#if 0
2697typedef struct fid_parse_ident_allow_reserved_words_locals {
2698 struct fid_parse_ident_allow_reserved_words_arg arg;
2699} fid_parse_ident_allow_reserved_words_locals_t;
2700#else
2701typedef cr_zero_size_type_t fid_parse_ident_allow_reserved_words_locals_t;
2702#endif
2703
2704#define CALL_PARSE_IDENT_ALLOW_RESERVED_WORDS(_label) \
2705 do { \
2706 CR_CALL(fid_parse_ident_allow_reserved_words, _label); \
2707 } while (0)
2708/* }}} */
2709
2710/* parse_funcdecl {{{ */
2711/* parse_funcdecl's arguments */
2712typedef struct fid_parse_funcdecl_arg {
2713 uint8_t require_named;
2714 uint8_t reserved_name;
2715} fid_parse_funcdecl_arg_t;
2716
2717/* parse_funcdecl's data on stack */
2718typedef struct fid_parse_funcdecl_locals {
2719 struct fid_parse_funcdecl_arg arg;
2720
2721 ast_off_t start;
2722 ast_off_t outer_last_var_node;
2723 uint8_t saved_in_function;
2724 uint8_t saved_in_strict;
2725} fid_parse_funcdecl_locals_t;
2726
2727#define CALL_PARSE_FUNCDECL(_require_named, _reserved_name, _label) \
2728 do { \
2729 N.fid_parse_funcdecl.require_named = (_require_named); \
2730 N.fid_parse_funcdecl.reserved_name = (_reserved_name); \
2731 CR_CALL(fid_parse_funcdecl, _label); \
2732 } while (0)
2733/* }}} */
2734
2735/* parse_arglist {{{ */
2736/* parse_arglist's arguments */
2737#if 0
2738typedef struct fid_parse_arglist_arg {
2739} fid_parse_arglist_arg_t;
2740#else
2741typedef cr_zero_size_type_t fid_parse_arglist_arg_t;
2742#endif
2743
2744/* parse_arglist's data on stack */
2745#if 0
2746typedef struct fid_parse_arglist_locals {
2747 struct fid_parse_arglist_arg arg;
2748} fid_parse_arglist_locals_t;
2749#else
2750typedef cr_zero_size_type_t fid_parse_arglist_locals_t;
2751#endif
2752
2753#define CALL_PARSE_ARGLIST(_label) \
2754 do { \
2755 CR_CALL(fid_parse_arglist, _label); \
2756 } while (0)
2757/* }}} */
2758
2759/* parse_member {{{ */
2760/* parse_member's arguments */
2761typedef struct fid_parse_member_arg { ast_off_t pos; } fid_parse_member_arg_t;
2762
2763/* parse_member's data on stack */
2764typedef struct fid_parse_member_locals {
2765 struct fid_parse_member_arg arg;
2766} fid_parse_member_locals_t;
2767
2768#define CALL_PARSE_MEMBER(_pos, _label) \
2769 do { \
2770 N.fid_parse_member.pos = (_pos); \
2771 CR_CALL(fid_parse_member, _label); \
2772 } while (0)
2773/* }}} */
2774
2775/* parse_memberexpr {{{ */
2776/* parse_memberexpr's arguments */
2777#if 0
2778typedef struct fid_parse_memberexpr_arg {
2779} fid_parse_memberexpr_arg_t;
2780#else
2781typedef cr_zero_size_type_t fid_parse_memberexpr_arg_t;
2782#endif
2783
2784/* parse_memberexpr's data on stack */
2785typedef struct fid_parse_memberexpr_locals {
2786#if 0
2787 struct fid_parse_memberexpr_arg arg;
2788#endif
2789
2790 ast_off_t pos;
2791} fid_parse_memberexpr_locals_t;
2792
2793#define CALL_PARSE_MEMBEREXPR(_label) \
2794 do { \
2795 CR_CALL(fid_parse_memberexpr, _label); \
2796 } while (0)
2797/* }}} */
2798
2799/* parse_var {{{ */
2800/* parse_var's arguments */
2801#if 0
2802typedef struct fid_parse_var_arg {
2803} fid_parse_var_arg_t;
2804#else
2805typedef cr_zero_size_type_t fid_parse_var_arg_t;
2806#endif
2807
2808/* parse_var's data on stack */
2809typedef struct fid_parse_var_locals {
2810#if 0
2811 struct fid_parse_var_arg arg;
2812#endif
2813
2814 ast_off_t start;
2815} fid_parse_var_locals_t;
2816
2817#define CALL_PARSE_VAR(_label) \
2818 do { \
2819 CR_CALL(fid_parse_var, _label); \
2820 } while (0)
2821/* }}} */
2822
2823/* parse_prop {{{ */
2824/* parse_prop's arguments */
2825#if 0
2826typedef struct fid_parse_prop_arg {
2827} fid_parse_prop_arg_t;
2828#else
2829typedef cr_zero_size_type_t fid_parse_prop_arg_t;
2830#endif
2831
2832/* parse_prop's data on stack */
2833#if 0
2834typedef struct fid_parse_prop_locals {
2835 struct fid_parse_prop_arg arg;
2836} fid_parse_prop_locals_t;
2837#else
2838typedef cr_zero_size_type_t fid_parse_prop_locals_t;
2839#endif
2840
2841#define CALL_PARSE_PROP(_label) \
2842 do { \
2843 CR_CALL(fid_parse_prop, _label); \
2844 } while (0)
2845/* }}} */
2846
2847/* parse_dowhile {{{ */
2848/* parse_dowhile's arguments */
2849#if 0
2850typedef struct fid_parse_dowhile_arg {
2851} fid_parse_dowhile_arg_t;
2852#else
2853typedef cr_zero_size_type_t fid_parse_dowhile_arg_t;
2854#endif
2855
2856/* parse_dowhile's data on stack */
2857typedef struct fid_parse_dowhile_locals {
2858#if 0
2859 struct fid_parse_dowhile_arg arg;
2860#endif
2861
2862 ast_off_t start;
2863 uint8_t saved_in_loop;
2864} fid_parse_dowhile_locals_t;
2865
2866#define CALL_PARSE_DOWHILE(_label) \
2867 do { \
2868 CR_CALL(fid_parse_dowhile, _label); \
2869 } while (0)
2870/* }}} */
2871
2872/* parse_for {{{ */
2873/* parse_for's arguments */
2874#if 0
2875typedef struct fid_parse_for_arg {
2876} fid_parse_for_arg_t;
2877#else
2878typedef cr_zero_size_type_t fid_parse_for_arg_t;
2879#endif
2880
2881/* parse_for's data on stack */
2882typedef struct fid_parse_for_locals {
2883#if 0
2884 struct fid_parse_for_arg arg;
2885#endif
2886
2887 ast_off_t start;
2888 uint8_t saved_in_loop;
2889} fid_parse_for_locals_t;
2890
2891#define CALL_PARSE_FOR(_label) \
2892 do { \
2893 CR_CALL(fid_parse_for, _label); \
2894 } while (0)
2895/* }}} */
2896
2897/* parse_try {{{ */
2898/* parse_try's arguments */
2899#if 0
2900typedef struct fid_parse_try_arg {
2901} fid_parse_try_arg_t;
2902#else
2903typedef cr_zero_size_type_t fid_parse_try_arg_t;
2904#endif
2905
2906/* parse_try's data on stack */
2907typedef struct fid_parse_try_locals {
2908#if 0
2909 struct fid_parse_try_arg arg;
2910#endif
2911
2912 ast_off_t start;
2913 uint8_t catch_or_finally;
2914} fid_parse_try_locals_t;
2915
2916#define CALL_PARSE_TRY(_label) \
2917 do { \
2918 CR_CALL(fid_parse_try, _label); \
2919 } while (0)
2920/* }}} */
2921
2922/* parse_switch {{{ */
2923/* parse_switch's arguments */
2924#if 0
2925typedef struct fid_parse_switch_arg {
2926} fid_parse_switch_arg_t;
2927#else
2928typedef cr_zero_size_type_t fid_parse_switch_arg_t;
2929#endif
2930
2931/* parse_switch's data on stack */
2932typedef struct fid_parse_switch_locals {
2933#if 0
2934 struct fid_parse_switch_arg arg;
2935#endif
2936
2937 ast_off_t start;
2938 int saved_in_switch;
2939 ast_off_t case_start;
2940} fid_parse_switch_locals_t;
2941
2942#define CALL_PARSE_SWITCH(_label) \
2943 do { \
2944 CR_CALL(fid_parse_switch, _label); \
2945 } while (0)
2946/* }}} */
2947
2948/* parse_with {{{ */
2949/* parse_with's arguments */
2950#if 0
2951typedef struct fid_parse_with_arg {
2952} fid_parse_with_arg_t;
2953#else
2954typedef cr_zero_size_type_t fid_parse_with_arg_t;
2955#endif
2956
2957/* parse_with's data on stack */
2958typedef struct fid_parse_with_locals {
2959#if 0
2960 struct fid_parse_with_arg arg;
2961#endif
2962
2963 ast_off_t start;
2964} fid_parse_with_locals_t;
2965
2966#define CALL_PARSE_WITH(_label) \
2967 do { \
2968 CR_CALL(fid_parse_with, _label); \
2969 } while (0)
2970/* }}} */
2971
2972/* }}} */
2973
2974/*
2975 * Array of "function" descriptors. Each descriptor contains just a size
2976 * of "function"'s locals.
2977 */
2978static const struct cr_func_desc _fid_descrs[MY_FID_CNT] = {
2979
2980 /* fid_none */
2981 {0},
2982
2983 /* fid_parse_script ----------------------------------------- */
2984 /* fid_parse_script */
2985 {CR_LOCALS_SIZEOF(fid_parse_script_locals_t)},
2986 /* fid_p_script_1 */
2987 {CR_LOCALS_SIZEOF(fid_parse_script_locals_t)},
2988 /* fid_p_script_2 */
2989 {CR_LOCALS_SIZEOF(fid_parse_script_locals_t)},
2990 /* fid_p_script_3 */
2991 {CR_LOCALS_SIZEOF(fid_parse_script_locals_t)},
2992 /* fid_p_script_4 */
2993 {CR_LOCALS_SIZEOF(fid_parse_script_locals_t)},
2994
2995 /* fid_parse_use_strict ----------------------------------------- */
2996 /* fid_parse_use_strict */
2997 {CR_LOCALS_SIZEOF(fid_parse_use_strict_locals_t)},
2998
2999 /* fid_parse_body ----------------------------------------- */
3000 /* fid_parse_body */
3001 {CR_LOCALS_SIZEOF(fid_parse_body_locals_t)},
3002 /* fid_p_body_1 */
3003 {CR_LOCALS_SIZEOF(fid_parse_body_locals_t)},
3004 /* fid_p_body_2 */
3005 {CR_LOCALS_SIZEOF(fid_parse_body_locals_t)},
3006
3007 /* fid_parse_statement ----------------------------------------- */
3008 /* fid_parse_statement */
3009 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3010 /* fid_p_stat_1 */
3011 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3012 /* fid_p_stat_2 */
3013 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3014 /* fid_p_stat_3 */
3015 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3016 /* fid_p_stat_4 */
3017 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3018 /* fid_p_stat_5 */
3019 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3020 /* fid_p_stat_6 */
3021 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3022 /* fid_p_stat_7 */
3023 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3024 /* fid_p_stat_8 */
3025 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3026 /* fid_p_stat_9 */
3027 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3028 /* fid_p_stat_10 */
3029 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3030 /* fid_p_stat_11 */
3031 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3032 /* fid_p_stat_12 */
3033 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3034 /* fid_p_stat_13 */
3035 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3036 /* fid_p_stat_14 */
3037 {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
3038
3039 /* fid_parse_expression ----------------------------------------- */
3040 /* fid_parse_expression */
3041 {CR_LOCALS_SIZEOF(fid_parse_expression_locals_t)},
3042 /* fid_p_expr_1 */
3043 {CR_LOCALS_SIZEOF(fid_parse_expression_locals_t)},
3044
3045 /* fid_parse_assign ----------------------------------------- */
3046 /* fid_parse_assign */
3047 {CR_LOCALS_SIZEOF(fid_parse_assign_locals_t)},
3048 /* fid_p_assign_1 */
3049 {CR_LOCALS_SIZEOF(fid_parse_assign_locals_t)},
3050
3051 /* fid_parse_binary ----------------------------------------- */
3052 /* fid_parse_binary */
3053 {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
3054 /* fid_p_binary_1 */
3055 {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
3056 /* fid_p_binary_2 */
3057 {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
3058 /* fid_p_binary_3 */
3059 {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
3060 /* fid_p_binary_4 */
3061 {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
3062 /* fid_p_binary_5 */
3063 {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
3064 /* fid_p_binary_6 */
3065 {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
3066
3067 /* fid_parse_prefix ----------------------------------------- */
3068 /* fid_parse_prefix */
3069 {CR_LOCALS_SIZEOF(fid_parse_prefix_locals_t)},
3070 /* fid_p_prefix_1 */
3071 {CR_LOCALS_SIZEOF(fid_parse_prefix_locals_t)},
3072
3073 /* fid_parse_postfix ----------------------------------------- */
3074 /* fid_parse_postfix */
3075 {CR_LOCALS_SIZEOF(fid_parse_postfix_locals_t)},
3076 /* fid_p_postfix_1 */
3077 {CR_LOCALS_SIZEOF(fid_parse_postfix_locals_t)},
3078
3079 /* fid_parse_callexpr ----------------------------------------- */
3080 /* fid_parse_callexpr */
3081 {CR_LOCALS_SIZEOF(fid_parse_callexpr_locals_t)},
3082 /* fid_p_callexpr_1 */
3083 {CR_LOCALS_SIZEOF(fid_parse_callexpr_locals_t)},
3084 /* fid_p_callexpr_2 */
3085 {CR_LOCALS_SIZEOF(fid_parse_callexpr_locals_t)},
3086 /* fid_p_callexpr_3 */
3087 {CR_LOCALS_SIZEOF(fid_parse_callexpr_locals_t)},
3088
3089 /* fid_parse_newexpr ----------------------------------------- */
3090 /* fid_parse_newexpr */
3091 {CR_LOCALS_SIZEOF(fid_parse_newexpr_locals_t)},
3092 /* fid_p_newexpr_1 */
3093 {CR_LOCALS_SIZEOF(fid_parse_newexpr_locals_t)},
3094 /* fid_p_newexpr_2 */
3095 {CR_LOCALS_SIZEOF(fid_parse_newexpr_locals_t)},
3096 /* fid_p_newexpr_3 */
3097 {CR_LOCALS_SIZEOF(fid_parse_newexpr_locals_t)},
3098 /* fid_p_newexpr_4 */
3099 {CR_LOCALS_SIZEOF(fid_parse_newexpr_locals_t)},
3100
3101 /* fid_parse_terminal ----------------------------------------- */
3102 /* fid_parse_terminal */
3103 {CR_LOCALS_SIZEOF(fid_parse_terminal_locals_t)},
3104 /* fid_p_terminal_1 */
3105 {CR_LOCALS_SIZEOF(fid_parse_terminal_locals_t)},
3106 /* fid_p_terminal_2 */
3107 {CR_LOCALS_SIZEOF(fid_parse_terminal_locals_t)},
3108 /* fid_p_terminal_3 */
3109 {CR_LOCALS_SIZEOF(fid_parse_terminal_locals_t)},
3110 /* fid_p_terminal_4 */
3111 {CR_LOCALS_SIZEOF(fid_parse_terminal_locals_t)},
3112
3113 /* fid_parse_block ----------------------------------------- */
3114 /* fid_parse_block */
3115 {CR_LOCALS_SIZEOF(fid_parse_block_locals_t)},
3116 /* fid_p_block_1 */
3117 {CR_LOCALS_SIZEOF(fid_parse_block_locals_t)},
3118
3119 /* fid_parse_if ----------------------------------------- */
3120 /* fid_parse_if */
3121 {CR_LOCALS_SIZEOF(fid_parse_if_locals_t)},
3122 /* fid_p_if_1 */
3123 {CR_LOCALS_SIZEOF(fid_parse_if_locals_t)},
3124 /* fid_p_if_2 */
3125 {CR_LOCALS_SIZEOF(fid_parse_if_locals_t)},
3126 /* fid_p_if_3 */
3127 {CR_LOCALS_SIZEOF(fid_parse_if_locals_t)},
3128
3129 /* fid_parse_while ----------------------------------------- */
3130 /* fid_parse_while */
3131 {CR_LOCALS_SIZEOF(fid_parse_while_locals_t)},
3132 /* fid_p_while_1 */
3133 {CR_LOCALS_SIZEOF(fid_parse_while_locals_t)},
3134 /* fid_p_while_2 */
3135 {CR_LOCALS_SIZEOF(fid_parse_while_locals_t)},
3136
3137 /* fid_parse_ident ----------------------------------------- */
3138 /* fid_parse_ident */
3139 {CR_LOCALS_SIZEOF(fid_parse_ident_locals_t)},
3140
3141 /* fid_parse_ident_allow_reserved_words -------------------- */
3142 /* fid_parse_ident_allow_reserved_words */
3143 {CR_LOCALS_SIZEOF(fid_parse_ident_allow_reserved_words_locals_t)},
3144 /* fid_p_ident_allow_reserved_words_1 */
3145 {CR_LOCALS_SIZEOF(fid_parse_ident_allow_reserved_words_locals_t)},
3146
3147 /* fid_parse_funcdecl ----------------------------------------- */
3148 /* fid_parse_funcdecl */
3149 {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
3150 /* fid_p_funcdecl_1 */
3151 {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
3152 /* fid_p_funcdecl_2 */
3153 {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
3154 /* fid_p_funcdecl_3 */
3155 {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
3156 /* fid_p_funcdecl_4 */
3157 {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
3158 /* fid_p_funcdecl_5 */
3159 {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
3160 /* fid_p_funcdecl_6 */
3161 {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
3162 /* fid_p_funcdecl_7 */
3163 {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
3164 /* fid_p_funcdecl_8 */
3165 {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
3166 /* fid_p_funcdecl_9 */
3167 {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
3168
3169 /* fid_parse_arglist ----------------------------------------- */
3170 /* fid_parse_arglist */
3171 {CR_LOCALS_SIZEOF(fid_parse_arglist_locals_t)},
3172 /* fid_p_arglist_1 */
3173 {CR_LOCALS_SIZEOF(fid_parse_arglist_locals_t)},
3174
3175 /* fid_parse_member ----------------------------------------- */
3176 /* fid_parse_member */
3177 {CR_LOCALS_SIZEOF(fid_parse_member_locals_t)},
3178 /* fid_p_member_1 */
3179 {CR_LOCALS_SIZEOF(fid_parse_member_locals_t)},
3180
3181 /* fid_parse_memberexpr ----------------------------------------- */
3182 /* fid_parse_memberexpr */
3183 {CR_LOCALS_SIZEOF(fid_parse_memberexpr_locals_t)},
3184 /* fid_p_memberexpr_1 */
3185 {CR_LOCALS_SIZEOF(fid_parse_memberexpr_locals_t)},
3186 /* fid_p_memberexpr_2 */
3187 {CR_LOCALS_SIZEOF(fid_parse_memberexpr_locals_t)},
3188
3189 /* fid_parse_var ----------------------------------------- */
3190 /* fid_parse_var */
3191 {CR_LOCALS_SIZEOF(fid_parse_var_locals_t)},
3192 /* fid_p_var_1 */
3193 {CR_LOCALS_SIZEOF(fid_parse_var_locals_t)},
3194
3195 /* fid_parse_prop ----------------------------------------- */
3196 /* fid_parse_prop */
3197 {CR_LOCALS_SIZEOF(fid_parse_prop_locals_t)},
3198#if V7_ENABLE_JS_GETTERS
3199 /* fid_p_prop_1_getter */
3200 {CR_LOCALS_SIZEOF(fid_parse_prop_locals_t)},
3201#endif
3202 /* fid_p_prop_2 */
3203 {CR_LOCALS_SIZEOF(fid_parse_prop_locals_t)},
3204#if V7_ENABLE_JS_SETTERS
3205 /* fid_p_prop_3_setter */
3206 {CR_LOCALS_SIZEOF(fid_parse_prop_locals_t)},
3207#endif
3208 /* fid_p_prop_4 */
3209 {CR_LOCALS_SIZEOF(fid_parse_prop_locals_t)},
3210
3211 /* fid_parse_dowhile ----------------------------------------- */
3212 /* fid_parse_dowhile */
3213 {CR_LOCALS_SIZEOF(fid_parse_dowhile_locals_t)},
3214 /* fid_p_dowhile_1 */
3215 {CR_LOCALS_SIZEOF(fid_parse_dowhile_locals_t)},
3216 /* fid_p_dowhile_2 */
3217 {CR_LOCALS_SIZEOF(fid_parse_dowhile_locals_t)},
3218
3219 /* fid_parse_for ----------------------------------------- */
3220 /* fid_parse_for */
3221 {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
3222 /* fid_p_for_1 */
3223 {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
3224 /* fid_p_for_2 */
3225 {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
3226 /* fid_p_for_3 */
3227 {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
3228 /* fid_p_for_4 */
3229 {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
3230 /* fid_p_for_5 */
3231 {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
3232 /* fid_p_for_6 */
3233 {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
3234
3235 /* fid_parse_try ----------------------------------------- */
3236 /* fid_parse_try */
3237 {CR_LOCALS_SIZEOF(fid_parse_try_locals_t)},
3238 /* fid_p_try_1 */
3239 {CR_LOCALS_SIZEOF(fid_parse_try_locals_t)},
3240 /* fid_p_try_2 */
3241 {CR_LOCALS_SIZEOF(fid_parse_try_locals_t)},
3242 /* fid_p_try_3 */
3243 {CR_LOCALS_SIZEOF(fid_parse_try_locals_t)},
3244 /* fid_p_try_4 */
3245 {CR_LOCALS_SIZEOF(fid_parse_try_locals_t)},
3246
3247 /* fid_parse_switch ----------------------------------------- */
3248 /* fid_parse_switch */
3249 {CR_LOCALS_SIZEOF(fid_parse_switch_locals_t)},
3250 /* fid_p_switch_1 */
3251 {CR_LOCALS_SIZEOF(fid_parse_switch_locals_t)},
3252 /* fid_p_switch_2 */
3253 {CR_LOCALS_SIZEOF(fid_parse_switch_locals_t)},
3254 /* fid_p_switch_3 */
3255 {CR_LOCALS_SIZEOF(fid_parse_switch_locals_t)},
3256 /* fid_p_switch_4 */
3257 {CR_LOCALS_SIZEOF(fid_parse_switch_locals_t)},
3258
3259 /* fid_parse_with ----------------------------------------- */
3260 /* fid_parse_with */
3261 {CR_LOCALS_SIZEOF(fid_parse_with_locals_t)},
3262 /* fid_p_with_1 */
3263 {CR_LOCALS_SIZEOF(fid_parse_with_locals_t)},
3264 /* fid_p_with_2 */
3265 {CR_LOCALS_SIZEOF(fid_parse_with_locals_t)},
3266
3267};
3268
3269/*
3270 * Union of arguments and return values for all existing "functions".
3271 *
3272 * Used as an accumulator when we call function, return from function,
3273 * yield, or resume.
3274 */
3275union user_arg_ret {
3276 /* arguments to the next function */
3277 union {
3278#if 0
3279 fid_parse_script_arg_t fid_parse_script;
3280 fid_parse_use_strict_arg_t fid_parse_use_strict;
3281 fid_parse_statement_arg_t fid_parse_statement;
3282 fid_parse_expression_arg_t fid_parse_expression;
3283 fid_parse_assign_arg_t fid_parse_assign;
3284 fid_parse_prefix_arg_t fid_parse_prefix;
3285 fid_parse_postfix_arg_t fid_parse_postfix;
3286 fid_parse_callexpr_arg_t fid_parse_callexpr;
3287 fid_parse_newexpr_arg_t fid_parse_newexpr;
3288 fid_parse_terminal_arg_t fid_parse_terminal;
3289 fid_parse_block_arg_t fid_parse_block;
3290 fid_parse_if_arg_t fid_parse_if;
3291 fid_parse_while_arg_t fid_parse_while;
3292 fid_parse_ident_arg_t fid_parse_ident;
3293 fid_parse_ident_allow_reserved_words_arg_t
3294 fid_parse_ident_allow_reserved_words;
3295 fid_parse_arglist_arg_t fid_parse_arglist;
3296 fid_parse_memberexpr_arg_t fid_parse_memberexpr;
3297 fid_parse_var_arg_t fid_parse_var;
3298 fid_parse_prop_arg_t fid_parse_prop;
3299 fid_parse_dowhile_arg_t fid_parse_dowhile;
3300 fid_parse_for_arg_t fid_parse_for;
3301 fid_parse_try_arg_t fid_parse_try;
3302 fid_parse_switch_arg_t fid_parse_switch;
3303 fid_parse_with_arg_t fid_parse_with;
3304#endif
3305 fid_parse_body_arg_t fid_parse_body;
3306 fid_parse_binary_arg_t fid_parse_binary;
3307 fid_parse_funcdecl_arg_t fid_parse_funcdecl;
3308 fid_parse_member_arg_t fid_parse_member;
3309 } arg;
3310
3311 /* value returned from function */
3312 /*
3313 union {
3314 } ret;
3315 */
3316};
3317
3318static enum v7_tok next_tok(struct v7 *v7) {
3319 int prev_line_no = v7->pstate.prev_line_no;
3320 v7->pstate.prev_line_no = v7->pstate.line_no;
3321 v7->pstate.line_no += skip_to_next_tok(&v7->pstate.pc, v7->pstate.src_end);
3322 v7->after_newline = prev_line_no != v7->pstate.line_no;
3323 v7->tok = v7->pstate.pc;
3324 v7->cur_tok = get_tok(&v7->pstate.pc, v7->pstate.src_end, &v7->cur_tok_dbl,
3325 v7->cur_tok);
3326 v7->tok_len = v7->pstate.pc - v7->tok;
3327 v7->pstate.line_no += skip_to_next_tok(&v7->pstate.pc, v7->pstate.src_end);
3328 return v7->cur_tok;
3329}
3330
3331#if !V7_DISABLE_LINE_NUMBERS
3332/*
3333 * Assumes `offset` points to the byte right after a tag
3334 */
3335static void insert_line_no_if_changed(struct v7 *v7, struct ast *a,
3336 ast_off_t offset) {
3337 if (v7->pstate.prev_line_no != v7->line_no) {
3338 v7->line_no = v7->pstate.prev_line_no;
3339 ast_add_line_no(a, offset - 1, v7->line_no);
3340 } else {
3341#if V7_AST_FORCE_LINE_NUMBERS
3342 /*
3343 * This mode is needed for debug only: to make sure AST consumers correctly
3344 * consume all nodes with line numbers data encoded
3345 */
3346 ast_add_line_no(a, offset - 1, 0);
3347#endif
3348 }
3349}
3350#else
3351static void insert_line_no_if_changed(struct v7 *v7, struct ast *a,
3352 ast_off_t offset) {
3353 (void) v7;
3354 (void) a;
3355 (void) offset;
3356}
3357#endif
3358
3359static ast_off_t insert_node(struct v7 *v7, struct ast *a, ast_off_t start,
3360 enum ast_tag tag) {
3361 ast_off_t ret = ast_insert_node(a, start, tag);
3362 insert_line_no_if_changed(v7, a, ret);
3363 return ret;
3364}
3365
3366static ast_off_t add_node(struct v7 *v7, struct ast *a, enum ast_tag tag) {
3367 return insert_node(v7, a, a->mbuf.len, tag);
3368}
3369
3370static ast_off_t insert_inlined_node(struct v7 *v7, struct ast *a,
3371 ast_off_t start, enum ast_tag tag,
3372 const char *name, size_t len) {
3373 ast_off_t ret = ast_insert_inlined_node(a, start, tag, name, len);
3374 insert_line_no_if_changed(v7, a, ret);
3375 return ret;
3376}
3377
3378static ast_off_t add_inlined_node(struct v7 *v7, struct ast *a,
3379 enum ast_tag tag, const char *name,
3380 size_t len) {
3381 return insert_inlined_node(v7, a, a->mbuf.len, tag, name, len);
3382}
3383
3384static unsigned long get_column(const char *code, const char *pos) {
3385 const char *p = pos;
3386 while (p > code && *p != '\n') {
3387 p--;
3388 }
3389 return p == code ? pos - p : pos - (p + 1);
3390}
3391
3392static enum v7_err end_of_statement(struct v7 *v7) {
3393 if (v7->cur_tok == TOK_SEMICOLON || v7->cur_tok == TOK_END_OF_INPUT ||
3394 v7->cur_tok == TOK_CLOSE_CURLY || v7->after_newline) {
3395 return V7_OK;
3396 }
3397 return V7_SYNTAX_ERROR;
3398}
3399
3400static enum v7_tok lookahead(const struct v7 *v7) {
3401 const char *s = v7->pstate.pc;
3402 double d;
3403 return get_tok(&s, v7->pstate.src_end, &d, v7->cur_tok);
3404}
3405
3406static int parse_optional(struct v7 *v7, struct ast *a,
3407 enum v7_tok terminator) {
3408 if (v7->cur_tok != terminator) {
3409 return 1;
3410 }
3411 add_node(v7, a, AST_NOP);
3412 return 0;
3413}
3414
3415/*
3416 * On ESP8266 'levels' declaration have to be outside of 'parse_binary'
3417 * in order to prevent reboot on return from this function
3418 * TODO(alashkin): understand why
3419 */
3420#define NONE \
3421 { (enum v7_tok) 0, (enum v7_tok) 0, (enum ast_tag) 0 }
3422
3423static const struct {
3424 int len, left_to_right;
3425 struct {
3426 enum v7_tok start_tok, end_tok;
3427 enum ast_tag start_ast;
3428 } parts[2];
3429} levels[] = {
3430 {1, 0, {{TOK_ASSIGN, TOK_URSHIFT_ASSIGN, AST_ASSIGN}, NONE}},
3431 {1, 0, {{TOK_QUESTION, TOK_QUESTION, AST_COND}, NONE}},
3432 {1, 1, {{TOK_LOGICAL_OR, TOK_LOGICAL_OR, AST_LOGICAL_OR}, NONE}},
3433 {1, 1, {{TOK_LOGICAL_AND, TOK_LOGICAL_AND, AST_LOGICAL_AND}, NONE}},
3434 {1, 1, {{TOK_OR, TOK_OR, AST_OR}, NONE}},
3435 {1, 1, {{TOK_XOR, TOK_XOR, AST_XOR}, NONE}},
3436 {1, 1, {{TOK_AND, TOK_AND, AST_AND}, NONE}},
3437 {1, 1, {{TOK_EQ, TOK_NE_NE, AST_EQ}, NONE}},
3438 {2, 1, {{TOK_LE, TOK_GT, AST_LE}, {TOK_IN, TOK_INSTANCEOF, AST_IN}}},
3439 {1, 1, {{TOK_LSHIFT, TOK_URSHIFT, AST_LSHIFT}, NONE}},
3440 {1, 1, {{TOK_PLUS, TOK_MINUS, AST_ADD}, NONE}},
3441 {1, 1, {{TOK_REM, TOK_DIV, AST_REM}, NONE}}};
3442
3443enum cr_status parser_cr_exec(struct cr_ctx *p_ctx, struct v7 *v7,
3444 struct ast *a) {
3445 enum cr_status rc = CR_RES__OK;
3446
3447_cr_iter_begin:
3448
3449 rc = cr_on_iter_begin(p_ctx);
3450 if (rc != CR_RES__OK) {
3451 return rc;
3452 }
3453
3454 /*
3455 * dispatcher switch: depending on the fid, jump to the corresponding label
3456 */
3457 switch ((enum my_fid) CR_CURR_FUNC()) {
3458 CR_DEFINE_ENTRY_POINT(fid_none);
3459
3460 CR_DEFINE_ENTRY_POINT(fid_parse_script);
3461 CR_DEFINE_ENTRY_POINT(fid_p_script_1);
3462 CR_DEFINE_ENTRY_POINT(fid_p_script_2);
3463 CR_DEFINE_ENTRY_POINT(fid_p_script_3);
3464 CR_DEFINE_ENTRY_POINT(fid_p_script_4);
3465
3466 CR_DEFINE_ENTRY_POINT(fid_parse_use_strict);
3467
3468 CR_DEFINE_ENTRY_POINT(fid_parse_body);
3469 CR_DEFINE_ENTRY_POINT(fid_p_body_1);
3470 CR_DEFINE_ENTRY_POINT(fid_p_body_2);
3471
3472 CR_DEFINE_ENTRY_POINT(fid_parse_statement);
3473 CR_DEFINE_ENTRY_POINT(fid_p_stat_1);
3474 CR_DEFINE_ENTRY_POINT(fid_p_stat_2);
3475 CR_DEFINE_ENTRY_POINT(fid_p_stat_3);
3476 CR_DEFINE_ENTRY_POINT(fid_p_stat_4);
3477 CR_DEFINE_ENTRY_POINT(fid_p_stat_5);
3478 CR_DEFINE_ENTRY_POINT(fid_p_stat_6);
3479 CR_DEFINE_ENTRY_POINT(fid_p_stat_7);
3480 CR_DEFINE_ENTRY_POINT(fid_p_stat_8);
3481 CR_DEFINE_ENTRY_POINT(fid_p_stat_9);
3482 CR_DEFINE_ENTRY_POINT(fid_p_stat_10);
3483 CR_DEFINE_ENTRY_POINT(fid_p_stat_11);
3484 CR_DEFINE_ENTRY_POINT(fid_p_stat_12);
3485 CR_DEFINE_ENTRY_POINT(fid_p_stat_13);
3486 CR_DEFINE_ENTRY_POINT(fid_p_stat_14);
3487
3488 CR_DEFINE_ENTRY_POINT(fid_parse_expression);
3489 CR_DEFINE_ENTRY_POINT(fid_p_expr_1);
3490
3491 CR_DEFINE_ENTRY_POINT(fid_parse_assign);
3492 CR_DEFINE_ENTRY_POINT(fid_p_assign_1);
3493
3494 CR_DEFINE_ENTRY_POINT(fid_parse_binary);
3495 CR_DEFINE_ENTRY_POINT(fid_p_binary_2);
3496 CR_DEFINE_ENTRY_POINT(fid_p_binary_3);
3497 CR_DEFINE_ENTRY_POINT(fid_p_binary_4);
3498 CR_DEFINE_ENTRY_POINT(fid_p_binary_5);
3499 CR_DEFINE_ENTRY_POINT(fid_p_binary_6);
3500
3501 CR_DEFINE_ENTRY_POINT(fid_parse_prefix);
3502 CR_DEFINE_ENTRY_POINT(fid_p_prefix_1);
3503
3504 CR_DEFINE_ENTRY_POINT(fid_parse_postfix);
3505 CR_DEFINE_ENTRY_POINT(fid_p_postfix_1);
3506
3507 CR_DEFINE_ENTRY_POINT(fid_parse_callexpr);
3508 CR_DEFINE_ENTRY_POINT(fid_p_callexpr_1);
3509 CR_DEFINE_ENTRY_POINT(fid_p_callexpr_2);
3510 CR_DEFINE_ENTRY_POINT(fid_p_callexpr_3);
3511
3512 CR_DEFINE_ENTRY_POINT(fid_parse_newexpr);
3513 CR_DEFINE_ENTRY_POINT(fid_p_newexpr_1);
3514 CR_DEFINE_ENTRY_POINT(fid_p_newexpr_2);
3515 CR_DEFINE_ENTRY_POINT(fid_p_newexpr_3);
3516 CR_DEFINE_ENTRY_POINT(fid_p_newexpr_4);
3517
3518 CR_DEFINE_ENTRY_POINT(fid_parse_terminal);
3519 CR_DEFINE_ENTRY_POINT(fid_p_terminal_1);
3520 CR_DEFINE_ENTRY_POINT(fid_p_terminal_2);
3521 CR_DEFINE_ENTRY_POINT(fid_p_terminal_3);
3522 CR_DEFINE_ENTRY_POINT(fid_p_terminal_4);
3523
3524 CR_DEFINE_ENTRY_POINT(fid_parse_block);
3525 CR_DEFINE_ENTRY_POINT(fid_p_block_1);
3526
3527 CR_DEFINE_ENTRY_POINT(fid_parse_if);
3528 CR_DEFINE_ENTRY_POINT(fid_p_if_1);
3529 CR_DEFINE_ENTRY_POINT(fid_p_if_2);
3530 CR_DEFINE_ENTRY_POINT(fid_p_if_3);
3531
3532 CR_DEFINE_ENTRY_POINT(fid_parse_while);
3533 CR_DEFINE_ENTRY_POINT(fid_p_while_1);
3534 CR_DEFINE_ENTRY_POINT(fid_p_while_2);
3535
3536 CR_DEFINE_ENTRY_POINT(fid_parse_ident);
3537
3538 CR_DEFINE_ENTRY_POINT(fid_parse_ident_allow_reserved_words);
3539 CR_DEFINE_ENTRY_POINT(fid_p_ident_arw_1);
3540
3541 CR_DEFINE_ENTRY_POINT(fid_parse_funcdecl);
3542 CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_1);
3543 CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_2);
3544 CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_3);
3545 CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_4);
3546 CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_5);
3547 CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_6);
3548 CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_7);
3549 CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_8);
3550 CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_9);
3551
3552 CR_DEFINE_ENTRY_POINT(fid_parse_arglist);
3553 CR_DEFINE_ENTRY_POINT(fid_p_arglist_1);
3554
3555 CR_DEFINE_ENTRY_POINT(fid_parse_member);
3556 CR_DEFINE_ENTRY_POINT(fid_p_member_1);
3557
3558 CR_DEFINE_ENTRY_POINT(fid_parse_memberexpr);
3559 CR_DEFINE_ENTRY_POINT(fid_p_memberexpr_1);
3560 CR_DEFINE_ENTRY_POINT(fid_p_memberexpr_2);
3561
3562 CR_DEFINE_ENTRY_POINT(fid_parse_var);
3563 CR_DEFINE_ENTRY_POINT(fid_p_var_1);
3564
3565 CR_DEFINE_ENTRY_POINT(fid_parse_prop);
3566#if V7_ENABLE_JS_GETTERS
3567 CR_DEFINE_ENTRY_POINT(fid_p_prop_1_getter);
3568#endif
3569 CR_DEFINE_ENTRY_POINT(fid_p_prop_2);
3570#if V7_ENABLE_JS_SETTERS
3571 CR_DEFINE_ENTRY_POINT(fid_p_prop_3_setter);
3572#endif
3573 CR_DEFINE_ENTRY_POINT(fid_p_prop_4);
3574
3575 CR_DEFINE_ENTRY_POINT(fid_parse_dowhile);
3576 CR_DEFINE_ENTRY_POINT(fid_p_dowhile_1);
3577 CR_DEFINE_ENTRY_POINT(fid_p_dowhile_2);
3578
3579 CR_DEFINE_ENTRY_POINT(fid_parse_for);
3580 CR_DEFINE_ENTRY_POINT(fid_p_for_1);
3581 CR_DEFINE_ENTRY_POINT(fid_p_for_2);
3582 CR_DEFINE_ENTRY_POINT(fid_p_for_3);
3583 CR_DEFINE_ENTRY_POINT(fid_p_for_4);
3584 CR_DEFINE_ENTRY_POINT(fid_p_for_5);
3585 CR_DEFINE_ENTRY_POINT(fid_p_for_6);
3586
3587 CR_DEFINE_ENTRY_POINT(fid_parse_try);
3588 CR_DEFINE_ENTRY_POINT(fid_p_try_1);
3589 CR_DEFINE_ENTRY_POINT(fid_p_try_2);
3590 CR_DEFINE_ENTRY_POINT(fid_p_try_3);
3591 CR_DEFINE_ENTRY_POINT(fid_p_try_4);
3592
3593 CR_DEFINE_ENTRY_POINT(fid_parse_switch);
3594 CR_DEFINE_ENTRY_POINT(fid_p_switch_1);
3595 CR_DEFINE_ENTRY_POINT(fid_p_switch_2);
3596 CR_DEFINE_ENTRY_POINT(fid_p_switch_3);
3597 CR_DEFINE_ENTRY_POINT(fid_p_switch_4);
3598
3599 CR_DEFINE_ENTRY_POINT(fid_parse_with);
3600 CR_DEFINE_ENTRY_POINT(fid_p_with_1);
3601 CR_DEFINE_ENTRY_POINT(fid_p_with_2);
3602
3603 default:
3604 /* should never be here */
3605 printf("fatal: wrong func id: %d", CR_CURR_FUNC());
3606 break;
3607 };
3608
3609/* static enum v7_err parse_script(struct v7 *v7, struct ast *a) */
3610fid_parse_script :
3611#undef L
3612#define L CR_CUR_LOCALS_PT(fid_parse_script_locals_t)
3613{
3614 L->start = add_node(v7, a, AST_SCRIPT);
3615 L->outer_last_var_node = v7->last_var_node;
3616 L->saved_in_strict = v7->pstate.in_strict;
3617
3618 v7->last_var_node = L->start;
3619 ast_modify_skip(a, L->start, L->start, AST_FUNC_FIRST_VAR_SKIP);
3620
3621 CR_TRY(fid_p_script_1);
3622 {
3623 CALL_PARSE_USE_STRICT(fid_p_script_3);
3624 v7->pstate.in_strict = 1;
3625 }
3626 CR_CATCH(PARSER_EXC_ID__SYNTAX_ERROR, fid_p_script_1, fid_p_script_2);
3627 CR_ENDCATCH(fid_p_script_2);
3628
3629 CALL_PARSE_BODY(TOK_END_OF_INPUT, fid_p_script_4);
3630 ast_set_skip(a, L->start, AST_END_SKIP);
3631 v7->pstate.in_strict = L->saved_in_strict;
3632 v7->last_var_node = L->outer_last_var_node;
3633
3634 CR_RETURN_VOID();
3635}
3636
3637/* static enum v7_err parse_use_strict(struct v7 *v7, struct ast *a) */
3638fid_parse_use_strict :
3639#undef L
3640#define L CR_CUR_LOCALS_PT(fid_parse_use_strict_locals_t)
3641{
3642 if (v7->cur_tok == TOK_STRING_LITERAL &&
3643 (strncmp(v7->tok, "\"use strict\"", v7->tok_len) == 0 ||
3644 strncmp(v7->tok, "'use strict'", v7->tok_len) == 0)) {
3645 next_tok(v7);
3646 add_node(v7, a, AST_USE_STRICT);
3647 CR_RETURN_VOID();
3648 } else {
3649 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
3650 }
3651}
3652
3653/*
3654 * static enum v7_err parse_body(struct v7 *v7, struct ast *a,
3655 * enum v7_tok end)
3656 */
3657fid_parse_body :
3658#undef L
3659#define L CR_CUR_LOCALS_PT(fid_parse_body_locals_t)
3660{
3661 while (v7->cur_tok != L->arg.end) {
3662 if (ACCEPT(TOK_FUNCTION)) {
3663 if (v7->cur_tok != TOK_IDENTIFIER) {
3664 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
3665 }
3666 L->start = add_node(v7, a, AST_VAR);
3667 ast_modify_skip(a, v7->last_var_node, L->start, AST_FUNC_FIRST_VAR_SKIP);
3668 /* zero out var node pointer */
3669 ast_modify_skip(a, L->start, L->start, AST_FUNC_FIRST_VAR_SKIP);
3670 v7->last_var_node = L->start;
3671 add_inlined_node(v7, a, AST_FUNC_DECL, v7->tok, v7->tok_len);
3672
3673 CALL_PARSE_FUNCDECL(1, 0, fid_p_body_1);
3674 ast_set_skip(a, L->start, AST_END_SKIP);
3675 } else {
3676 CALL_PARSE_STATEMENT(fid_p_body_2);
3677 }
3678 }
3679 CR_RETURN_VOID();
3680}
3681
3682/* static enum v7_err parse_statement(struct v7 *v7, struct ast *a) */
3683fid_parse_statement :
3684#undef L
3685#define L CR_CUR_LOCALS_PT(fid_parse_statement_locals_t)
3686{
3687 switch (v7->cur_tok) {
3688 case TOK_SEMICOLON:
3689 next_tok(v7);
3690 /* empty statement */
3691 CR_RETURN_VOID();
3692 case TOK_OPEN_CURLY: /* block */
3693 CALL_PARSE_BLOCK(fid_p_stat_3);
3694 /* returning because no semicolon required */
3695 CR_RETURN_VOID();
3696 case TOK_IF:
3697 next_tok(v7);
3698 CALL_PARSE_IF(fid_p_stat_4);
3699 CR_RETURN_VOID();
3700 case TOK_WHILE:
3701 next_tok(v7);
3702 CALL_PARSE_WHILE(fid_p_stat_5);
3703 CR_RETURN_VOID();
3704 case TOK_DO:
3705 next_tok(v7);
3706 CALL_PARSE_DOWHILE(fid_p_stat_10);
3707 CR_RETURN_VOID();
3708 case TOK_FOR:
3709 next_tok(v7);
3710 CALL_PARSE_FOR(fid_p_stat_11);
3711 CR_RETURN_VOID();
3712 case TOK_TRY:
3713 next_tok(v7);
3714 CALL_PARSE_TRY(fid_p_stat_12);
3715 CR_RETURN_VOID();
3716 case TOK_SWITCH:
3717 next_tok(v7);
3718 CALL_PARSE_SWITCH(fid_p_stat_13);
3719 CR_RETURN_VOID();
3720 case TOK_WITH:
3721 next_tok(v7);
3722 CALL_PARSE_WITH(fid_p_stat_14);
3723 CR_RETURN_VOID();
3724 case TOK_BREAK:
3725 if (!(v7->pstate.in_loop || v7->pstate.in_switch)) {
3726 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
3727 }
3728 next_tok(v7);
3729 PARSE_WITH_OPT_ARG(AST_BREAK, AST_LABELED_BREAK, CALL_PARSE_IDENT,
3730 fid_p_stat_7);
3731 break;
3732 case TOK_CONTINUE:
3733 if (!v7->pstate.in_loop) {
3734 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
3735 }
3736 next_tok(v7);
3737 PARSE_WITH_OPT_ARG(AST_CONTINUE, AST_LABELED_CONTINUE, CALL_PARSE_IDENT,
3738 fid_p_stat_8);
3739 break;
3740 case TOK_RETURN:
3741 if (!v7->pstate.in_function) {
3742 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
3743 }
3744 next_tok(v7);
3745 PARSE_WITH_OPT_ARG(AST_RETURN, AST_VALUE_RETURN, CALL_PARSE_EXPRESSION,
3746 fid_p_stat_6);
3747 break;
3748 case TOK_THROW:
3749 next_tok(v7);
3750 add_node(v7, a, AST_THROW);
3751 CALL_PARSE_EXPRESSION(fid_p_stat_2);
3752 break;
3753 case TOK_DEBUGGER:
3754 next_tok(v7);
3755 add_node(v7, a, AST_DEBUGGER);
3756 break;
3757 case TOK_VAR:
3758 next_tok(v7);
3759 CALL_PARSE_VAR(fid_p_stat_9);
3760 break;
3761 case TOK_IDENTIFIER:
3762 if (lookahead(v7) == TOK_COLON) {
3763 add_inlined_node(v7, a, AST_LABEL, v7->tok, v7->tok_len);
3764 next_tok(v7);
3765 EXPECT(TOK_COLON);
3766 CR_RETURN_VOID();
3767 }
3768 /* fall through */
3769 default:
3770 CALL_PARSE_EXPRESSION(fid_p_stat_1);
3771 break;
3772 }
3773
3774 if (end_of_statement(v7) != V7_OK) {
3775 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
3776 }
3777 ACCEPT(TOK_SEMICOLON); /* swallow optional semicolon */
3778 CR_RETURN_VOID();
3779}
3780
3781/* static enum v7_err parse_expression(struct v7 *v7, struct ast *a) */
3782fid_parse_expression :
3783#undef L
3784#define L CR_CUR_LOCALS_PT(fid_parse_expression_locals_t)
3785{
3786 L->pos = a->mbuf.len;
3787 L->group = 0;
3788 while (1) {
3789 CALL_PARSE_ASSIGN(fid_p_expr_1);
3790 if (ACCEPT(TOK_COMMA)) {
3791 L->group = 1;
3792 } else {
3793 break;
3794 }
3795 }
3796 if (L->group) {
3797 insert_node(v7, a, L->pos, AST_SEQ);
3798 }
3799 CR_RETURN_VOID();
3800}
3801
3802/* static enum v7_err parse_assign(struct v7 *v7, struct ast *a) */
3803fid_parse_assign :
3804#undef L
3805#define L CR_CUR_LOCALS_PT(fid_parse_assign_locals_t)
3806{
3807 CALL_PARSE_BINARY(0, a->mbuf.len, fid_p_assign_1);
3808 CR_RETURN_VOID();
3809}
3810
3811/*
3812 * static enum v7_err parse_binary(struct v7 *v7, struct ast *a, int level,
3813 * ast_off_t pos)
3814 */
3815#if 1
3816fid_parse_binary :
3817#undef L
3818#define L CR_CUR_LOCALS_PT(fid_parse_binary_locals_t)
3819{
3820/*
3821 * Note: we use macro CUR_POS instead of a local variable, since this
3822 * function is called really a lot, so, each byte on stack frame counts.
3823 *
3824 * It will work a bit slower of course, but slowness is not a problem
3825 */
3826#define CUR_POS ((L->level > L->arg.min_level) ? L->saved_mbuf_len : L->arg.pos)
3827 L->saved_mbuf_len = a->mbuf.len;
3828
3829 CALL_PARSE_PREFIX(fid_p_binary_6);
3830
3831 for (L->level = (int) ARRAY_SIZE(levels) - 1; L->level >= L->arg.min_level;
3832 L->level--) {
3833 for (L->i = 0; L->i < levels[L->level].len; L->i++) {
3834 L->tok = levels[L->level].parts[L->i].start_tok;
3835 L->ast = levels[L->level].parts[L->i].start_ast;
3836 do {
3837 if (v7->pstate.inhibit_in && L->tok == TOK_IN) {
3838 continue;
3839 }
3840
3841 /*
3842 * Ternary operator sits in the middle of the binary operator
3843 * precedence chain. Deal with it as an exception and don't break
3844 * the chain.
3845 */
3846 if (L->tok == TOK_QUESTION && v7->cur_tok == TOK_QUESTION) {
3847 next_tok(v7);
3848 CALL_PARSE_ASSIGN(fid_p_binary_2);
3849 EXPECT(TOK_COLON);
3850 CALL_PARSE_ASSIGN(fid_p_binary_3);
3851 insert_node(v7, a, CUR_POS, AST_COND);
3852 CR_RETURN_VOID();
3853 } else if (ACCEPT(L->tok)) {
3854 if (levels[L->level].left_to_right) {
3855 insert_node(v7, a, CUR_POS, (enum ast_tag) L->ast);
3856 CALL_PARSE_BINARY(L->level, CUR_POS, fid_p_binary_4);
3857 } else {
3858 CALL_PARSE_BINARY(L->level, a->mbuf.len, fid_p_binary_5);
3859 insert_node(v7, a, CUR_POS, (enum ast_tag) L->ast);
3860 }
3861 }
3862 } while (L->ast = (enum ast_tag)(L->ast + 1),
3863 L->tok < levels[L->level].parts[L->i].end_tok &&
3864 (L->tok = (enum v7_tok)(L->tok + 1)));
3865 }
3866 }
3867
3868 CR_RETURN_VOID();
3869#undef CUR_POS
3870}
3871#endif
3872
3873/* enum v7_err parse_prefix(struct v7 *v7, struct ast *a) */
3874fid_parse_prefix :
3875#undef L
3876#define L CR_CUR_LOCALS_PT(fid_parse_prefix_locals_t)
3877{
3878 for (;;) {
3879 switch (v7->cur_tok) {
3880 case TOK_PLUS:
3881 next_tok(v7);
3882 add_node(v7, a, AST_POSITIVE);
3883 break;
3884 case TOK_MINUS:
3885 next_tok(v7);
3886 add_node(v7, a, AST_NEGATIVE);
3887 break;
3888 case TOK_PLUS_PLUS:
3889 next_tok(v7);
3890 add_node(v7, a, AST_PREINC);
3891 break;
3892 case TOK_MINUS_MINUS:
3893 next_tok(v7);
3894 add_node(v7, a, AST_PREDEC);
3895 break;
3896 case TOK_TILDA:
3897 next_tok(v7);
3898 add_node(v7, a, AST_NOT);
3899 break;
3900 case TOK_NOT:
3901 next_tok(v7);
3902 add_node(v7, a, AST_LOGICAL_NOT);
3903 break;
3904 case TOK_VOID:
3905 next_tok(v7);
3906 add_node(v7, a, AST_VOID);
3907 break;
3908 case TOK_DELETE:
3909 next_tok(v7);
3910 add_node(v7, a, AST_DELETE);
3911 break;
3912 case TOK_TYPEOF:
3913 next_tok(v7);
3914 add_node(v7, a, AST_TYPEOF);
3915 break;
3916 default:
3917 CALL_PARSE_POSTFIX(fid_p_prefix_1);
3918 CR_RETURN_VOID();
3919 }
3920 }
3921}
3922
3923/* static enum v7_err parse_postfix(struct v7 *v7, struct ast *a) */
3924fid_parse_postfix :
3925#undef L
3926#define L CR_CUR_LOCALS_PT(fid_parse_postfix_locals_t)
3927{
3928 L->pos = a->mbuf.len;
3929 CALL_PARSE_CALLEXPR(fid_p_postfix_1);
3930
3931 if (v7->after_newline) {
3932 CR_RETURN_VOID();
3933 }
3934 switch (v7->cur_tok) {
3935 case TOK_PLUS_PLUS:
3936 next_tok(v7);
3937 insert_node(v7, a, L->pos, AST_POSTINC);
3938 break;
3939 case TOK_MINUS_MINUS:
3940 next_tok(v7);
3941 insert_node(v7, a, L->pos, AST_POSTDEC);
3942 break;
3943 default:
3944 break; /* nothing */
3945 }
3946 CR_RETURN_VOID();
3947}
3948
3949/* static enum v7_err parse_callexpr(struct v7 *v7, struct ast *a) */
3950fid_parse_callexpr :
3951#undef L
3952#define L CR_CUR_LOCALS_PT(fid_parse_callexpr_locals_t)
3953{
3954 L->pos = a->mbuf.len;
3955 CALL_PARSE_NEWEXPR(fid_p_callexpr_1);
3956
3957 for (;;) {
3958 switch (v7->cur_tok) {
3959 case TOK_DOT:
3960 case TOK_OPEN_BRACKET:
3961 CALL_PARSE_MEMBER(L->pos, fid_p_callexpr_3);
3962 break;
3963 case TOK_OPEN_PAREN:
3964 next_tok(v7);
3965 CALL_PARSE_ARGLIST(fid_p_callexpr_2);
3966 EXPECT(TOK_CLOSE_PAREN);
3967 insert_node(v7, a, L->pos, AST_CALL);
3968 break;
3969 default:
3970 CR_RETURN_VOID();
3971 }
3972 }
3973}
3974
3975/* static enum v7_err parse_newexpr(struct v7 *v7, struct ast *a) */
3976fid_parse_newexpr :
3977#undef L
3978#define L CR_CUR_LOCALS_PT(fid_parse_newexpr_locals_t)
3979{
3980 switch (v7->cur_tok) {
3981 case TOK_NEW:
3982 next_tok(v7);
3983 L->start = add_node(v7, a, AST_NEW);
3984 CALL_PARSE_MEMBEREXPR(fid_p_newexpr_3);
3985 if (ACCEPT(TOK_OPEN_PAREN)) {
3986 CALL_PARSE_ARGLIST(fid_p_newexpr_4);
3987 EXPECT(TOK_CLOSE_PAREN);
3988 }
3989 ast_set_skip(a, L->start, AST_END_SKIP);
3990 break;
3991 case TOK_FUNCTION:
3992 next_tok(v7);
3993 CALL_PARSE_FUNCDECL(0, 0, fid_p_newexpr_2);
3994 break;
3995 default:
3996 CALL_PARSE_TERMINAL(fid_p_newexpr_1);
3997 break;
3998 }
3999 CR_RETURN_VOID();
4000}
4001
4002/* static enum v7_err parse_terminal(struct v7 *v7, struct ast *a) */
4003fid_parse_terminal :
4004#undef L
4005#define L CR_CUR_LOCALS_PT(fid_parse_terminal_locals_t)
4006{
4007 switch (v7->cur_tok) {
4008 case TOK_OPEN_PAREN:
4009 next_tok(v7);
4010 CALL_PARSE_EXPRESSION(fid_p_terminal_1);
4011 EXPECT(TOK_CLOSE_PAREN);
4012 break;
4013 case TOK_OPEN_BRACKET:
4014 next_tok(v7);
4015 L->start = add_node(v7, a, AST_ARRAY);
4016 while (v7->cur_tok != TOK_CLOSE_BRACKET) {
4017 if (v7->cur_tok == TOK_COMMA) {
4018 /* Array literals allow missing elements, e.g. [,,1,] */
4019 add_node(v7, a, AST_NOP);
4020 } else {
4021 CALL_PARSE_ASSIGN(fid_p_terminal_2);
4022 }
4023 ACCEPT(TOK_COMMA);
4024 }
4025 EXPECT(TOK_CLOSE_BRACKET);
4026 ast_set_skip(a, L->start, AST_END_SKIP);
4027 break;
4028 case TOK_OPEN_CURLY:
4029 next_tok(v7);
4030 L->start = add_node(v7, a, AST_OBJECT);
4031 if (v7->cur_tok != TOK_CLOSE_CURLY) {
4032 do {
4033 if (v7->cur_tok == TOK_CLOSE_CURLY) {
4034 break;
4035 }
4036 CALL_PARSE_PROP(fid_p_terminal_3);
4037 } while (ACCEPT(TOK_COMMA));
4038 }
4039 EXPECT(TOK_CLOSE_CURLY);
4040 ast_set_skip(a, L->start, AST_END_SKIP);
4041 break;
4042 case TOK_THIS:
4043 next_tok(v7);
4044 add_node(v7, a, AST_THIS);
4045 break;
4046 case TOK_TRUE:
4047 next_tok(v7);
4048 add_node(v7, a, AST_TRUE);
4049 break;
4050 case TOK_FALSE:
4051 next_tok(v7);
4052 add_node(v7, a, AST_FALSE);
4053 break;
4054 case TOK_NULL:
4055 next_tok(v7);
4056 add_node(v7, a, AST_NULL);
4057 break;
4058 case TOK_STRING_LITERAL:
4059 add_inlined_node(v7, a, AST_STRING, v7->tok + 1, v7->tok_len - 2);
4060 next_tok(v7);
4061 break;
4062 case TOK_NUMBER:
4063 add_inlined_node(v7, a, AST_NUM, v7->tok, v7->tok_len);
4064 next_tok(v7);
4065 break;
4066 case TOK_REGEX_LITERAL:
4067 add_inlined_node(v7, a, AST_REGEX, v7->tok, v7->tok_len);
4068 next_tok(v7);
4069 break;
4070 case TOK_IDENTIFIER:
4071 if (v7->tok_len == 9 && strncmp(v7->tok, "undefined", v7->tok_len) == 0) {
4072 add_node(v7, a, AST_UNDEFINED);
4073 next_tok(v7);
4074 break;
4075 }
4076 /* fall through */
4077 default:
4078 CALL_PARSE_IDENT(fid_p_terminal_4);
4079 }
4080 CR_RETURN_VOID();
4081}
4082
4083/* static enum v7_err parse_block(struct v7 *v7, struct ast *a) */
4084fid_parse_block :
4085#undef L
4086#define L CR_CUR_LOCALS_PT(fid_parse_block_locals_t)
4087{
4088 EXPECT(TOK_OPEN_CURLY);
4089 CALL_PARSE_BODY(TOK_CLOSE_CURLY, fid_p_block_1);
4090 EXPECT(TOK_CLOSE_CURLY);
4091 CR_RETURN_VOID();
4092}
4093
4094/* static enum v7_err parse_if(struct v7 *v7, struct ast *a) */
4095fid_parse_if :
4096#undef L
4097#define L CR_CUR_LOCALS_PT(fid_parse_if_locals_t)
4098{
4099 L->start = add_node(v7, a, AST_IF);
4100 EXPECT(TOK_OPEN_PAREN);
4101 CALL_PARSE_EXPRESSION(fid_p_if_1);
4102 EXPECT(TOK_CLOSE_PAREN);
4103 CALL_PARSE_STATEMENT(fid_p_if_2);
4104 ast_set_skip(a, L->start, AST_END_IF_TRUE_SKIP);
4105 if (ACCEPT(TOK_ELSE)) {
4106 CALL_PARSE_STATEMENT(fid_p_if_3);
4107 }
4108 ast_set_skip(a, L->start, AST_END_SKIP);
4109 CR_RETURN_VOID();
4110}
4111
4112/* static enum v7_err parse_while(struct v7 *v7, struct ast *a) */
4113fid_parse_while :
4114#undef L
4115#define L CR_CUR_LOCALS_PT(fid_parse_while_locals_t)
4116{
4117 L->start = add_node(v7, a, AST_WHILE);
4118 L->saved_in_loop = v7->pstate.in_loop;
4119 EXPECT(TOK_OPEN_PAREN);
4120 CALL_PARSE_EXPRESSION(fid_p_while_1);
4121 EXPECT(TOK_CLOSE_PAREN);
4122 v7->pstate.in_loop = 1;
4123 CALL_PARSE_STATEMENT(fid_p_while_2);
4124 ast_set_skip(a, L->start, AST_END_SKIP);
4125 v7->pstate.in_loop = L->saved_in_loop;
4126 CR_RETURN_VOID();
4127}
4128
4129/* static enum v7_err parse_ident(struct v7 *v7, struct ast *a) */
4130fid_parse_ident :
4131#undef L
4132#define L CR_CUR_LOCALS_PT(fid_parse_ident_locals_t)
4133{
4134 if (v7->cur_tok == TOK_IDENTIFIER) {
4135 add_inlined_node(v7, a, AST_IDENT, v7->tok, v7->tok_len);
4136 next_tok(v7);
4137 CR_RETURN_VOID();
4138 }
4139 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
4140}
4141
4142/*
4143 * static enum v7_err parse_ident_allow_reserved_words(struct v7 *v7,
4144 * struct ast *a)
4145 *
4146 */
4147fid_parse_ident_allow_reserved_words :
4148#undef L
4149#define L CR_CUR_LOCALS_PT(fid_parse_ident_allow_reserved_words_locals_t)
4150{
4151 /* Allow reserved words as property names. */
4152 if (is_reserved_word_token(v7->cur_tok)) {
4153 add_inlined_node(v7, a, AST_IDENT, v7->tok, v7->tok_len);
4154 next_tok(v7);
4155 } else {
4156 CALL_PARSE_IDENT(fid_p_ident_arw_1);
4157 }
4158 CR_RETURN_VOID();
4159}
4160
4161/* static enum v7_err parse_funcdecl(struct v7 *, struct ast *, int, int) */
4162fid_parse_funcdecl :
4163#undef L
4164#define L CR_CUR_LOCALS_PT(fid_parse_funcdecl_locals_t)
4165{
4166 L->start = add_node(v7, a, AST_FUNC);
4167 L->outer_last_var_node = v7->last_var_node;
4168 L->saved_in_function = v7->pstate.in_function;
4169 L->saved_in_strict = v7->pstate.in_strict;
4170
4171 v7->last_var_node = L->start;
4172 ast_modify_skip(a, L->start, L->start, AST_FUNC_FIRST_VAR_SKIP);
4173
4174 CR_TRY(fid_p_funcdecl_2);
4175 {
4176 if (L->arg.reserved_name) {
4177 CALL_PARSE_IDENT_ALLOW_RESERVED_WORDS(fid_p_funcdecl_1);
4178 } else {
4179 CALL_PARSE_IDENT(fid_p_funcdecl_9);
4180 }
4181 }
4182 CR_CATCH(PARSER_EXC_ID__SYNTAX_ERROR, fid_p_funcdecl_2, fid_p_funcdecl_3);
4183 {
4184 if (L->arg.require_named) {
4185 /* function name is required, so, rethrow SYNTAX ERROR */
4186 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
4187 } else {
4188 /* it's ok not to have a function name, just insert NOP */
4189 add_node(v7, a, AST_NOP);
4190 }
4191 }
4192 CR_ENDCATCH(fid_p_funcdecl_3);
4193
4194 EXPECT(TOK_OPEN_PAREN);
4195 CALL_PARSE_ARGLIST(fid_p_funcdecl_4);
4196 EXPECT(TOK_CLOSE_PAREN);
4197 ast_set_skip(a, L->start, AST_FUNC_BODY_SKIP);
4198 v7->pstate.in_function = 1;
4199 EXPECT(TOK_OPEN_CURLY);
4200
4201 CR_TRY(fid_p_funcdecl_5);
4202 {
4203 CALL_PARSE_USE_STRICT(fid_p_funcdecl_7);
4204 v7->pstate.in_strict = 1;
4205 }
4206 CR_CATCH(PARSER_EXC_ID__SYNTAX_ERROR, fid_p_funcdecl_5, fid_p_funcdecl_6);
4207 CR_ENDCATCH(fid_p_funcdecl_6);
4208
4209 CALL_PARSE_BODY(TOK_CLOSE_CURLY, fid_p_funcdecl_8);
4210 EXPECT(TOK_CLOSE_CURLY);
4211 v7->pstate.in_strict = L->saved_in_strict;
4212 v7->pstate.in_function = L->saved_in_function;
4213 ast_set_skip(a, L->start, AST_END_SKIP);
4214 v7->last_var_node = L->outer_last_var_node;
4215
4216 CR_RETURN_VOID();
4217}
4218
4219/* static enum v7_err parse_arglist(struct v7 *v7, struct ast *a) */
4220fid_parse_arglist :
4221#undef L
4222#define L CR_CUR_LOCALS_PT(fid_parse_arglist_locals_t)
4223{
4224 if (v7->cur_tok != TOK_CLOSE_PAREN) {
4225 do {
4226 CALL_PARSE_ASSIGN(fid_p_arglist_1);
4227 } while (ACCEPT(TOK_COMMA));
4228 }
4229 CR_RETURN_VOID();
4230}
4231
4232/*
4233 * static enum v7_err parse_member(struct v7 *v7, struct ast *a, ast_off_t pos)
4234 */
4235fid_parse_member :
4236#undef L
4237#define L CR_CUR_LOCALS_PT(fid_parse_member_locals_t)
4238{
4239 switch (v7->cur_tok) {
4240 case TOK_DOT:
4241 next_tok(v7);
4242 /* Allow reserved words as member identifiers */
4243 if (is_reserved_word_token(v7->cur_tok) ||
4244 v7->cur_tok == TOK_IDENTIFIER) {
4245 insert_inlined_node(v7, a, L->arg.pos, AST_MEMBER, v7->tok,
4246 v7->tok_len);
4247 next_tok(v7);
4248 } else {
4249 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
4250 }
4251 break;
4252 case TOK_OPEN_BRACKET:
4253 next_tok(v7);
4254 CALL_PARSE_EXPRESSION(fid_p_member_1);
4255 EXPECT(TOK_CLOSE_BRACKET);
4256 insert_node(v7, a, L->arg.pos, AST_INDEX);
4257 break;
4258 default:
4259 CR_RETURN_VOID();
4260 }
4261 /* not necessary, but let it be anyway */
4262 CR_RETURN_VOID();
4263}
4264
4265/* static enum v7_err parse_memberexpr(struct v7 *v7, struct ast *a) */
4266fid_parse_memberexpr :
4267#undef L
4268#define L CR_CUR_LOCALS_PT(fid_parse_memberexpr_locals_t)
4269{
4270 L->pos = a->mbuf.len;
4271 CALL_PARSE_NEWEXPR(fid_p_memberexpr_1);
4272
4273 for (;;) {
4274 switch (v7->cur_tok) {
4275 case TOK_DOT:
4276 case TOK_OPEN_BRACKET:
4277 CALL_PARSE_MEMBER(L->pos, fid_p_memberexpr_2);
4278 break;
4279 default:
4280 CR_RETURN_VOID();
4281 }
4282 }
4283}
4284
4285/* static enum v7_err parse_var(struct v7 *v7, struct ast *a) */
4286fid_parse_var :
4287#undef L
4288#define L CR_CUR_LOCALS_PT(fid_parse_var_locals_t)
4289{
4290 L->start = add_node(v7, a, AST_VAR);
4291 ast_modify_skip(a, v7->last_var_node, L->start, AST_FUNC_FIRST_VAR_SKIP);
4292 /* zero out var node pointer */
4293 ast_modify_skip(a, L->start, L->start, AST_FUNC_FIRST_VAR_SKIP);
4294 v7->last_var_node = L->start;
4295 do {
4296 add_inlined_node(v7, a, AST_VAR_DECL, v7->tok, v7->tok_len);
4297 EXPECT(TOK_IDENTIFIER);
4298 if (ACCEPT(TOK_ASSIGN)) {
4299 CALL_PARSE_ASSIGN(fid_p_var_1);
4300 } else {
4301 add_node(v7, a, AST_NOP);
4302 }
4303 } while (ACCEPT(TOK_COMMA));
4304 ast_set_skip(a, L->start, AST_END_SKIP);
4305 CR_RETURN_VOID();
4306}
4307
4308/* static enum v7_err parse_prop(struct v7 *v7, struct ast *a) */
4309fid_parse_prop :
4310#undef L
4311#define L CR_CUR_LOCALS_PT(fid_parse_prop_locals_t)
4312{
4313#if V7_ENABLE_JS_GETTERS
4314 if (v7->cur_tok == TOK_IDENTIFIER && v7->tok_len == 3 &&
4315 strncmp(v7->tok, "get", v7->tok_len) == 0 && lookahead(v7) != TOK_COLON) {
4316 next_tok(v7);
4317 add_node(v7, a, AST_GETTER);
4318 CALL_PARSE_FUNCDECL(1, 1, fid_p_prop_1_getter);
4319 } else
4320#endif
4321 if (v7->cur_tok == TOK_IDENTIFIER && lookahead(v7) == TOK_OPEN_PAREN) {
4322 /* ecmascript 6 feature */
4323 CALL_PARSE_FUNCDECL(1, 1, fid_p_prop_2);
4324#if V7_ENABLE_JS_SETTERS
4325 } else if (v7->cur_tok == TOK_IDENTIFIER && v7->tok_len == 3 &&
4326 strncmp(v7->tok, "set", v7->tok_len) == 0 &&
4327 lookahead(v7) != TOK_COLON) {
4328 next_tok(v7);
4329 add_node(v7, a, AST_SETTER);
4330 CALL_PARSE_FUNCDECL(1, 1, fid_p_prop_3_setter);
4331#endif
4332 } else {
4333 /* Allow reserved words as property names. */
4334 if (is_reserved_word_token(v7->cur_tok) || v7->cur_tok == TOK_IDENTIFIER ||
4335 v7->cur_tok == TOK_NUMBER) {
4336 add_inlined_node(v7, a, AST_PROP, v7->tok, v7->tok_len);
4337 } else if (v7->cur_tok == TOK_STRING_LITERAL) {
4338 add_inlined_node(v7, a, AST_PROP, v7->tok + 1, v7->tok_len - 2);
4339 } else {
4340 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
4341 }
4342 next_tok(v7);
4343 EXPECT(TOK_COLON);
4344 CALL_PARSE_ASSIGN(fid_p_prop_4);
4345 }
4346 CR_RETURN_VOID();
4347}
4348
4349/* static enum v7_err parse_dowhile(struct v7 *v7, struct ast *a) */
4350fid_parse_dowhile :
4351#undef L
4352#define L CR_CUR_LOCALS_PT(fid_parse_dowhile_locals_t)
4353{
4354 L->start = add_node(v7, a, AST_DOWHILE);
4355 L->saved_in_loop = v7->pstate.in_loop;
4356
4357 v7->pstate.in_loop = 1;
4358 CALL_PARSE_STATEMENT(fid_p_dowhile_1);
4359 v7->pstate.in_loop = L->saved_in_loop;
4360 ast_set_skip(a, L->start, AST_DO_WHILE_COND_SKIP);
4361 EXPECT(TOK_WHILE);
4362 EXPECT(TOK_OPEN_PAREN);
4363 CALL_PARSE_EXPRESSION(fid_p_dowhile_2);
4364 EXPECT(TOK_CLOSE_PAREN);
4365 ast_set_skip(a, L->start, AST_END_SKIP);
4366 CR_RETURN_VOID();
4367}
4368
4369/* static enum v7_err parse_for(struct v7 *v7, struct ast *a) */
4370fid_parse_for :
4371#undef L
4372#define L CR_CUR_LOCALS_PT(fid_parse_for_locals_t)
4373{
4374 /* TODO(mkm): for of, for each in */
4375 /*
4376 ast_off_t start;
4377 int saved_in_loop;
4378 */
4379
4380 L->start = add_node(v7, a, AST_FOR);
4381 L->saved_in_loop = v7->pstate.in_loop;
4382
4383 EXPECT(TOK_OPEN_PAREN);
4384
4385 if (parse_optional(v7, a, TOK_SEMICOLON)) {
4386 /*
4387 * TODO(mkm): make this reentrant otherwise this pearl won't parse:
4388 * for((function(){return 1 in o.a ? o : x})().a in [1,2,3])
4389 */
4390 v7->pstate.inhibit_in = 1;
4391 if (ACCEPT(TOK_VAR)) {
4392 CALL_PARSE_VAR(fid_p_for_1);
4393 } else {
4394 CALL_PARSE_EXPRESSION(fid_p_for_2);
4395 }
4396 v7->pstate.inhibit_in = 0;
4397
4398 if (ACCEPT(TOK_IN)) {
4399 CALL_PARSE_EXPRESSION(fid_p_for_3);
4400 add_node(v7, a, AST_NOP);
4401 /*
4402 * Assumes that for and for in have the same AST format which is
4403 * suboptimal but avoids the need of fixing up the var offset chain.
4404 * TODO(mkm) improve this
4405 */
4406 ast_modify_tag(a, L->start - 1, AST_FOR_IN);
4407 goto for_loop_body;
4408 }
4409 }
4410
4411 EXPECT(TOK_SEMICOLON);
4412 if (parse_optional(v7, a, TOK_SEMICOLON)) {
4413 CALL_PARSE_EXPRESSION(fid_p_for_4);
4414 }
4415 EXPECT(TOK_SEMICOLON);
4416 if (parse_optional(v7, a, TOK_CLOSE_PAREN)) {
4417 CALL_PARSE_EXPRESSION(fid_p_for_5);
4418 }
4419
4420for_loop_body:
4421 EXPECT(TOK_CLOSE_PAREN);
4422 ast_set_skip(a, L->start, AST_FOR_BODY_SKIP);
4423 v7->pstate.in_loop = 1;
4424 CALL_PARSE_STATEMENT(fid_p_for_6);
4425 v7->pstate.in_loop = L->saved_in_loop;
4426 ast_set_skip(a, L->start, AST_END_SKIP);
4427 CR_RETURN_VOID();
4428}
4429
4430/* static enum v7_err parse_try(struct v7 *v7, struct ast *a) */
4431fid_parse_try :
4432#undef L
4433#define L CR_CUR_LOCALS_PT(fid_parse_try_locals_t)
4434{
4435 L->start = add_node(v7, a, AST_TRY);
4436 L->catch_or_finally = 0;
4437 CALL_PARSE_BLOCK(fid_p_try_1);
4438 ast_set_skip(a, L->start, AST_TRY_CATCH_SKIP);
4439 if (ACCEPT(TOK_CATCH)) {
4440 L->catch_or_finally = 1;
4441 EXPECT(TOK_OPEN_PAREN);
4442 CALL_PARSE_IDENT(fid_p_try_2);
4443 EXPECT(TOK_CLOSE_PAREN);
4444 CALL_PARSE_BLOCK(fid_p_try_3);
4445 }
4446 ast_set_skip(a, L->start, AST_TRY_FINALLY_SKIP);
4447 if (ACCEPT(TOK_FINALLY)) {
4448 L->catch_or_finally = 1;
4449 CALL_PARSE_BLOCK(fid_p_try_4);
4450 }
4451 ast_set_skip(a, L->start, AST_END_SKIP);
4452
4453 /* make sure `catch` and `finally` aren't both missing */
4454 if (!L->catch_or_finally) {
4455 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
4456 }
4457
4458 CR_RETURN_VOID();
4459}
4460
4461/* static enum v7_err parse_switch(struct v7 *v7, struct ast *a) */
4462fid_parse_switch :
4463#undef L
4464#define L CR_CUR_LOCALS_PT(fid_parse_switch_locals_t)
4465{
4466 L->start = add_node(v7, a, AST_SWITCH);
4467 L->saved_in_switch = v7->pstate.in_switch;
4468
4469 ast_set_skip(a, L->start, AST_SWITCH_DEFAULT_SKIP); /* clear out */
4470 EXPECT(TOK_OPEN_PAREN);
4471 CALL_PARSE_EXPRESSION(fid_p_switch_1);
4472 EXPECT(TOK_CLOSE_PAREN);
4473 EXPECT(TOK_OPEN_CURLY);
4474 v7->pstate.in_switch = 1;
4475 while (v7->cur_tok != TOK_CLOSE_CURLY) {
4476 switch (v7->cur_tok) {
4477 case TOK_CASE:
4478 next_tok(v7);
4479 L->case_start = add_node(v7, a, AST_CASE);
4480 CALL_PARSE_EXPRESSION(fid_p_switch_2);
4481 EXPECT(TOK_COLON);
4482 while (v7->cur_tok != TOK_CASE && v7->cur_tok != TOK_DEFAULT &&
4483 v7->cur_tok != TOK_CLOSE_CURLY) {
4484 CALL_PARSE_STATEMENT(fid_p_switch_3);
4485 }
4486 ast_set_skip(a, L->case_start, AST_END_SKIP);
4487 break;
4488 case TOK_DEFAULT:
4489 next_tok(v7);
4490 EXPECT(TOK_COLON);
4491 ast_set_skip(a, L->start, AST_SWITCH_DEFAULT_SKIP);
4492 L->case_start = add_node(v7, a, AST_DEFAULT);
4493 while (v7->cur_tok != TOK_CASE && v7->cur_tok != TOK_DEFAULT &&
4494 v7->cur_tok != TOK_CLOSE_CURLY) {
4495 CALL_PARSE_STATEMENT(fid_p_switch_4);
4496 }
4497 ast_set_skip(a, L->case_start, AST_END_SKIP);
4498 break;
4499 default:
4500 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
4501 }
4502 }
4503 EXPECT(TOK_CLOSE_CURLY);
4504 ast_set_skip(a, L->start, AST_END_SKIP);
4505 v7->pstate.in_switch = L->saved_in_switch;
4506 CR_RETURN_VOID();
4507}
4508
4509/* static enum v7_err parse_with(struct v7 *v7, struct ast *a) */
4510fid_parse_with :
4511#undef L
4512#define L CR_CUR_LOCALS_PT(fid_parse_with_locals_t)
4513{
4514 L->start = add_node(v7, a, AST_WITH);
4515 if (v7->pstate.in_strict) {
4516 CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
4517 }
4518 EXPECT(TOK_OPEN_PAREN);
4519 CALL_PARSE_EXPRESSION(fid_p_with_1);
4520 EXPECT(TOK_CLOSE_PAREN);
4521 CALL_PARSE_STATEMENT(fid_p_with_2);
4522 ast_set_skip(a, L->start, AST_END_SKIP);
4523 CR_RETURN_VOID();
4524}
4525
4526fid_none:
4527 /* stack is empty, so we're done; return */
4528 return rc;
4529}
4530
4531V7_PRIVATE enum v7_err parse(struct v7 *v7, struct ast *a, const char *src,
4532 size_t src_len, int is_json) {
4533 enum v7_err rcode;
4534 const char *error_msg = NULL;
4535 const char *p;
4536 struct cr_ctx cr_ctx;
4537 union user_arg_ret arg_retval;
4538 enum cr_status rc;
4539#if V7_ENABLE_STACK_TRACKING
4540 struct stack_track_ctx stack_track_ctx;
4541#endif
4542 int saved_line_no = v7->line_no;
4543
4544#if V7_ENABLE_STACK_TRACKING
4545 v7_stack_track_start(v7, &stack_track_ctx);
4546#endif
4547
4548 v7->pstate.source_code = v7->pstate.pc = src;
4549 v7->pstate.src_end = src + src_len;
4550 v7->pstate.file_name = "<stdin>";
4551 v7->pstate.line_no = 1;
4552 v7->pstate.in_function = 0;
4553 v7->pstate.in_loop = 0;
4554 v7->pstate.in_switch = 0;
4555
4556 /*
4557 * TODO(dfrank): `v7->parser.line_no` vs `v7->line_no` is confusing. probaby
4558 * we need to refactor it.
4559 *
4560 * See comment for v7->line_no in core.h for some details.
4561 */
4562 v7->line_no = 1;
4563
4564 next_tok(v7);
4565 /*
4566 * setup initial state for "after newline" tracking.
4567 * next_tok will consume our token and position the current line
4568 * position at the beginning of the next token.
4569 * While processing the first token, both the leading and the
4570 * trailing newlines will be counted and thus it will create a spurious
4571 * "after newline" condition at the end of the first token
4572 * regardless if there is actually a newline after it.
4573 */
4574 for (p = src; isspace((int) *p); p++) {
4575 if (*p == '\n') {
4576 v7->pstate.prev_line_no++;
4577 }
4578 }
4579
4580 /* init cr context */
4581 cr_context_init(&cr_ctx, &arg_retval, sizeof(arg_retval), _fid_descrs);
4582
4583 /* prepare first function call: fid_mul_sum */
4584 if (is_json) {
4585 CR_FIRST_CALL_PREPARE_C(&cr_ctx, fid_parse_terminal);
4586 } else {
4587 CR_FIRST_CALL_PREPARE_C(&cr_ctx, fid_parse_script);
4588 }
4589
4590 /* proceed to coroutine execution */
4591 rc = parser_cr_exec(&cr_ctx, v7, a);
4592
4593 /* set `rcode` depending on coroutine state */
4594 switch (rc) {
4595 case CR_RES__OK:
4596 rcode = V7_OK;
4597 break;
4598 case CR_RES__ERR_UNCAUGHT_EXCEPTION:
4599 switch ((enum parser_exc_id) CR_THROWN_C(&cr_ctx)) {
4600 case PARSER_EXC_ID__SYNTAX_ERROR:
4601 rcode = V7_SYNTAX_ERROR;
4602 error_msg = "Syntax error";
4603 break;
4604
4605 default:
4606 rcode = V7_INTERNAL_ERROR;
4607 error_msg = "Internal error: no exception id set";
4608 break;
4609 }
4610 break;
4611 default:
4612 rcode = V7_INTERNAL_ERROR;
4613 error_msg = "Internal error: unexpected parser coroutine return code";
4614 break;
4615 }
4616
4617#if defined(V7_TRACK_MAX_PARSER_STACK_SIZE)
4618 /* remember how much stack space was consumed */
4619
4620 if (v7->parser_stack_data_max_size < cr_ctx.stack_data.size) {
4621 v7->parser_stack_data_max_size = cr_ctx.stack_data.size;
4622#ifndef NO_LIBC
4623 printf("parser_stack_data_max_size=%u\n",
4624 (unsigned int) v7->parser_stack_data_max_size);
4625#endif
4626 }
4627
4628 if (v7->parser_stack_ret_max_size < cr_ctx.stack_ret.size) {
4629 v7->parser_stack_ret_max_size = cr_ctx.stack_ret.size;
4630#ifndef NO_LIBC
4631 printf("parser_stack_ret_max_size=%u\n",
4632 (unsigned int) v7->parser_stack_ret_max_size);
4633#endif
4634 }
4635
4636#if defined(CR_TRACK_MAX_STACK_LEN)
4637 if (v7->parser_stack_data_max_len < cr_ctx.stack_data_max_len) {
4638 v7->parser_stack_data_max_len = cr_ctx.stack_data_max_len;
4639#ifndef NO_LIBC
4640 printf("parser_stack_data_max_len=%u\n",
4641 (unsigned int) v7->parser_stack_data_max_len);
4642#endif
4643 }
4644
4645 if (v7->parser_stack_ret_max_len < cr_ctx.stack_ret_max_len) {
4646 v7->parser_stack_ret_max_len = cr_ctx.stack_ret_max_len;
4647#ifndef NO_LIBC
4648 printf("parser_stack_ret_max_len=%u\n",
4649 (unsigned int) v7->parser_stack_ret_max_len);
4650#endif
4651 }
4652#endif
4653
4654#endif
4655
4656 /* free resources occupied by context (at least, "stack" arrays) */
4657 cr_context_free(&cr_ctx);
4658
4659#if V7_ENABLE_STACK_TRACKING
4660 {
4661 int diff = v7_stack_track_end(v7, &stack_track_ctx);
4662 if (diff > v7->stack_stat[V7_STACK_STAT_PARSER]) {
4663 v7->stack_stat[V7_STACK_STAT_PARSER] = diff;
4664 }
4665 }
4666#endif
4667
4668 /* Check if AST was overflown */
4669 if (a->has_overflow) {
4670 rcode = v7_throwf(v7, SYNTAX_ERROR,
4671 "Script too large (try V7_LARGE_AST build option)");
4672 V7_THROW(V7_AST_TOO_LARGE);
4673 }
4674
4675 if (rcode == V7_OK && v7->cur_tok != TOK_END_OF_INPUT) {
4676 rcode = V7_SYNTAX_ERROR;
4677 error_msg = "Syntax error";
4678 }
4679
4680 if (rcode != V7_OK) {
4681 unsigned long col = get_column(v7->pstate.source_code, v7->tok);
4682 int line_len = 0;
4683
4684 assert(error_msg != NULL);
4685
4686 for (p = v7->tok - col; p < v7->pstate.src_end && *p != '\0' && *p != '\n';
4687 p++) {
4688 line_len++;
4689 }
4690
4691 /* fixup line number: line_no points to the beginning of the next token */
4692 for (; p < v7->pstate.pc; p++) {
4693 if (*p == '\n') {
4694 v7->pstate.line_no--;
4695 }
4696 }
4697
4698 /*
4699 * We already have a proper `rcode`, that's why we discard returned value
4700 * of `v7_throwf()`, which is always `V7_EXEC_EXCEPTION`.
4701 *
4702 * TODO(dfrank): probably get rid of distinct error types, and use just
4703 * `V7_JS_EXCEPTION`. However it would be good to have a way to get exact
4704 * error type, so probably error object should contain some property with
4705 * error code, but it would make exceptions even more expensive, etc, etc.
4706 */
4707 {
4708 enum v7_err _tmp;
4709 _tmp = v7_throwf(v7, SYNTAX_ERROR, "%s at line %d col %lu:\n%.*s\n%*s^",
4710 error_msg, v7->pstate.line_no, col, line_len,
4711 v7->tok - col, (int) col - 1, "");
4712 (void) _tmp;
4713 }
4714 V7_THROW(rcode);
4715 }
4716
4717clean:
4718 v7->line_no = saved_line_no;
4719 return rcode;
4720}
4721
4722#endif /* V7_NO_COMPILER */
4723#ifdef V7_MODULE_LINES
4724#line 1 "v7/src/compiler.c"
4725#endif
4726/*
4727 * Copyright (c) 2014 Cesanta Software Limited
4728 * All rights reserved
4729 */
4730
4731/* Amalgamated: #include "v7/src/internal.h" */
4732/* Amalgamated: #include "v7/src/compiler.h" */
4733/* Amalgamated: #include "v7/src/std_error.h" */
4734/* Amalgamated: #include "v7/src/core.h" */
4735/* Amalgamated: #include "v7/src/function.h" */
4736/* Amalgamated: #include "v7/src/exceptions.h" */
4737/* Amalgamated: #include "v7/src/conversion.h" */
4738/* Amalgamated: #include "v7/src/regexp.h" */
4739
4740#if !defined(V7_NO_COMPILER)
4741
4742/*
4743 * The bytecode compiler takes an AST as input and produces one or more
4744 * bcode structure as output.
4745 *
4746 * Each script or function body is compiled into it's own bcode structure.
4747 *
4748 * Each bcode stream produces a new value on the stack, i.e. its overall
4749 * stack diagram is: `( -- a)`
4750 *
4751 * This value will be then popped by the function caller or by v7_exec in case
4752 * of scripts.
4753 *
4754 * In JS, the value of a script is the value of the last statement.
4755 * A script with no statement has an `undefined` value.
4756 * Functions instead require an explicit return value, so this matters only
4757 * for `v7_exec` and JS `eval`.
4758 *
4759 * Since an empty script has an undefined value, and each script has to
4760 * yield a value, the script/function prologue consists of a PUSH_UNDEFINED.
4761 *
4762 * Each statement will be compiled to push a value on the stack.
4763 * When a statement begins evaluating, the current TOS is thus either
4764 * the value of the previous statement or `undefined` in case of the first
4765 * statement.
4766 *
4767 * Every statement of a given script/function body always evaluates at the same
4768 * stack depth.
4769 *
4770 * In order to achieve that, after a statement is compiled out, a SWAP_DROP
4771 * opcode is emitted, that drops the value of the previous statement (or the
4772 * initial `undefined`). Dropping the value after the next statement is
4773 * evaluated and not before has allows us to correctly implement exception
4774 * behaviour and the break statement.
4775 *
4776 * Compound statements are constructs such as `if`/`while`/`for`/`try`. These
4777 * constructs contain a body consisting of a possibly empty statement list.
4778 *
4779 * Unlike normal statements, compound statements don't produce a value
4780 * themselves. Their value is either the value of their last executed statement
4781 * in their body, or the previous statement in case their body is empty or not
4782 * evaluated at all.
4783 *
4784 * An example is:
4785 *
4786 * [source,js]
4787 * ----
4788 * try {
4789 * 42;
4790 * someUnexistingVariable;
4791 * } catch(e) {
4792 * while(true) {}
4793 * if(true) {
4794 * }
4795 * if(false) {
4796 * 2;
4797 * }
4798 * break;
4799 * }
4800 * }
4801 * ----
4802 */
4803
4804static const enum ast_tag assign_ast_map[] = {
4805 AST_REM, AST_MUL, AST_DIV, AST_XOR, AST_ADD, AST_SUB,
4806 AST_OR, AST_AND, AST_LSHIFT, AST_RSHIFT, AST_URSHIFT};
4807
4808#ifdef V7_BCODE_DUMP
4809extern void dump_bcode(struct v7 *v7, FILE *f, struct bcode *bcode);
4810#endif
4811
4812V7_PRIVATE enum v7_err compile_expr_builder(struct bcode_builder *bbuilder,
4813 struct ast *a, ast_off_t *ppos);
4814
4815V7_PRIVATE enum v7_err compile_function(struct v7 *v7, struct ast *a,
4816 ast_off_t *ppos, struct bcode *bcode);
4817
4818V7_PRIVATE enum v7_err binary_op(struct bcode_builder *bbuilder,
4819 enum ast_tag tag) {
4820 uint8_t op;
4821 enum v7_err rcode = V7_OK;
4822 struct v7 *v7 = bbuilder->v7;
4823
4824 switch (tag) {
4825 case AST_ADD:
4826 op = OP_ADD;
4827 break;
4828 case AST_SUB:
4829 op = OP_SUB;
4830 break;
4831 case AST_REM:
4832 op = OP_REM;
4833 break;
4834 case AST_MUL:
4835 op = OP_MUL;
4836 break;
4837 case AST_DIV:
4838 op = OP_DIV;
4839 break;
4840 case AST_LSHIFT:
4841 op = OP_LSHIFT;
4842 break;
4843 case AST_RSHIFT:
4844 op = OP_RSHIFT;
4845 break;
4846 case AST_URSHIFT:
4847 op = OP_URSHIFT;
4848 break;
4849 case AST_OR:
4850 op = OP_OR;
4851 break;
4852 case AST_XOR:
4853 op = OP_XOR;
4854 break;
4855 case AST_AND:
4856 op = OP_AND;
4857 break;
4858 case AST_EQ_EQ:
4859 op = OP_EQ_EQ;
4860 break;
4861 case AST_EQ:
4862 op = OP_EQ;
4863 break;
4864 case AST_NE:
4865 op = OP_NE;
4866 break;
4867 case AST_NE_NE:
4868 op = OP_NE_NE;
4869 break;
4870 case AST_LT:
4871 op = OP_LT;
4872 break;
4873 case AST_LE:
4874 op = OP_LE;
4875 break;
4876 case AST_GT:
4877 op = OP_GT;
4878 break;
4879 case AST_GE:
4880 op = OP_GE;
4881 break;
4882 case AST_INSTANCEOF:
4883 op = OP_INSTANCEOF;
4884 break;
4885 default:
4886 rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "unknown binary ast node");
4887 V7_THROW(V7_SYNTAX_ERROR);
4888 }
4889 bcode_op(bbuilder, op);
4890clean:
4891 return rcode;
4892}
4893
4894V7_PRIVATE enum v7_err compile_binary(struct bcode_builder *bbuilder,
4895 struct ast *a, ast_off_t *ppos,
4896 enum ast_tag tag) {
4897 enum v7_err rcode = V7_OK;
4898 struct v7 *v7 = bbuilder->v7;
4899 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
4900 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
4901
4902 V7_TRY(binary_op(bbuilder, tag));
4903clean:
4904 return rcode;
4905}
4906
4907/*
4908 * `pos` should be an offset of the byte right after a tag
4909 */
4910static lit_t string_lit(struct bcode_builder *bbuilder, struct ast *a,
4911 ast_off_t pos) {
4912 size_t i = 0, name_len;
4913 val_t v = V7_UNDEFINED;
4914 struct mbuf *m = &bbuilder->lit;
4915 char *name = ast_get_inlined_data(a, pos, &name_len);
4916
4917/* temp disabled because of short lits */
4918#if 0
4919 for (i = 0; i < m->len / sizeof(val_t); i++) {
4920 v = ((val_t *) m->buf)[i];
4921 if (v7_is_string(v)) {
4922 size_t l;
4923 const char *s = v7_get_string(bbuilder->v7, &v, &l);
4924 if (name_len == l && memcmp(name, s, name_len) == 0) {
4925 lit_t res;
4926 memset(&res, 0, sizeof(res));
4927 res.idx = i + bcode_max_inline_type_tag;
4928 return res;
4929 }
4930 }
4931 }
4932#else
4933 (void) i;
4934 (void) v;
4935 (void) m;
4936#endif
4937 return bcode_add_lit(bbuilder, v7_mk_string(bbuilder->v7, name, name_len, 1));
4938}
4939
4940#if V7_ENABLE__RegExp
4941WARN_UNUSED_RESULT
4942static enum v7_err regexp_lit(struct bcode_builder *bbuilder, struct ast *a,
4943 ast_off_t pos, lit_t *res) {
4944 enum v7_err rcode = V7_OK;
4945 size_t name_len;
4946 char *p;
4947 char *name = ast_get_inlined_data(a, pos, &name_len);
4948 val_t tmp = V7_UNDEFINED;
4949 struct v7 *v7 = bbuilder->v7;
4950
4951 for (p = name + name_len - 1; *p != '/';) p--;
4952
4953 V7_TRY(v7_mk_regexp(bbuilder->v7, name + 1, p - (name + 1), p + 1,
4954 (name + name_len) - p - 1, &tmp));
4955
4956 *res = bcode_add_lit(bbuilder, tmp);
4957
4958clean:
4959 return rcode;
4960}
4961#endif
4962
4963#if !V7_DISABLE_LINE_NUMBERS
4964static void append_lineno_if_changed(struct v7 *v7,
4965 struct bcode_builder *bbuilder,
4966 int line_no) {
4967 (void) v7;
4968 if (line_no != 0 && line_no != v7->line_no) {
4969 v7->line_no = line_no;
4970 bcode_append_lineno(bbuilder, line_no);
4971 }
4972}
4973#else
4974static void append_lineno_if_changed(struct v7 *v7,
4975 struct bcode_builder *bbuilder,
4976 int line_no) {
4977 (void) v7;
4978 (void) bbuilder;
4979 (void) line_no;
4980}
4981#endif
4982
4983static enum ast_tag fetch_tag(struct v7 *v7, struct bcode_builder *bbuilder,
4984 struct ast *a, ast_off_t *ppos,
4985 ast_off_t *ppos_after_tag) {
4986 enum ast_tag ret = ast_fetch_tag(a, ppos);
4987 int line_no = ast_get_line_no(a, *ppos);
4988 append_lineno_if_changed(v7, bbuilder, line_no);
4989 if (ppos_after_tag != NULL) {
4990 *ppos_after_tag = *ppos;
4991 }
4992 ast_move_to_children(a, ppos);
4993 return ret;
4994}
4995
4996/*
4997 * a++ and a-- need to ignore the updated value.
4998 *
4999 * Call this before updating the lhs.
5000 */
5001static void fixup_post_op(struct bcode_builder *bbuilder, enum ast_tag tag) {
5002 if (tag == AST_POSTINC || tag == AST_POSTDEC) {
5003 bcode_op(bbuilder, OP_UNSTASH);
5004 }
5005}
5006
5007/*
5008 * evaluate rhs expression.
5009 * ++a and a++ are equivalent to a+=1
5010 */
5011static enum v7_err eval_assign_rhs(struct bcode_builder *bbuilder,
5012 struct ast *a, ast_off_t *ppos,
5013 enum ast_tag tag) {
5014 enum v7_err rcode = V7_OK;
5015 struct v7 *v7 = bbuilder->v7;
5016
5017 /* a++ and a-- need to preserve initial value. */
5018 if (tag == AST_POSTINC || tag == AST_POSTDEC) {
5019 bcode_op(bbuilder, OP_STASH);
5020 }
5021 if (tag >= AST_PREINC && tag <= AST_POSTDEC) {
5022 bcode_op(bbuilder, OP_PUSH_ONE);
5023 } else {
5024 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5025 }
5026
5027 switch (tag) {
5028 case AST_PREINC:
5029 case AST_POSTINC:
5030 bcode_op(bbuilder, OP_ADD);
5031 break;
5032 case AST_PREDEC:
5033 case AST_POSTDEC:
5034 bcode_op(bbuilder, OP_SUB);
5035 break;
5036 case AST_ASSIGN:
5037 /* no operation */
5038 break;
5039 default:
5040 binary_op(bbuilder, assign_ast_map[tag - AST_ASSIGN - 1]);
5041 }
5042
5043clean:
5044 return rcode;
5045}
5046
5047static enum v7_err compile_assign(struct bcode_builder *bbuilder, struct ast *a,
5048 ast_off_t *ppos, enum ast_tag tag) {
5049 lit_t lit;
5050 enum ast_tag ntag;
5051 enum v7_err rcode = V7_OK;
5052 struct v7 *v7 = bbuilder->v7;
5053 ast_off_t pos_after_tag;
5054
5055 ntag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
5056
5057 switch (ntag) {
5058 case AST_IDENT:
5059 lit = string_lit(bbuilder, a, pos_after_tag);
5060 if (tag != AST_ASSIGN) {
5061 bcode_op_lit(bbuilder, OP_GET_VAR, lit);
5062 }
5063
5064 V7_TRY(eval_assign_rhs(bbuilder, a, ppos, tag));
5065 bcode_op_lit(bbuilder, OP_SET_VAR, lit);
5066
5067 fixup_post_op(bbuilder, tag);
5068 break;
5069 case AST_MEMBER:
5070 case AST_INDEX:
5071 switch (ntag) {
5072 case AST_MEMBER:
5073 lit = string_lit(bbuilder, a, pos_after_tag);
5074 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5075 bcode_push_lit(bbuilder, lit);
5076 break;
5077 case AST_INDEX:
5078 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5079 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5080 break;
5081 default:
5082 /* unreachable, compilers are dumb */
5083 V7_THROW(V7_SYNTAX_ERROR);
5084 }
5085 if (tag != AST_ASSIGN) {
5086 bcode_op(bbuilder, OP_2DUP);
5087 bcode_op(bbuilder, OP_GET);
5088 }
5089
5090 V7_TRY(eval_assign_rhs(bbuilder, a, ppos, tag));
5091 bcode_op(bbuilder, OP_SET);
5092
5093 fixup_post_op(bbuilder, tag);
5094 break;
5095 default:
5096 /* We end up here on expressions like `1 = 2;`, it's a ReferenceError */
5097 rcode = v7_throwf(bbuilder->v7, REFERENCE_ERROR, "unexpected ast node");
5098 V7_THROW(V7_SYNTAX_ERROR);
5099 }
5100clean:
5101 return rcode;
5102}
5103
5104/*
5105 * Walks through all declarations (`var` and `function`) in the current scope,
5106 * and adds names of all of them to `bcode->ops`. Additionally, `function`
5107 * declarations are compiled right here, since they're hoisted in JS.
5108 */
5109static enum v7_err compile_local_vars(struct bcode_builder *bbuilder,
5110 struct ast *a, ast_off_t start,
5111 ast_off_t fvar) {
5112 ast_off_t next, fvar_end;
5113 char *name;
5114 size_t name_len;
5115 lit_t lit;
5116 enum v7_err rcode = V7_OK;
5117 struct v7 *v7 = bbuilder->v7;
5118 size_t names_end = 0;
5119 ast_off_t pos_after_tag;
5120
5121 /* calculate `names_end`: offset at which names in `bcode->ops` end */
5122 names_end =
5123 (size_t)(bcode_end_names(bbuilder->ops.buf, bbuilder->bcode->names_cnt) -
5124 bbuilder->ops.buf);
5125
5126 if (fvar != start) {
5127 /* iterate all `AST_VAR`s in the current scope */
5128 do {
5129 V7_CHECK_INTERNAL(fetch_tag(v7, bbuilder, a, &fvar, &pos_after_tag) ==
5130 AST_VAR);
5131
5132 next = ast_get_skip(a, pos_after_tag, AST_VAR_NEXT_SKIP);
5133 if (next == pos_after_tag) {
5134 next = 0;
5135 }
5136
5137 fvar_end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
5138
5139 /*
5140 * iterate all `AST_VAR_DECL`s and `AST_FUNC_DECL`s in the current
5141 * `AST_VAR`
5142 */
5143 while (fvar < fvar_end) {
5144 enum ast_tag tag = fetch_tag(v7, bbuilder, a, &fvar, &pos_after_tag);
5145 V7_CHECK_INTERNAL(tag == AST_VAR_DECL || tag == AST_FUNC_DECL);
5146 name = ast_get_inlined_data(a, pos_after_tag, &name_len);
5147 if (tag == AST_VAR_DECL) {
5148 /*
5149 * it's a `var` declaration, so, skip the value for now, it'll be set
5150 * to `undefined` initially
5151 */
5152 ast_skip_tree(a, &fvar);
5153 } else {
5154 /*
5155 * tag is an AST_FUNC_DECL: since functions in JS are hoisted,
5156 * we compile it and put `OP_SET_VAR` directly here
5157 */
5158 lit = string_lit(bbuilder, a, pos_after_tag);
5159 V7_TRY(compile_expr_builder(bbuilder, a, &fvar));
5160 bcode_op_lit(bbuilder, OP_SET_VAR, lit);
5161
5162 /* function declarations are stack-neutral */
5163 bcode_op(bbuilder, OP_DROP);
5164 /*
5165 * Note: the `is_stack_neutral` flag will be set by `compile_stmt`
5166 * later, when it encounters `AST_FUNC_DECL` again.
5167 */
5168 }
5169 V7_TRY(bcode_add_name(bbuilder, name, name_len, &names_end));
5170 }
5171
5172 if (next > 0) {
5173 fvar = next - 1;
5174 }
5175
5176 } while (next != 0);
5177 }
5178
5179clean:
5180 return rcode;
5181}
5182
5183/*
5184 * Just like `compile_expr_builder`, but it takes additional argument:
5185 *`for_call`.
5186 * If it's non-zero, the stack is additionally populated with `this` value
5187 * for call.
5188 *
5189 * If there is a refinement (a dot, or a subscript), then it'll be the
5190 * appropriate object. Otherwise, it's `undefined`.
5191 *
5192 * In non-strict mode, `undefined` will be changed to Global Object at runtime,
5193 * see `OP_CALL` handling in `eval_bcode()`.
5194 */
5195V7_PRIVATE enum v7_err compile_expr_ext(struct bcode_builder *bbuilder,
5196 struct ast *a, ast_off_t *ppos,
5197 uint8_t for_call) {
5198 enum v7_err rcode = V7_OK;
5199 struct v7 *v7 = bbuilder->v7;
5200 ast_off_t pos_after_tag;
5201 enum ast_tag tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
5202
5203 switch (tag) {
5204 case AST_MEMBER: {
5205 lit_t lit = string_lit(bbuilder, a, pos_after_tag);
5206 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5207 if (for_call) {
5208 /* current TOS will be used as `this` */
5209 bcode_op(bbuilder, OP_DUP);
5210 }
5211 bcode_push_lit(bbuilder, lit);
5212 bcode_op(bbuilder, OP_GET);
5213 break;
5214 }
5215
5216 case AST_INDEX:
5217 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5218 if (for_call) {
5219 /* current TOS will be used as `this` */
5220 bcode_op(bbuilder, OP_DUP);
5221 }
5222 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5223 bcode_op(bbuilder, OP_GET);
5224 break;
5225
5226 default:
5227 if (for_call) {
5228 /*
5229 * `this` will be an `undefined` (but it may change to Global Object
5230 * at runtime)
5231 */
5232 bcode_op(bbuilder, OP_PUSH_UNDEFINED);
5233 }
5234 *ppos = pos_after_tag - 1;
5235 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5236 break;
5237 }
5238
5239clean:
5240 return rcode;
5241}
5242
5243V7_PRIVATE enum v7_err compile_delete(struct bcode_builder *bbuilder,
5244 struct ast *a, ast_off_t *ppos) {
5245 enum v7_err rcode = V7_OK;
5246 struct v7 *v7 = bbuilder->v7;
5247 ast_off_t pos_after_tag;
5248 enum ast_tag tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
5249
5250 switch (tag) {
5251 case AST_MEMBER: {
5252 /* Delete a specified property of an object */
5253 lit_t lit = string_lit(bbuilder, a, pos_after_tag);
5254 /* put an object to delete property from */
5255 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5256 /* put a property name */
5257 bcode_push_lit(bbuilder, lit);
5258 bcode_op(bbuilder, OP_DELETE);
5259 break;
5260 }
5261
5262 case AST_INDEX:
5263 /* Delete a specified property of an object */
5264 /* put an object to delete property from */
5265 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5266 /* put a property name */
5267 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5268 bcode_op(bbuilder, OP_DELETE);
5269 break;
5270
5271 case AST_IDENT:
5272 /* Delete the scope variable (or throw an error if strict mode) */
5273 if (!bbuilder->bcode->strict_mode) {
5274 /* put a property name */
5275 bcode_push_lit(bbuilder, string_lit(bbuilder, a, pos_after_tag));
5276 bcode_op(bbuilder, OP_DELETE_VAR);
5277 } else {
5278 rcode =
5279 v7_throwf(bbuilder->v7, SYNTAX_ERROR,
5280 "Delete of an unqualified identifier in strict mode.");
5281 V7_THROW(V7_SYNTAX_ERROR);
5282 }
5283 break;
5284
5285 case AST_UNDEFINED:
5286 /*
5287 * `undefined` should actually be an undeletable property of the Global
5288 * Object, so, trying to delete it just yields `false`
5289 */
5290 bcode_op(bbuilder, OP_PUSH_FALSE);
5291 break;
5292
5293 default:
5294 /*
5295 * For all other cases, we evaluate the expression given to `delete`
5296 * for side effects, then drop the result, and yield `true`
5297 */
5298 *ppos = pos_after_tag - 1;
5299 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5300 bcode_op(bbuilder, OP_DROP);
5301 bcode_op(bbuilder, OP_PUSH_TRUE);
5302 break;
5303 }
5304
5305clean:
5306 return rcode;
5307}
5308
5309V7_PRIVATE enum v7_err compile_expr_builder(struct bcode_builder *bbuilder,
5310 struct ast *a, ast_off_t *ppos) {
5311 enum v7_err rcode = V7_OK;
5312 struct v7 *v7 = bbuilder->v7;
5313 ast_off_t pos_after_tag;
5314 enum ast_tag tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
5315
5316 switch (tag) {
5317 case AST_ADD:
5318 case AST_SUB:
5319 case AST_REM:
5320 case AST_MUL:
5321 case AST_DIV:
5322 case AST_LSHIFT:
5323 case AST_RSHIFT:
5324 case AST_URSHIFT:
5325 case AST_OR:
5326 case AST_XOR:
5327 case AST_AND:
5328 case AST_EQ_EQ:
5329 case AST_EQ:
5330 case AST_NE:
5331 case AST_NE_NE:
5332 case AST_LT:
5333 case AST_LE:
5334 case AST_GT:
5335 case AST_GE:
5336 case AST_INSTANCEOF:
5337 V7_TRY(compile_binary(bbuilder, a, ppos, tag));
5338 break;
5339 case AST_LOGICAL_NOT:
5340 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5341 bcode_op(bbuilder, OP_LOGICAL_NOT);
5342 break;
5343 case AST_NOT:
5344 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5345 bcode_op(bbuilder, OP_NOT);
5346 break;
5347 case AST_POSITIVE:
5348 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5349 bcode_op(bbuilder, OP_POS);
5350 break;
5351 case AST_NEGATIVE:
5352 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5353 bcode_op(bbuilder, OP_NEG);
5354 break;
5355 case AST_IDENT:
5356 bcode_op_lit(bbuilder, OP_GET_VAR,
5357 string_lit(bbuilder, a, pos_after_tag));
5358 break;
5359 case AST_MEMBER:
5360 case AST_INDEX:
5361 /*
5362 * These two are handled by the "extended" version of this function,
5363 * since we may need to put `this` value on stack, for "method pattern
5364 * invocation".
5365 *
5366 * First of all, restore starting AST position, and then call extended
5367 * function.
5368 */
5369 *ppos = pos_after_tag - 1;
5370 V7_TRY(compile_expr_ext(bbuilder, a, ppos, 0 /*not for call*/));
5371 break;
5372 case AST_IN:
5373 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5374 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5375 bcode_op(bbuilder, OP_IN);
5376 break;
5377 case AST_TYPEOF: {
5378 ast_off_t lookahead = *ppos;
5379 tag = fetch_tag(v7, bbuilder, a, &lookahead, &pos_after_tag);
5380 if (tag == AST_IDENT) {
5381 *ppos = lookahead;
5382 bcode_op_lit(bbuilder, OP_SAFE_GET_VAR,
5383 string_lit(bbuilder, a, pos_after_tag));
5384 } else {
5385 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5386 }
5387 bcode_op(bbuilder, OP_TYPEOF);
5388 break;
5389 }
5390 case AST_ASSIGN:
5391 case AST_PREINC:
5392 case AST_PREDEC:
5393 case AST_POSTINC:
5394 case AST_POSTDEC:
5395 case AST_REM_ASSIGN:
5396 case AST_MUL_ASSIGN:
5397 case AST_DIV_ASSIGN:
5398 case AST_XOR_ASSIGN:
5399 case AST_PLUS_ASSIGN:
5400 case AST_MINUS_ASSIGN:
5401 case AST_OR_ASSIGN:
5402 case AST_AND_ASSIGN:
5403 case AST_LSHIFT_ASSIGN:
5404 case AST_RSHIFT_ASSIGN:
5405 case AST_URSHIFT_ASSIGN:
5406 V7_TRY(compile_assign(bbuilder, a, ppos, tag));
5407 break;
5408 case AST_COND: {
5409 /*
5410 * A ? B : C
5411 *
5412 * ->
5413 *
5414 * <A>
5415 * JMP_FALSE false
5416 * <B>
5417 * JMP end
5418 * false:
5419 * <C>
5420 * end:
5421 *
5422 */
5423 bcode_off_t false_label, end_label;
5424 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5425 false_label = bcode_op_target(bbuilder, OP_JMP_FALSE);
5426 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5427 end_label = bcode_op_target(bbuilder, OP_JMP);
5428 bcode_patch_target(bbuilder, false_label, bcode_pos(bbuilder));
5429 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5430 bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
5431 break;
5432 }
5433 case AST_LOGICAL_OR:
5434 case AST_LOGICAL_AND: {
5435 /*
5436 * A && B
5437 *
5438 * ->
5439 *
5440 * <A>
5441 * JMP_FALSE end
5442 * POP
5443 * <B>
5444 * end:
5445 *
5446 */
5447 bcode_off_t end_label;
5448 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5449 bcode_op(bbuilder, OP_DUP);
5450 end_label = bcode_op_target(
5451 bbuilder, tag == AST_LOGICAL_AND ? OP_JMP_FALSE : OP_JMP_TRUE);
5452 bcode_op(bbuilder, OP_DROP);
5453 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5454 bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
5455 break;
5456 }
5457 /*
5458 * A, B, C
5459 *
5460 * ->
5461 *
5462 * <A>
5463 * DROP
5464 * <B>
5465 * DROP
5466 * <C>
5467 */
5468 case AST_SEQ: {
5469 ast_off_t end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
5470 while (*ppos < end) {
5471 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5472 if (*ppos < end) {
5473 bcode_op(bbuilder, OP_DROP);
5474 }
5475 }
5476 break;
5477 }
5478 case AST_CALL:
5479 case AST_NEW: {
5480 /*
5481 * f()
5482 *
5483 * ->
5484 *
5485 * PUSH_UNDEFINED (value for `this`)
5486 * GET_VAR "f"
5487 * CHECK_CALL
5488 * CALL 0 args
5489 *
5490 * ---------------
5491 *
5492 * f(a, b)
5493 *
5494 * ->
5495 *
5496 * PUSH_UNDEFINED (value for `this`)
5497 * GET_VAR "f"
5498 * CHECK_CALL
5499 * GET_VAR "a"
5500 * GET_VAR "b"
5501 * CALL 2 args
5502 *
5503 * ---------------
5504 *
5505 * o.f(a, b)
5506 *
5507 * ->
5508 *
5509 * GET_VAR "o" (so that `this` will be an `o`)
5510 * DUP (we'll also need `o` for GET below, so, duplicate it)
5511 * PUSH_LIT "f"
5512 * GET (get property "f" of the object "o")
5513 * CHECK_CALL
5514 * GET_VAR "a"
5515 * GET_VAR "b"
5516 * CALL 2 args
5517 *
5518 */
5519 int args;
5520 ast_off_t end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
5521
5522 V7_TRY(compile_expr_ext(bbuilder, a, ppos, 1 /*for call*/));
5523 bcode_op(bbuilder, OP_CHECK_CALL);
5524 for (args = 0; *ppos < end; args++) {
5525 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5526 }
5527 bcode_op(bbuilder, (tag == AST_CALL ? OP_CALL : OP_NEW));
5528 if (args > 0x7f) {
5529 rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "too many arguments");
5530 V7_THROW(V7_SYNTAX_ERROR);
5531 }
5532 bcode_op(bbuilder, (uint8_t) args);
5533 break;
5534 }
5535 case AST_DELETE: {
5536 V7_TRY(compile_delete(bbuilder, a, ppos));
5537 break;
5538 }
5539 case AST_OBJECT: {
5540 /*
5541 * {a:<B>, ...}
5542 *
5543 * ->
5544 *
5545 * CREATE_OBJ
5546 * DUP
5547 * PUSH_LIT "a"
5548 * <B>
5549 * SET
5550 * POP
5551 * ...
5552 */
5553
5554 /*
5555 * Literal indices of property names of current object literal.
5556 * Needed for strict mode: we need to keep track of the added
5557 * properties, since duplicates are not allowed
5558 */
5559 struct mbuf cur_literals;
5560 lit_t lit;
5561 ast_off_t end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
5562 mbuf_init(&cur_literals, 0);
5563
5564 bcode_op(bbuilder, OP_CREATE_OBJ);
5565 while (*ppos < end) {
5566 tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
5567 switch (tag) {
5568 case AST_PROP:
5569 bcode_op(bbuilder, OP_DUP);
5570 lit = string_lit(bbuilder, a, pos_after_tag);
5571
5572/* disabled because we broke get_lit */
5573#if 0
5574 if (bbuilder->bcode->strict_mode) {
5575 /*
5576 * In strict mode, check for duplicate property names in
5577 * object literals
5578 */
5579 char *plit;
5580 for (plit = (char *) cur_literals.buf;
5581 (char *) plit < cur_literals.buf + cur_literals.len;
5582 plit++) {
5583 const char *str1, *str2;
5584 size_t size1, size2;
5585 v7_val_t val1, val2;
5586
5587 val1 = bcode_get_lit(bbuilder->bcode, lit);
5588 str1 = v7_get_string(bbuilder->v7, &val1, &size1);
5589
5590 val2 = bcode_get_lit(bbuilder->bcode, *plit);
5591 str2 = v7_get_string(bbuilder->v7, &val2, &size2);
5592
5593 if (size1 == size2 && memcmp(str1, str2, size1) == 0) {
5594 /* found already existing property of the same name */
5595 rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR,
5596 "duplicate data property in object literal "
5597 "is not allowed in strict mode");
5598 V7_THROW2(V7_SYNTAX_ERROR, ast_object_clean);
5599 }
5600 }
5601 mbuf_append(&cur_literals, &lit, sizeof(lit));
5602 }
5603#endif
5604 bcode_push_lit(bbuilder, lit);
5605 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5606 bcode_op(bbuilder, OP_SET);
5607 bcode_op(bbuilder, OP_DROP);
5608 break;
5609 default:
5610 rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "not implemented");
5611 V7_THROW2(V7_SYNTAX_ERROR, ast_object_clean);
5612 }
5613 }
5614
5615 ast_object_clean:
5616 mbuf_free(&cur_literals);
5617 if (rcode != V7_OK) {
5618 V7_THROW(rcode);
5619 }
5620 break;
5621 }
5622 case AST_ARRAY: {
5623 /*
5624 * [<A>,,<B>,...]
5625 *
5626 * ->
5627 *
5628 * CREATE_ARR
5629 * PUSH_ZERO
5630 *
5631 * 2DUP
5632 * <A>
5633 * SET
5634 * POP
5635 * PUSH_ONE
5636 * ADD
5637 *
5638 * PUSH_ONE
5639 * ADD
5640 *
5641 * 2DUP
5642 * <B>
5643 * ...
5644 * POP // tmp index
5645 *
5646 * TODO(mkm): optimize this out. we can have more compact array push
5647 * that uses a special marker value for missing array elements
5648 * (which are not the same as undefined btw)
5649 */
5650 ast_off_t end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
5651 bcode_op(bbuilder, OP_CREATE_ARR);
5652 bcode_op(bbuilder, OP_PUSH_ZERO);
5653 while (*ppos < end) {
5654 ast_off_t lookahead = *ppos;
5655 tag = fetch_tag(v7, bbuilder, a, &lookahead, &pos_after_tag);
5656 if (tag != AST_NOP) {
5657 bcode_op(bbuilder, OP_2DUP);
5658 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5659 bcode_op(bbuilder, OP_SET);
5660 bcode_op(bbuilder, OP_DROP);
5661 } else {
5662 *ppos = lookahead; /* skip nop */
5663 }
5664 bcode_op(bbuilder, OP_PUSH_ONE);
5665 bcode_op(bbuilder, OP_ADD);
5666 }
5667 bcode_op(bbuilder, OP_DROP);
5668 break;
5669 }
5670 case AST_FUNC: {
5671 lit_t flit;
5672
5673 /*
5674 * Create half-done function: without scope and prototype. The real
5675 * function will be created from this one during bcode evaluation: see
5676 * `bcode_instantiate_function()`.
5677 */
5678 val_t funv = mk_js_function(bbuilder->v7, NULL, V7_UNDEFINED);
5679
5680 /* Create bcode in this half-done function */
5681 struct v7_js_function *func = get_js_function_struct(funv);
5682 func->bcode = (struct bcode *) calloc(1, sizeof(*bbuilder->bcode));
5683 bcode_init(func->bcode, bbuilder->bcode->strict_mode,
5684 NULL /* will be set below */, 0);
5685 bcode_copy_filename_from(func->bcode, bbuilder->bcode);
5686 retain_bcode(bbuilder->v7, func->bcode);
5687 flit = bcode_add_lit(bbuilder, funv);
5688
5689 *ppos = pos_after_tag - 1;
5690 V7_TRY(compile_function(v7, a, ppos, func->bcode));
5691 bcode_push_lit(bbuilder, flit);
5692 bcode_op(bbuilder, OP_FUNC_LIT);
5693 break;
5694 }
5695 case AST_THIS:
5696 bcode_op(bbuilder, OP_PUSH_THIS);
5697 break;
5698 case AST_VOID:
5699 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5700 bcode_op(bbuilder, OP_DROP);
5701 bcode_op(bbuilder, OP_PUSH_UNDEFINED);
5702 break;
5703 case AST_NULL:
5704 bcode_op(bbuilder, OP_PUSH_NULL);
5705 break;
5706 case AST_NOP:
5707 case AST_UNDEFINED:
5708 bcode_op(bbuilder, OP_PUSH_UNDEFINED);
5709 break;
5710 case AST_TRUE:
5711 bcode_op(bbuilder, OP_PUSH_TRUE);
5712 break;
5713 case AST_FALSE:
5714 bcode_op(bbuilder, OP_PUSH_FALSE);
5715 break;
5716 case AST_NUM: {
5717 double dv = ast_get_num(a, pos_after_tag);
5718 if (dv == 0) {
5719 bcode_op(bbuilder, OP_PUSH_ZERO);
5720 } else if (dv == 1) {
5721 bcode_op(bbuilder, OP_PUSH_ONE);
5722 } else {
5723 bcode_push_lit(bbuilder, bcode_add_lit(bbuilder, v7_mk_number(v7, dv)));
5724 }
5725 break;
5726 }
5727 case AST_STRING:
5728 bcode_push_lit(bbuilder, string_lit(bbuilder, a, pos_after_tag));
5729 break;
5730 case AST_REGEX:
5731#if V7_ENABLE__RegExp
5732 {
5733 lit_t tmp;
5734 rcode = regexp_lit(bbuilder, a, pos_after_tag, &tmp);
5735 if (rcode != V7_OK) {
5736 rcode = V7_SYNTAX_ERROR;
5737 goto clean;
5738 }
5739
5740 bcode_push_lit(bbuilder, tmp);
5741 break;
5742 }
5743#else
5744 rcode =
5745 v7_throwf(bbuilder->v7, SYNTAX_ERROR, "Regexp support is disabled");
5746 V7_THROW(V7_SYNTAX_ERROR);
5747#endif
5748 case AST_LABEL:
5749 case AST_LABELED_BREAK:
5750 case AST_LABELED_CONTINUE:
5751 /* TODO(dfrank): implement */
5752 rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "not implemented");
5753 V7_THROW(V7_SYNTAX_ERROR);
5754 case AST_WITH:
5755 rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "not implemented");
5756 V7_THROW(V7_SYNTAX_ERROR);
5757 default:
5758 /*
5759 * We end up here if the AST is broken.
5760 *
5761 * It might be appropriate to return `V7_INTERNAL_ERROR` here, but since
5762 * we might receive AST from network or something, we just interpret
5763 * it as SyntaxError.
5764 */
5765 rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "unknown ast node %d",
5766 (int) tag);
5767 V7_THROW(V7_SYNTAX_ERROR);
5768 }
5769clean:
5770 return rcode;
5771}
5772
5773V7_PRIVATE enum v7_err compile_stmt(struct bcode_builder *bbuilder,
5774 struct ast *a, ast_off_t *ppos);
5775
5776V7_PRIVATE enum v7_err compile_stmts(struct bcode_builder *bbuilder,
5777 struct ast *a, ast_off_t *ppos,
5778 ast_off_t end) {
5779 enum v7_err rcode = V7_OK;
5780 struct v7 *v7 = bbuilder->v7;
5781
5782 while (*ppos < end) {
5783 V7_TRY(compile_stmt(bbuilder, a, ppos));
5784 if (!bbuilder->v7->is_stack_neutral) {
5785 bcode_op(bbuilder, OP_SWAP_DROP);
5786 } else {
5787 bbuilder->v7->is_stack_neutral = 0;
5788 }
5789 }
5790clean:
5791 return rcode;
5792}
5793
5794V7_PRIVATE enum v7_err compile_stmt(struct bcode_builder *bbuilder,
5795 struct ast *a, ast_off_t *ppos) {
5796 ast_off_t end;
5797 enum ast_tag tag;
5798 ast_off_t cond, pos_after_tag;
5799 bcode_off_t body_target, body_label, cond_label;
5800 struct mbuf case_labels;
5801 enum v7_err rcode = V7_OK;
5802 struct v7 *v7 = bbuilder->v7;
5803
5804 tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
5805
5806 mbuf_init(&case_labels, 0);
5807
5808 switch (tag) {
5809 /*
5810 * if(E) {
5811 * BT...
5812 * } else {
5813 * BF...
5814 * }
5815 *
5816 * ->
5817 *
5818 * <E>
5819 * JMP_FALSE body
5820 * <BT>
5821 * JMP end
5822 * body:
5823 * <BF>
5824 * end:
5825 *
5826 * If else clause is omitted, it will emit output equivalent to:
5827 *
5828 * if(E) {BT} else undefined;
5829 */
5830 case AST_IF: {
5831 ast_off_t if_false;
5832 bcode_off_t end_label, if_false_label;
5833 end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
5834 if_false = ast_get_skip(a, pos_after_tag, AST_END_IF_TRUE_SKIP);
5835
5836 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
5837 if_false_label = bcode_op_target(bbuilder, OP_JMP_FALSE);
5838
5839 /* body if true */
5840 V7_TRY(compile_stmts(bbuilder, a, ppos, if_false));
5841
5842 if (if_false != end) {
5843 /* `else` branch is present */
5844 end_label = bcode_op_target(bbuilder, OP_JMP);
5845
5846 /* will jump here if `false` */
5847 bcode_patch_target(bbuilder, if_false_label, bcode_pos(bbuilder));
5848
5849 /* body if false */
5850 V7_TRY(compile_stmts(bbuilder, a, ppos, end));
5851
5852 bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
5853 } else {
5854 /*
5855 * `else` branch is not present: just remember where we should
5856 * jump in case of `false`
5857 */
5858 bcode_patch_target(bbuilder, if_false_label, bcode_pos(bbuilder));
5859 }
5860
5861 bbuilder->v7->is_stack_neutral = 1;
5862 break;
5863 }
5864 /*
5865 * while(C) {
5866 * B...
5867 * }
5868 *
5869 * ->
5870 *
5871 * TRY_PUSH_LOOP end
5872 * JMP cond
5873 * body:
5874 * <B>
5875 * cond:
5876 * <C>
5877 * JMP_TRUE body
5878 * end:
5879 * JMP_IF_CONTINUE cond
5880 * TRY_POP
5881 *
5882 */
5883 case AST_WHILE: {
5884 bcode_off_t end_label, continue_label, continue_target;
5885
5886 end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
5887 cond = *ppos;
5888 ast_skip_tree(a, ppos);
5889
5890 end_label = bcode_op_target(bbuilder, OP_TRY_PUSH_LOOP);
5891
5892 /*
5893 * Condition check is at the end of the loop, this layout
5894 * reduces the number of jumps in the steady state.
5895 */
5896 cond_label = bcode_op_target(bbuilder, OP_JMP);
5897 body_target = bcode_pos(bbuilder);
5898
5899 V7_TRY(compile_stmts(bbuilder, a, ppos, end));
5900
5901 continue_target = bcode_pos(bbuilder);
5902 bcode_patch_target(bbuilder, cond_label, continue_target);
5903
5904 V7_TRY(compile_expr_builder(bbuilder, a, &cond));
5905 body_label = bcode_op_target(bbuilder, OP_JMP_TRUE);
5906 bcode_patch_target(bbuilder, body_label, body_target);
5907
5908 bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
5909 continue_label = bcode_op_target(bbuilder, OP_JMP_IF_CONTINUE);
5910 bcode_patch_target(bbuilder, continue_label, continue_target);
5911 bcode_op(bbuilder, OP_TRY_POP);
5912
5913 bbuilder->v7->is_stack_neutral = 1;
5914 break;
5915 }
5916 case AST_BREAK:
5917 bcode_op(bbuilder, OP_BREAK);
5918 break;
5919 case AST_CONTINUE:
5920 bcode_op(bbuilder, OP_CONTINUE);
5921 break;
5922 /*
5923 * Frame objects (`v7->vals.call_stack`) contain one more hidden property:
5924 * `____t`, which is an array of offsets in bcode. Each element of the array
5925 * is an offset of either `catch` or `finally` block (distinguished by the
5926 * tag: `OFFSET_TAG_CATCH` or `OFFSET_TAG_FINALLY`). Let's call this array
5927 * as a "try stack". When evaluator enters new `try` block, it adds
5928 * appropriate offset(s) at the top of "try stack", and when we unwind the
5929 * stack, we can "pop" offsets from "try stack" at each level.
5930 *
5931 * try {
5932 * TRY_B
5933 * } catch (e) {
5934 * CATCH_B
5935 * } finally {
5936 * FIN_B
5937 * }
5938 *
5939 * ->
5940 * OP_TRY_PUSH_FINALLY finally
5941 * OP_TRY_PUSH_CATCH catch
5942 * <TRY_B>
5943 * OP_TRY_POP
5944 * JMP finally
5945 * catch:
5946 * OP_TRY_POP
5947 * OP_ENTER_CATCH <e>
5948 * <CATCH_B>
5949 * OP_EXIT_CATCH
5950 * finally:
5951 * OP_TRY_POP
5952 * <FIN_B>
5953 * OP_AFTER_FINALLY
5954 *
5955 * ---------------
5956 *
5957 * try {
5958 * TRY_B
5959 * } catch (e) {
5960 * CATCH_B
5961 * }
5962 *
5963 * ->
5964 * OP_TRY_PUSH_CATCH catch
5965 * <TRY_B>
5966 * OP_TRY_POP
5967 * JMP end
5968 * catch:
5969 * OP_TRY_POP
5970 * OP_ENTER_CATCH <e>
5971 * <CATCH_B>
5972 * OP_EXIT_CATCH
5973 * end:
5974 *
5975 * ---------------
5976 *
5977 * try {
5978 * TRY_B
5979 * } finally {
5980 * FIN_B
5981 * }
5982 *
5983 * ->
5984 * OP_TRY_PUSH_FINALLY finally
5985 * <TRY_B>
5986 * finally:
5987 * OP_TRY_POP
5988 * <FIN_B>
5989 * OP_AFTER_FINALLY
5990 */
5991 case AST_TRY: {
5992 ast_off_t acatch, afinally;
5993 bcode_off_t finally_label, catch_label;
5994
5995 end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
5996 acatch = ast_get_skip(a, pos_after_tag, AST_TRY_CATCH_SKIP);
5997 afinally = ast_get_skip(a, pos_after_tag, AST_TRY_FINALLY_SKIP);
5998
5999 if (afinally != end) {
6000 /* `finally` clause is present: push its offset */
6001 finally_label = bcode_op_target(bbuilder, OP_TRY_PUSH_FINALLY);
6002 }
6003
6004 if (acatch != afinally) {
6005 /* `catch` clause is present: push its offset */
6006 catch_label = bcode_op_target(bbuilder, OP_TRY_PUSH_CATCH);
6007 }
6008
6009 /* compile statements of `try` block */
6010 V7_TRY(compile_stmts(bbuilder, a, ppos, acatch));
6011
6012 if (acatch != afinally) {
6013 /* `catch` clause is present: compile it */
6014 bcode_off_t after_catch_label;
6015
6016 /*
6017 * pop offset pushed by OP_TRY_PUSH_CATCH, and jump over the `catch`
6018 * block
6019 */
6020 bcode_op(bbuilder, OP_TRY_POP);
6021 after_catch_label = bcode_op_target(bbuilder, OP_JMP);
6022
6023 /* --- catch --- */
6024
6025 /* in case of exception in the `try` block above, we'll get here */
6026 bcode_patch_target(bbuilder, catch_label, bcode_pos(bbuilder));
6027
6028 /* pop offset pushed by OP_TRY_PUSH_CATCH */
6029 bcode_op(bbuilder, OP_TRY_POP);
6030
6031 /*
6032 * retrieve identifier where to store thrown error, and make sure
6033 * it is actually an indentifier (AST_IDENT)
6034 */
6035 tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
6036 V7_CHECK(tag == AST_IDENT, V7_SYNTAX_ERROR);
6037
6038 /*
6039 * when we enter `catch` block, the TOS contains thrown value.
6040 * We should create private frame for the `catch` clause, and populate
6041 * a variable with the thrown value there.
6042 * The `OP_ENTER_CATCH` opcode does just that.
6043 */
6044 bcode_op_lit(bbuilder, OP_ENTER_CATCH,
6045 string_lit(bbuilder, a, pos_after_tag));
6046
6047 /*
6048 * compile statements until the end of `catch` clause
6049 * (`afinally` points to the end of the `catch` clause independently
6050 * of whether the `finally` clause is present)
6051 */
6052 V7_TRY(compile_stmts(bbuilder, a, ppos, afinally));
6053
6054 /* pop private frame */
6055 bcode_op(bbuilder, OP_EXIT_CATCH);
6056
6057 bcode_patch_target(bbuilder, after_catch_label, bcode_pos(bbuilder));
6058 }
6059
6060 if (afinally != end) {
6061 /* `finally` clause is present: compile it */
6062
6063 /* --- finally --- */
6064
6065 /* after the `try` block above executes, we'll get here */
6066 bcode_patch_target(bbuilder, finally_label, bcode_pos(bbuilder));
6067
6068 /* pop offset pushed by OP_TRY_PUSH_FINALLY */
6069 bcode_op(bbuilder, OP_TRY_POP);
6070
6071 /* compile statements until the end of `finally` clause */
6072 V7_TRY(compile_stmts(bbuilder, a, ppos, end));
6073
6074 bcode_op(bbuilder, OP_AFTER_FINALLY);
6075 }
6076
6077 bbuilder->v7->is_stack_neutral = 1;
6078 break;
6079 }
6080
6081 case AST_THROW: {
6082 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
6083 bcode_op(bbuilder, OP_THROW);
6084 break;
6085 }
6086
6087 /*
6088 * switch(E) {
6089 * default:
6090 * D...
6091 * case C1:
6092 * B1...
6093 * case C2:
6094 * B2...
6095 * }
6096 *
6097 * ->
6098 *
6099 * TRY_PUSH_SWITCH end
6100 * <E>
6101 * DUP
6102 * <C1>
6103 * EQ
6104 * JMP_TRUE_DROP l1
6105 * DUP
6106 * <C2>
6107 * EQ
6108 * JMP_TRUE_DROP l2
6109 * DROP
6110 * JMP dfl
6111 *
6112 * dfl:
6113 * <D>
6114 *
6115 * l1:
6116 * <B1>
6117 *
6118 * l2:
6119 * <B2>
6120 *
6121 * end:
6122 * TRY_POP
6123 *
6124 * If the default case is missing we treat it as if had an empty body and
6125 * placed in last position (i.e. `dfl` label is replaced with `end`).
6126 *
6127 * Before emitting a case/default block (except the first one) we have to
6128 * drop the TOS resulting from evaluating the last expression
6129 */
6130 case AST_SWITCH: {
6131 bcode_off_t dfl_label, end_label;
6132 ast_off_t case_end, case_start;
6133 enum ast_tag case_tag;
6134 int i, has_default = 0, cases = 0;
6135
6136 end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
6137
6138 end_label = bcode_op_target(bbuilder, OP_TRY_PUSH_SWITCH);
6139
6140 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
6141
6142 case_start = *ppos;
6143 /* first pass: evaluate case expression and generate jump table */
6144 while (*ppos < end) {
6145 case_tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
6146 assert(case_tag == AST_DEFAULT || case_tag == AST_CASE);
6147
6148 case_end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
6149
6150 switch (case_tag) {
6151 case AST_DEFAULT:
6152 /* default jump table entry must be the last one */
6153 break;
6154 case AST_CASE: {
6155 bcode_off_t case_label;
6156 bcode_op(bbuilder, OP_DUP);
6157 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
6158 bcode_op(bbuilder, OP_EQ);
6159 case_label = bcode_op_target(bbuilder, OP_JMP_TRUE_DROP);
6160 cases++;
6161 mbuf_append(&case_labels, &case_label, sizeof(case_label));
6162 break;
6163 }
6164 default:
6165 assert(case_tag == AST_DEFAULT || case_tag == AST_CASE);
6166 }
6167 *ppos = case_end;
6168 }
6169
6170 /* jmp table epilogue: unconditional jump to default case */
6171 bcode_op(bbuilder, OP_DROP);
6172 dfl_label = bcode_op_target(bbuilder, OP_JMP);
6173
6174 *ppos = case_start;
6175 /* second pass: emit case bodies and patch jump table */
6176
6177 for (i = 0; *ppos < end;) {
6178 case_tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
6179 assert(case_tag == AST_DEFAULT || case_tag == AST_CASE);
6180 assert(i <= cases);
6181
6182 case_end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
6183
6184 switch (case_tag) {
6185 case AST_DEFAULT:
6186 has_default = 1;
6187 bcode_patch_target(bbuilder, dfl_label, bcode_pos(bbuilder));
6188 V7_TRY(compile_stmts(bbuilder, a, ppos, case_end));
6189 break;
6190 case AST_CASE: {
6191 bcode_off_t case_label = ((bcode_off_t *) case_labels.buf)[i++];
6192 bcode_patch_target(bbuilder, case_label, bcode_pos(bbuilder));
6193 ast_skip_tree(a, ppos);
6194 V7_TRY(compile_stmts(bbuilder, a, ppos, case_end));
6195 break;
6196 }
6197 default:
6198 assert(case_tag == AST_DEFAULT || case_tag == AST_CASE);
6199 }
6200
6201 *ppos = case_end;
6202 }
6203 mbuf_free(&case_labels);
6204
6205 if (!has_default) {
6206 bcode_patch_target(bbuilder, dfl_label, bcode_pos(bbuilder));
6207 }
6208
6209 bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
6210 bcode_op(bbuilder, OP_TRY_POP);
6211
6212 bbuilder->v7->is_stack_neutral = 1;
6213 break;
6214 }
6215 /*
6216 * for(INIT,COND,IT) {
6217 * B...
6218 * }
6219 *
6220 * ->
6221 *
6222 * <INIT>
6223 * DROP
6224 * TRY_PUSH_LOOP end
6225 * JMP cond
6226 * body:
6227 * <B>
6228 * next:
6229 * <IT>
6230 * DROP
6231 * cond:
6232 * <COND>
6233 * JMP_TRUE body
6234 * end:
6235 * JMP_IF_CONTINUE next
6236 * TRY_POP
6237 *
6238 */
6239 case AST_FOR: {
6240 ast_off_t iter, body, lookahead;
6241 bcode_off_t end_label, continue_label, continue_target;
6242 end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
6243 body = ast_get_skip(a, pos_after_tag, AST_FOR_BODY_SKIP);
6244
6245 lookahead = *ppos;
6246 tag = fetch_tag(v7, bbuilder, a, &lookahead, &pos_after_tag);
6247 /*
6248 * Support for `var` declaration in INIT
6249 */
6250 if (tag == AST_VAR) {
6251 ast_off_t fvar_end;
6252 lit_t lit;
6253
6254 *ppos = lookahead;
6255 fvar_end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
6256
6257 /*
6258 * Iterate through all vars in the given `var` declaration: they are
6259 * just like assigments here
6260 */
6261 while (*ppos < fvar_end) {
6262 tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
6263 /* Only var declarations are allowed (not function declarations) */
6264 V7_CHECK_INTERNAL(tag == AST_VAR_DECL);
6265 lit = string_lit(bbuilder, a, pos_after_tag);
6266 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
6267
6268 /* Just like an assigment */
6269 bcode_op_lit(bbuilder, OP_SET_VAR, lit);
6270
6271 /* INIT is stack-neutral */
6272 bcode_op(bbuilder, OP_DROP);
6273 }
6274 } else {
6275 /* normal expression in INIT (not `var` declaration) */
6276 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
6277 /* INIT is stack-neutral */
6278 bcode_op(bbuilder, OP_DROP);
6279 }
6280 cond = *ppos;
6281 ast_skip_tree(a, ppos);
6282 iter = *ppos;
6283 *ppos = body;
6284
6285 end_label = bcode_op_target(bbuilder, OP_TRY_PUSH_LOOP);
6286 cond_label = bcode_op_target(bbuilder, OP_JMP);
6287 body_target = bcode_pos(bbuilder);
6288 V7_TRY(compile_stmts(bbuilder, a, ppos, end));
6289
6290 continue_target = bcode_pos(bbuilder);
6291
6292 V7_TRY(compile_expr_builder(bbuilder, a, &iter));
6293 bcode_op(bbuilder, OP_DROP);
6294
6295 bcode_patch_target(bbuilder, cond_label, bcode_pos(bbuilder));
6296
6297 /*
6298 * Handle for(INIT;;ITER)
6299 */
6300 lookahead = cond;
6301 tag = fetch_tag(v7, bbuilder, a, &lookahead, &pos_after_tag);
6302 if (tag == AST_NOP) {
6303 bcode_op(bbuilder, OP_JMP);
6304 } else {
6305 V7_TRY(compile_expr_builder(bbuilder, a, &cond));
6306 bcode_op(bbuilder, OP_JMP_TRUE);
6307 }
6308 body_label = bcode_add_target(bbuilder);
6309 bcode_patch_target(bbuilder, body_label, body_target);
6310 bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
6311
6312 continue_label = bcode_op_target(bbuilder, OP_JMP_IF_CONTINUE);
6313 bcode_patch_target(bbuilder, continue_label, continue_target);
6314
6315 bcode_op(bbuilder, OP_TRY_POP);
6316
6317 bbuilder->v7->is_stack_neutral = 1;
6318 break;
6319 }
6320 /*
6321 * for(I in O) {
6322 * B...
6323 * }
6324 *
6325 * ->
6326 *
6327 * DUP
6328 * <O>
6329 * SWAP
6330 * STASH
6331 * DROP
6332 * PUSH_PROP_ITER_CTX # push initial iteration context
6333 * TRY_PUSH_LOOP brend
6334 * loop:
6335 * NEXT_PROP
6336 * JMP_FALSE end
6337 * SET_VAR <I>
6338 * UNSTASH
6339 * <B>
6340 * next:
6341 * STASH
6342 * DROP
6343 * JMP loop
6344 * end:
6345 * UNSTASH
6346 * JMP try_pop:
6347 * brend:
6348 * # got here after a `break` or `continue` from a loop body:
6349 * JMP_IF_CONTINUE next
6350 *
6351 * # we're not going to `continue`, so, need to remove an
6352 * # extra stuff that was needed for the NEXT_PROP
6353 *
6354 * SWAP_DROP # drop iteration context
6355 * SWAP_DROP # drop <O>
6356 * SWAP_DROP # drop the value preceding the loop
6357 * try_pop:
6358 * TRY_POP
6359 *
6360 */
6361 case AST_FOR_IN: {
6362 lit_t lit;
6363 bcode_off_t loop_label, loop_target, end_label, brend_label,
6364 continue_label, pop_label, continue_target;
6365 ast_off_t end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
6366
6367 tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
6368 /* TODO(mkm) accept any l-value */
6369 if (tag == AST_VAR) {
6370 tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
6371 V7_CHECK_INTERNAL(tag == AST_VAR_DECL);
6372 lit = string_lit(bbuilder, a, pos_after_tag);
6373 ast_skip_tree(a, ppos);
6374 } else {
6375 V7_CHECK_INTERNAL(tag == AST_IDENT);
6376 lit = string_lit(bbuilder, a, pos_after_tag);
6377 }
6378
6379 /*
6380 * preserve previous statement value.
6381 * We need to feed the previous value into the stash
6382 * because it's required for the loop steady state.
6383 *
6384 * The stash register is required to simplify the steady state stack
6385 * management, in particular the removal of value in 3rd position in case
6386 * a of not taken exit.
6387 *
6388 * TODO(mkm): consider having a stash OP that moves a value to the stash
6389 * register instead of copying it. The current behaviour has been
6390 * optimized for the `assign` use case which seems more common.
6391 */
6392 bcode_op(bbuilder, OP_DUP);
6393 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
6394 bcode_op(bbuilder, OP_SWAP);
6395 bcode_op(bbuilder, OP_STASH);
6396 bcode_op(bbuilder, OP_DROP);
6397
6398 /*
6399 * OP_NEXT_PROP needs the iteration context, let's push the initial one.
6400 */
6401 bcode_op(bbuilder, OP_PUSH_PROP_ITER_CTX);
6402
6403 brend_label = bcode_op_target(bbuilder, OP_TRY_PUSH_LOOP);
6404
6405 /* loop: */
6406 loop_target = bcode_pos(bbuilder);
6407
6408 /*
6409 * The loop stead state begins with the following stack layout:
6410 * `( S:v o h )`
6411 */
6412
6413 bcode_op(bbuilder, OP_NEXT_PROP);
6414 end_label = bcode_op_target(bbuilder, OP_JMP_FALSE);
6415 bcode_op_lit(bbuilder, OP_SET_VAR, lit);
6416
6417 /*
6418 * The stash register contains the value of the previous statement,
6419 * being it the statement before the for..in statement or
6420 * the previous iteration. We move it to the data stack. It will
6421 * be replaced by the values of the body statements as usual.
6422 */
6423 bcode_op(bbuilder, OP_UNSTASH);
6424
6425 /*
6426 * This node is always a NOP, for compatibility
6427 * with the layout of the AST_FOR node.
6428 */
6429 ast_skip_tree(a, ppos);
6430
6431 V7_TRY(compile_stmts(bbuilder, a, ppos, end));
6432
6433 continue_target = bcode_pos(bbuilder);
6434
6435 /*
6436 * Save the last body statement. If next evaluation of NEXT_PROP returns
6437 * false, we'll unstash it.
6438 */
6439 bcode_op(bbuilder, OP_STASH);
6440 bcode_op(bbuilder, OP_DROP);
6441
6442 loop_label = bcode_op_target(bbuilder, OP_JMP);
6443 bcode_patch_target(bbuilder, loop_label, loop_target);
6444
6445 /* end: */
6446 bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
6447 bcode_op(bbuilder, OP_UNSTASH);
6448
6449 pop_label = bcode_op_target(bbuilder, OP_JMP);
6450
6451 /* brend: */
6452 bcode_patch_target(bbuilder, brend_label, bcode_pos(bbuilder));
6453
6454 continue_label = bcode_op_target(bbuilder, OP_JMP_IF_CONTINUE);
6455 bcode_patch_target(bbuilder, continue_label, continue_target);
6456
6457 bcode_op(bbuilder, OP_SWAP_DROP);
6458 bcode_op(bbuilder, OP_SWAP_DROP);
6459 bcode_op(bbuilder, OP_SWAP_DROP);
6460
6461 /* try_pop: */
6462 bcode_patch_target(bbuilder, pop_label, bcode_pos(bbuilder));
6463
6464 bcode_op(bbuilder, OP_TRY_POP);
6465
6466 bbuilder->v7->is_stack_neutral = 1;
6467 break;
6468 }
6469 /*
6470 * do {
6471 * B...
6472 * } while(COND);
6473 *
6474 * ->
6475 *
6476 * TRY_PUSH_LOOP end
6477 * body:
6478 * <B>
6479 * cond:
6480 * <COND>
6481 * JMP_TRUE body
6482 * end:
6483 * JMP_IF_CONTINUE cond
6484 * TRY_POP
6485 *
6486 */
6487 case AST_DOWHILE: {
6488 bcode_off_t end_label, continue_label, continue_target;
6489 end = ast_get_skip(a, pos_after_tag, AST_DO_WHILE_COND_SKIP);
6490 end_label = bcode_op_target(bbuilder, OP_TRY_PUSH_LOOP);
6491 body_target = bcode_pos(bbuilder);
6492 V7_TRY(compile_stmts(bbuilder, a, ppos, end));
6493
6494 continue_target = bcode_pos(bbuilder);
6495 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
6496 body_label = bcode_op_target(bbuilder, OP_JMP_TRUE);
6497 bcode_patch_target(bbuilder, body_label, body_target);
6498
6499 bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
6500 continue_label = bcode_op_target(bbuilder, OP_JMP_IF_CONTINUE);
6501 bcode_patch_target(bbuilder, continue_label, continue_target);
6502 bcode_op(bbuilder, OP_TRY_POP);
6503
6504 bbuilder->v7->is_stack_neutral = 1;
6505 break;
6506 }
6507 case AST_VAR: {
6508 /*
6509 * Var decls are hoisted when the function frame is created. Vars
6510 * declared inside a `with` or `catch` block belong to the function
6511 * lexical scope, and although those clauses create an inner frame
6512 * no new variables should be created in it. A var decl thus
6513 * behaves as a normal assignment at runtime.
6514 */
6515 lit_t lit;
6516 end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
6517 while (*ppos < end) {
6518 tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
6519 if (tag == AST_FUNC_DECL) {
6520 /*
6521 * function declarations are already set during hoisting (see
6522 * `compile_local_vars()`), so, skip it.
6523 *
6524 * Plus, they are stack-neutral, so don't forget to set
6525 * `is_stack_neutral`.
6526 */
6527 ast_skip_tree(a, ppos);
6528 bbuilder->v7->is_stack_neutral = 1;
6529 } else {
6530 /*
6531 * compile `var` declaration: basically it looks similar to an
6532 * assignment, but it differs from an assignment is that it's
6533 * stack-neutral: `1; var a = 5;` yields `1`, not `5`.
6534 */
6535 V7_CHECK_INTERNAL(tag == AST_VAR_DECL);
6536 lit = string_lit(bbuilder, a, pos_after_tag);
6537 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
6538 bcode_op_lit(bbuilder, OP_SET_VAR, lit);
6539
6540 /* `var` declaration is stack-neutral */
6541 bcode_op(bbuilder, OP_DROP);
6542 bbuilder->v7->is_stack_neutral = 1;
6543 }
6544 }
6545 break;
6546 }
6547 case AST_RETURN:
6548 bcode_op(bbuilder, OP_PUSH_UNDEFINED);
6549 bcode_op(bbuilder, OP_RET);
6550 break;
6551 case AST_VALUE_RETURN:
6552 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
6553 bcode_op(bbuilder, OP_RET);
6554 break;
6555 default:
6556 *ppos = pos_after_tag - 1;
6557 V7_TRY(compile_expr_builder(bbuilder, a, ppos));
6558 }
6559
6560clean:
6561 mbuf_free(&case_labels);
6562 return rcode;
6563}
6564
6565static enum v7_err compile_body(struct bcode_builder *bbuilder, struct ast *a,
6566 ast_off_t start, ast_off_t end, ast_off_t body,
6567 ast_off_t fvar, ast_off_t *ppos) {
6568 enum v7_err rcode = V7_OK;
6569 struct v7 *v7 = bbuilder->v7;
6570
6571#ifndef V7_FORCE_STRICT_MODE
6572 /* check 'use strict' */
6573 if (*ppos < end) {
6574 ast_off_t tmp_pos = body;
6575 if (fetch_tag(v7, bbuilder, a, &tmp_pos, NULL) == AST_USE_STRICT) {
6576 bbuilder->bcode->strict_mode = 1;
6577 /* move `body` offset, effectively removing `AST_USE_STRICT` from it */
6578 body = tmp_pos;
6579 }
6580 }
6581#endif
6582
6583 /* put initial value for the function body execution */
6584 bcode_op(bbuilder, OP_PUSH_UNDEFINED);
6585
6586 /*
6587 * populate `bcode->ops` with function's local variable names. Note that we
6588 * should do this *after* `OP_PUSH_UNDEFINED`, since `compile_local_vars`
6589 * emits code that assigns the hoisted functions to local variables, and
6590 * those statements assume that the stack contains `undefined`.
6591 */
6592 V7_TRY(compile_local_vars(bbuilder, a, start, fvar));
6593
6594 /* compile body */
6595 *ppos = body;
6596 V7_TRY(compile_stmts(bbuilder, a, ppos, end));
6597
6598clean:
6599 return rcode;
6600}
6601
6602/*
6603 * Compiles a given script and populates a bcode structure.
6604 * The AST must start with an AST_SCRIPT node.
6605 */
6606V7_PRIVATE enum v7_err compile_script(struct v7 *v7, struct ast *a,
6607 struct bcode *bcode) {
6608 ast_off_t pos_after_tag, end, fvar, pos = 0;
6609 int saved_line_no = v7->line_no;
6610 enum v7_err rcode = V7_OK;
6611 struct bcode_builder bbuilder;
6612 enum ast_tag tag;
6613
6614 bcode_builder_init(v7, &bbuilder, bcode);
6615 v7->line_no = 1;
6616
6617 tag = fetch_tag(v7, &bbuilder, a, &pos, &pos_after_tag);
6618
6619 /* first tag should always be AST_SCRIPT */
6620 assert(tag == AST_SCRIPT);
6621 (void) tag;
6622
6623 end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
6624 fvar = ast_get_skip(a, pos_after_tag, AST_FUNC_FIRST_VAR_SKIP) - 1;
6625
6626 V7_TRY(compile_body(&bbuilder, a, pos_after_tag - 1, end, pos /* body */,
6627 fvar, &pos));
6628
6629clean:
6630
6631 bcode_builder_finalize(&bbuilder);
6632
6633#ifdef V7_BCODE_DUMP
6634 if (rcode == V7_OK) {
6635 fprintf(stderr, "--- script ---\n");
6636 dump_bcode(v7, stderr, bcode);
6637 }
6638#endif
6639
6640 v7->line_no = saved_line_no;
6641
6642 return rcode;
6643}
6644
6645/*
6646 * Compiles a given function and populates a bcode structure.
6647 * The AST must contain an AST_FUNC node at offset ast_off.
6648 */
6649V7_PRIVATE enum v7_err compile_function(struct v7 *v7, struct ast *a,
6650 ast_off_t *ppos, struct bcode *bcode) {
6651 ast_off_t pos_after_tag, start, end, body, fvar;
6652 const char *name;
6653 size_t name_len;
6654 size_t args_cnt;
6655 enum v7_err rcode = V7_OK;
6656 struct bcode_builder bbuilder;
6657 enum ast_tag tag;
6658 size_t names_end = 0;
6659 bcode_builder_init(v7, &bbuilder, bcode);
6660 tag = fetch_tag(v7, &bbuilder, a, ppos, &pos_after_tag);
6661 start = pos_after_tag - 1;
6662
6663 (void) tag;
6664 assert(tag == AST_FUNC);
6665 end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
6666 body = ast_get_skip(a, pos_after_tag, AST_FUNC_BODY_SKIP);
6667 fvar = ast_get_skip(a, pos_after_tag, AST_FUNC_FIRST_VAR_SKIP) - 1;
6668
6669 /* retrieve function name */
6670 tag = fetch_tag(v7, &bbuilder, a, ppos, &pos_after_tag);
6671 if (tag == AST_IDENT) {
6672 /* function name is provided */
6673 name = ast_get_inlined_data(a, pos_after_tag, &name_len);
6674 V7_TRY(bcode_add_name(&bbuilder, name, name_len, &names_end));
6675 } else {
6676 /* no name: anonymous function */
6677 V7_TRY(bcode_add_name(&bbuilder, "", 0, &names_end));
6678 }
6679
6680 /* retrieve function's argument names */
6681 for (args_cnt = 0; *ppos < body; args_cnt++) {
6682 if (args_cnt > V7_ARGS_CNT_MAX) {
6683 /* too many arguments */
6684 rcode = v7_throwf(v7, SYNTAX_ERROR, "Too many arguments");
6685 V7_THROW(V7_SYNTAX_ERROR);
6686 }
6687
6688 tag = fetch_tag(v7, &bbuilder, a, ppos, &pos_after_tag);
6689 /*
6690 * TODO(dfrank): it's not actually an internal error, we get here if
6691 * we compile e.g. the following: (function(1){})
6692 */
6693 V7_CHECK_INTERNAL(tag == AST_IDENT);
6694 name = ast_get_inlined_data(a, pos_after_tag, &name_len);
6695 V7_TRY(bcode_add_name(&bbuilder, name, name_len, &names_end));
6696 }
6697
6698 bcode->args_cnt = args_cnt;
6699 bcode->func_name_present = 1;
6700
6701 V7_TRY(compile_body(&bbuilder, a, start, end, body, fvar, ppos));
6702
6703clean:
6704 bcode_builder_finalize(&bbuilder);
6705
6706#ifdef V7_BCODE_DUMP
6707 if (rcode == V7_OK) {
6708 fprintf(stderr, "--- function ---\n");
6709 dump_bcode(v7, stderr, bcode);
6710 }
6711#endif
6712
6713 return rcode;
6714}
6715
6716V7_PRIVATE enum v7_err compile_expr(struct v7 *v7, struct ast *a,
6717 ast_off_t *ppos, struct bcode *bcode) {
6718 enum v7_err rcode = V7_OK;
6719 struct bcode_builder bbuilder;
6720 int saved_line_no = v7->line_no;
6721
6722 bcode_builder_init(v7, &bbuilder, bcode);
6723 v7->line_no = 1;
6724
6725 rcode = compile_expr_builder(&bbuilder, a, ppos);
6726
6727 bcode_builder_finalize(&bbuilder);
6728 v7->line_no = saved_line_no;
6729 return rcode;
6730}
6731
6732#endif /* V7_NO_COMPILER */
6733#ifdef V7_MODULE_LINES
6734#line 1 "v7/src/stdlib.c"
6735#endif
6736/*
6737 * Copyright (c) 2014 Cesanta Software Limited
6738 * All rights reserved
6739 */
6740
6741/* Amalgamated: #include "common/cs_strtod.h" */
6742
6743/* Amalgamated: #include "v7/src/internal.h" */
6744/* Amalgamated: #include "v7/src/core.h" */
6745/* Amalgamated: #include "v7/src/primitive.h" */
6746/* Amalgamated: #include "v7/src/conversion.h" */
6747/* Amalgamated: #include "v7/src/stdlib.h" */
6748/* Amalgamated: #include "v7/src/std_array.h" */
6749/* Amalgamated: #include "v7/src/std_boolean.h" */
6750/* Amalgamated: #include "v7/src/std_date.h" */
6751/* Amalgamated: #include "v7/src/std_error.h" */
6752/* Amalgamated: #include "v7/src/std_function.h" */
6753/* Amalgamated: #include "v7/src/std_json.h" */
6754/* Amalgamated: #include "v7/src/std_math.h" */
6755/* Amalgamated: #include "v7/src/std_number.h" */
6756/* Amalgamated: #include "v7/src/std_object.h" */
6757/* Amalgamated: #include "v7/src/std_regex.h" */
6758/* Amalgamated: #include "v7/src/std_string.h" */
6759/* Amalgamated: #include "v7/src/std_proxy.h" */
6760/* Amalgamated: #include "v7/src/js_stdlib.h" */
6761/* Amalgamated: #include "v7/src/object.h" */
6762/* Amalgamated: #include "v7/src/string.h" */
6763/* Amalgamated: #include "v7/src/util.h" */
6764/* Amalgamated: #include "v7/src/exec.h" */
6765
6766#ifdef NO_LIBC
6767void print_str(const char *str);
6768#endif
6769
6770WARN_UNUSED_RESULT
6771V7_PRIVATE enum v7_err Std_print(struct v7 *v7, v7_val_t *res) {
6772 enum v7_err rcode = V7_OK;
6773 int i, num_args = v7_argc(v7);
6774 val_t v;
6775
6776 (void) res;
6777
6778 for (i = 0; i < num_args; i++) {
6779 v = v7_arg(v7, i);
6780 if (v7_is_string(v)) {
6781 size_t n;
6782 const char *s = v7_get_string(v7, &v, &n);
6783 printf("%.*s", (int) n, s);
6784 } else {
6785 v7_print(v7, v);
6786 }
6787 printf(" ");
6788 }
6789 printf(ENDL);
6790
6791 return rcode;
6792}
6793
6794WARN_UNUSED_RESULT
6795V7_PRIVATE enum v7_err std_eval(struct v7 *v7, v7_val_t arg, val_t this_obj,
6796 int is_json, v7_val_t *res) {
6797 enum v7_err rcode = V7_OK;
6798 char buf[100], *p = buf;
6799 struct v7_exec_opts opts;
6800 memset(&opts, 0x00, sizeof(opts));
6801 opts.filename = "Eval'd code";
6802
6803 if (arg != V7_UNDEFINED) {
6804 size_t len;
6805 rcode = to_string(v7, arg, NULL, buf, sizeof(buf), &len);
6806 if (rcode != V7_OK) {
6807 goto clean;
6808 }
6809
6810 /* Fit null terminating byte and quotes */
6811 if (len >= sizeof(buf) - 2) {
6812 /* Buffer is not large enough. Allocate a bigger one */
6813 p = (char *) malloc(len + 3);
6814 rcode = to_string(v7, arg, NULL, p, len + 2, NULL);
6815 if (rcode != V7_OK) {
6816 goto clean;
6817 }
6818 }
6819
6820 v7_set_gc_enabled(v7, 1);
6821 if (is_json) {
6822 opts.is_json = 1;
6823 } else {
6824 opts.this_obj = this_obj;
6825 }
6826 rcode = v7_exec_opt(v7, p, &opts, res);
6827 if (rcode != V7_OK) {
6828 goto clean;
6829 }
6830 }
6831
6832clean:
6833 if (p != buf) {
6834 free(p);
6835 }
6836
6837 return rcode;
6838}
6839
6840WARN_UNUSED_RESULT
6841V7_PRIVATE enum v7_err Std_eval(struct v7 *v7, v7_val_t *res) {
6842 val_t this_obj = v7_get_this(v7);
6843 v7_val_t arg = v7_arg(v7, 0);
6844 return std_eval(v7, arg, this_obj, 0, res);
6845}
6846
6847WARN_UNUSED_RESULT
6848V7_PRIVATE enum v7_err Std_parseInt(struct v7 *v7, v7_val_t *res) {
6849 enum v7_err rcode = V7_OK;
6850 v7_val_t arg0 = V7_UNDEFINED;
6851 v7_val_t arg1 = V7_UNDEFINED;
6852 long sign = 1, base, n;
6853 char buf[20], *p = buf, *end;
6854
6855 *res = V7_TAG_NAN;
6856
6857 arg0 = v7_arg(v7, 0);
6858 arg1 = v7_arg(v7, 1);
6859
6860 rcode = to_string(v7, arg0, &arg0, NULL, 0, NULL);
6861 if (rcode != V7_OK) {
6862 goto clean;
6863 }
6864
6865 rcode = to_number_v(v7, arg1, &arg1);
6866 if (rcode != V7_OK) {
6867 goto clean;
6868 }
6869
6870 if (is_finite(v7, arg1)) {
6871 base = v7_get_double(v7, arg1);
6872 } else {
6873 base = 0;
6874 }
6875
6876 if (base == 0) {
6877 base = 10;
6878 }
6879
6880 if (base < 2 || base > 36) {
6881 *res = V7_TAG_NAN;
6882 goto clean;
6883 }
6884
6885 {
6886 size_t str_len;
6887 p = (char *) v7_get_string(v7, &arg0, &str_len);
6888 }
6889
6890 /* Strip leading whitespaces */
6891 while (*p != '\0' && isspace(*(unsigned char *) p)) {
6892 p++;
6893 }
6894
6895 if (*p == '+') {
6896 sign = 1;
6897 p++;
6898 } else if (*p == '-') {
6899 sign = -1;
6900 p++;
6901 }
6902
6903 if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
6904 base = 16;
6905 p += 2;
6906 }
6907
6908 n = strtol(p, &end, base);
6909
6910 *res = (p == end) ? V7_TAG_NAN : v7_mk_number(v7, n * sign);
6911
6912clean:
6913 return rcode;
6914}
6915
6916WARN_UNUSED_RESULT
6917V7_PRIVATE enum v7_err Std_parseFloat(struct v7 *v7, v7_val_t *res) {
6918 enum v7_err rcode = V7_OK;
6919 v7_val_t arg0 = V7_UNDEFINED;
6920 char buf[20], *p = buf, *end;
6921 double result;
6922
6923 rcode = to_primitive(v7, v7_arg(v7, 0), V7_TO_PRIMITIVE_HINT_NUMBER, &arg0);
6924 if (rcode != V7_OK) {
6925 goto clean;
6926 }
6927
6928 if (v7_is_string(arg0)) {
6929 size_t str_len;
6930 p = (char *) v7_get_string(v7, &arg0, &str_len);
6931 } else {
6932 rcode = to_string(v7, arg0, NULL, buf, sizeof(buf), NULL);
6933 if (rcode != V7_OK) {
6934 goto clean;
6935 }
6936 buf[sizeof(buf) - 1] = '\0';
6937 }
6938
6939 while (*p != '\0' && isspace(*(unsigned char *) p)) {
6940 p++;
6941 }
6942
6943 result = cs_strtod(p, &end);
6944
6945 *res = (p == end) ? V7_TAG_NAN : v7_mk_number(v7, result);
6946
6947clean:
6948 return rcode;
6949}
6950
6951WARN_UNUSED_RESULT
6952V7_PRIVATE enum v7_err Std_isNaN(struct v7 *v7, v7_val_t *res) {
6953 enum v7_err rcode = V7_OK;
6954 v7_val_t arg0 = V7_TAG_NAN;
6955 rcode = to_number_v(v7, v7_arg(v7, 0), &arg0);
6956 if (rcode != V7_OK) {
6957 goto clean;
6958 }
6959
6960 *res = v7_mk_boolean(v7, isnan(v7_get_double(v7, arg0)));
6961
6962clean:
6963 return rcode;
6964}
6965
6966WARN_UNUSED_RESULT
6967V7_PRIVATE enum v7_err Std_isFinite(struct v7 *v7, v7_val_t *res) {
6968 enum v7_err rcode = V7_OK;
6969 v7_val_t arg0 = V7_TAG_NAN;
6970
6971 rcode = to_number_v(v7, v7_arg(v7, 0), &arg0);
6972 if (rcode != V7_OK) {
6973 goto clean;
6974 }
6975
6976 *res = v7_mk_boolean(v7, is_finite(v7, arg0));
6977
6978clean:
6979 return rcode;
6980}
6981
6982#ifndef NO_LIBC
6983WARN_UNUSED_RESULT
6984V7_PRIVATE enum v7_err Std_exit(struct v7 *v7, v7_val_t *res) {
6985 enum v7_err rcode = V7_OK;
6986 long exit_code;
6987
6988 (void) res;
6989
6990 rcode = to_long(v7, v7_arg(v7, 0), 0, &exit_code);
6991 if (rcode != V7_OK) {
6992 /* `to_long` has thrown, so, will return 1 */
6993 exit_code = 1;
6994 }
6995 exit(exit_code);
6996
6997 return rcode;
6998}
6999#endif
7000
7001/*
7002 * Initialize standard library.
7003 *
7004 * This function is used only internally, but used in a complicated mix of
7005 * configurations, hence the commented V7_PRIVATE
7006 */
7007/*V7_PRIVATE*/ void init_stdlib(struct v7 *v7) {
7008 v7_prop_attr_desc_t attr_internal =
7009 (V7_DESC_ENUMERABLE(0) | V7_DESC_WRITABLE(0) | V7_DESC_CONFIGURABLE(0));
7010
7011 /*
7012 * Ensure the first call to v7_mk_value will use a null proto:
7013 * {}.__proto__.__proto__ == null
7014 */
7015 v7->vals.object_prototype = mk_object(v7, V7_NULL);
7016 v7->vals.array_prototype = v7_mk_object(v7);
7017 v7->vals.boolean_prototype = v7_mk_object(v7);
7018 v7->vals.string_prototype = v7_mk_object(v7);
7019 v7->vals.regexp_prototype = v7_mk_object(v7);
7020 v7->vals.number_prototype = v7_mk_object(v7);
7021 v7->vals.error_prototype = v7_mk_object(v7);
7022 v7->vals.global_object = v7_mk_object(v7);
7023 v7->vals.date_prototype = v7_mk_object(v7);
7024 v7->vals.function_prototype = v7_mk_object(v7);
7025 v7->vals.proxy_prototype = v7_mk_object(v7);
7026
7027 set_method(v7, v7->vals.global_object, "eval", Std_eval, 1);
7028 set_method(v7, v7->vals.global_object, "print", Std_print, 1);
7029#ifndef NO_LIBC
7030 set_method(v7, v7->vals.global_object, "exit", Std_exit, 1);
7031#endif
7032 set_method(v7, v7->vals.global_object, "parseInt", Std_parseInt, 2);
7033 set_method(v7, v7->vals.global_object, "parseFloat", Std_parseFloat, 1);
7034 set_method(v7, v7->vals.global_object, "isNaN", Std_isNaN, 1);
7035 set_method(v7, v7->vals.global_object, "isFinite", Std_isFinite, 1);
7036
7037 v7_def(v7, v7->vals.global_object, "Infinity", 8, attr_internal,
7038 v7_mk_number(v7, INFINITY));
7039 v7_set(v7, v7->vals.global_object, "global", 6, v7->vals.global_object);
7040
7041 init_object(v7);
7042 init_array(v7);
7043 init_error(v7);
7044 init_boolean(v7);
7045#if V7_ENABLE__Math
7046 init_math(v7);
7047#endif
7048 init_string(v7);
7049#if V7_ENABLE__RegExp
7050 init_regex(v7);
7051#endif
7052 init_number(v7);
7053 init_json(v7);
7054#if V7_ENABLE__Date
7055 init_date(v7);
7056#endif
7057 init_function(v7);
7058 init_js_stdlib(v7);
7059
7060#if V7_ENABLE__Proxy
7061 init_proxy(v7);
7062#endif
7063}
7064#ifdef V7_MODULE_LINES
7065#line 1 "v7/src/js_stdlib.c"
7066#endif
7067/*
7068 * Copyright (c) 2014 Cesanta Software Limited
7069 * All rights reserved
7070 */
7071
7072/* clang-format off */
7073/* because clang-format would break JS code, e.g. === converted to == = ... */
7074
7075/* Amalgamated: #include "v7/src/internal.h" */
7076/* Amalgamated: #include "v7/src/core.h" */
7077/* Amalgamated: #include "v7/src/exec.h" */
7078/* Amalgamated: #include "v7/src/util.h" */
7079
7080#define STRINGIFY(x) #x
7081
7082#if defined(__cplusplus)
7083extern "C" {
7084#endif /* __cplusplus */
7085
7086static const char js_array_indexOf[] = STRINGIFY(
7087 Object.defineProperty(Array.prototype, "indexOf", {
7088 writable:true,
7089 configurable: true,
7090 value: function(a, x) {
7091 var i; var r = -1; var b = +x;
7092 if (!b || b < 0) b = 0;
7093 for (i in this) if (i >= b && (r < 0 || i < r) && this[i] === a) r = +i;
7094 return r;
7095 }}););
7096
7097static const char js_array_lastIndexOf[] = STRINGIFY(
7098 Object.defineProperty(Array.prototype, "lastIndexOf", {
7099 writable:true,
7100 configurable: true,
7101 value: function(a, x) {
7102 var i; var r = -1; var b = +x;
7103 if (isNaN(b) || b < 0 || b >= this.length) b = this.length - 1;
7104 for (i in this) if (i <= b && (r < 0 || i > r) && this[i] === a) r = +i;
7105 return r;
7106 }}););
7107
7108#if V7_ENABLE__Array__reduce
7109static const char js_array_reduce[] = STRINGIFY(
7110 Object.defineProperty(Array.prototype, "reduce", {
7111 writable:true,
7112 configurable: true,
7113 value: function(a, b) {
7114 var f = 0;
7115 if (typeof(a) != "function") {
7116 throw new TypeError(a + " is not a function");
7117 }
7118 for (var k in this) {
7119 if (k > this.length) break;
7120 if (f == 0 && b === undefined) {
7121 b = this[k];
7122 f = 1;
7123 } else {
7124 b = a(b, this[k], k, this);
7125 }
7126 }
7127 return b;
7128 }}););
7129#endif
7130
7131static const char js_array_pop[] = STRINGIFY(
7132 Object.defineProperty(Array.prototype, "pop", {
7133 writable:true,
7134 configurable: true,
7135 value: function() {
7136 var i = this.length - 1;
7137 return this.splice(i, 1)[0];
7138 }}););
7139
7140static const char js_array_shift[] = STRINGIFY(
7141 Object.defineProperty(Array.prototype, "shift", {
7142 writable:true,
7143 configurable: true,
7144 value: function() {
7145 return this.splice(0, 1)[0];
7146 }}););
7147
7148#if V7_ENABLE__Function__call
7149static const char js_function_call[] = STRINGIFY(
7150 Object.defineProperty(Function.prototype, "call", {
7151 writable:true,
7152 configurable: true,
7153 value: function() {
7154 var t = arguments.splice(0, 1)[0];
7155 return this.apply(t, arguments);
7156 }}););
7157#endif
7158
7159#if V7_ENABLE__Function__bind
7160static const char js_function_bind[] = STRINGIFY(
7161 Object.defineProperty(Function.prototype, "bind", {
7162 writable:true,
7163 configurable: true,
7164 value: function(t) {
7165 var f = this;
7166 return function() {
7167 return f.apply(t, arguments);
7168 };
7169 }}););
7170#endif
7171
7172#if V7_ENABLE__Blob
7173static const char js_Blob[] = STRINGIFY(
7174 function Blob(a) {
7175 this.a = a;
7176 });
7177#endif
7178
7179static const char * const js_functions[] = {
7180#if V7_ENABLE__Blob
7181 js_Blob,
7182#endif
7183#if V7_ENABLE__Function__call
7184 js_function_call,
7185#endif
7186#if V7_ENABLE__Function__bind
7187 js_function_bind,
7188#endif
7189#if V7_ENABLE__Array__reduce
7190 js_array_reduce,
7191#endif
7192 js_array_indexOf,
7193 js_array_lastIndexOf,
7194 js_array_pop,
7195 js_array_shift
7196};
7197
7198 V7_PRIVATE void init_js_stdlib(struct v7 *v7) {
7199 val_t res;
7200 int i;
7201
7202 for(i = 0; i < (int) ARRAY_SIZE(js_functions); i++) {
7203 if (v7_exec(v7, js_functions[i], &res) != V7_OK) {
7204 fprintf(stderr, "ex: %s:\n", js_functions[i]);
7205 v7_fprintln(stderr, v7, res);
7206 }
7207 }
7208
7209 /* TODO(lsm): re-enable in a separate PR */
7210#if 0
7211 v7_exec(v7, &res, STRINGIFY(
7212 Array.prototype.unshift = function() {
7213 var a = new Array(0, 0);
7214 Array.prototype.push.apply(a, arguments);
7215 Array.prototype.splice.apply(this, a);
7216 return this.length;
7217 };));
7218#endif
7219}
7220
7221#if defined(__cplusplus)
7222}
7223#endif /* __cplusplus */
7224#ifdef V7_MODULE_LINES
7225#line 1 "v7/src/slre.c"
7226#endif
7227/*
7228 * Copyright (c) 2014 Cesanta Software Limited
7229 * All rights reserved
7230 *
7231 * This software is dual-licensed: you can redistribute it and/or modify
7232 * it under the terms of the GNU General Public License version 2 as
7233 * published by the Free Software Foundation. For the terms of this
7234 * license, see <http://www.gnu.org/licenses/>.
7235 *
7236 * You are free to use this software under the terms of the GNU General
7237 * Public License, but WITHOUT ANY WARRANTY; without even the implied
7238 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7239 * See the GNU General Public License for more details.
7240 *
7241 * Alternatively, you can license this software under a commercial
7242 * license, as set out in <https://www.cesanta.com/license>.
7243 */
7244
7245/* Amalgamated: #include "v7/src/v7_features.h" */
7246
7247#include <setjmp.h>
7248#include <stdlib.h>
7249#include <stdio.h>
7250#include <string.h>
7251
7252#ifndef NO_LIBC
7253#include <ctype.h>
7254#endif
7255
7256/* Amalgamated: #include "common/utf.h" */
7257/* Amalgamated: #include "v7/src/slre.h" */
7258
7259/* Limitations */
7260#define SLRE_MAX_RANGES 32
7261#define SLRE_MAX_SETS 16
7262#define SLRE_MAX_REP 0xFFFF
7263
7264#define SLRE_MALLOC malloc
7265#define SLRE_FREE free
7266#define SLRE_THROW(e, err_code) longjmp((e)->jmp_buf, (err_code))
7267
7268static int hex(int c) {
7269 if (c >= '0' && c <= '9') return c - '0';
7270 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
7271 if (c >= 'A' && c <= 'F') return c - 'A' + 10;
7272 return -SLRE_INVALID_HEX_DIGIT;
7273}
7274
7275int nextesc(const char **p) {
7276 const unsigned char *s = (unsigned char *) (*p)++;
7277 switch (*s) {
7278 case 0:
7279 return -SLRE_UNTERM_ESC_SEQ;
7280 case 'c':
7281 ++*p;
7282 return *s & 31;
7283 case 'b':
7284 return '\b';
7285 case 't':
7286 return '\t';
7287 case 'n':
7288 return '\n';
7289 case 'v':
7290 return '\v';
7291 case 'f':
7292 return '\f';
7293 case 'r':
7294 return '\r';
7295 case '\\':
7296 return '\\';
7297 case 'u':
7298 if (isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) &&
7299 isxdigit(s[4])) {
7300 (*p) += 4;
7301 return hex(s[1]) << 12 | hex(s[2]) << 8 | hex(s[3]) << 4 | hex(s[4]);
7302 }
7303 return -SLRE_INVALID_HEX_DIGIT;
7304 case 'x':
7305 if (isxdigit(s[1]) && isxdigit(s[2])) {
7306 (*p) += 2;
7307 return (hex(s[1]) << 4) | hex(s[2]);
7308 }
7309 return -SLRE_INVALID_HEX_DIGIT;
7310 default:
7311 return -SLRE_INVALID_ESC_CHAR;
7312 }
7313}
7314
7315#if V7_ENABLE__RegExp
7316
7317/* Parser Information */
7318struct slre_node {
7319 unsigned char type;
7320 union {
7321 Rune c; /* character */
7322 struct slre_class *cp; /* class pointer */
7323 struct {
7324 struct slre_node *x;
7325 union {
7326 struct slre_node *y;
7327 unsigned char n;
7328 struct {
7329 unsigned char ng; /* not greedy flag */
7330 unsigned short min;
7331 unsigned short max;
7332 } rp;
7333 } y;
7334 } xy;
7335 } par;
7336};
7337
7338struct slre_range {
7339 unsigned short s, e;
7340};
7341
7342/* character class, each pair of rune's defines a range */
7343struct slre_class {
7344 struct slre_range *end;
7345 struct slre_range spans[SLRE_MAX_RANGES];
7346};
7347
7348struct slre_instruction {
7349 unsigned char opcode;
7350 union {
7351 unsigned char n;
7352 Rune c; /* character */
7353 struct slre_class *cp; /* class pointer */
7354 struct {
7355 struct slre_instruction *x;
7356 union {
7357 struct {
7358 unsigned short min;
7359 unsigned short max;
7360 } rp;
7361 struct slre_instruction *y;
7362 } y;
7363 } xy;
7364 } par;
7365};
7366
7367struct slre_prog {
7368 struct slre_instruction *start, *end;
7369 unsigned int num_captures;
7370 int flags;
7371 struct slre_class charset[SLRE_MAX_SETS];
7372};
7373
7374struct slre_env {
7375 int is_regex;
7376 const char *src;
7377 const char *src_end;
7378 Rune curr_rune;
7379
7380 struct slre_prog *prog;
7381 struct slre_node *pstart, *pend;
7382
7383 struct slre_node *caps[SLRE_MAX_CAPS];
7384 unsigned int num_captures;
7385 unsigned int sets_num;
7386
7387 int lookahead;
7388 struct slre_class *curr_set;
7389 int min_rep, max_rep;
7390
7391#if defined(__cplusplus)
7392 ::jmp_buf jmp_buf;
7393#else
7394 jmp_buf jmp_buf;
7395#endif
7396};
7397
7398struct slre_thread {
7399 struct slre_thread *prev;
7400 struct slre_instruction *pc;
7401 const char *start;
7402 struct slre_loot loot;
7403};
7404
7405enum slre_opcode {
7406 I_END = 10, /* Terminate: match found */
7407 I_ANY,
7408 P_ANY = I_ANY, /* Any character except newline, . */
7409 I_ANYNL, /* Any character including newline, . */
7410 I_BOL,
7411 P_BOL = I_BOL, /* Beginning of line, ^ */
7412 I_CH,
7413 P_CH = I_CH,
7414 I_EOL,
7415 P_EOL = I_EOL, /* End of line, $ */
7416 I_EOS,
7417 P_EOS = I_EOS, /* End of string, \0 */
7418 I_JUMP,
7419 I_LA,
7420 P_LA = I_LA,
7421 I_LA_N,
7422 P_LA_N = I_LA_N,
7423 I_LBRA,
7424 P_BRA = I_LBRA, /* Left bracket, ( */
7425 I_REF,
7426 P_REF = I_REF,
7427 I_REP,
7428 P_REP = I_REP,
7429 I_REP_INI,
7430 I_RBRA, /* Right bracket, ) */
7431 I_SET,
7432 P_SET = I_SET, /* Character set, [] */
7433 I_SET_N,
7434 P_SET_N = I_SET_N, /* Negated character set, [] */
7435 I_SPLIT,
7436 I_WORD,
7437 P_WORD = I_WORD,
7438 I_WORD_N,
7439 P_WORD_N = I_WORD_N,
7440 P_ALT, /* Alternation, | */
7441 P_CAT, /* Concatentation, implicit operator */
7442 L_CH = 256,
7443 L_COUNT, /* {M,N} */
7444 L_EOS, /* End of string, \0 */
7445 L_LA, /* "(?=" lookahead */
7446 L_LA_CAP, /* "(?:" lookahead, capture */
7447 L_LA_N, /* "(?!" negative lookahead */
7448 L_REF, /* "\1" back-reference */
7449 L_CHSET, /* character set */
7450 L_SET_N, /* negative character set */
7451 L_WORD, /* "\b" word boundary */
7452 L_WORD_N /* "\B" non-word boundary */
7453};
7454
7455static signed char dec(int c) {
7456 if (isdigitrune(c)) return c - '0';
7457 return SLRE_INVALID_DEC_DIGIT;
7458}
7459
7460static unsigned char re_dec_digit(struct slre_env *e, int c) {
7461 signed char ret = dec(c);
7462 if (ret < 0) {
7463 SLRE_THROW(e, SLRE_INVALID_DEC_DIGIT);
7464 }
7465 return ret;
7466}
7467
7468static int re_nextc(Rune *r, const char **src, const char *src_end) {
7469 *r = 0;
7470 if (*src >= src_end) return 0;
7471 *src += chartorune(r, *src);
7472 if (*r == '\\') {
7473 const char *tmp_s = *src;
7474 int i = nextesc(src);
7475 switch (i) {
7476 case -SLRE_INVALID_ESC_CHAR:
7477 *r = '\\';
7478 *src = tmp_s;
7479 *src += chartorune(r, *src);
7480 break;
7481 case -SLRE_INVALID_HEX_DIGIT:
7482 default:
7483 *r = i;
7484 }
7485 return 1;
7486 }
7487 return 0;
7488}
7489
7490static int re_nextc_raw(Rune *r, const char **src, const char *src_end) {
7491 *r = 0;
7492 if (*src >= src_end) return 0;
7493 *src += chartorune(r, *src);
7494 return 0;
7495}
7496
7497static int re_nextc_env(struct slre_env *e) {
7498 return re_nextc(&e->curr_rune, &e->src, e->src_end);
7499}
7500
7501static void re_nchset(struct slre_env *e) {
7502 if (e->sets_num >= nelem(e->prog->charset)) {
7503 SLRE_THROW(e, SLRE_TOO_MANY_CHARSETS);
7504 }
7505 e->curr_set = e->prog->charset + e->sets_num++;
7506 e->curr_set->end = e->curr_set->spans;
7507}
7508
7509static void re_rng2set(struct slre_env *e, Rune start, Rune end) {
7510 if (start > end) {
7511 SLRE_THROW(e, SLRE_INV_CHARSET_RANGE);
7512 }
7513 if (e->curr_set->end + 2 == e->curr_set->spans + nelem(e->curr_set->spans)) {
7514 SLRE_THROW(e, SLRE_CHARSET_TOO_LARGE);
7515 }
7516 e->curr_set->end->s = start;
7517 e->curr_set->end->e = end;
7518 e->curr_set->end++;
7519}
7520
7521#define re_char2set(e, c) re_rng2set(e, c, c)
7522
7523#define re_d_2set(e) re_rng2set(e, '0', '9')
7524
7525static void re_D_2set(struct slre_env *e) {
7526 re_rng2set(e, 0, '0' - 1);
7527 re_rng2set(e, '9' + 1, 0xFFFF);
7528}
7529
7530static void re_s_2set(struct slre_env *e) {
7531 re_char2set(e, 0x9);
7532 re_rng2set(e, 0xA, 0xD);
7533 re_char2set(e, 0x20);
7534 re_char2set(e, 0xA0);
7535 re_rng2set(e, 0x2028, 0x2029);
7536 re_char2set(e, 0xFEFF);
7537}
7538
7539static void re_S_2set(struct slre_env *e) {
7540 re_rng2set(e, 0, 0x9 - 1);
7541 re_rng2set(e, 0xD + 1, 0x20 - 1);
7542 re_rng2set(e, 0x20 + 1, 0xA0 - 1);
7543 re_rng2set(e, 0xA0 + 1, 0x2028 - 1);
7544 re_rng2set(e, 0x2029 + 1, 0xFEFF - 1);
7545 re_rng2set(e, 0xFEFF + 1, 0xFFFF);
7546}
7547
7548static void re_w_2set(struct slre_env *e) {
7549 re_d_2set(e);
7550 re_rng2set(e, 'A', 'Z');
7551 re_char2set(e, '_');
7552 re_rng2set(e, 'a', 'z');
7553}
7554
7555static void re_W_2set(struct slre_env *e) {
7556 re_rng2set(e, 0, '0' - 1);
7557 re_rng2set(e, '9' + 1, 'A' - 1);
7558 re_rng2set(e, 'Z' + 1, '_' - 1);
7559 re_rng2set(e, '_' + 1, 'a' - 1);
7560 re_rng2set(e, 'z' + 1, 0xFFFF);
7561}
7562
7563static unsigned char re_endofcount(Rune c) {
7564 switch (c) {
7565 case ',':
7566 case '}':
7567 return 1;
7568 }
7569 return 0;
7570}
7571
7572static void re_ex_num_overfl(struct slre_env *e) {
7573 SLRE_THROW(e, SLRE_NUM_OVERFLOW);
7574}
7575
7576static enum slre_opcode re_countrep(struct slre_env *e) {
7577 e->min_rep = 0;
7578 while (e->src < e->src_end && !re_endofcount(e->curr_rune = *e->src++)) {
7579 e->min_rep = e->min_rep * 10 + re_dec_digit(e, e->curr_rune);
7580 if (e->min_rep >= SLRE_MAX_REP) re_ex_num_overfl(e);
7581 }
7582
7583 if (e->curr_rune != ',') {
7584 e->max_rep = e->min_rep;
7585 return L_COUNT;
7586 }
7587 e->max_rep = 0;
7588 while (e->src < e->src_end && (e->curr_rune = *e->src++) != '}') {
7589 e->max_rep = e->max_rep * 10 + re_dec_digit(e, e->curr_rune);
7590 if (e->max_rep >= SLRE_MAX_REP) re_ex_num_overfl(e);
7591 }
7592 if (!e->max_rep) {
7593 e->max_rep = SLRE_MAX_REP;
7594 return L_COUNT;
7595 }
7596
7597 return L_COUNT;
7598}
7599
7600static enum slre_opcode re_lexset(struct slre_env *e) {
7601 Rune ch = 0;
7602 unsigned char esc, ch_fl = 0, dash_fl = 0;
7603 enum slre_opcode type = L_CHSET;
7604
7605 re_nchset(e);
7606
7607 esc = re_nextc_env(e);
7608 if (!esc && e->curr_rune == '^') {
7609 type = L_SET_N;
7610 esc = re_nextc_env(e);
7611 }
7612
7613 for (; esc || e->curr_rune != ']'; esc = re_nextc_env(e)) {
7614 if (!e->curr_rune) {
7615 SLRE_THROW(e, SLRE_MALFORMED_CHARSET);
7616 }
7617 if (esc) {
7618 if (strchr("DdSsWw", e->curr_rune)) {
7619 if (ch_fl) {
7620 re_char2set(e, ch);
7621 if (dash_fl) re_char2set(e, '-');
7622 }
7623 switch (e->curr_rune) {
7624 case 'D':
7625 re_D_2set(e);
7626 break;
7627 case 'd':
7628 re_d_2set(e);
7629 break;
7630 case 'S':
7631 re_S_2set(e);
7632 break;
7633 case 's':
7634 re_s_2set(e);
7635 break;
7636 case 'W':
7637 re_W_2set(e);
7638 break;
7639 case 'w':
7640 re_w_2set(e);
7641 break;
7642 }
7643 ch_fl = dash_fl = 0;
7644 continue;
7645 }
7646 switch (e->curr_rune) {
7647 default:
7648 /* case '-':
7649 case '\\':
7650 case '.':
7651 case '/':
7652 case ']':
7653 case '|': */
7654 break;
7655 case '0':
7656 e->curr_rune = 0;
7657 break;
7658 case 'b':
7659 e->curr_rune = '\b';
7660 break;
7661 /* default:
7662 SLRE_THROW(e->catch_point, e->err_msg,
7663 SLRE_INVALID_ESC_CHAR); */
7664 }
7665 } else {
7666 if (e->curr_rune == '-') {
7667 if (ch_fl) {
7668 if (dash_fl) {
7669 re_rng2set(e, ch, '-');
7670 ch_fl = dash_fl = 0;
7671 } else
7672 dash_fl = 1;
7673 } else {
7674 ch = '-';
7675 ch_fl = 1;
7676 }
7677 continue;
7678 }
7679 }
7680 if (ch_fl) {
7681 if (dash_fl) {
7682 re_rng2set(e, ch, e->curr_rune);
7683 ch_fl = dash_fl = 0;
7684 } else {
7685 re_char2set(e, ch);
7686 ch = e->curr_rune;
7687 }
7688 } else {
7689 ch = e->curr_rune;
7690 ch_fl = 1;
7691 }
7692 }
7693 if (ch_fl) {
7694 re_char2set(e, ch);
7695 if (dash_fl) re_char2set(e, '-');
7696 }
7697 return type;
7698}
7699
7700static int re_lexer(struct slre_env *e) {
7701 if (re_nextc_env(e)) {
7702 switch (e->curr_rune) {
7703 case '0':
7704 e->curr_rune = 0;
7705 return L_EOS;
7706 case 'b':
7707 return L_WORD;
7708 case 'B':
7709 return L_WORD_N;
7710 case 'd':
7711 re_nchset(e);
7712 re_d_2set(e);
7713 return L_CHSET;
7714 case 'D':
7715 re_nchset(e);
7716 re_d_2set(e);
7717 return L_SET_N;
7718 case 's':
7719 re_nchset(e);
7720 re_s_2set(e);
7721 return L_CHSET;
7722 case 'S':
7723 re_nchset(e);
7724 re_s_2set(e);
7725 return L_SET_N;
7726 case 'w':
7727 re_nchset(e);
7728 re_w_2set(e);
7729 return L_CHSET;
7730 case 'W':
7731 re_nchset(e);
7732 re_w_2set(e);
7733 return L_SET_N;
7734 }
7735 if (isdigitrune(e->curr_rune)) {
7736 e->curr_rune -= '0';
7737 if (isdigitrune(*e->src))
7738 e->curr_rune = e->curr_rune * 10 + *e->src++ - '0';
7739 return L_REF;
7740 }
7741 return L_CH;
7742 }
7743
7744 if (e->is_regex) {
7745 switch (e->curr_rune) {
7746 case 0:
7747 return 0;
7748 case '$':
7749 case ')':
7750 case '*':
7751 case '+':
7752 case '.':
7753 case '?':
7754 case '^':
7755 case '|':
7756 return e->curr_rune;
7757 case '{':
7758 return re_countrep(e);
7759 case '[':
7760 return re_lexset(e);
7761 case '(':
7762 if (e->src[0] == '?') switch (e->src[1]) {
7763 case '=':
7764 e->src += 2;
7765 return L_LA;
7766 case ':':
7767 e->src += 2;
7768 return L_LA_CAP;
7769 case '!':
7770 e->src += 2;
7771 return L_LA_N;
7772 }
7773 return '(';
7774 }
7775 } else if (e->curr_rune == 0) {
7776 return 0;
7777 }
7778
7779 return L_CH;
7780}
7781
7782#define RE_NEXT(env) (env)->lookahead = re_lexer(env)
7783#define RE_ACCEPT(env, t) ((env)->lookahead == (t) ? RE_NEXT(env), 1 : 0)
7784
7785static struct slre_node *re_nnode(struct slre_env *e, int type) {
7786 memset(e->pend, 0, sizeof(struct slre_node));
7787 e->pend->type = type;
7788 return e->pend++;
7789}
7790
7791static unsigned char re_isemptynd(struct slre_node *nd) {
7792 if (!nd) return 1;
7793 switch (nd->type) {
7794 default:
7795 return 1;
7796 case P_ANY:
7797 case P_CH:
7798 case P_SET:
7799 case P_SET_N:
7800 return 0;
7801 case P_BRA:
7802 case P_REF:
7803 return re_isemptynd(nd->par.xy.x);
7804 case P_CAT:
7805 return re_isemptynd(nd->par.xy.x) && re_isemptynd(nd->par.xy.y.y);
7806 case P_ALT:
7807 return re_isemptynd(nd->par.xy.x) || re_isemptynd(nd->par.xy.y.y);
7808 case P_REP:
7809 return re_isemptynd(nd->par.xy.x) || !nd->par.xy.y.rp.min;
7810 }
7811}
7812
7813static struct slre_node *re_nrep(struct slre_env *e, struct slre_node *nd,
7814 int ng, unsigned short min,
7815 unsigned short max) {
7816 struct slre_node *rep = re_nnode(e, P_REP);
7817 if (max == SLRE_MAX_REP && re_isemptynd(nd)) {
7818 SLRE_THROW(e, SLRE_INF_LOOP_M_EMP_STR);
7819 }
7820 rep->par.xy.y.rp.ng = ng;
7821 rep->par.xy.y.rp.min = min;
7822 rep->par.xy.y.rp.max = max;
7823 rep->par.xy.x = nd;
7824 return rep;
7825}
7826
7827static struct slre_node *re_parser(struct slre_env *e);
7828
7829static struct slre_node *re_parse_la(struct slre_env *e) {
7830 struct slre_node *nd;
7831 int min, max;
7832 switch (e->lookahead) {
7833 case '^':
7834 RE_NEXT(e);
7835 return re_nnode(e, P_BOL);
7836 case '$':
7837 RE_NEXT(e);
7838 return re_nnode(e, P_EOL);
7839 case L_EOS:
7840 RE_NEXT(e);
7841 return re_nnode(e, P_EOS);
7842 case L_WORD:
7843 RE_NEXT(e);
7844 return re_nnode(e, P_WORD);
7845 case L_WORD_N:
7846 RE_NEXT(e);
7847 return re_nnode(e, P_WORD_N);
7848 }
7849
7850 switch (e->lookahead) {
7851 case L_CH:
7852 nd = re_nnode(e, P_CH);
7853 nd->par.c = e->curr_rune;
7854 RE_NEXT(e);
7855 break;
7856 case L_CHSET:
7857 nd = re_nnode(e, P_SET);
7858 nd->par.cp = e->curr_set;
7859 RE_NEXT(e);
7860 break;
7861 case L_SET_N:
7862 nd = re_nnode(e, P_SET_N);
7863 nd->par.cp = e->curr_set;
7864 RE_NEXT(e);
7865 break;
7866 case L_REF:
7867 nd = re_nnode(e, P_REF);
7868 if (!e->curr_rune || e->curr_rune > e->num_captures ||
7869 !e->caps[e->curr_rune]) {
7870 SLRE_THROW(e, SLRE_INVALID_BACK_REFERENCE);
7871 }
7872 nd->par.xy.y.n = e->curr_rune;
7873 nd->par.xy.x = e->caps[e->curr_rune];
7874 RE_NEXT(e);
7875 break;
7876 case '.':
7877 RE_NEXT(e);
7878 nd = re_nnode(e, P_ANY);
7879 break;
7880 case '(':
7881 RE_NEXT(e);
7882 nd = re_nnode(e, P_BRA);
7883 if (e->num_captures == SLRE_MAX_CAPS) {
7884 SLRE_THROW(e, SLRE_TOO_MANY_CAPTURES);
7885 }
7886 nd->par.xy.y.n = e->num_captures++;
7887 nd->par.xy.x = re_parser(e);
7888 e->caps[nd->par.xy.y.n] = nd;
7889 if (!RE_ACCEPT(e, ')')) {
7890 SLRE_THROW(e, SLRE_UNMATCH_LBR);
7891 }
7892 break;
7893 case L_LA:
7894 RE_NEXT(e);
7895 nd = re_nnode(e, P_LA);
7896 nd->par.xy.x = re_parser(e);
7897 if (!RE_ACCEPT(e, ')')) {
7898 SLRE_THROW(e, SLRE_UNMATCH_LBR);
7899 }
7900 break;
7901 case L_LA_CAP:
7902 RE_NEXT(e);
7903 nd = re_parser(e);
7904 if (!RE_ACCEPT(e, ')')) {
7905 SLRE_THROW(e, SLRE_UNMATCH_LBR);
7906 }
7907 break;
7908 case L_LA_N:
7909 RE_NEXT(e);
7910 nd = re_nnode(e, P_LA_N);
7911 nd->par.xy.x = re_parser(e);
7912 if (!RE_ACCEPT(e, ')')) {
7913 SLRE_THROW(e, SLRE_UNMATCH_LBR);
7914 }
7915 break;
7916 default:
7917 SLRE_THROW(e, SLRE_SYNTAX_ERROR);
7918 }
7919
7920 switch (e->lookahead) {
7921 case '*':
7922 RE_NEXT(e);
7923 return re_nrep(e, nd, RE_ACCEPT(e, '?'), 0, SLRE_MAX_REP);
7924 case '+':
7925 RE_NEXT(e);
7926 return re_nrep(e, nd, RE_ACCEPT(e, '?'), 1, SLRE_MAX_REP);
7927 case '?':
7928 RE_NEXT(e);
7929 return re_nrep(e, nd, RE_ACCEPT(e, '?'), 0, 1);
7930 case L_COUNT:
7931 min = e->min_rep, max = e->max_rep;
7932 RE_NEXT(e);
7933 if (max < min) {
7934 SLRE_THROW(e, SLRE_INVALID_QUANTIFIER);
7935 }
7936 return re_nrep(e, nd, RE_ACCEPT(e, '?'), min, max);
7937 }
7938 return nd;
7939}
7940
7941static unsigned char re_endofcat(Rune c, int is_regex) {
7942 switch (c) {
7943 case 0:
7944 return 1;
7945 case '|':
7946 case ')':
7947 if (is_regex) return 1;
7948 }
7949 return 0;
7950}
7951
7952static struct slre_node *re_parser(struct slre_env *e) {
7953 struct slre_node *alt = NULL, *cat, *nd;
7954 if (!re_endofcat(e->lookahead, e->is_regex)) {
7955 cat = re_parse_la(e);
7956 while (!re_endofcat(e->lookahead, e->is_regex)) {
7957 nd = cat;
7958 cat = re_nnode(e, P_CAT);
7959 cat->par.xy.x = nd;
7960 cat->par.xy.y.y = re_parse_la(e);
7961 }
7962 alt = cat;
7963 }
7964 if (e->lookahead == '|') {
7965 RE_NEXT(e);
7966 nd = alt;
7967 alt = re_nnode(e, P_ALT);
7968 alt->par.xy.x = nd;
7969 alt->par.xy.y.y = re_parser(e);
7970 }
7971 return alt;
7972}
7973
7974static unsigned int re_nodelen(struct slre_node *nd) {
7975 unsigned int n = 0;
7976 if (!nd) return 0;
7977 switch (nd->type) {
7978 case P_ALT:
7979 n = 2;
7980 case P_CAT:
7981 return re_nodelen(nd->par.xy.x) + re_nodelen(nd->par.xy.y.y) + n;
7982 case P_BRA:
7983 case P_LA:
7984 case P_LA_N:
7985 return re_nodelen(nd->par.xy.x) + 2;
7986 case P_REP:
7987 n = nd->par.xy.y.rp.max - nd->par.xy.y.rp.min;
7988 switch (nd->par.xy.y.rp.min) {
7989 case 0:
7990 if (!n) return 0;
7991 if (nd->par.xy.y.rp.max >= SLRE_MAX_REP)
7992 return re_nodelen(nd->par.xy.x) + 2;
7993 case 1:
7994 if (!n) return re_nodelen(nd->par.xy.x);
7995 if (nd->par.xy.y.rp.max >= SLRE_MAX_REP)
7996 return re_nodelen(nd->par.xy.x) + 1;
7997 default:
7998 n = 4;
7999 if (nd->par.xy.y.rp.max >= SLRE_MAX_REP) n++;
8000 return re_nodelen(nd->par.xy.x) + n;
8001 }
8002 default:
8003 return 1;
8004 }
8005}
8006
8007static struct slre_instruction *re_newinst(struct slre_prog *prog, int opcode) {
8008 memset(prog->end, 0, sizeof(struct slre_instruction));
8009 prog->end->opcode = opcode;
8010 return prog->end++;
8011}
8012
8013static void re_compile(struct slre_env *e, struct slre_node *nd) {
8014 struct slre_instruction *inst, *split, *jump, *rep;
8015 unsigned int n;
8016
8017 if (!nd) return;
8018
8019 switch (nd->type) {
8020 case P_ALT:
8021 split = re_newinst(e->prog, I_SPLIT);
8022 re_compile(e, nd->par.xy.x);
8023 jump = re_newinst(e->prog, I_JUMP);
8024 re_compile(e, nd->par.xy.y.y);
8025 split->par.xy.x = split + 1;
8026 split->par.xy.y.y = jump + 1;
8027 jump->par.xy.x = e->prog->end;
8028 break;
8029
8030 case P_ANY:
8031 re_newinst(e->prog, I_ANY);
8032 break;
8033
8034 case P_BOL:
8035 re_newinst(e->prog, I_BOL);
8036 break;
8037
8038 case P_BRA:
8039 inst = re_newinst(e->prog, I_LBRA);
8040 inst->par.n = nd->par.xy.y.n;
8041 re_compile(e, nd->par.xy.x);
8042 inst = re_newinst(e->prog, I_RBRA);
8043 inst->par.n = nd->par.xy.y.n;
8044 break;
8045
8046 case P_CAT:
8047 re_compile(e, nd->par.xy.x);
8048 re_compile(e, nd->par.xy.y.y);
8049 break;
8050
8051 case P_CH:
8052 inst = re_newinst(e->prog, I_CH);
8053 inst->par.c = nd->par.c;
8054 break;
8055
8056 case P_EOL:
8057 re_newinst(e->prog, I_EOL);
8058 break;
8059
8060 case P_EOS:
8061 re_newinst(e->prog, I_EOS);
8062 break;
8063
8064 case P_LA:
8065 split = re_newinst(e->prog, I_LA);
8066 re_compile(e, nd->par.xy.x);
8067 re_newinst(e->prog, I_END);
8068 split->par.xy.x = split + 1;
8069 split->par.xy.y.y = e->prog->end;
8070 break;
8071 case P_LA_N:
8072 split = re_newinst(e->prog, I_LA_N);
8073 re_compile(e, nd->par.xy.x);
8074 re_newinst(e->prog, I_END);
8075 split->par.xy.x = split + 1;
8076 split->par.xy.y.y = e->prog->end;
8077 break;
8078
8079 case P_REF:
8080 inst = re_newinst(e->prog, I_REF);
8081 inst->par.n = nd->par.xy.y.n;
8082 break;
8083
8084 case P_REP:
8085 n = nd->par.xy.y.rp.max - nd->par.xy.y.rp.min;
8086 switch (nd->par.xy.y.rp.min) {
8087 case 0:
8088 if (!n) break;
8089 if (nd->par.xy.y.rp.max >= SLRE_MAX_REP) {
8090 split = re_newinst(e->prog, I_SPLIT);
8091 re_compile(e, nd->par.xy.x);
8092 jump = re_newinst(e->prog, I_JUMP);
8093 jump->par.xy.x = split;
8094 split->par.xy.x = split + 1;
8095 split->par.xy.y.y = e->prog->end;
8096 if (nd->par.xy.y.rp.ng) {
8097 split->par.xy.y.y = split + 1;
8098 split->par.xy.x = e->prog->end;
8099 }
8100 break;
8101 }
8102 case 1:
8103 if (!n) {
8104 re_compile(e, nd->par.xy.x);
8105 break;
8106 }
8107 if (nd->par.xy.y.rp.max >= SLRE_MAX_REP) {
8108 inst = e->prog->end;
8109 re_compile(e, nd->par.xy.x);
8110 split = re_newinst(e->prog, I_SPLIT);
8111 split->par.xy.x = inst;
8112 split->par.xy.y.y = e->prog->end;
8113 if (nd->par.xy.y.rp.ng) {
8114 split->par.xy.y.y = inst;
8115 split->par.xy.x = e->prog->end;
8116 }
8117 break;
8118 }
8119 default:
8120 inst = re_newinst(e->prog, I_REP_INI);
8121 inst->par.xy.y.rp.min = nd->par.xy.y.rp.min;
8122 inst->par.xy.y.rp.max = n;
8123 rep = re_newinst(e->prog, I_REP);
8124 split = re_newinst(e->prog, I_SPLIT);
8125 re_compile(e, nd->par.xy.x);
8126 jump = re_newinst(e->prog, I_JUMP);
8127 jump->par.xy.x = rep;
8128 rep->par.xy.x = e->prog->end;
8129 split->par.xy.x = split + 1;
8130 split->par.xy.y.y = e->prog->end;
8131 if (nd->par.xy.y.rp.ng) {
8132 split->par.xy.y.y = split + 1;
8133 split->par.xy.x = e->prog->end;
8134 }
8135 if (nd->par.xy.y.rp.max >= SLRE_MAX_REP) {
8136 inst = split + 1;
8137 split = re_newinst(e->prog, I_SPLIT);
8138 split->par.xy.x = inst;
8139 split->par.xy.y.y = e->prog->end;
8140 if (nd->par.xy.y.rp.ng) {
8141 split->par.xy.y.y = inst;
8142 split->par.xy.x = e->prog->end;
8143 }
8144 break;
8145 }
8146 break;
8147 }
8148 break;
8149
8150 case P_SET:
8151 inst = re_newinst(e->prog, I_SET);
8152 inst->par.cp = nd->par.cp;
8153 break;
8154 case P_SET_N:
8155 inst = re_newinst(e->prog, I_SET_N);
8156 inst->par.cp = nd->par.cp;
8157 break;
8158
8159 case P_WORD:
8160 re_newinst(e->prog, I_WORD);
8161 break;
8162 case P_WORD_N:
8163 re_newinst(e->prog, I_WORD_N);
8164 break;
8165 }
8166}
8167
8168#ifdef RE_TEST
8169static void print_set(struct slre_class *cp) {
8170 struct slre_range *p;
8171 for (p = cp->spans; p < cp->end; p++) {
8172 printf("%s", p == cp->spans ? "'" : ",'");
8173 printf(
8174 p->s >= 32 && p->s < 127 ? "%c" : (p->s < 256 ? "\\x%02X" : "\\u%04X"),
8175 p->s);
8176 if (p->s != p->e) {
8177 printf(p->e >= 32 && p->e < 127 ? "-%c"
8178 : (p->e < 256 ? "-\\x%02X" : "-\\u%04X"),
8179 p->e);
8180 }
8181 printf("'");
8182 }
8183 printf("]");
8184}
8185
8186static void node_print(struct slre_node *nd) {
8187 if (!nd) {
8188 printf("Empty");
8189 return;
8190 }
8191 switch (nd->type) {
8192 case P_ALT:
8193 printf("{");
8194 node_print(nd->par.xy.x);
8195 printf(" | ");
8196 node_print(nd->par.xy.y.y);
8197 printf("}");
8198 break;
8199 case P_ANY:
8200 printf(".");
8201 break;
8202 case P_BOL:
8203 printf("^");
8204 break;
8205 case P_BRA:
8206 node_print(nd->par.xy.x);
8207 printf(")");
8208 break;
8209 case P_CAT:
8210 printf("{");
8211 node_print(nd->par.xy.x);
8212 printf(" & ");
8213 node_print(nd->par.xy.y.y);
8214 printf("}");
8215 break;
8216 case P_CH:
8217 printf(nd->par.c >= 32 && nd->par.c < 127 ? "'%c'" : "'\\u%04X'",
8218 nd->par.c);
8219 break;
8220 case P_EOL:
8221 printf("$");
8222 break;
8223 case P_EOS:
8224 printf("\\0");
8225 break;
8226 case P_LA:
8227 printf("LA(");
8228 node_print(nd->par.xy.x);
8229 printf(")");
8230 break;
8231 case P_LA_N:
8232 printf("LA_N(");
8233 node_print(nd->par.xy.x);
8234 printf(")");
8235 break;
8236 case P_REF:
8237 printf("\\%d", nd->par.xy.y.n);
8238 break;
8239 case P_REP:
8240 node_print(nd->par.xy.x);
8241 printf(nd->par.xy.y.rp.ng ? "{%d,%d}?" : "{%d,%d}", nd->par.xy.y.rp.min,
8242 nd->par.xy.y.rp.max);
8243 break;
8244 case P_SET:
8245 printf("[");
8246 print_set(nd->par.cp);
8247 break;
8248 case P_SET_N:
8249 printf("[^");
8250 print_set(nd->par.cp);
8251 break;
8252 case P_WORD:
8253 printf("\\b");
8254 break;
8255 case P_WORD_N:
8256 printf("\\B");
8257 break;
8258 }
8259}
8260
8261static void program_print(struct slre_prog *prog) {
8262 struct slre_instruction *inst;
8263 for (inst = prog->start; inst < prog->end; ++inst) {
8264 printf("%3d: ", inst - prog->start);
8265 switch (inst->opcode) {
8266 case I_END:
8267 puts("end");
8268 break;
8269 case I_ANY:
8270 puts(".");
8271 break;
8272 case I_ANYNL:
8273 puts(". | '\\r' | '\\n'");
8274 break;
8275 case I_BOL:
8276 puts("^");
8277 break;
8278 case I_CH:
8279 printf(
8280 inst->par.c >= 32 && inst->par.c < 127 ? "'%c'\n" : "'\\u%04X'\n",
8281 inst->par.c);
8282 break;
8283 case I_EOL:
8284 puts("$");
8285 break;
8286 case I_EOS:
8287 puts("\\0");
8288 break;
8289 case I_JUMP:
8290 printf("-->%d\n", inst->par.xy.x - prog->start);
8291 break;
8292 case I_LA:
8293 printf("la %d %d\n", inst->par.xy.x - prog->start,
8294 inst->par.xy.y.y - prog->start);
8295 break;
8296 case I_LA_N:
8297 printf("la_n %d %d\n", inst->par.xy.x - prog->start,
8298 inst->par.xy.y.y - prog->start);
8299 break;
8300 case I_LBRA:
8301 printf("( %d\n", inst->par.n);
8302 break;
8303 case I_RBRA:
8304 printf(") %d\n", inst->par.n);
8305 break;
8306 case I_SPLIT:
8307 printf("-->%d | -->%d\n", inst->par.xy.x - prog->start,
8308 inst->par.xy.y.y - prog->start);
8309 break;
8310 case I_REF:
8311 printf("\\%d\n", inst->par.n);
8312 break;
8313 case I_REP:
8314 printf("repeat -->%d\n", inst->par.xy.x - prog->start);
8315 break;
8316 case I_REP_INI:
8317 printf("init_rep %d %d\n", inst->par.xy.y.rp.min,
8318 inst->par.xy.y.rp.min + inst->par.xy.y.rp.max);
8319 break;
8320 case I_SET:
8321 printf("[");
8322 print_set(inst->par.cp);
8323 puts("");
8324 break;
8325 case I_SET_N:
8326 printf("[^");
8327 print_set(inst->par.cp);
8328 puts("");
8329 break;
8330 case I_WORD:
8331 puts("\\w");
8332 break;
8333 case I_WORD_N:
8334 puts("\\W");
8335 break;
8336 }
8337 }
8338}
8339#endif
8340
8341int slre_compile(const char *pat, size_t pat_len, const char *flags,
8342 volatile size_t fl_len, struct slre_prog **pr, int is_regex) {
8343 struct slre_env e;
8344 struct slre_node *nd;
8345 struct slre_instruction *split, *jump;
8346 int err_code;
8347
8348 e.is_regex = is_regex;
8349 e.prog = (struct slre_prog *) SLRE_MALLOC(sizeof(struct slre_prog));
8350 e.pstart = e.pend =
8351 (struct slre_node *) SLRE_MALLOC(sizeof(struct slre_node) * pat_len * 2);
8352 e.prog->flags = is_regex ? SLRE_FLAG_RE : 0;
8353
8354 if ((err_code = setjmp(e.jmp_buf)) != SLRE_OK) {
8355 SLRE_FREE(e.pstart);
8356 SLRE_FREE(e.prog);
8357 return err_code;
8358 }
8359
8360 while (fl_len--) {
8361 switch (flags[fl_len]) {
8362 case 'g':
8363 e.prog->flags |= SLRE_FLAG_G;
8364 break;
8365 case 'i':
8366 e.prog->flags |= SLRE_FLAG_I;
8367 break;
8368 case 'm':
8369 e.prog->flags |= SLRE_FLAG_M;
8370 break;
8371 }
8372 }
8373
8374 e.src = pat;
8375 e.src_end = pat + pat_len;
8376 e.sets_num = 0;
8377 e.num_captures = 1;
8378 /*e.flags = flags;*/
8379 memset(e.caps, 0, sizeof(e.caps));
8380
8381 RE_NEXT(&e);
8382 nd = re_parser(&e);
8383 if (e.lookahead == ')') {
8384 SLRE_THROW(&e, SLRE_UNMATCH_RBR);
8385 }
8386 if (e.lookahead != 0) {
8387 SLRE_THROW(&e, SLRE_SYNTAX_ERROR);
8388 }
8389
8390 e.prog->num_captures = e.num_captures;
8391 e.prog->start = e.prog->end = (struct slre_instruction *) SLRE_MALLOC(
8392 (re_nodelen(nd) + 6) * sizeof(struct slre_instruction));
8393
8394 split = re_newinst(e.prog, I_SPLIT);
8395 split->par.xy.x = split + 3;
8396 split->par.xy.y.y = split + 1;
8397 re_newinst(e.prog, I_ANYNL);
8398 jump = re_newinst(e.prog, I_JUMP);
8399 jump->par.xy.x = split;
8400 re_newinst(e.prog, I_LBRA);
8401 re_compile(&e, nd);
8402 re_newinst(e.prog, I_RBRA);
8403 re_newinst(e.prog, I_END);
8404
8405#ifdef RE_TEST
8406 node_print(nd);
8407 putchar('\n');
8408 program_print(e.prog);
8409#endif
8410
8411 SLRE_FREE(e.pstart);
8412
8413 if (pr != NULL) {
8414 *pr = e.prog;
8415 } else {
8416 slre_free(e.prog);
8417 }
8418
8419 return err_code;
8420}
8421
8422void slre_free(struct slre_prog *prog) {
8423 if (prog) {
8424 SLRE_FREE(prog->start);
8425 SLRE_FREE(prog);
8426 }
8427}
8428
8429static struct slre_thread *re_newthread(struct slre_thread *t,
8430 struct slre_instruction *pc,
8431 const char *start,
8432 struct slre_loot *loot) {
8433 struct slre_thread *new_thread =
8434 (struct slre_thread *) SLRE_MALLOC(sizeof(struct slre_thread));
8435 if (new_thread != NULL) new_thread->prev = t;
8436 t->pc = pc;
8437 t->start = start;
8438 t->loot = *loot;
8439 return new_thread;
8440}
8441
8442static struct slre_thread *get_prev_thread(struct slre_thread *t) {
8443 struct slre_thread *tmp_thr = t->prev;
8444 SLRE_FREE(t);
8445 return tmp_thr;
8446}
8447
8448static void free_threads(struct slre_thread *t) {
8449 while (t->prev != NULL) t = get_prev_thread(t);
8450}
8451
8452static unsigned char re_match(struct slre_instruction *pc, const char *current,
8453 const char *end, const char *bol,
8454 unsigned int flags, struct slre_loot *loot) {
8455 struct slre_loot sub, tmpsub;
8456 Rune c, r;
8457 struct slre_range *p;
8458 size_t i;
8459 struct slre_thread thread, *curr_thread, *tmp_thr;
8460
8461 /* queue initial thread */
8462 thread.prev = NULL;
8463 curr_thread = re_newthread(&thread, pc, current, loot);
8464
8465 /* run threads in stack order */
8466 do {
8467 curr_thread = get_prev_thread(curr_thread);
8468 pc = curr_thread->pc;
8469 current = curr_thread->start;
8470 sub = curr_thread->loot;
8471 for (;;) {
8472 switch (pc->opcode) {
8473 case I_END:
8474 memcpy(loot->caps, sub.caps, sizeof loot->caps);
8475 free_threads(curr_thread);
8476 return 1;
8477 case I_ANY:
8478 case I_ANYNL:
8479 if (current < end) {
8480 current += chartorune(&c, current);
8481 if (c && !(pc->opcode == I_ANY && isnewline(c))) break;
8482 }
8483 goto no_match;
8484
8485 case I_BOL:
8486 if (current == bol) break;
8487 if ((flags & SLRE_FLAG_M) && isnewline(current[-1])) break;
8488 goto no_match;
8489 case I_CH:
8490 if (current < end) {
8491 current += chartorune(&c, current);
8492 if (c &&
8493 (c == pc->par.c || ((flags & SLRE_FLAG_I) &&
8494 tolowerrune(c) == tolowerrune(pc->par.c))))
8495 break;
8496 }
8497 goto no_match;
8498 case I_EOL:
8499 if (current >= end) break;
8500 if ((flags & SLRE_FLAG_M) && isnewline(*current)) break;
8501 goto no_match;
8502 case I_EOS:
8503 if (current >= end) break;
8504 goto no_match;
8505
8506 case I_JUMP:
8507 pc = pc->par.xy.x;
8508 continue;
8509
8510 case I_LA:
8511 if (re_match(pc->par.xy.x, current, end, bol, flags, &sub)) {
8512 pc = pc->par.xy.y.y;
8513 continue;
8514 }
8515 goto no_match;
8516 case I_LA_N:
8517 tmpsub = sub;
8518 if (!re_match(pc->par.xy.x, current, end, bol, flags, &tmpsub)) {
8519 pc = pc->par.xy.y.y;
8520 continue;
8521 }
8522 goto no_match;
8523
8524 case I_LBRA:
8525 sub.caps[pc->par.n].start = current;
8526 break;
8527
8528 case I_REF:
8529 i = sub.caps[pc->par.n].end - sub.caps[pc->par.n].start;
8530 if (flags & SLRE_FLAG_I) {
8531 int num = i;
8532 const char *s = current, *p = sub.caps[pc->par.n].start;
8533 Rune rr;
8534 for (; num && *s && *p; num--) {
8535 s += chartorune(&r, s);
8536 p += chartorune(&rr, p);
8537 if (tolowerrune(r) != tolowerrune(rr)) break;
8538 }
8539 if (num) goto no_match;
8540 } else if (strncmp(current, sub.caps[pc->par.n].start, i)) {
8541 goto no_match;
8542 }
8543 if (i > 0) current += i;
8544 break;
8545
8546 case I_REP:
8547 if (pc->par.xy.y.rp.min) {
8548 pc->par.xy.y.rp.min--;
8549 pc++;
8550 } else if (!pc->par.xy.y.rp.max--) {
8551 pc = pc->par.xy.x;
8552 continue;
8553 }
8554 break;
8555
8556 case I_REP_INI:
8557 (pc + 1)->par.xy.y.rp.min = pc->par.xy.y.rp.min;
8558 (pc + 1)->par.xy.y.rp.max = pc->par.xy.y.rp.max;
8559 break;
8560
8561 case I_RBRA:
8562 sub.caps[pc->par.n].end = current;
8563 break;
8564
8565 case I_SET:
8566 case I_SET_N:
8567 if (current >= end) goto no_match;
8568 current += chartorune(&c, current);
8569 if (!c) goto no_match;
8570
8571 i = 1;
8572 for (p = pc->par.cp->spans; i && p < pc->par.cp->end; p++)
8573 if (flags & SLRE_FLAG_I) {
8574 for (r = p->s; r <= p->e; ++r)
8575 if (tolowerrune(c) == tolowerrune(r)) {
8576 i = 0;
8577 break;
8578 }
8579 } else if (p->s <= c && c <= p->e)
8580 i = 0;
8581
8582 if (pc->opcode == I_SET) i = !i;
8583 if (i) break;
8584 goto no_match;
8585
8586 case I_SPLIT:
8587 tmp_thr = curr_thread;
8588 curr_thread =
8589 re_newthread(curr_thread, pc->par.xy.y.y, current, &sub);
8590 if (curr_thread == NULL) {
8591 fprintf(stderr, "re_match: no memory for thread!\n");
8592 free_threads(tmp_thr);
8593 return 0;
8594 }
8595 pc = pc->par.xy.x;
8596 continue;
8597
8598 case I_WORD:
8599 case I_WORD_N:
8600 i = (current > bol && iswordchar(current[-1]));
8601 if (iswordchar(current[0])) i = !i;
8602 if (pc->opcode == I_WORD_N) i = !i;
8603 if (i) break;
8604 /* goto no_match; */
8605
8606 default:
8607 goto no_match;
8608 }
8609 pc++;
8610 }
8611 no_match:
8612 ;
8613 } while (curr_thread->prev != NULL);
8614 return 0;
8615}
8616
8617int slre_exec(struct slre_prog *prog, int flag_g, const char *start,
8618 const char *end, struct slre_loot *loot) {
8619 struct slre_loot tmpsub;
8620 const char *st = start;
8621
8622 if (!loot) loot = &tmpsub;
8623 memset(loot, 0, sizeof(*loot));
8624
8625 if (!flag_g) {
8626 loot->num_captures = prog->num_captures;
8627 return !re_match(prog->start, start, end, start, prog->flags, loot);
8628 }
8629
8630 while (re_match(prog->start, st, end, start, prog->flags, &tmpsub)) {
8631 unsigned int i;
8632 st = tmpsub.caps[0].end;
8633 for (i = 0; i < prog->num_captures; i++) {
8634 struct slre_cap *l = &loot->caps[loot->num_captures + i];
8635 struct slre_cap *s = &tmpsub.caps[i];
8636 l->start = s->start;
8637 l->end = s->end;
8638 }
8639 loot->num_captures += prog->num_captures;
8640 }
8641 return !loot->num_captures;
8642}
8643
8644int slre_replace(struct slre_loot *loot, const char *src, size_t src_len,
8645 const char *rstr, size_t rstr_len, struct slre_loot *dstsub) {
8646 int size = 0, n;
8647 Rune curr_rune;
8648 const char *const rstr_end = rstr + rstr_len;
8649
8650 memset(dstsub, 0, sizeof(*dstsub));
8651 while (rstr < rstr_end && !(n = re_nextc_raw(&curr_rune, &rstr, rstr_end)) &&
8652 curr_rune) {
8653 int sz;
8654 if (n < 0) return n;
8655 if (curr_rune == '$') {
8656 n = re_nextc(&curr_rune, &rstr, rstr_end);
8657 if (n < 0) return n;
8658 switch (curr_rune) {
8659 case '&':
8660 sz = loot->caps[0].end - loot->caps[0].start;
8661 size += sz;
8662 dstsub->caps[dstsub->num_captures++] = loot->caps[0];
8663 break;
8664 case '0':
8665 case '1':
8666 case '2':
8667 case '3':
8668 case '4':
8669 case '5':
8670 case '6':
8671 case '7':
8672 case '8':
8673 case '9': {
8674 int sbn = dec(curr_rune);
8675 if (0 == sbn && rstr[0] && isdigitrune(rstr[0])) {
8676 n = re_nextc(&curr_rune, &rstr, rstr_end);
8677 if (n < 0) return n;
8678 sz = dec(curr_rune);
8679 sbn = sbn * 10 + sz;
8680 }
8681 if (sbn >= loot->num_captures) break;
8682 sz = loot->caps[sbn].end - loot->caps[sbn].start;
8683 size += sz;
8684 dstsub->caps[dstsub->num_captures++] = loot->caps[sbn];
8685 break;
8686 }
8687 case '`':
8688 sz = loot->caps[0].start - src;
8689 size += sz;
8690 dstsub->caps[dstsub->num_captures].start = src;
8691 dstsub->caps[dstsub->num_captures++].end = loot->caps[0].start;
8692 break;
8693 case '\'':
8694 sz = src + src_len - loot->caps[0].end;
8695 size += sz;
8696 dstsub->caps[dstsub->num_captures].start = loot->caps[0].end;
8697 dstsub->caps[dstsub->num_captures++].end = loot->caps[0].end + sz;
8698 break;
8699 case '$':
8700 size++;
8701 dstsub->caps[dstsub->num_captures].start = rstr - 1;
8702 dstsub->caps[dstsub->num_captures++].end = rstr;
8703 break;
8704 default:
8705 return SLRE_BAD_CHAR_AFTER_USD;
8706 }
8707 } else {
8708 char tmps[300], *d = tmps;
8709 size += (sz = runetochar(d, &curr_rune));
8710 if (!dstsub->num_captures ||
8711 dstsub->caps[dstsub->num_captures - 1].end != rstr - sz) {
8712 dstsub->caps[dstsub->num_captures].start = rstr - sz;
8713 dstsub->caps[dstsub->num_captures++].end = rstr;
8714 } else
8715 dstsub->caps[dstsub->num_captures - 1].end = rstr;
8716 }
8717 }
8718 return size;
8719}
8720
8721int slre_match(const char *re, size_t re_len, const char *flags, size_t fl_len,
8722 const char *str, size_t str_len, struct slre_loot *loot) {
8723 struct slre_prog *prog = NULL;
8724 int res;
8725
8726 if ((res = slre_compile(re, re_len, flags, fl_len, &prog, 1)) == SLRE_OK) {
8727 res = slre_exec(prog, prog->flags & SLRE_FLAG_G, str, str + str_len, loot);
8728 slre_free(prog);
8729 }
8730
8731 return res;
8732}
8733
8734int slre_get_flags(struct slre_prog *crp) {
8735 return crp->flags;
8736}
8737
8738#ifdef SLRE_TEST
8739
8740#include <errno.h>
8741
8742static const char *err_code_to_str(int err_code) {
8743 static const char *ar[] = {
8744 "no error", "invalid decimal digit", "invalid hex digit",
8745 "invalid escape character", "invalid unterminated escape sequence",
8746 "syntax error", "unmatched left parenthesis",
8747 "unmatched right parenthesis", "numeric overflow",
8748 "infinite loop empty string", "too many charsets",
8749 "invalid charset range", "charset is too large", "malformed charset",
8750 "invalid back reference", "too many captures", "invalid quantifier",
8751 "bad character after $"};
8752
8753 typedef char static_assertion_err_codes_out_of_sync
8754 [2 * !!(((sizeof(ar) / sizeof(ar[0])) == SLRE_BAD_CHAR_AFTER_USD + 1)) -
8755 1];
8756
8757 return err_code >= 0 && err_code < (int) (sizeof(ar) / sizeof(ar[0]))
8758 ? ar[err_code]
8759 : "invalid error code";
8760}
8761
8762#define RE_TEST_STR_SIZE 2000
8763
8764static unsigned get_flags(const char *ch) {
8765 unsigned int flags = 0;
8766
8767 while (*ch != '\0') {
8768 switch (*ch) {
8769 case 'g':
8770 flags |= SLRE_FLAG_G;
8771 break;
8772 case 'i':
8773 flags |= SLRE_FLAG_I;
8774 break;
8775 case 'm':
8776 flags |= SLRE_FLAG_M;
8777 break;
8778 case 'r':
8779 flags |= SLRE_FLAG_RE;
8780 break;
8781 default:
8782 return flags;
8783 }
8784 ch++;
8785 }
8786 return flags;
8787}
8788
8789static void show_usage_and_exit(char *argv[]) {
8790 fprintf(stderr, "Usage: %s [OPTIONS]\n", argv[0]);
8791 fprintf(stderr, "%s\n", "OPTIONS:");
8792 fprintf(stderr, "%s\n", " -p <regex_pattern> Regex pattern");
8793 fprintf(stderr, "%s\n", " -o <regex_flags> Combination of g,i,m");
8794 fprintf(stderr, "%s\n", " -s <string> String to match");
8795 fprintf(stderr, "%s\n", " -f <file_name> Match lines from file");
8796 fprintf(stderr, "%s\n", " -n <cap_no> Show given capture");
8797 fprintf(stderr, "%s\n", " -r <replace_str> Replace given capture");
8798 fprintf(stderr, "%s\n", " -v Show verbose stats");
8799 exit(1);
8800}
8801
8802static int process_line(struct slre_prog *pr, const char *flags,
8803 const char *line, const char *cap_no,
8804 const char *replace, const char *verbose) {
8805 struct slre_loot loot;
8806 unsigned int fl = flags == NULL ? 0 : get_flags(flags);
8807 int i, n = cap_no == NULL ? -1 : atoi(cap_no), err_code = 0;
8808 struct slre_cap *cap = &loot.caps[n];
8809
8810 err_code =
8811 slre_exec(pr, pr->flags & SLRE_FLAG_G, line, line + strlen(line), &loot);
8812 if (err_code == SLRE_OK) {
8813 if (n >= 0 && n < loot.num_captures && replace != NULL) {
8814 struct slre_cap *cap = &loot.caps[n];
8815 printf("%.*s", (int) (cap->start - line), line);
8816 printf("%s", replace);
8817 printf("%.*s", (int) ((line + strlen(line)) - cap->end), cap->end);
8818 } else if (n >= 0 && n < loot.num_captures) {
8819 printf("%.*s\n", (int) (cap->end - cap->start), cap->start);
8820 }
8821
8822 if (verbose != NULL) {
8823 fprintf(stderr, "%s\n", "Captures:");
8824 for (i = 0; i < loot.num_captures; i++) {
8825 fprintf(stderr, "%d [%.*s]\n", i,
8826 (int) (loot.caps[i].end - loot.caps[i].start),
8827 loot.caps[i].start);
8828 }
8829 }
8830 }
8831
8832 return err_code;
8833}
8834
8835int main(int argc, char **argv) {
8836 const char *str = NULL, *pattern = NULL, *replace = NULL;
8837 const char *flags = "", *file_name = NULL, *cap_no = NULL, *verbose = NULL;
8838 struct slre_prog *pr = NULL;
8839 int i, err_code = 0;
8840
8841 /* Execute inline code */
8842 for (i = 1; i < argc; i++) {
8843 if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
8844 pattern = argv[++i];
8845 } else if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) {
8846 flags = argv[++i];
8847 } else if (strcmp(argv[i], "-s") == 0 && i + 1 < argc) {
8848 str = argv[++i];
8849 } else if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) {
8850 file_name = argv[++i];
8851 } else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) {
8852 cap_no = argv[++i];
8853 } else if (strcmp(argv[i], "-r") == 0 && i + 1 < argc) {
8854 replace = argv[++i];
8855 } else if (strcmp(argv[i], "-v") == 0) {
8856 verbose = "";
8857 } else if (strcmp(argv[i], "-h") == 0) {
8858 show_usage_and_exit(argv);
8859 } else {
8860 show_usage_and_exit(argv);
8861 }
8862 }
8863
8864 if (pattern == NULL) {
8865 fprintf(stderr, "%s\n", "-p option is mandatory");
8866 exit(1);
8867 } else if ((err_code = slre_compile(pattern, strlen(pattern), flags,
8868 strlen(flags), &pr, 1)) != SLRE_OK) {
8869 fprintf(stderr, "slre_compile(%s): %s\n", argv[0],
8870 err_code_to_str(err_code));
8871 exit(1);
8872 } else if (str != NULL) {
8873 err_code = process_line(pr, flags, str, cap_no, replace, verbose);
8874 } else if (file_name != NULL) {
8875 FILE *fp = strcmp(file_name, "-") == 0 ? stdin : fopen(file_name, "rb");
8876 char line[20 * 1024];
8877 if (fp == NULL) {
8878 fprintf(stderr, "Cannot open %s: %s\n", file_name, strerror(errno));
8879 exit(1);
8880 } else {
8881 /* Return success if at least one line matches */
8882 err_code = 1;
8883 while (fgets(line, sizeof(line), fp) != NULL) {
8884 if (process_line(pr, flags, line, cap_no, replace, verbose) ==
8885 SLRE_OK) {
8886 err_code = 0;
8887 }
8888 }
8889 fclose(fp); /* If fp == stdin, it is safe to close, too */
8890 }
8891 } else {
8892 fprintf(stderr, "%s\n", "Please specify one of -s or -f options");
8893 exit(1);
8894 }
8895 slre_free(pr);
8896
8897 return err_code;
8898}
8899#endif /* SLRE_TEST */
8900
8901#endif /* V7_ENABLE__RegExp */
8902#ifdef V7_MODULE_LINES
8903#line 1 "v7/src/heapusage.c"
8904#endif
8905/*
8906 * Copyright (c) 2014-2016 Cesanta Software Limited
8907 * All rights reserved
8908 */
8909
8910#include <stdlib.h>
8911#include <stdio.h>
8912#include <assert.h>
8913
8914/* Amalgamated: #include "v7/src/internal.h" */
8915
8916#if V7_HEAPUSAGE_ENABLE
8917
8918/*
8919 * A flag that is set by GC before allocating its buffers, so we can
8920 * distinguish these buffers from other allocations
8921 */
8922volatile int heap_dont_count = 0;
8923
8924extern void *__real_malloc(size_t size);
8925extern void *__real_calloc(size_t num, size_t size);
8926extern void *__real_realloc(void *p, size_t size);
8927extern void __real_free(void *p);
8928
8929/* TODO(dfrank): make it dynamically allocated from heap */
8930#define CELLS_CNT (1024 * 32)
8931
8932typedef struct cell {
8933 void *p;
8934 unsigned dont_count : 1;
8935 unsigned size : 31;
8936} cell_t;
8937
8938typedef struct alloc_registry {
8939 size_t used_cells_cnt;
8940 size_t allocated_size;
8941 size_t real_used_cells_cnt;
8942 size_t real_allocated_size;
8943 cell_t cells[CELLS_CNT];
8944} alloc_registry_t;
8945
8946static alloc_registry_t registry = {0};
8947
8948/*
8949 * Make a record about an allocated buffer `p` of size `size`
8950 */
8951static void cell_allocated(void *p, size_t size) {
8952 int i;
8953 int cell_num = -1;
8954
8955 if (p != NULL && size != 0) {
8956 /* TODO(dfrank): make it dynamically allocated from heap */
8957 assert(registry.real_used_cells_cnt < CELLS_CNT);
8958
8959 for (i = 0; i < CELLS_CNT; ++i) {
8960 if (registry.cells[i].p == NULL) {
8961 cell_num = i;
8962 break;
8963 }
8964 }
8965
8966 assert(cell_num != -1);
8967
8968 registry.cells[cell_num].p = p;
8969 registry.cells[cell_num].size = size;
8970 registry.cells[cell_num].dont_count = !!heap_dont_count;
8971
8972 registry.real_allocated_size += size;
8973 registry.real_used_cells_cnt += 1;
8974
8975 if (!heap_dont_count) {
8976 registry.allocated_size += size;
8977 registry.used_cells_cnt += 1;
8978 }
8979
8980#if 0
8981 printf("alloc=0x%lx, size=%lu, total=%lu\n", (unsigned long)p, size,
8982 registry.allocated_size);
8983#endif
8984 }
8985}
8986
8987/*
8988 * Delete a record about an allocated buffer `p`. If our registry does not
8989 * contain anything about the given pointer, the call is ignored. We can't
8990 * generate an error because shared libraries still use unwrapped heap
8991 * functions, so we can face "unknown" pointers.
8992 */
8993static void cell_freed(void *p) {
8994 int i;
8995 int cell_num = -1;
8996
8997 if (p != NULL) {
8998 assert(registry.real_used_cells_cnt > 0);
8999
9000 for (i = 0; i < CELLS_CNT; ++i) {
9001 if (registry.cells[i].p == p) {
9002 cell_num = i;
9003 break;
9004 }
9005 }
9006
9007 /*
9008 * NOTE: it would be nice to have `assert(cell_num != -1);`, but
9009 * unfortunately not all allocations are wrapped: shared libraries will
9010 * still use unwrapped mallocs, so we might get unknown pointers here.
9011 */
9012
9013 if (cell_num != -1) {
9014 registry.real_allocated_size -= registry.cells[cell_num].size;
9015 registry.real_used_cells_cnt -= 1;
9016
9017 if (!registry.cells[cell_num].dont_count) {
9018 registry.allocated_size -= registry.cells[cell_num].size;
9019 registry.used_cells_cnt -= 1;
9020 }
9021
9022 registry.cells[cell_num].p = NULL;
9023 registry.cells[cell_num].size = 0;
9024 registry.cells[cell_num].dont_count = 0;
9025
9026#if 0
9027 printf("free=0x%lx, total=%lu\n", (unsigned long)p, registry.allocated_size);
9028#endif
9029 }
9030 }
9031}
9032
9033/*
9034 * Wrappers of the standard heap functions
9035 */
9036
9037void *__wrap_malloc(size_t size) {
9038 void *ret = __real_malloc(size);
9039 cell_allocated(ret, size);
9040 return ret;
9041}
9042
9043void *__wrap_calloc(size_t num, size_t size) {
9044 void *ret = __real_calloc(num, size);
9045 cell_allocated(ret, num * size);
9046 return ret;
9047}
9048
9049void *__wrap_realloc(void *p, size_t size) {
9050 void *ret;
9051 cell_freed(p);
9052 ret = __real_realloc(p, size);
9053 cell_allocated(ret, size);
9054 return ret;
9055}
9056
9057void __wrap_free(void *p) {
9058 __real_free(p);
9059 cell_freed(p);
9060}
9061
9062/*
9063 * Small API to get some stats, see header file for details
9064 */
9065
9066size_t heapusage_alloc_size(void) {
9067 return registry.allocated_size;
9068}
9069
9070size_t heapusage_allocs_cnt(void) {
9071 return registry.used_cells_cnt;
9072}
9073
9074#endif /* V7_HEAPUSAGE_ENABLE */
9075#ifdef V7_MODULE_LINES
9076#line 1 "v7/src/cyg_profile.c"
9077#endif
9078/*
9079 * Copyright (c) 2014 Cesanta Software Limited
9080 * All rights reserved
9081 */
9082
9083/*
9084 * This file contains GCC/clang instrumentation callbacks. The actual
9085 * code in these callbacks depends on enabled features.
9086 *
9087 * Currently, the code from different subsystems is embedded right into
9088 * callbacks for performance reasons. It would be probably more elegant
9089 * to have subsystem-specific functions that will be called from these
9090 * callbacks, but since the callbacks are called really a lot (on each v7
9091 * function call), I decided it's better to inline the code right here.
9092 */
9093
9094/* Amalgamated: #include "v7/src/internal.h" */
9095/* Amalgamated: #include "v7/src/cyg_profile.h" */
9096/* Amalgamated: #include "v7/src/core.h" */
9097
9098#if defined(V7_CYG_PROFILE_ON)
9099
9100#ifndef IRAM
9101#define IRAM
9102#endif
9103
9104#ifndef NOINSTR
9105#define NOINSTR __attribute__((no_instrument_function))
9106#endif
9107
9108#if defined(__cplusplus)
9109extern "C" {
9110#endif /* __cplusplus */
9111IRAM NOINSTR void __cyg_profile_func_enter(void *this_fn, void *call_site);
9112
9113IRAM NOINSTR void __cyg_profile_func_exit(void *this_fn, void *call_site);
9114
9115#if defined(__cplusplus)
9116}
9117#endif /* __cplusplus */
9118
9119IRAM void __cyg_profile_func_enter(void *this_fn, void *call_site) {
9120#if defined(V7_STACK_GUARD_MIN_SIZE)
9121 {
9122 static int profile_enter = 0;
9123 void *fp = __builtin_frame_address(0);
9124
9125 (void) call_site;
9126
9127 if (profile_enter || v7_sp_limit == NULL) return;
9128
9129 profile_enter++;
9130 if (v7_head != NULL && fp < v7_head->sp_lwm) v7_head->sp_lwm = fp;
9131
9132 if (((int) fp - (int) v7_sp_limit) < V7_STACK_GUARD_MIN_SIZE) {
9133 printf("fun %p sp %p limit %p left %d\n", this_fn, fp, v7_sp_limit,
9134 (int) fp - (int) v7_sp_limit);
9135 abort();
9136 }
9137 profile_enter--;
9138 }
9139#endif
9140
9141#if V7_ENABLE_GC_CHECK
9142 {
9143 (void) this_fn;
9144 (void) call_site;
9145 }
9146#endif
9147
9148#if V7_ENABLE_STACK_TRACKING
9149 {
9150 struct v7 *v7;
9151 struct stack_track_ctx *ctx;
9152 void *fp = __builtin_frame_address(1);
9153
9154 (void) this_fn;
9155 (void) call_site;
9156
9157 /*
9158 * TODO(dfrank): it actually won't work for multiple instances of v7 running
9159 * in parallel threads. We need to know the exact v7 instance for which
9160 * current function is called, but so far I failed to find a way to do this.
9161 */
9162 for (v7 = v7_head; v7 != NULL; v7 = v7->next_v7) {
9163 for (ctx = v7->stack_track_ctx; ctx != NULL; ctx = ctx->next) {
9164 /* commented because it fails on legal code compiled with -O3 */
9165 /*assert(fp <= ctx->start);*/
9166
9167 if (fp < ctx->max) {
9168 ctx->max = fp;
9169 }
9170 }
9171 }
9172 }
9173#endif
9174
9175#if V7_ENABLE_CALL_TRACE
9176 if (call_trace.size < CALL_TRACE_SIZE) {
9177 call_trace.addresses[call_trace.size] = this_fn;
9178 }
9179 call_trace.size++;
9180#endif
9181}
9182
9183IRAM void __cyg_profile_func_exit(void *this_fn, void *call_site) {
9184#if defined(V7_STACK_GUARD_MIN_SIZE)
9185 {
9186 (void) this_fn;
9187 (void) call_site;
9188 }
9189#endif
9190
9191#if V7_ENABLE_GC_CHECK
9192 {
9193 struct v7 *v7;
9194 void *fp = __builtin_frame_address(1);
9195
9196 (void) this_fn;
9197 (void) call_site;
9198
9199 for (v7 = v7_head; v7 != NULL; v7 = v7->next_v7) {
9200 v7_val_t **vp;
9201 if (v7->owned_values.buf == NULL) continue;
9202 vp = (v7_val_t **) (v7->owned_values.buf + v7->owned_values.len -
9203 sizeof(v7_val_t *));
9204
9205 for (; (char *) vp >= v7->owned_values.buf; vp--) {
9206 /*
9207 * Check if a variable belongs to a dead stack frame.
9208 * Addresses lower than the parent frame belong to the
9209 * stack frame of the function about to return.
9210 * But the heap also usually below the stack and
9211 * we don't know the end of the stack. But this hook
9212 * is called at each function return, so we have
9213 * to check only up to the maximum stack frame size,
9214 * let's arbitrarily but reasonably set that at 8k.
9215 */
9216 if ((void *) *vp <= fp && (void *) *vp > (fp + 8196)) {
9217 fprintf(stderr, "Found owned variable after return\n");
9218 abort();
9219 }
9220 }
9221 }
9222 }
9223#endif
9224
9225#if V7_ENABLE_STACK_TRACKING
9226 {
9227 (void) this_fn;
9228 (void) call_site;
9229 }
9230#endif
9231
9232#if V7_ENABLE_CALL_TRACE
9233 if (call_trace.size > 0) call_trace.size--;
9234#endif
9235}
9236
9237#if V7_ENABLE_STACK_TRACKING
9238
9239void v7_stack_track_start(struct v7 *v7, struct stack_track_ctx *ctx) {
9240 /* insert new context at the head of the list */
9241 ctx->next = v7->stack_track_ctx;
9242 v7->stack_track_ctx = ctx;
9243
9244 /* init both `max` and `start` to the current frame pointer */
9245 ctx->max = ctx->start = __builtin_frame_address(0);
9246}
9247
9248int v7_stack_track_end(struct v7 *v7, struct stack_track_ctx *ctx) {
9249 int diff;
9250
9251 /* this function can be called only for the head context */
9252 assert(v7->stack_track_ctx == ctx);
9253
9254 diff = (int) ((char *) ctx->start - (char *) ctx->max);
9255
9256 /* remove context from the linked list */
9257 v7->stack_track_ctx = ctx->next;
9258
9259 return (int) diff;
9260}
9261
9262#endif /* V7_ENABLE_STACK_TRACKING */
9263#endif /* V7_CYG_PROFILE_ON */
9264#ifdef V7_MODULE_LINES
9265#line 1 "v7/src/std_object.c"
9266#endif
9267/*
9268 * Copyright (c) 2014 Cesanta Software Limited
9269 * All rights reserved
9270 */
9271
9272/* Amalgamated: #include "common/str_util.h" */
9273/* Amalgamated: #include "v7/src/internal.h" */
9274/* Amalgamated: #include "v7/src/std_object.h" */
9275/* Amalgamated: #include "v7/src/function.h" */
9276/* Amalgamated: #include "v7/src/core.h" */
9277/* Amalgamated: #include "v7/src/conversion.h" */
9278/* Amalgamated: #include "v7/src/array.h" */
9279/* Amalgamated: #include "v7/src/object.h" */
9280/* Amalgamated: #include "v7/src/exceptions.h" */
9281/* Amalgamated: #include "v7/src/primitive.h" */
9282/* Amalgamated: #include "v7/src/string.h" */
9283/* Amalgamated: #include "v7/src/regexp.h" */
9284/* Amalgamated: #include "v7/src/exec.h" */
9285
9286#if V7_ENABLE__Object__getPrototypeOf
9287WARN_UNUSED_RESULT
9288V7_PRIVATE enum v7_err Obj_getPrototypeOf(struct v7 *v7, v7_val_t *res) {
9289 enum v7_err rcode = V7_OK;
9290 val_t arg = v7_arg(v7, 0);
9291
9292 if (!v7_is_object(arg)) {
9293 rcode =
9294 v7_throwf(v7, TYPE_ERROR, "Object.getPrototypeOf called on non-object");
9295 goto clean;
9296 }
9297 *res = v7_get_proto(v7, arg);
9298
9299clean:
9300 return rcode;
9301}
9302#endif
9303
9304#if V7_ENABLE__Object__isPrototypeOf
9305WARN_UNUSED_RESULT
9306V7_PRIVATE enum v7_err Obj_isPrototypeOf(struct v7 *v7, v7_val_t *res) {
9307 enum v7_err rcode = V7_OK;
9308 val_t obj = v7_arg(v7, 0);
9309 val_t proto = v7_get_this(v7);
9310
9311 *res = v7_mk_boolean(v7, is_prototype_of(v7, obj, proto));
9312
9313 return rcode;
9314}
9315#endif
9316
9317#if V7_ENABLE__Object__getOwnPropertyNames || V7_ENABLE__Object__keys
9318/*
9319 * Hack to ensure that the iteration order of the keys array is consistent
9320 * with the iteration order if properties in `for in`
9321 * This will be obsoleted when arrays will have a special object type.
9322 */
9323static void _Obj_append_reverse(struct v7 *v7, struct v7_property *p, val_t res,
9324 int i, v7_prop_attr_t ignore_flags) {
9325 while (p && p->attributes & ignore_flags) p = p->next;
9326 if (p == NULL) return;
9327 if (p->next) _Obj_append_reverse(v7, p->next, res, i + 1, ignore_flags);
9328
9329 v7_array_set(v7, res, i, p->name);
9330}
9331
9332WARN_UNUSED_RESULT
9333static enum v7_err _Obj_ownKeys(struct v7 *v7, unsigned int ignore_flags,
9334 val_t *res) {
9335 enum v7_err rcode = V7_OK;
9336 val_t obj = v7_arg(v7, 0);
9337
9338 *res = v7_mk_dense_array(v7);
9339
9340 if (!v7_is_object(obj)) {
9341 rcode = v7_throwf(v7, TYPE_ERROR, "Object.keys called on non-object");
9342 goto clean;
9343 }
9344
9345 _Obj_append_reverse(v7, get_object_struct(obj)->properties, *res, 0,
9346 ignore_flags);
9347
9348clean:
9349 return rcode;
9350}
9351#endif
9352
9353#if V7_ENABLE__Object__hasOwnProperty || \
9354 V7_ENABLE__Object__propertyIsEnumerable || \
9355 V7_ENABLE__Object__getOwnPropertyDescriptor
9356static enum v7_err _Obj_getOwnProperty(struct v7 *v7, val_t obj, val_t name,
9357 struct v7_property **res) {
9358 enum v7_err rcode = V7_OK;
9359 char name_buf[512];
9360 size_t name_len;
9361
9362 rcode = to_string(v7, name, NULL, name_buf, sizeof(name_buf), &name_len);
9363 if (rcode != V7_OK) {
9364 goto clean;
9365 }
9366
9367 *res = v7_get_own_property(v7, obj, name_buf, name_len);
9368
9369clean:
9370 return rcode;
9371}
9372#endif
9373
9374#if V7_ENABLE__Object__keys
9375WARN_UNUSED_RESULT
9376V7_PRIVATE enum v7_err Obj_keys(struct v7 *v7, v7_val_t *res) {
9377 return _Obj_ownKeys(v7, _V7_PROPERTY_HIDDEN | V7_PROPERTY_NON_ENUMERABLE,
9378 res);
9379}
9380#endif
9381
9382#if V7_ENABLE__Object__getOwnPropertyNames
9383WARN_UNUSED_RESULT
9384V7_PRIVATE enum v7_err Obj_getOwnPropertyNames(struct v7 *v7, v7_val_t *res) {
9385 return _Obj_ownKeys(v7, _V7_PROPERTY_HIDDEN, res);
9386}
9387#endif
9388
9389#if V7_ENABLE__Object__getOwnPropertyDescriptor
9390WARN_UNUSED_RESULT
9391V7_PRIVATE enum v7_err Obj_getOwnPropertyDescriptor(struct v7 *v7,
9392 v7_val_t *res) {
9393 enum v7_err rcode = V7_OK;
9394 struct v7_property *prop;
9395 val_t obj = v7_arg(v7, 0);
9396 val_t name = v7_arg(v7, 1);
9397 val_t desc;
9398
9399 rcode = _Obj_getOwnProperty(v7, obj, name, &prop);
9400 if (rcode != V7_OK) {
9401 goto clean;
9402 }
9403
9404 if (prop == NULL) {
9405 goto clean;
9406 }
9407
9408 desc = v7_mk_object(v7);
9409 v7_set(v7, desc, "value", 5, prop->value);
9410 v7_set(v7, desc, "writable", 8,
9411 v7_mk_boolean(v7, !(prop->attributes & V7_PROPERTY_NON_WRITABLE)));
9412 v7_set(v7, desc, "enumerable", 10,
9413 v7_mk_boolean(v7, !(prop->attributes & (_V7_PROPERTY_HIDDEN |
9414 V7_PROPERTY_NON_ENUMERABLE))));
9415 v7_set(v7, desc, "configurable", 12,
9416 v7_mk_boolean(v7, !(prop->attributes & V7_PROPERTY_NON_CONFIGURABLE)));
9417
9418 *res = desc;
9419
9420clean:
9421 return rcode;
9422}
9423#endif
9424
9425WARN_UNUSED_RESULT
9426static enum v7_err o_set_attr(struct v7 *v7, val_t desc, const char *name,
9427 size_t n, v7_prop_attr_desc_t *pattrs_delta,
9428 v7_prop_attr_desc_t flag_true,
9429 v7_prop_attr_desc_t flag_false) {
9430 enum v7_err rcode = V7_OK;
9431
9432 val_t v = V7_UNDEFINED;
9433 rcode = v7_get_throwing(v7, desc, name, n, &v);
9434 if (rcode != V7_OK) {
9435 goto clean;
9436 }
9437
9438 if (v7_is_truthy(v7, v)) {
9439 *pattrs_delta |= flag_true;
9440 } else {
9441 *pattrs_delta |= flag_false;
9442 }
9443
9444clean:
9445 return rcode;
9446}
9447
9448WARN_UNUSED_RESULT
9449static enum v7_err _Obj_defineProperty(struct v7 *v7, val_t obj,
9450 const char *name, int name_len,
9451 val_t desc, val_t *res) {
9452 enum v7_err rcode = V7_OK;
9453 val_t val = V7_UNDEFINED;
9454 v7_prop_attr_desc_t attrs_desc = 0;
9455
9456 /*
9457 * get provided value, or set `V7_DESC_PRESERVE_VALUE` flag if no value is
9458 * provided at all
9459 */
9460 {
9461 struct v7_property *prop = v7_get_property(v7, desc, "value", 5);
9462 if (prop == NULL) {
9463 /* no value is provided */
9464 attrs_desc |= V7_DESC_PRESERVE_VALUE;
9465 } else {
9466 /* value is provided: use it */
9467 rcode = v7_property_value(v7, desc, prop, &val);
9468 if (rcode != V7_OK) {
9469 goto clean;
9470 }
9471 }
9472 }
9473
9474 /* Examine given properties, and set appropriate flags for `def_property` */
9475
9476 rcode = o_set_attr(v7, desc, "enumerable", 10, &attrs_desc,
9477 V7_DESC_ENUMERABLE(1), V7_DESC_ENUMERABLE(0));
9478 if (rcode != V7_OK) {
9479 goto clean;
9480 }
9481
9482 rcode = o_set_attr(v7, desc, "writable", 8, &attrs_desc, V7_DESC_WRITABLE(1),
9483 V7_DESC_WRITABLE(0));
9484 if (rcode != V7_OK) {
9485 goto clean;
9486 }
9487
9488 rcode = o_set_attr(v7, desc, "configurable", 12, &attrs_desc,
9489 V7_DESC_CONFIGURABLE(1), V7_DESC_CONFIGURABLE(0));
9490 if (rcode != V7_OK) {
9491 goto clean;
9492 }
9493
9494 /* TODO(dfrank) : add getter/setter support */
9495
9496 /* Finally, do the job on defining the property */
9497 rcode = def_property(v7, obj, name, name_len, attrs_desc, val,
9498 0 /*not assign*/, NULL);
9499 if (rcode != V7_OK) {
9500 goto clean;
9501 }
9502
9503 *res = obj;
9504 goto clean;
9505
9506clean:
9507 return rcode;
9508}
9509
9510WARN_UNUSED_RESULT
9511V7_PRIVATE enum v7_err Obj_defineProperty(struct v7 *v7, v7_val_t *res) {
9512 enum v7_err rcode = V7_OK;
9513 val_t obj = v7_arg(v7, 0);
9514 val_t name = v7_arg(v7, 1);
9515 val_t desc = v7_arg(v7, 2);
9516 char name_buf[512];
9517 size_t name_len;
9518
9519 if (!v7_is_object(obj)) {
9520 rcode = v7_throwf(v7, TYPE_ERROR, "object expected");
9521 goto clean;
9522 }
9523
9524 rcode = to_string(v7, name, NULL, name_buf, sizeof(name_buf), &name_len);
9525 if (rcode != V7_OK) {
9526 goto clean;
9527 }
9528
9529 rcode = _Obj_defineProperty(v7, obj, name_buf, name_len, desc, res);
9530 goto clean;
9531
9532clean:
9533 return rcode;
9534}
9535
9536#if V7_ENABLE__Object__create || V7_ENABLE__Object__defineProperties
9537WARN_UNUSED_RESULT
9538static enum v7_err o_define_props(struct v7 *v7, val_t obj, val_t descs,
9539 val_t *res) {
9540 enum v7_err rcode = V7_OK;
9541 struct v7_property *p;
9542
9543 if (!v7_is_object(descs)) {
9544 rcode = v7_throwf(v7, TYPE_ERROR, "object expected");
9545 goto clean;
9546 }
9547
9548 for (p = get_object_struct(descs)->properties; p; p = p->next) {
9549 size_t n;
9550 const char *s = v7_get_string(v7, &p->name, &n);
9551 if (p->attributes & (_V7_PROPERTY_HIDDEN | V7_PROPERTY_NON_ENUMERABLE)) {
9552 continue;
9553 }
9554 rcode = _Obj_defineProperty(v7, obj, s, n, p->value, res);
9555 if (rcode != V7_OK) {
9556 goto clean;
9557 }
9558 }
9559
9560clean:
9561 return rcode;
9562}
9563#endif
9564
9565#if V7_ENABLE__Object__defineProperties
9566WARN_UNUSED_RESULT
9567V7_PRIVATE enum v7_err Obj_defineProperties(struct v7 *v7, v7_val_t *res) {
9568 enum v7_err rcode = V7_OK;
9569 val_t descs = V7_UNDEFINED;
9570
9571 *res = v7_arg(v7, 0);
9572 descs = v7_arg(v7, 1);
9573 rcode = o_define_props(v7, *res, descs, res);
9574 if (rcode != V7_OK) {
9575 goto clean;
9576 }
9577
9578clean:
9579 return rcode;
9580}
9581#endif
9582
9583#if V7_ENABLE__Object__create
9584WARN_UNUSED_RESULT
9585V7_PRIVATE enum v7_err Obj_create(struct v7 *v7, v7_val_t *res) {
9586 enum v7_err rcode = V7_OK;
9587 val_t proto = v7_arg(v7, 0);
9588 val_t descs = v7_arg(v7, 1);
9589 if (!v7_is_null(proto) && !v7_is_object(proto)) {
9590 rcode = v7_throwf(v7, TYPE_ERROR,
9591 "Object prototype may only be an Object or null");
9592 goto clean;
9593 }
9594 *res = mk_object(v7, proto);
9595 if (v7_is_object(descs)) {
9596 rcode = o_define_props(v7, *res, descs, res);
9597 if (rcode != V7_OK) {
9598 goto clean;
9599 }
9600 }
9601
9602clean:
9603 return rcode;
9604}
9605#endif
9606
9607#if V7_ENABLE__Object__propertyIsEnumerable
9608WARN_UNUSED_RESULT
9609V7_PRIVATE enum v7_err Obj_propertyIsEnumerable(struct v7 *v7, v7_val_t *res) {
9610 enum v7_err rcode = V7_OK;
9611 val_t this_obj = v7_get_this(v7);
9612 struct v7_property *prop;
9613 val_t name = v7_arg(v7, 0);
9614
9615 rcode = _Obj_getOwnProperty(v7, this_obj, name, &prop);
9616 if (rcode != V7_OK) {
9617 goto clean;
9618 }
9619
9620 if (prop == NULL) {
9621 *res = v7_mk_boolean(v7, 0);
9622 } else {
9623 *res =
9624 v7_mk_boolean(v7, !(prop->attributes & (_V7_PROPERTY_HIDDEN |
9625 V7_PROPERTY_NON_ENUMERABLE)));
9626 }
9627
9628 goto clean;
9629
9630clean:
9631 return rcode;
9632}
9633#endif
9634
9635#if V7_ENABLE__Object__hasOwnProperty
9636WARN_UNUSED_RESULT
9637V7_PRIVATE enum v7_err Obj_hasOwnProperty(struct v7 *v7, v7_val_t *res) {
9638 enum v7_err rcode = V7_OK;
9639 val_t this_obj = v7_get_this(v7);
9640 val_t name = v7_arg(v7, 0);
9641 struct v7_property *ptmp = NULL;
9642
9643 rcode = _Obj_getOwnProperty(v7, this_obj, name, &ptmp);
9644 if (rcode != V7_OK) {
9645 goto clean;
9646 }
9647
9648 *res = v7_mk_boolean(v7, ptmp != NULL);
9649 goto clean;
9650
9651clean:
9652 return rcode;
9653}
9654#endif
9655
9656WARN_UNUSED_RESULT
9657V7_PRIVATE enum v7_err Obj_valueOf(struct v7 *v7, v7_val_t *res) {
9658 enum v7_err rcode = V7_OK;
9659 val_t this_obj = v7_get_this(v7);
9660 struct v7_property *p;
9661
9662 *res = this_obj;
9663
9664 if (v7_is_regexp(v7, this_obj)) {
9665 /* res is `this_obj` */
9666 goto clean;
9667 }
9668
9669 p = v7_get_own_property2(v7, this_obj, "", 0, _V7_PROPERTY_HIDDEN);
9670 if (p != NULL) {
9671 *res = p->value;
9672 goto clean;
9673 }
9674
9675clean:
9676 return rcode;
9677}
9678
9679WARN_UNUSED_RESULT
9680V7_PRIVATE enum v7_err Obj_toString(struct v7 *v7, v7_val_t *res) {
9681 enum v7_err rcode = V7_OK;
9682 val_t ctor, name, this_obj = v7_get_this(v7);
9683 char buf[20];
9684 const char *str = "Object";
9685 size_t name_len = ~0;
9686
9687 if (v7_is_undefined(this_obj)) {
9688 str = "Undefined";
9689 } else if (v7_is_null(this_obj)) {
9690 str = "Null";
9691 } else if (v7_is_number(this_obj)) {
9692 str = "Number";
9693 } else if (v7_is_boolean(this_obj)) {
9694 str = "Boolean";
9695 } else if (v7_is_string(this_obj)) {
9696 str = "String";
9697 } else if (v7_is_callable(v7, this_obj)) {
9698 str = "Function";
9699 } else {
9700 rcode = v7_get_throwing(v7, this_obj, "constructor", ~0, &ctor);
9701 if (rcode != V7_OK) {
9702 goto clean;
9703 }
9704
9705 if (!v7_is_undefined(ctor)) {
9706 rcode = v7_get_throwing(v7, ctor, "name", ~0, &name);
9707 if (rcode != V7_OK) {
9708 goto clean;
9709 }
9710
9711 if (!v7_is_undefined(name)) {
9712 size_t tmp_len;
9713 const char *tmp_str;
9714 tmp_str = v7_get_string(v7, &name, &tmp_len);
9715 /*
9716 * objects constructed with an anonymous constructor are represented as
9717 * Object, ch11/11.1/11.1.1/S11.1.1_A4.2.js
9718 */
9719 if (tmp_len > 0) {
9720 str = tmp_str;
9721 name_len = tmp_len;
9722 }
9723 }
9724 }
9725 }
9726
9727 if (name_len == (size_t) ~0) {
9728 name_len = strlen(str);
9729 }
9730
9731 c_snprintf(buf, sizeof(buf), "[object %.*s]", (int) name_len, str);
9732 *res = v7_mk_string(v7, buf, strlen(buf), 1);
9733
9734clean:
9735 return rcode;
9736}
9737
9738#if V7_ENABLE__Object__preventExtensions
9739WARN_UNUSED_RESULT
9740V7_PRIVATE enum v7_err Obj_preventExtensions(struct v7 *v7, v7_val_t *res) {
9741 enum v7_err rcode = V7_OK;
9742 val_t arg = v7_arg(v7, 0);
9743 if (!v7_is_object(arg)) {
9744 rcode = v7_throwf(v7, TYPE_ERROR, "Object expected");
9745 goto clean;
9746 }
9747 get_object_struct(arg)->attributes |= V7_OBJ_NOT_EXTENSIBLE;
9748 *res = arg;
9749
9750clean:
9751 return rcode;
9752}
9753#endif
9754
9755#if V7_ENABLE__Object__isExtensible
9756WARN_UNUSED_RESULT
9757V7_PRIVATE enum v7_err Obj_isExtensible(struct v7 *v7, v7_val_t *res) {
9758 enum v7_err rcode = V7_OK;
9759 val_t arg = v7_arg(v7, 0);
9760
9761 if (!v7_is_object(arg)) {
9762 rcode = v7_throwf(v7, TYPE_ERROR, "Object expected");
9763 goto clean;
9764 }
9765
9766 *res = v7_mk_boolean(
9767 v7, !(get_object_struct(arg)->attributes & V7_OBJ_NOT_EXTENSIBLE));
9768
9769clean:
9770 return rcode;
9771}
9772#endif
9773
9774#if V7_ENABLE__Object__isFrozen || V7_ENABLE__Object__isSealed
9775static enum v7_err is_rigid(struct v7 *v7, v7_val_t *res, int is_frozen) {
9776 enum v7_err rcode = V7_OK;
9777 int ok = 0;
9778 val_t arg = v7_arg(v7, 0);
9779
9780 if (!v7_is_object(arg)) {
9781 rcode = v7_throwf(v7, TYPE_ERROR, "Object expected");
9782 goto clean;
9783 }
9784
9785 *res = v7_mk_boolean(v7, 0);
9786
9787 if (get_object_struct(arg)->attributes & V7_OBJ_NOT_EXTENSIBLE) {
9788 v7_prop_attr_t attrs = 0;
9789 struct prop_iter_ctx ctx;
9790 memset(&ctx, 0, sizeof(ctx));
9791 V7_TRY2(init_prop_iter_ctx(v7, arg, 1, &ctx), clean_iter);
9792 while (1) {
9793 V7_TRY2(next_prop(v7, &ctx, NULL, NULL, &attrs, &ok), clean_iter);
9794 if (!ok) {
9795 break;
9796 }
9797 if (!(attrs & V7_PROPERTY_NON_CONFIGURABLE)) {
9798 goto clean_iter;
9799 }
9800 if (is_frozen) {
9801 if (!(attrs & V7_PROPERTY_SETTER) &&
9802 !(attrs & V7_PROPERTY_NON_WRITABLE)) {
9803 goto clean_iter;
9804 }
9805 }
9806 }
9807
9808 *res = v7_mk_boolean(v7, 1);
9809
9810 clean_iter:
9811 v7_destruct_prop_iter_ctx(v7, &ctx);
9812 goto clean;
9813 }
9814
9815clean:
9816 return rcode;
9817}
9818#endif
9819
9820#if V7_ENABLE__Object__isSealed
9821WARN_UNUSED_RESULT
9822V7_PRIVATE enum v7_err Obj_isSealed(struct v7 *v7, v7_val_t *res) {
9823 return is_rigid(v7, res, 0 /* is_frozen */);
9824}
9825#endif
9826
9827#if V7_ENABLE__Object__isFrozen
9828WARN_UNUSED_RESULT
9829V7_PRIVATE enum v7_err Obj_isFrozen(struct v7 *v7, v7_val_t *res) {
9830 return is_rigid(v7, res, 1 /* is_frozen */);
9831}
9832#endif
9833
9834static const char js_function_Object[] =
9835 "function Object(v) {"
9836 "if (typeof v === 'boolean') return new Boolean(v);"
9837 "if (typeof v === 'number') return new Number(v);"
9838 "if (typeof v === 'string') return new String(v);"
9839 "if (typeof v === 'date') return new Date(v);"
9840 "}";
9841
9842V7_PRIVATE void init_object(struct v7 *v7) {
9843 enum v7_err rcode = V7_OK;
9844 val_t object, v;
9845 /* TODO(mkm): initialize global object without requiring a parser */
9846 rcode = v7_exec(v7, js_function_Object, &v);
9847 assert(rcode == V7_OK);
9848#if defined(NDEBUG)
9849 (void) rcode;
9850#endif
9851
9852 object = v7_get(v7, v7->vals.global_object, "Object", 6);
9853 v7_set(v7, object, "prototype", 9, v7->vals.object_prototype);
9854 v7_def(v7, v7->vals.object_prototype, "constructor", 11,
9855 V7_DESC_ENUMERABLE(0), object);
9856
9857 set_method(v7, v7->vals.object_prototype, "toString", Obj_toString, 0);
9858#if V7_ENABLE__Object__getPrototypeOf
9859 set_cfunc_prop(v7, object, "getPrototypeOf", Obj_getPrototypeOf);
9860#endif
9861#if V7_ENABLE__Object__getOwnPropertyDescriptor
9862 set_cfunc_prop(v7, object, "getOwnPropertyDescriptor",
9863 Obj_getOwnPropertyDescriptor);
9864#endif
9865
9866 /* defineProperty is currently required to perform stdlib initialization */
9867 set_method(v7, object, "defineProperty", Obj_defineProperty, 3);
9868
9869#if V7_ENABLE__Object__defineProperties
9870 set_cfunc_prop(v7, object, "defineProperties", Obj_defineProperties);
9871#endif
9872#if V7_ENABLE__Object__create
9873 set_cfunc_prop(v7, object, "create", Obj_create);
9874#endif
9875#if V7_ENABLE__Object__keys
9876 set_cfunc_prop(v7, object, "keys", Obj_keys);
9877#endif
9878#if V7_ENABLE__Object__getOwnPropertyNames
9879 set_cfunc_prop(v7, object, "getOwnPropertyNames", Obj_getOwnPropertyNames);
9880#endif
9881#if V7_ENABLE__Object__preventExtensions
9882 set_method(v7, object, "preventExtensions", Obj_preventExtensions, 1);
9883#endif
9884#if V7_ENABLE__Object__isExtensible
9885 set_method(v7, object, "isExtensible", Obj_isExtensible, 1);
9886#endif
9887#if V7_ENABLE__Object__isSealed
9888 set_method(v7, object, "isSealed", Obj_isSealed, 1);
9889#endif
9890#if V7_ENABLE__Object__isFrozen
9891 set_method(v7, object, "isFrozen", Obj_isFrozen, 1);
9892#endif
9893
9894#if V7_ENABLE__Object__propertyIsEnumerable
9895 set_cfunc_prop(v7, v7->vals.object_prototype, "propertyIsEnumerable",
9896 Obj_propertyIsEnumerable);
9897#endif
9898#if V7_ENABLE__Object__hasOwnProperty
9899 set_cfunc_prop(v7, v7->vals.object_prototype, "hasOwnProperty",
9900 Obj_hasOwnProperty);
9901#endif
9902#if V7_ENABLE__Object__isPrototypeOf
9903 set_cfunc_prop(v7, v7->vals.object_prototype, "isPrototypeOf",
9904 Obj_isPrototypeOf);
9905#endif
9906 set_cfunc_prop(v7, v7->vals.object_prototype, "valueOf", Obj_valueOf);
9907}
9908#ifdef V7_MODULE_LINES
9909#line 1 "v7/src/std_error.c"
9910#endif
9911/*
9912 * Copyright (c) 2014 Cesanta Software Limited
9913 * All rights reserved
9914 */
9915
9916/* Amalgamated: #include "v7/src/internal.h" */
9917/* Amalgamated: #include "v7/src/core.h" */
9918/* Amalgamated: #include "v7/src/function.h" */
9919/* Amalgamated: #include "v7/src/string.h" */
9920/* Amalgamated: #include "v7/src/std_error.h" */
9921/* Amalgamated: #include "v7/src/object.h" */
9922/* Amalgamated: #include "v7/src/bcode.h" */
9923/* Amalgamated: #include "v7/src/primitive.h" */
9924/* Amalgamated: #include "v7/src/util.h" */
9925
9926/*
9927 * TODO(dfrank): make the top of v7->call_frame to represent the current
9928 * frame, and thus get rid of the `CUR_LINENO()`
9929 */
9930#if !V7_DISABLE_LINE_NUMBERS
9931#define CALLFRAME_LINENO(call_frame) ((call_frame)->line_no)
9932#define CUR_LINENO() (v7->line_no)
9933#else
9934#define CALLFRAME_LINENO(call_frame) 0
9935#define CUR_LINENO() 0
9936#endif
9937
9938WARN_UNUSED_RESULT
9939V7_PRIVATE enum v7_err Error_ctor(struct v7 *v7, v7_val_t *res);
9940
9941#if !V7_DISABLE_FILENAMES && !V7_DISABLE_LINE_NUMBERS
9942static int printf_stack_line(char *p, size_t len, struct bcode *bcode,
9943 int line_no, const char *leading) {
9944 int ret;
9945 const char *fn = bcode_get_filename(bcode);
9946 if (fn == NULL) {
9947 fn = "<no filename>";
9948 }
9949
9950 if (bcode->func_name_present) {
9951 /* this is a function's bcode: let's show the function's name as well */
9952 char *funcname;
9953
9954 /*
9955 * read first name from the bcode ops, which is the function name,
9956 * since `func_name_present` is set
9957 */
9958 bcode_next_name(bcode->ops.p, &funcname, NULL);
9959
9960 /* Check if it's an anonymous function */
9961 if (funcname[0] == '\0') {
9962 funcname = (char *) "<anonymous>";
9963 }
9964 ret =
9965 snprintf(p, len, "%s at %s (%s:%d)", leading, funcname, fn, line_no);
9966 } else {
9967 /* it's a file's bcode: show only filename and line number */
9968 ret = snprintf(p, len, "%s at %s:%d", leading, fn, line_no);
9969 }
9970 return ret;
9971}
9972
9973static int printf_stack_line_cfunc(char *p, size_t len, v7_cfunction_t *cfunc,
9974 const char *leading) {
9975 int ret = 0;
9976
9977#if !defined(V7_FILENAMES_SUPPRESS_CFUNC_ADDR)
9978 int name_len =
9979 snprintf(NULL, 0, "cfunc_%p", (void *) cfunc) + 1 /*null-term*/;
9980 char *buf = (char *) malloc(name_len);
9981
9982 snprintf(buf, name_len, "cfunc_%p", (void *) cfunc);
9983#else
9984 /*
9985 * We need this mode only for ecma test reporting, so that the
9986 * report is not different from one run to another
9987 */
9988 char *buf = (char *) "cfunc";
9989 (void) cfunc;
9990#endif
9991
9992 ret = snprintf(p, len, "%s at %s", leading, buf);
9993
9994#if !defined(V7_FILENAMES_SUPPRESS_CFUNC_ADDR)
9995 free(buf);
9996#endif
9997
9998 return ret;
9999}
10000
10001static int print_stack_trace(char *p, size_t len,
10002 struct v7_call_frame_base *call_frame) {
10003 char *p_cur = p;
10004 int total_len = 0;
10005
10006 assert(call_frame->type_mask == V7_CALL_FRAME_MASK_CFUNC &&
10007 ((struct v7_call_frame_cfunc *) call_frame)->cfunc == Error_ctor);
10008 call_frame = call_frame->prev;
10009
10010 while (call_frame != NULL) {
10011 int cur_len = 0;
10012 const char *leading = (total_len ? "\n" : "");
10013 size_t line_len = len - (p_cur - p);
10014
10015 if (call_frame->type_mask & V7_CALL_FRAME_MASK_BCODE) {
10016 struct bcode *bcode = ((struct v7_call_frame_bcode *) call_frame)->bcode;
10017 if (bcode != NULL) {
10018 cur_len = printf_stack_line(p_cur, line_len, bcode,
10019 CALLFRAME_LINENO(call_frame), leading);
10020 }
10021 } else if (call_frame->type_mask & V7_CALL_FRAME_MASK_CFUNC) {
10022 cur_len = printf_stack_line_cfunc(
10023 p_cur, line_len, ((struct v7_call_frame_cfunc *) call_frame)->cfunc,
10024 leading);
10025 }
10026
10027 total_len += cur_len;
10028 if (p_cur != NULL) {
10029 p_cur += cur_len;
10030 }
10031
10032 call_frame = call_frame->prev;
10033
10034#if !(V7_ENABLE__StackTrace)
10035 break;
10036#endif
10037 }
10038
10039 return total_len;
10040}
10041#endif
10042
10043WARN_UNUSED_RESULT
10044V7_PRIVATE enum v7_err Error_ctor(struct v7 *v7, v7_val_t *res) {
10045 enum v7_err rcode = V7_OK;
10046 val_t this_obj = v7_get_this(v7);
10047 val_t arg0 = v7_arg(v7, 0);
10048
10049 if (v7_is_object(this_obj) && this_obj != v7->vals.global_object) {
10050 *res = this_obj;
10051 } else {
10052 *res = mk_object(v7, v7->vals.error_prototype);
10053 }
10054 /* TODO(mkm): set non enumerable but provide toString method */
10055 v7_set(v7, *res, "message", 7, arg0);
10056
10057#if !V7_DISABLE_FILENAMES && !V7_DISABLE_LINE_NUMBERS
10058 /* Save the stack trace */
10059 {
10060 size_t len = 0;
10061 val_t st_v = V7_UNDEFINED;
10062
10063 v7_own(v7, &st_v);
10064
10065 len = print_stack_trace(NULL, 0, v7->call_stack);
10066
10067 if (len > 0) {
10068 /* Now, create a placeholder for string */
10069 st_v = v7_mk_string(v7, NULL, len, 1);
10070 len += 1 /*null-term*/;
10071
10072 /* And fill it with actual data */
10073 print_stack_trace((char *) v7_get_string(v7, &st_v, NULL), len,
10074 v7->call_stack);
10075
10076 v7_set(v7, *res, "stack", ~0, st_v);
10077 }
10078
10079 v7_disown(v7, &st_v);
10080 }
10081#endif
10082
10083 return rcode;
10084}
10085
10086WARN_UNUSED_RESULT
10087V7_PRIVATE enum v7_err Error_toString(struct v7 *v7, v7_val_t *res) {
10088 enum v7_err rcode = V7_OK;
10089 val_t this_obj = v7_get_this(v7);
10090 val_t prefix, msg = v7_get(v7, this_obj, "message", ~0);
10091
10092 if (!v7_is_string(msg)) {
10093 *res = v7_mk_string(v7, "Error", ~0, 1);
10094 goto clean;
10095 }
10096
10097 prefix = v7_mk_string(v7, "Error: ", ~0, 1);
10098 *res = s_concat(v7, prefix, msg);
10099 goto clean;
10100
10101clean:
10102 return rcode;
10103}
10104
10105static const char *const error_names[] = {TYPE_ERROR, SYNTAX_ERROR,
10106 REFERENCE_ERROR, INTERNAL_ERROR,
10107 RANGE_ERROR, EVAL_ERROR};
10108
10109V7_STATIC_ASSERT(ARRAY_SIZE(error_names) == ERROR_CTOR_MAX,
10110 error_name_count_mismatch);
10111
10112V7_PRIVATE void init_error(struct v7 *v7) {
10113 val_t error;
10114 size_t i;
10115
10116 error =
10117 mk_cfunction_obj_with_proto(v7, Error_ctor, 1, v7->vals.error_prototype);
10118 v7_def(v7, v7->vals.global_object, "Error", 5, V7_DESC_ENUMERABLE(0), error);
10119 set_method(v7, v7->vals.error_prototype, "toString", Error_toString, 0);
10120
10121 for (i = 0; i < ARRAY_SIZE(error_names); i++) {
10122 error = mk_cfunction_obj_with_proto(
10123 v7, Error_ctor, 1, mk_object(v7, v7->vals.error_prototype));
10124 v7_def(v7, v7->vals.global_object, error_names[i], strlen(error_names[i]),
10125 V7_DESC_ENUMERABLE(0), error);
10126 v7->vals.error_objects[i] = error;
10127 }
10128}
10129#ifdef V7_MODULE_LINES
10130#line 1 "v7/src/std_number.c"
10131#endif
10132/*
10133 * Copyright (c) 2014 Cesanta Software Limited
10134 * All rights reserved
10135 */
10136
10137/* Amalgamated: #include "v7/src/internal.h" */
10138/* Amalgamated: #include "v7/src/std_object.h" */
10139/* Amalgamated: #include "v7/src/conversion.h" */
10140/* Amalgamated: #include "v7/src/core.h" */
10141/* Amalgamated: #include "v7/src/function.h" */
10142/* Amalgamated: #include "v7/src/object.h" */
10143/* Amalgamated: #include "v7/src/primitive.h" */
10144/* Amalgamated: #include "v7/src/string.h" */
10145/* Amalgamated: #include "v7/src/exceptions.h" */
10146
10147#if defined(__cplusplus)
10148extern "C" {
10149#endif /* __cplusplus */
10150
10151WARN_UNUSED_RESULT
10152V7_PRIVATE enum v7_err Number_ctor(struct v7 *v7, v7_val_t *res) {
10153 enum v7_err rcode = V7_OK;
10154 val_t this_obj = v7_get_this(v7);
10155 val_t arg0 = v7_argc(v7) == 0 ? v7_mk_number(v7, 0.0) : v7_arg(v7, 0);
10156
10157 if (v7_is_number(arg0)) {
10158 *res = arg0;
10159 } else {
10160 rcode = to_number_v(v7, arg0, res);
10161 if (rcode != V7_OK) {
10162 goto clean;
10163 }
10164 }
10165
10166 if (v7_is_generic_object(this_obj) && this_obj != v7->vals.global_object) {
10167 obj_prototype_set(v7, get_object_struct(this_obj),
10168 get_object_struct(v7->vals.number_prototype));
10169 v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), *res);
10170
10171 /*
10172 * implicitly returning `this`: `call_cfunction()` in bcode.c will do
10173 * that for us
10174 */
10175 }
10176
10177clean:
10178 return rcode;
10179}
10180
10181WARN_UNUSED_RESULT
10182V7_PRIVATE enum v7_err n_to_str(struct v7 *v7, const char *format, val_t *res) {
10183 enum v7_err rcode = V7_OK;
10184 val_t this_obj = v7_get_this(v7);
10185 val_t arg0 = v7_arg(v7, 0);
10186 int len, digits = 0;
10187 char fmt[10], buf[100];
10188
10189 rcode = to_number_v(v7, arg0, &arg0);
10190 if (rcode != V7_OK) {
10191 goto clean;
10192 }
10193
10194 if (v7_get_double(v7, arg0) > 0) {
10195 digits = (int) v7_get_double(v7, arg0);
10196 }
10197
10198 /*
10199 * NOTE: we don't own `arg0` and `this_obj`, since this function is called
10200 * from cfunctions only, and GC is inhibited during these calls
10201 */
10202
10203 rcode = obj_value_of(v7, this_obj, &this_obj);
10204 if (rcode != V7_OK) {
10205 goto clean;
10206 }
10207
10208 snprintf(fmt, sizeof(fmt), format, digits);
10209 len = snprintf(buf, sizeof(buf), fmt, v7_get_double(v7, this_obj));
10210
10211 *res = v7_mk_string(v7, buf, len, 1);
10212
10213clean:
10214 return rcode;
10215}
10216
10217WARN_UNUSED_RESULT
10218V7_PRIVATE enum v7_err Number_toFixed(struct v7 *v7, v7_val_t *res) {
10219 return n_to_str(v7, "%%.%dlf", res);
10220}
10221
10222WARN_UNUSED_RESULT
10223V7_PRIVATE enum v7_err Number_toExp(struct v7 *v7, v7_val_t *res) {
10224 return n_to_str(v7, "%%.%de", res);
10225}
10226
10227WARN_UNUSED_RESULT
10228V7_PRIVATE enum v7_err Number_toPrecision(struct v7 *v7, v7_val_t *res) {
10229 return Number_toExp(v7, res);
10230}
10231
10232WARN_UNUSED_RESULT
10233V7_PRIVATE enum v7_err Number_valueOf(struct v7 *v7, v7_val_t *res) {
10234 enum v7_err rcode = V7_OK;
10235 val_t this_obj = v7_get_this(v7);
10236
10237 if (!v7_is_number(this_obj) &&
10238 (v7_is_object(this_obj) &&
10239 v7_get_proto(v7, this_obj) != v7->vals.number_prototype)) {
10240 rcode =
10241 v7_throwf(v7, TYPE_ERROR, "Number.valueOf called on non-number object");
10242 goto clean;
10243 }
10244
10245 rcode = Obj_valueOf(v7, res);
10246 if (rcode != V7_OK) {
10247 goto clean;
10248 }
10249
10250clean:
10251 return rcode;
10252}
10253
10254/*
10255 * Converts a 64 bit signed integer into a string of a given base.
10256 * Requires space for 65 bytes (64 bit + null terminator) in the result buffer
10257 */
10258static char *cs_itoa(int64_t value, char *result, int base) {
10259 char *ptr = result, *ptr1 = result, tmp_char;
10260 int64_t tmp_value;
10261 int64_t sign = value < 0 ? -1 : 1;
10262 const char *base36 = "0123456789abcdefghijklmnopqrstuvwxyz";
10263
10264 if (base < 2 || base > 36) {
10265 *result = '\0';
10266 return result;
10267 }
10268
10269 /* let's think positive */
10270 value = value * sign;
10271 do {
10272 tmp_value = value;
10273 value /= base;
10274 *ptr++ = base36[tmp_value - value * base];
10275 } while (value);
10276
10277 /* sign */
10278 if (sign < 0) *ptr++ = '-';
10279 *ptr-- = '\0';
10280 while (ptr1 < ptr) {
10281 tmp_char = *ptr;
10282 *ptr-- = *ptr1;
10283 *ptr1++ = tmp_char;
10284 }
10285 return result;
10286}
10287
10288WARN_UNUSED_RESULT
10289V7_PRIVATE enum v7_err Number_toString(struct v7 *v7, v7_val_t *res) {
10290 enum v7_err rcode = V7_OK;
10291 val_t this_obj = v7_get_this(v7);
10292 val_t radixv = v7_arg(v7, 0);
10293 char buf[65];
10294 double d, radix;
10295
10296 if (this_obj == v7->vals.number_prototype) {
10297 *res = v7_mk_string(v7, "0", 1, 1);
10298 goto clean;
10299 }
10300
10301 /* Make sure this function was called on Number instance */
10302 if (!v7_is_number(this_obj) &&
10303 !(v7_is_generic_object(this_obj) &&
10304 is_prototype_of(v7, this_obj, v7->vals.number_prototype))) {
10305 rcode = v7_throwf(v7, TYPE_ERROR,
10306 "Number.toString called on non-number object");
10307 goto clean;
10308 }
10309
10310 /* Get number primitive */
10311 rcode = to_number_v(v7, this_obj, &this_obj);
10312 if (rcode != V7_OK) {
10313 goto clean;
10314 }
10315
10316 /* Get radix if provided, or 10 otherwise */
10317 if (!v7_is_undefined(radixv)) {
10318 rcode = to_number_v(v7, radixv, &radixv);
10319 if (rcode != V7_OK) {
10320 goto clean;
10321 }
10322 radix = v7_get_double(v7, radixv);
10323 } else {
10324 radix = 10.0;
10325 }
10326
10327 d = v7_get_double(v7, this_obj);
10328 if (!isnan(d) && (int64_t) d == d && radix >= 2) {
10329 cs_itoa(d, buf, radix);
10330 *res = v7_mk_string(v7, buf, strlen(buf), 1);
10331 } else {
10332 rcode = to_string(v7, this_obj, res, NULL, 0, NULL);
10333 if (rcode != V7_OK) {
10334 goto clean;
10335 }
10336 }
10337
10338clean:
10339 return rcode;
10340}
10341
10342WARN_UNUSED_RESULT
10343V7_PRIVATE enum v7_err n_isNaN(struct v7 *v7, v7_val_t *res) {
10344 val_t arg0 = v7_arg(v7, 0);
10345 *res = v7_mk_boolean(v7, !v7_is_number(arg0) || arg0 == V7_TAG_NAN);
10346 return V7_OK;
10347}
10348
10349V7_PRIVATE void init_number(struct v7 *v7) {
10350 v7_prop_attr_desc_t attrs_desc =
10351 (V7_DESC_WRITABLE(0) | V7_DESC_ENUMERABLE(0) | V7_DESC_CONFIGURABLE(0));
10352 val_t num = mk_cfunction_obj_with_proto(v7, Number_ctor, 1,
10353 v7->vals.number_prototype);
10354
10355 v7_def(v7, v7->vals.global_object, "Number", 6, V7_DESC_ENUMERABLE(0), num);
10356
10357 set_cfunc_prop(v7, v7->vals.number_prototype, "toFixed", Number_toFixed);
10358 set_cfunc_prop(v7, v7->vals.number_prototype, "toPrecision",
10359 Number_toPrecision);
10360 set_cfunc_prop(v7, v7->vals.number_prototype, "toExponential", Number_toExp);
10361 set_cfunc_prop(v7, v7->vals.number_prototype, "valueOf", Number_valueOf);
10362 set_cfunc_prop(v7, v7->vals.number_prototype, "toString", Number_toString);
10363
10364 v7_def(v7, num, "MAX_VALUE", 9, attrs_desc,
10365 v7_mk_number(v7, 1.7976931348623157e+308));
10366 v7_def(v7, num, "MIN_VALUE", 9, attrs_desc, v7_mk_number(v7, 5e-324));
10367#if V7_ENABLE__NUMBER__NEGATIVE_INFINITY
10368 v7_def(v7, num, "NEGATIVE_INFINITY", 17, attrs_desc,
10369 v7_mk_number(v7, -INFINITY));
10370#endif
10371#if V7_ENABLE__NUMBER__POSITIVE_INFINITY
10372 v7_def(v7, num, "POSITIVE_INFINITY", 17, attrs_desc,
10373 v7_mk_number(v7, INFINITY));
10374#endif
10375 v7_def(v7, num, "NaN", 3, attrs_desc, V7_TAG_NAN);
10376
10377 v7_def(v7, v7->vals.global_object, "NaN", 3, attrs_desc, V7_TAG_NAN);
10378 v7_def(v7, v7->vals.global_object, "isNaN", 5, V7_DESC_ENUMERABLE(0),
10379 v7_mk_cfunction(n_isNaN));
10380}
10381
10382#if defined(__cplusplus)
10383}
10384#endif /* __cplusplus */
10385#ifdef V7_MODULE_LINES
10386#line 1 "v7/src/std_json.c"
10387#endif
10388/*
10389 * Copyright (c) 2014 Cesanta Software Limited
10390 * All rights reserved
10391 */
10392
10393/* Amalgamated: #include "v7/src/internal.h" */
10394/* Amalgamated: #include "v7/src/stdlib.h" */
10395/* Amalgamated: #include "v7/src/core.h" */
10396/* Amalgamated: #include "v7/src/object.h" */
10397/* Amalgamated: #include "v7/src/conversion.h" */
10398/* Amalgamated: #include "v7/src/string.h" */
10399/* Amalgamated: #include "v7/src/primitive.h" */
10400
10401#if defined(__cplusplus)
10402extern "C" {
10403#endif /* __cplusplus */
10404
10405#if defined(V7_ALT_JSON_PARSE)
10406extern enum v7_err v7_alt_json_parse(struct v7 *v7, v7_val_t json_string,
10407 v7_val_t *res);
10408#endif
10409
10410WARN_UNUSED_RESULT
10411V7_PRIVATE enum v7_err Json_stringify(struct v7 *v7, v7_val_t *res) {
10412 val_t arg0 = v7_arg(v7, 0);
10413 char buf[100], *p = v7_to_json(v7, arg0, buf, sizeof(buf));
10414 *res = v7_mk_string(v7, p, strlen(p), 1);
10415
10416 if (p != buf) free(p);
10417 return V7_OK;
10418}
10419
10420WARN_UNUSED_RESULT
10421V7_PRIVATE enum v7_err Json_parse(struct v7 *v7, v7_val_t *res) {
10422 v7_val_t arg = v7_arg(v7, 0);
10423 enum v7_err rcode = V7_OK;
10424#if defined(V7_ALT_JSON_PARSE)
10425 rcode = v7_alt_json_parse(v7, arg, res);
10426#else
10427 rcode = std_eval(v7, arg, V7_UNDEFINED, 1, res);
10428#endif
10429 return rcode;
10430}
10431
10432V7_PRIVATE void init_json(struct v7 *v7) {
10433 val_t o = v7_mk_object(v7);
10434 set_method(v7, o, "stringify", Json_stringify, 1);
10435 set_method(v7, o, "parse", Json_parse, 1);
10436 v7_def(v7, v7->vals.global_object, "JSON", 4, V7_DESC_ENUMERABLE(0), o);
10437}
10438
10439#if defined(__cplusplus)
10440}
10441#endif /* __cplusplus */
10442#ifdef V7_MODULE_LINES
10443#line 1 "v7/src/std_array.c"
10444#endif
10445/*
10446 * Copyright (c) 2014 Cesanta Software Limited
10447 * All rights reserved
10448 */
10449
10450/* Amalgamated: #include "common/str_util.h" */
10451/* Amalgamated: #include "v7/src/internal.h" */
10452/* Amalgamated: #include "v7/src/gc.h" */
10453/* Amalgamated: #include "v7/src/eval.h" */
10454/* Amalgamated: #include "v7/src/std_string.h" */
10455/* Amalgamated: #include "v7/src/conversion.h" */
10456/* Amalgamated: #include "v7/src/core.h" */
10457/* Amalgamated: #include "v7/src/function.h" */
10458/* Amalgamated: #include "v7/src/array.h" */
10459/* Amalgamated: #include "v7/src/object.h" */
10460/* Amalgamated: #include "v7/src/exceptions.h" */
10461
10462#if defined(__cplusplus)
10463extern "C" {
10464#endif /* __cplusplus */
10465
10466struct a_sort_data {
10467 val_t sort_func;
10468};
10469
10470WARN_UNUSED_RESULT
10471V7_PRIVATE enum v7_err Array_ctor(struct v7 *v7, v7_val_t *res) {
10472 enum v7_err rcode = V7_OK;
10473 unsigned long i, len;
10474
10475 (void) v7;
10476 *res = v7_mk_array(v7);
10477 /*
10478 * The interpreter passes dense array to C functions.
10479 * However dense array implementation is not yet complete
10480 * so we don't want to propagate them at each call to Array()
10481 */
10482 len = v7_argc(v7);
10483 for (i = 0; i < len; i++) {
10484 rcode = v7_array_set_throwing(v7, *res, i, v7_arg(v7, i), NULL);
10485 if (rcode != V7_OK) {
10486 goto clean;
10487 }
10488 }
10489
10490clean:
10491 return rcode;
10492}
10493
10494WARN_UNUSED_RESULT
10495V7_PRIVATE enum v7_err Array_push(struct v7 *v7, v7_val_t *res) {
10496 enum v7_err rcode = V7_OK;
10497 int i, len = v7_argc(v7);
10498
10499 *res = V7_UNDEFINED;
10500
10501 for (i = 0; i < len; i++) {
10502 *res = v7_arg(v7, i);
10503 rcode = v7_array_push_throwing(v7, v7_get_this(v7), *res, NULL);
10504 if (rcode != V7_OK) {
10505 goto clean;
10506 }
10507 }
10508
10509/*
10510 * TODO(dfrank) : we need to implement `length` as a real property, and here
10511 * we need to set new length and return it (even if the object is not an
10512 * array)
10513 */
10514
10515clean:
10516 return rcode;
10517}
10518
10519WARN_UNUSED_RESULT
10520V7_PRIVATE enum v7_err Array_get_length(struct v7 *v7, v7_val_t *res) {
10521 enum v7_err rcode = V7_OK;
10522 val_t this_obj = v7_get_this(v7);
10523 long len = 0;
10524
10525 if (is_prototype_of(v7, this_obj, v7->vals.array_prototype)) {
10526 len = v7_array_length(v7, this_obj);
10527 }
10528 *res = v7_mk_number(v7, len);
10529
10530 return rcode;
10531}
10532
10533WARN_UNUSED_RESULT
10534V7_PRIVATE enum v7_err Array_set_length(struct v7 *v7, v7_val_t *res) {
10535 enum v7_err rcode = V7_OK;
10536 val_t arg0 = v7_arg(v7, 0);
10537 val_t this_obj = v7_get_this(v7);
10538 long new_len = 0;
10539
10540 rcode = to_long(v7, v7_arg(v7, 0), -1, &new_len);
10541 if (rcode != V7_OK) {
10542 goto clean;
10543 }
10544
10545 if (!v7_is_object(this_obj)) {
10546 rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
10547 goto clean;
10548 } else if (new_len < 0 ||
10549 (v7_is_number(arg0) && (isnan(v7_get_double(v7, arg0)) ||
10550 isinf(v7_get_double(v7, arg0))))) {
10551 rcode = v7_throwf(v7, RANGE_ERROR, "Invalid array length");
10552 goto clean;
10553 } else {
10554 struct v7_property **p, **next;
10555 long index, max_index = -1;
10556
10557 /* Remove all items with an index higher than new_len */
10558 for (p = &get_object_struct(this_obj)->properties; *p != NULL; p = next) {
10559 size_t n;
10560 const char *s = v7_get_string(v7, &p[0]->name, &n);
10561 next = &p[0]->next;
10562 index = strtol(s, NULL, 10);
10563 if (index >= new_len) {
10564 v7_destroy_property(p);
10565 *p = *next;
10566 next = p;
10567 } else if (index > max_index) {
10568 max_index = index;
10569 }
10570 }
10571
10572 /* If we have to expand, insert an item with appropriate index */
10573 if (new_len > 0 && max_index < new_len - 1) {
10574 char buf[40];
10575 c_snprintf(buf, sizeof(buf), "%ld", new_len - 1);
10576 v7_set(v7, this_obj, buf, strlen(buf), V7_UNDEFINED);
10577 }
10578 }
10579
10580 *res = v7_mk_number(v7, new_len);
10581
10582clean:
10583 return rcode;
10584}
10585
10586WARN_UNUSED_RESULT
10587static enum v7_err a_cmp(struct v7 *v7, void *user_data, const void *pa,
10588 const void *pb, int *res) {
10589 enum v7_err rcode = V7_OK;
10590 struct a_sort_data *sort_data = (struct a_sort_data *) user_data;
10591 val_t a = *(val_t *) pa, b = *(val_t *) pb, func = sort_data->sort_func;
10592
10593 if (v7_is_callable(v7, func)) {
10594 int saved_inhibit_gc = v7->inhibit_gc;
10595 val_t vres = V7_UNDEFINED, args = v7_mk_dense_array(v7);
10596 v7_array_push(v7, args, a);
10597 v7_array_push(v7, args, b);
10598 v7->inhibit_gc = 0;
10599 rcode = b_apply(v7, func, V7_UNDEFINED, args, 0, &vres);
10600 if (rcode != V7_OK) {
10601 goto clean;
10602 }
10603 v7->inhibit_gc = saved_inhibit_gc;
10604 *res = (int) -v7_get_double(v7, vres);
10605 goto clean;
10606 } else {
10607 char sa[100], sb[100];
10608
10609 rcode = to_string(v7, a, NULL, sa, sizeof(sa), NULL);
10610 if (rcode != V7_OK) {
10611 goto clean;
10612 }
10613
10614 rcode = to_string(v7, b, NULL, sb, sizeof(sb), NULL);
10615 if (rcode != V7_OK) {
10616 goto clean;
10617 }
10618
10619 sa[sizeof(sa) - 1] = sb[sizeof(sb) - 1] = '\0';
10620 *res = strcmp(sb, sa);
10621 goto clean;
10622 }
10623
10624clean:
10625 return rcode;
10626}
10627
10628WARN_UNUSED_RESULT
10629static enum v7_err a_partition(struct v7 *v7, val_t *a, int l, int r,
10630 void *user_data, int *res) {
10631 enum v7_err rcode = V7_OK;
10632 val_t t, pivot = a[l];
10633 int i = l, j = r + 1;
10634
10635 for (;;) {
10636 while (1) {
10637 ++i;
10638
10639 if (i <= r) {
10640 int tmp = 0;
10641 rcode = a_cmp(v7, user_data, &a[i], &pivot, &tmp);
10642 if (rcode != V7_OK) {
10643 goto clean;
10644 }
10645
10646 if (tmp > 0) {
10647 break;
10648 }
10649 } else {
10650 break;
10651 }
10652 }
10653 while (1) {
10654 int tmp = 0;
10655 --j;
10656
10657 rcode = a_cmp(v7, user_data, &a[j], &pivot, &tmp);
10658 if (rcode != V7_OK) {
10659 goto clean;
10660 }
10661
10662 if (tmp <= 0) {
10663 break;
10664 }
10665 }
10666 if (i >= j) break;
10667 t = a[i];
10668 a[i] = a[j];
10669 a[j] = t;
10670 }
10671 t = a[l];
10672 a[l] = a[j];
10673 a[j] = t;
10674
10675 *res = j;
10676clean:
10677 return rcode;
10678}
10679
10680WARN_UNUSED_RESULT
10681static enum v7_err a_qsort(struct v7 *v7, val_t *a, int l, int r,
10682 void *user_data) {
10683 enum v7_err rcode = V7_OK;
10684 if (l < r) {
10685 int j = 0;
10686 rcode = a_partition(v7, a, l, r, user_data, &j);
10687 if (rcode != V7_OK) {
10688 goto clean;
10689 }
10690
10691 rcode = a_qsort(v7, a, l, j - 1, user_data);
10692 if (rcode != V7_OK) {
10693 goto clean;
10694 }
10695
10696 rcode = a_qsort(v7, a, j + 1, r, user_data);
10697 if (rcode != V7_OK) {
10698 goto clean;
10699 }
10700 }
10701clean:
10702 return rcode;
10703}
10704
10705WARN_UNUSED_RESULT
10706static enum v7_err a_sort(struct v7 *v7,
10707 enum v7_err (*sorting_func)(struct v7 *v7, void *,
10708 const void *,
10709 const void *, int *res),
10710 v7_val_t *res) {
10711 enum v7_err rcode = V7_OK;
10712 int i = 0, len = 0;
10713 val_t *arr = NULL;
10714 val_t arg0 = v7_arg(v7, 0);
10715
10716 *res = v7_get_this(v7);
10717 len = v7_array_length(v7, *res);
10718
10719 if (!v7_is_object(*res)) {
10720 goto clean;
10721 }
10722
10723 arr = (val_t *) malloc(len * sizeof(arr[0]));
10724
10725 assert(*res != v7->vals.global_object);
10726
10727 for (i = 0; i < len; i++) {
10728 arr[i] = v7_array_get(v7, *res, i);
10729 }
10730
10731 /* TODO(dfrank): sorting_func isn't actually used! something is wrong here */
10732 if (sorting_func != NULL) {
10733 struct a_sort_data sort_data;
10734 sort_data.sort_func = arg0;
10735 rcode = a_qsort(v7, arr, 0, len - 1, &sort_data);
10736 if (rcode != V7_OK) {
10737 goto clean;
10738 }
10739 }
10740
10741 for (i = 0; i < len; i++) {
10742 v7_array_set(v7, *res, i, arr[len - (i + 1)]);
10743 }
10744
10745clean:
10746 if (arr != NULL) {
10747 free(arr);
10748 }
10749 return rcode;
10750}
10751
10752WARN_UNUSED_RESULT
10753V7_PRIVATE enum v7_err Array_sort(struct v7 *v7, v7_val_t *res) {
10754 return a_sort(v7, a_cmp, res);
10755}
10756
10757WARN_UNUSED_RESULT
10758V7_PRIVATE enum v7_err Array_reverse(struct v7 *v7, v7_val_t *res) {
10759 return a_sort(v7, NULL, res);
10760}
10761
10762WARN_UNUSED_RESULT
10763V7_PRIVATE enum v7_err Array_join(struct v7 *v7, v7_val_t *res) {
10764 enum v7_err rcode = V7_OK;
10765 val_t this_obj = v7_get_this(v7);
10766 val_t arg0 = v7_arg(v7, 0);
10767 size_t sep_size = 0;
10768 const char *sep = NULL;
10769
10770 *res = V7_UNDEFINED;
10771
10772 /* Get pointer to the separator string */
10773 if (!v7_is_string(arg0)) {
10774 /* If no separator is provided, use comma */
10775 arg0 = v7_mk_string(v7, ",", 1, 1);
10776 }
10777 sep = v7_get_string(v7, &arg0, &sep_size);
10778
10779 /* Do the actual join */
10780 if (is_prototype_of(v7, this_obj, v7->vals.array_prototype)) {
10781 struct mbuf m;
10782 char buf[100], *p;
10783 long i, n, num_elems = v7_array_length(v7, this_obj);
10784
10785 mbuf_init(&m, 0);
10786
10787 for (i = 0; i < num_elems; i++) {
10788 /* Append separator */
10789 if (i > 0) {
10790 mbuf_append(&m, sep, sep_size);
10791 }
10792
10793 /* Append next item from an array */
10794 p = buf;
10795 {
10796 size_t tmp;
10797 rcode = to_string(v7, v7_array_get(v7, this_obj, i), NULL, buf,
10798 sizeof(buf), &tmp);
10799 if (rcode != V7_OK) {
10800 goto clean;
10801 }
10802 n = tmp;
10803 }
10804 if (n > (long) sizeof(buf)) {
10805 p = (char *) malloc(n + 1);
10806 rcode = to_string(v7, v7_array_get(v7, this_obj, i), NULL, p, n, NULL);
10807 if (rcode != V7_OK) {
10808 goto clean;
10809 }
10810 }
10811 mbuf_append(&m, p, n);
10812 if (p != buf) {
10813 free(p);
10814 }
10815 }
10816
10817 /* mbuf contains concatenated string now. Copy it to the result. */
10818 *res = v7_mk_string(v7, m.buf, m.len, 1);
10819 mbuf_free(&m);
10820 }
10821
10822clean:
10823 return rcode;
10824}
10825
10826WARN_UNUSED_RESULT
10827V7_PRIVATE enum v7_err Array_toString(struct v7 *v7, v7_val_t *res) {
10828 return Array_join(v7, res);
10829}
10830
10831WARN_UNUSED_RESULT
10832static enum v7_err a_splice(struct v7 *v7, int mutate, v7_val_t *res) {
10833 enum v7_err rcode = V7_OK;
10834 val_t this_obj = v7_get_this(v7);
10835 long i, len = v7_array_length(v7, this_obj);
10836 long num_args = v7_argc(v7);
10837 long elems_to_insert = num_args > 2 ? num_args - 2 : 0;
10838 long arg0, arg1;
10839
10840 if (!v7_is_object(this_obj)) {
10841 rcode = v7_throwf(v7, TYPE_ERROR,
10842 "Array.splice or Array.slice called on non-object value");
10843 goto clean;
10844 }
10845
10846 *res = v7_mk_dense_array(v7);
10847
10848 rcode = to_long(v7, v7_arg(v7, 0), 0, &arg0);
10849 if (rcode != V7_OK) {
10850 goto clean;
10851 }
10852
10853 rcode = to_long(v7, v7_arg(v7, 1), len, &arg1);
10854 if (rcode != V7_OK) {
10855 goto clean;
10856 }
10857
10858 /* Bounds check */
10859 if (!mutate && len <= 0) {
10860 goto clean;
10861 }
10862 if (arg0 < 0) arg0 = len + arg0;
10863 if (arg0 < 0) arg0 = 0;
10864 if (arg0 > len) arg0 = len;
10865 if (mutate) {
10866 if (arg1 < 0) arg1 = 0;
10867 arg1 += arg0;
10868 } else if (arg1 < 0) {
10869 arg1 = len + arg1;
10870 }
10871
10872 /* Create return value - slice */
10873 for (i = arg0; i < arg1 && i < len; i++) {
10874 rcode =
10875 v7_array_push_throwing(v7, *res, v7_array_get(v7, this_obj, i), NULL);
10876 if (rcode != V7_OK) {
10877 goto clean;
10878 }
10879 }
10880
10881 if (mutate && get_object_struct(this_obj)->attributes & V7_OBJ_DENSE_ARRAY) {
10882 /*
10883 * dense arrays are spliced by memmoving leaving the trailing
10884 * space allocated for future appends.
10885 * TODO(mkm): figure out if trimming is better
10886 */
10887 struct v7_property *p =
10888 v7_get_own_property2(v7, this_obj, "", 0, _V7_PROPERTY_HIDDEN);
10889 struct mbuf *abuf;
10890 if (p == NULL) {
10891 goto clean;
10892 }
10893 abuf = (struct mbuf *) v7_get_ptr(v7, p->value);
10894 if (abuf == NULL) {
10895 goto clean;
10896 }
10897
10898 memmove(abuf->buf + arg0 * sizeof(val_t), abuf->buf + arg1 * sizeof(val_t),
10899 (len - arg1) * sizeof(val_t));
10900 abuf->len -= (arg1 - arg0) * sizeof(val_t);
10901 } else if (mutate) {
10902 /* If splicing, modify this_obj array: remove spliced sub-array */
10903 struct v7_property **p, **next;
10904 long i;
10905
10906 for (p = &get_object_struct(this_obj)->properties; *p != NULL; p = next) {
10907 size_t n;
10908 const char *s = v7_get_string(v7, &p[0]->name, &n);
10909 next = &p[0]->next;
10910 i = strtol(s, NULL, 10);
10911 if (i >= arg0 && i < arg1) {
10912 /* Remove items from spliced sub-array */
10913 v7_destroy_property(p);
10914 *p = *next;
10915 next = p;
10916 } else if (i >= arg1) {
10917 /* Modify indices of the elements past sub-array */
10918 char key[20];
10919 size_t n = c_snprintf(key, sizeof(key), "%ld",
10920 i - (arg1 - arg0) + elems_to_insert);
10921 p[0]->name = v7_mk_string(v7, key, n, 1);
10922 }
10923 }
10924
10925 /* Insert optional extra elements */
10926 for (i = 2; i < num_args; i++) {
10927 char key[20];
10928 size_t n = c_snprintf(key, sizeof(key), "%ld", arg0 + i - 2);
10929 rcode = set_property(v7, this_obj, key, n, v7_arg(v7, i), NULL);
10930 if (rcode != V7_OK) {
10931 goto clean;
10932 }
10933 }
10934 }
10935
10936clean:
10937 return rcode;
10938}
10939
10940WARN_UNUSED_RESULT
10941V7_PRIVATE enum v7_err Array_slice(struct v7 *v7, v7_val_t *res) {
10942 return a_splice(v7, 0, res);
10943}
10944
10945WARN_UNUSED_RESULT
10946V7_PRIVATE enum v7_err Array_splice(struct v7 *v7, v7_val_t *res) {
10947 return a_splice(v7, 1, res);
10948}
10949
10950static void a_prep1(struct v7 *v7, val_t t, val_t *a0, val_t *a1) {
10951 *a0 = v7_arg(v7, 0);
10952 *a1 = v7_arg(v7, 1);
10953 if (v7_is_undefined(*a1)) {
10954 *a1 = t;
10955 }
10956}
10957
10958/*
10959 * Call callback function `cb`, passing `this_obj` as `this`, with the
10960 * following arguments:
10961 *
10962 * cb(v, n, this_obj);
10963 *
10964 */
10965WARN_UNUSED_RESULT
10966static enum v7_err a_prep2(struct v7 *v7, val_t cb, val_t v, val_t n,
10967 val_t this_obj, val_t *res) {
10968 enum v7_err rcode = V7_OK;
10969 int saved_inhibit_gc = v7->inhibit_gc;
10970 val_t args = v7_mk_dense_array(v7);
10971
10972 *res = v7_mk_dense_array(v7);
10973
10974 v7_own(v7, &args);
10975
10976 v7_array_push(v7, args, v);
10977 v7_array_push(v7, args, n);
10978 v7_array_push(v7, args, this_obj);
10979
10980 v7->inhibit_gc = 0;
10981 rcode = b_apply(v7, cb, this_obj, args, 0, res);
10982 if (rcode != V7_OK) {
10983 goto clean;
10984 }
10985
10986clean:
10987 v7->inhibit_gc = saved_inhibit_gc;
10988 v7_disown(v7, &args);
10989
10990 return rcode;
10991}
10992
10993WARN_UNUSED_RESULT
10994V7_PRIVATE enum v7_err Array_forEach(struct v7 *v7, v7_val_t *res) {
10995 enum v7_err rcode = V7_OK;
10996 val_t this_obj = v7_get_this(v7);
10997 val_t v = V7_UNDEFINED, cb = v7_arg(v7, 0);
10998 unsigned long len, i;
10999 int has;
11000 /* a_prep2 uninhibits GC when calling cb */
11001 struct gc_tmp_frame vf = new_tmp_frame(v7);
11002
11003 if (!v7_is_object(this_obj)) {
11004 rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
11005 goto clean;
11006 }
11007
11008 if (!v7_is_callable(v7, cb)) {
11009 rcode = v7_throwf(v7, TYPE_ERROR, "Function expected");
11010 goto clean;
11011 }
11012
11013 tmp_stack_push(&vf, &v);
11014
11015 len = v7_array_length(v7, this_obj);
11016 for (i = 0; i < len; i++) {
11017 v = v7_array_get2(v7, this_obj, i, &has);
11018 if (!has) continue;
11019
11020 rcode = a_prep2(v7, cb, v, v7_mk_number(v7, i), this_obj, res);
11021 if (rcode != V7_OK) {
11022 goto clean;
11023 }
11024 }
11025
11026clean:
11027 tmp_frame_cleanup(&vf);
11028 return rcode;
11029}
11030
11031WARN_UNUSED_RESULT
11032V7_PRIVATE enum v7_err Array_map(struct v7 *v7, v7_val_t *res) {
11033 enum v7_err rcode = V7_OK;
11034 val_t this_obj = v7_get_this(v7);
11035 val_t arg0, arg1, el, v;
11036 unsigned long len, i;
11037 int has;
11038 /* a_prep2 uninhibits GC when calling cb */
11039 struct gc_tmp_frame vf = new_tmp_frame(v7);
11040
11041 if (!v7_is_object(this_obj)) {
11042 rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
11043 goto clean;
11044 } else {
11045 a_prep1(v7, this_obj, &arg0, &arg1);
11046 *res = v7_mk_dense_array(v7);
11047 len = v7_array_length(v7, this_obj);
11048
11049 tmp_stack_push(&vf, &arg0);
11050 tmp_stack_push(&vf, &arg1);
11051 tmp_stack_push(&vf, &v);
11052
11053 for (i = 0; i < len; i++) {
11054 v = v7_array_get2(v7, this_obj, i, &has);
11055 if (!has) continue;
11056 rcode = a_prep2(v7, arg0, v, v7_mk_number(v7, i), arg1, &el);
11057 if (rcode != V7_OK) {
11058 goto clean;
11059 }
11060
11061 rcode = v7_array_set_throwing(v7, *res, i, el, NULL);
11062 if (rcode != V7_OK) {
11063 goto clean;
11064 }
11065 }
11066 }
11067
11068clean:
11069 tmp_frame_cleanup(&vf);
11070 return rcode;
11071}
11072
11073WARN_UNUSED_RESULT
11074V7_PRIVATE enum v7_err Array_every(struct v7 *v7, v7_val_t *res) {
11075 enum v7_err rcode = V7_OK;
11076 val_t this_obj = v7_get_this(v7);
11077 val_t arg0, arg1, el, v;
11078 unsigned long i, len;
11079 int has;
11080 /* a_prep2 uninhibits GC when calling cb */
11081 struct gc_tmp_frame vf = new_tmp_frame(v7);
11082
11083 *res = v7_mk_boolean(v7, 0);
11084
11085 if (!v7_is_object(this_obj)) {
11086 rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
11087 goto clean;
11088 } else {
11089 a_prep1(v7, this_obj, &arg0, &arg1);
11090
11091 tmp_stack_push(&vf, &arg0);
11092 tmp_stack_push(&vf, &arg1);
11093 tmp_stack_push(&vf, &v);
11094
11095 len = v7_array_length(v7, this_obj);
11096 for (i = 0; i < len; i++) {
11097 v = v7_array_get2(v7, this_obj, i, &has);
11098 if (!has) continue;
11099 rcode = a_prep2(v7, arg0, v, v7_mk_number(v7, i), arg1, &el);
11100 if (rcode != V7_OK) {
11101 goto clean;
11102 }
11103 if (!v7_is_truthy(v7, el)) {
11104 *res = v7_mk_boolean(v7, 0);
11105 goto clean;
11106 }
11107 }
11108 }
11109
11110 *res = v7_mk_boolean(v7, 1);
11111
11112clean:
11113 tmp_frame_cleanup(&vf);
11114 return rcode;
11115}
11116
11117WARN_UNUSED_RESULT
11118V7_PRIVATE enum v7_err Array_some(struct v7 *v7, v7_val_t *res) {
11119 enum v7_err rcode = V7_OK;
11120 val_t this_obj = v7_get_this(v7);
11121 val_t arg0, arg1, el, v;
11122 unsigned long i, len;
11123 int has;
11124 /* a_prep2 uninhibits GC when calling cb */
11125 struct gc_tmp_frame vf = new_tmp_frame(v7);
11126
11127 *res = v7_mk_boolean(v7, 1);
11128
11129 if (!v7_is_object(this_obj)) {
11130 rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
11131 goto clean;
11132 } else {
11133 a_prep1(v7, this_obj, &arg0, &arg1);
11134
11135 tmp_stack_push(&vf, &arg0);
11136 tmp_stack_push(&vf, &arg1);
11137 tmp_stack_push(&vf, &v);
11138
11139 len = v7_array_length(v7, this_obj);
11140 for (i = 0; i < len; i++) {
11141 v = v7_array_get2(v7, this_obj, i, &has);
11142 if (!has) continue;
11143 rcode = a_prep2(v7, arg0, v, v7_mk_number(v7, i), arg1, &el);
11144 if (rcode != V7_OK) {
11145 goto clean;
11146 }
11147 if (v7_is_truthy(v7, el)) {
11148 *res = v7_mk_boolean(v7, 1);
11149 goto clean;
11150 }
11151 }
11152 }
11153
11154 *res = v7_mk_boolean(v7, 0);
11155
11156clean:
11157 tmp_frame_cleanup(&vf);
11158 return rcode;
11159}
11160
11161WARN_UNUSED_RESULT
11162V7_PRIVATE enum v7_err Array_filter(struct v7 *v7, v7_val_t *res) {
11163 enum v7_err rcode = V7_OK;
11164 val_t this_obj = v7_get_this(v7);
11165 val_t arg0, arg1, el, v;
11166 unsigned long len, i;
11167 int has;
11168 /* a_prep2 uninhibits GC when calling cb */
11169 struct gc_tmp_frame vf = new_tmp_frame(v7);
11170
11171 if (!v7_is_object(this_obj)) {
11172 rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
11173 goto clean;
11174 } else {
11175 a_prep1(v7, this_obj, &arg0, &arg1);
11176 *res = v7_mk_dense_array(v7);
11177 len = v7_array_length(v7, this_obj);
11178
11179 tmp_stack_push(&vf, &arg0);
11180 tmp_stack_push(&vf, &arg1);
11181 tmp_stack_push(&vf, &v);
11182
11183 for (i = 0; i < len; i++) {
11184 v = v7_array_get2(v7, this_obj, i, &has);
11185 if (!has) continue;
11186 rcode = a_prep2(v7, arg0, v, v7_mk_number(v7, i), arg1, &el);
11187 if (rcode != V7_OK) {
11188 goto clean;
11189 }
11190 if (v7_is_truthy(v7, el)) {
11191 rcode = v7_array_push_throwing(v7, *res, v, NULL);
11192 if (rcode != V7_OK) {
11193 goto clean;
11194 }
11195 }
11196 }
11197 }
11198
11199clean:
11200 tmp_frame_cleanup(&vf);
11201 return rcode;
11202}
11203
11204WARN_UNUSED_RESULT
11205V7_PRIVATE enum v7_err Array_concat(struct v7 *v7, v7_val_t *res) {
11206 enum v7_err rcode = V7_OK;
11207 val_t this_obj = v7_get_this(v7);
11208 size_t i, j, len;
11209 val_t saved_args;
11210
11211 if (!v7_is_array(v7, this_obj)) {
11212 rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
11213 goto clean;
11214 }
11215
11216 len = v7_argc(v7);
11217
11218 /*
11219 * reuse a_splice but override it's arguments. a_splice
11220 * internally uses a lot of helpers that fetch arguments
11221 * from the v7 context.
11222 * TODO(mkm): we need a better helper call another cfunction
11223 * from a cfunction.
11224 */
11225 saved_args = v7->vals.arguments;
11226 v7->vals.arguments = V7_UNDEFINED;
11227 rcode = a_splice(v7, 1, res);
11228 if (rcode != V7_OK) {
11229 goto clean;
11230 }
11231 v7->vals.arguments = saved_args;
11232
11233 for (i = 0; i < len; i++) {
11234 val_t a = v7_arg(v7, i);
11235 if (!v7_is_array(v7, a)) {
11236 rcode = v7_array_push_throwing(v7, *res, a, NULL);
11237 if (rcode != V7_OK) {
11238 goto clean;
11239 }
11240 } else {
11241 size_t alen = v7_array_length(v7, a);
11242 for (j = 0; j < alen; j++) {
11243 rcode = v7_array_push_throwing(v7, *res, v7_array_get(v7, a, j), NULL);
11244 if (rcode != V7_OK) {
11245 goto clean;
11246 }
11247 }
11248 }
11249 }
11250
11251clean:
11252 return rcode;
11253}
11254
11255WARN_UNUSED_RESULT
11256V7_PRIVATE enum v7_err Array_isArray(struct v7 *v7, v7_val_t *res) {
11257 val_t arg0 = v7_arg(v7, 0);
11258 *res = v7_mk_boolean(v7, v7_is_array(v7, arg0));
11259 return V7_OK;
11260}
11261
11262V7_PRIVATE void init_array(struct v7 *v7) {
11263 val_t ctor = mk_cfunction_obj(v7, Array_ctor, 1);
11264 val_t length = v7_mk_dense_array(v7);
11265
11266 v7_set(v7, ctor, "prototype", 9, v7->vals.array_prototype);
11267 set_method(v7, ctor, "isArray", Array_isArray, 1);
11268 v7_set(v7, v7->vals.global_object, "Array", 5, ctor);
11269 v7_def(v7, v7->vals.array_prototype, "constructor", ~0, _V7_DESC_HIDDEN(1),
11270 ctor);
11271 v7_set(v7, ctor, "name", 4, v7_mk_string(v7, "Array", ~0, 1));
11272
11273 set_method(v7, v7->vals.array_prototype, "concat", Array_concat, 1);
11274 set_method(v7, v7->vals.array_prototype, "every", Array_every, 1);
11275 set_method(v7, v7->vals.array_prototype, "filter", Array_filter, 1);
11276 set_method(v7, v7->vals.array_prototype, "forEach", Array_forEach, 1);
11277 set_method(v7, v7->vals.array_prototype, "join", Array_join, 1);
11278 set_method(v7, v7->vals.array_prototype, "map", Array_map, 1);
11279 set_method(v7, v7->vals.array_prototype, "push", Array_push, 1);
11280 set_method(v7, v7->vals.array_prototype, "reverse", Array_reverse, 0);
11281 set_method(v7, v7->vals.array_prototype, "slice", Array_slice, 2);
11282 set_method(v7, v7->vals.array_prototype, "some", Array_some, 1);
11283 set_method(v7, v7->vals.array_prototype, "sort", Array_sort, 1);
11284 set_method(v7, v7->vals.array_prototype, "splice", Array_splice, 2);
11285 set_method(v7, v7->vals.array_prototype, "toString", Array_toString, 0);
11286
11287 v7_array_set(v7, length, 0, v7_mk_cfunction(Array_get_length));
11288 v7_array_set(v7, length, 1, v7_mk_cfunction(Array_set_length));
11289 v7_def(v7, v7->vals.array_prototype, "length", 6,
11290 V7_DESC_ENUMERABLE(0) | V7_DESC_GETTER(1) | V7_DESC_SETTER(1), length);
11291}
11292
11293#if defined(__cplusplus)
11294}
11295#endif /* __cplusplus */
11296#ifdef V7_MODULE_LINES
11297#line 1 "v7/src/std_boolean.c"
11298#endif
11299/*
11300 * Copyright (c) 2014 Cesanta Software Limited
11301 * All rights reserved
11302 */
11303
11304/* Amalgamated: #include "v7/src/internal.h" */
11305/* Amalgamated: #include "v7/src/std_object.h" */
11306/* Amalgamated: #include "v7/src/core.h" */
11307/* Amalgamated: #include "v7/src/function.h" */
11308/* Amalgamated: #include "v7/src/object.h" */
11309/* Amalgamated: #include "v7/src/conversion.h" */
11310/* Amalgamated: #include "v7/src/primitive.h" */
11311/* Amalgamated: #include "v7/src/exceptions.h" */
11312/* Amalgamated: #include "v7/src/string.h" */
11313
11314#if defined(__cplusplus)
11315extern "C" {
11316#endif /* __cplusplus */
11317
11318WARN_UNUSED_RESULT
11319V7_PRIVATE enum v7_err Boolean_ctor(struct v7 *v7, v7_val_t *res) {
11320 enum v7_err rcode = V7_OK;
11321 val_t this_obj = v7_get_this(v7);
11322
11323 *res = to_boolean_v(v7, v7_arg(v7, 0));
11324
11325 if (v7_is_generic_object(this_obj) && this_obj != v7->vals.global_object) {
11326 /* called as "new Boolean(...)" */
11327 obj_prototype_set(v7, get_object_struct(this_obj),
11328 get_object_struct(v7->vals.boolean_prototype));
11329 v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), *res);
11330
11331 /*
11332 * implicitly returning `this`: `call_cfunction()` in bcode.c will do
11333 * that for us
11334 */
11335 }
11336
11337 return rcode;
11338}
11339
11340WARN_UNUSED_RESULT
11341V7_PRIVATE enum v7_err Boolean_valueOf(struct v7 *v7, v7_val_t *res) {
11342 enum v7_err rcode = V7_OK;
11343 val_t this_obj = v7_get_this(v7);
11344 if (!v7_is_boolean(this_obj) &&
11345 (v7_is_object(this_obj) &&
11346 v7_get_proto(v7, this_obj) != v7->vals.boolean_prototype)) {
11347 rcode = v7_throwf(v7, TYPE_ERROR,
11348 "Boolean.valueOf called on non-boolean object");
11349 goto clean;
11350 }
11351
11352 rcode = Obj_valueOf(v7, res);
11353 if (rcode != V7_OK) {
11354 goto clean;
11355 }
11356
11357clean:
11358 return rcode;
11359}
11360
11361WARN_UNUSED_RESULT
11362V7_PRIVATE enum v7_err Boolean_toString(struct v7 *v7, v7_val_t *res) {
11363 enum v7_err rcode = V7_OK;
11364 val_t this_obj = v7_get_this(v7);
11365
11366 *res = V7_UNDEFINED;
11367
11368 if (this_obj == v7->vals.boolean_prototype) {
11369 *res = v7_mk_string(v7, "false", 5, 1);
11370 goto clean;
11371 }
11372
11373 if (!v7_is_boolean(this_obj) &&
11374 !(v7_is_generic_object(this_obj) &&
11375 is_prototype_of(v7, this_obj, v7->vals.boolean_prototype))) {
11376 rcode = v7_throwf(v7, TYPE_ERROR,
11377 "Boolean.toString called on non-boolean object");
11378 goto clean;
11379 }
11380
11381 rcode = obj_value_of(v7, this_obj, res);
11382 if (rcode != V7_OK) {
11383 goto clean;
11384 }
11385
11386 rcode = primitive_to_str(v7, *res, res, NULL, 0, NULL);
11387 if (rcode != V7_OK) {
11388 goto clean;
11389 }
11390
11391clean:
11392 return rcode;
11393}
11394
11395V7_PRIVATE void init_boolean(struct v7 *v7) {
11396 val_t ctor = mk_cfunction_obj_with_proto(v7, Boolean_ctor, 1,
11397 v7->vals.boolean_prototype);
11398 v7_set(v7, v7->vals.global_object, "Boolean", 7, ctor);
11399
11400 set_cfunc_prop(v7, v7->vals.boolean_prototype, "valueOf", Boolean_valueOf);
11401 set_cfunc_prop(v7, v7->vals.boolean_prototype, "toString", Boolean_toString);
11402}
11403
11404#if defined(__cplusplus)
11405}
11406#endif /* __cplusplus */
11407#ifdef V7_MODULE_LINES
11408#line 1 "v7/src/std_math.c"
11409#endif
11410/*
11411 * Copyright (c) 2014 Cesanta Software Limited
11412 * All rights reserved
11413 */
11414
11415/* Amalgamated: #include "v7/src/internal.h" */
11416/* Amalgamated: #include "v7/src/core.h" */
11417/* Amalgamated: #include "v7/src/object.h" */
11418/* Amalgamated: #include "v7/src/primitive.h" */
11419
11420#if V7_ENABLE__Math
11421
11422#if defined(__cplusplus)
11423extern "C" {
11424#endif /* __cplusplus */
11425
11426#ifdef __WATCOM__
11427int matherr(struct _exception *exc) {
11428 if (exc->type == DOMAIN) {
11429 exc->retval = NAN;
11430 return 0;
11431 }
11432}
11433#endif
11434
11435#if V7_ENABLE__Math__abs || V7_ENABLE__Math__acos || V7_ENABLE__Math__asin || \
11436 V7_ENABLE__Math__atan || V7_ENABLE__Math__ceil || V7_ENABLE__Math__cos || \
11437 V7_ENABLE__Math__exp || V7_ENABLE__Math__floor || V7_ENABLE__Math__log || \
11438 V7_ENABLE__Math__round || V7_ENABLE__Math__sin || V7_ENABLE__Math__sqrt || \
11439 V7_ENABLE__Math__tan
11440WARN_UNUSED_RESULT
11441static enum v7_err m_one_arg(struct v7 *v7, double (*f)(double), val_t *res) {
11442 enum v7_err rcode = V7_OK;
11443 val_t arg0 = v7_arg(v7, 0);
11444 double d0 = v7_get_double(v7, arg0);
11445#ifdef V7_BROKEN_NAN
11446 if (isnan(d0)) {
11447 *res = V7_TAG_NAN;
11448 goto clean;
11449 }
11450#endif
11451 *res = v7_mk_number(v7, f(d0));
11452 goto clean;
11453
11454clean:
11455 return rcode;
11456}
11457#endif /* V7_ENABLE__Math__* */
11458
11459#if V7_ENABLE__Math__pow || V7_ENABLE__Math__atan2
11460WARN_UNUSED_RESULT
11461static enum v7_err m_two_arg(struct v7 *v7, double (*f)(double, double),
11462 val_t *res) {
11463 enum v7_err rcode = V7_OK;
11464 val_t arg0 = v7_arg(v7, 0);
11465 val_t arg1 = v7_arg(v7, 1);
11466 double d0 = v7_get_double(v7, arg0);
11467 double d1 = v7_get_double(v7, arg1);
11468#ifdef V7_BROKEN_NAN
11469 /* pow(NaN,0) == 1, doesn't fix atan2, but who cares */
11470 if (isnan(d1)) {
11471 *res = V7_TAG_NAN;
11472 goto clean;
11473 }
11474#endif
11475 *res = v7_mk_number(v7, f(d0, d1));
11476 goto clean;
11477
11478clean:
11479 return rcode;
11480}
11481#endif /* V7_ENABLE__Math__pow || V7_ENABLE__Math__atan2 */
11482
11483#define DEFINE_WRAPPER(name, func) \
11484 WARN_UNUSED_RESULT \
11485 V7_PRIVATE enum v7_err Math_##name(struct v7 *v7, v7_val_t *res) { \
11486 return func(v7, name, res); \
11487 }
11488
11489/* Visual studio 2012+ has round() */
11490#if V7_ENABLE__Math__round && \
11491 ((defined(V7_WINDOWS) && _MSC_VER < 1700) || defined(__WATCOM__))
11492static double round(double n) {
11493 return n;
11494}
11495#endif
11496
11497#if V7_ENABLE__Math__abs
11498DEFINE_WRAPPER(fabs, m_one_arg)
11499#endif
11500#if V7_ENABLE__Math__acos
11501DEFINE_WRAPPER(acos, m_one_arg)
11502#endif
11503#if V7_ENABLE__Math__asin
11504DEFINE_WRAPPER(asin, m_one_arg)
11505#endif
11506#if V7_ENABLE__Math__atan
11507DEFINE_WRAPPER(atan, m_one_arg)
11508#endif
11509#if V7_ENABLE__Math__atan2
11510DEFINE_WRAPPER(atan2, m_two_arg)
11511#endif
11512#if V7_ENABLE__Math__ceil
11513DEFINE_WRAPPER(ceil, m_one_arg)
11514#endif
11515#if V7_ENABLE__Math__cos
11516DEFINE_WRAPPER(cos, m_one_arg)
11517#endif
11518#if V7_ENABLE__Math__exp
11519DEFINE_WRAPPER(exp, m_one_arg)
11520#endif
11521#if V7_ENABLE__Math__floor
11522DEFINE_WRAPPER(floor, m_one_arg)
11523#endif
11524#if V7_ENABLE__Math__log
11525DEFINE_WRAPPER(log, m_one_arg)
11526#endif
11527#if V7_ENABLE__Math__pow
11528DEFINE_WRAPPER(pow, m_two_arg)
11529#endif
11530#if V7_ENABLE__Math__round
11531DEFINE_WRAPPER(round, m_one_arg)
11532#endif
11533#if V7_ENABLE__Math__sin
11534DEFINE_WRAPPER(sin, m_one_arg)
11535#endif
11536#if V7_ENABLE__Math__sqrt
11537DEFINE_WRAPPER(sqrt, m_one_arg)
11538#endif
11539#if V7_ENABLE__Math__tan
11540DEFINE_WRAPPER(tan, m_one_arg)
11541#endif
11542
11543#if V7_ENABLE__Math__random
11544WARN_UNUSED_RESULT
11545V7_PRIVATE enum v7_err Math_random(struct v7 *v7, v7_val_t *res) {
11546 (void) v7;
11547 *res = v7_mk_number(v7, (double) rand() / RAND_MAX);
11548 return V7_OK;
11549}
11550#endif /* V7_ENABLE__Math__random */
11551
11552#if V7_ENABLE__Math__min || V7_ENABLE__Math__max
11553WARN_UNUSED_RESULT
11554static enum v7_err min_max(struct v7 *v7, int is_min, val_t *res) {
11555 enum v7_err rcode = V7_OK;
11556 double dres = NAN;
11557 int i, len = v7_argc(v7);
11558
11559 for (i = 0; i < len; i++) {
11560 double v = v7_get_double(v7, v7_arg(v7, i));
11561 if (isnan(dres) || (is_min && v < dres) || (!is_min && v > dres)) {
11562 dres = v;
11563 }
11564 }
11565
11566 *res = v7_mk_number(v7, dres);
11567
11568 return rcode;
11569}
11570#endif /* V7_ENABLE__Math__min || V7_ENABLE__Math__max */
11571
11572#if V7_ENABLE__Math__min
11573WARN_UNUSED_RESULT
11574V7_PRIVATE enum v7_err Math_min(struct v7 *v7, v7_val_t *res) {
11575 return min_max(v7, 1, res);
11576}
11577#endif
11578
11579#if V7_ENABLE__Math__max
11580WARN_UNUSED_RESULT
11581V7_PRIVATE enum v7_err Math_max(struct v7 *v7, v7_val_t *res) {
11582 return min_max(v7, 0, res);
11583}
11584#endif
11585
11586V7_PRIVATE void init_math(struct v7 *v7) {
11587 val_t math = v7_mk_object(v7);
11588
11589#if V7_ENABLE__Math__abs
11590 set_cfunc_prop(v7, math, "abs", Math_fabs);
11591#endif
11592#if V7_ENABLE__Math__acos
11593 set_cfunc_prop(v7, math, "acos", Math_acos);
11594#endif
11595#if V7_ENABLE__Math__asin
11596 set_cfunc_prop(v7, math, "asin", Math_asin);
11597#endif
11598#if V7_ENABLE__Math__atan
11599 set_cfunc_prop(v7, math, "atan", Math_atan);
11600#endif
11601#if V7_ENABLE__Math__atan2
11602 set_cfunc_prop(v7, math, "atan2", Math_atan2);
11603#endif
11604#if V7_ENABLE__Math__ceil
11605 set_cfunc_prop(v7, math, "ceil", Math_ceil);
11606#endif
11607#if V7_ENABLE__Math__cos
11608 set_cfunc_prop(v7, math, "cos", Math_cos);
11609#endif
11610#if V7_ENABLE__Math__exp
11611 set_cfunc_prop(v7, math, "exp", Math_exp);
11612#endif
11613#if V7_ENABLE__Math__floor
11614 set_cfunc_prop(v7, math, "floor", Math_floor);
11615#endif
11616#if V7_ENABLE__Math__log
11617 set_cfunc_prop(v7, math, "log", Math_log);
11618#endif
11619#if V7_ENABLE__Math__max
11620 set_cfunc_prop(v7, math, "max", Math_max);
11621#endif
11622#if V7_ENABLE__Math__min
11623 set_cfunc_prop(v7, math, "min", Math_min);
11624#endif
11625#if V7_ENABLE__Math__pow
11626 set_cfunc_prop(v7, math, "pow", Math_pow);
11627#endif
11628#if V7_ENABLE__Math__random
11629 /* Incorporate our pointer into the RNG.
11630 * If srand() has not been called before, this will provide some randomness.
11631 * If it has, it will hopefully not make things worse.
11632 */
11633 srand(rand() ^ ((uintptr_t) v7));
11634 set_cfunc_prop(v7, math, "random", Math_random);
11635#endif
11636#if V7_ENABLE__Math__round
11637 set_cfunc_prop(v7, math, "round", Math_round);
11638#endif
11639#if V7_ENABLE__Math__sin
11640 set_cfunc_prop(v7, math, "sin", Math_sin);
11641#endif
11642#if V7_ENABLE__Math__sqrt
11643 set_cfunc_prop(v7, math, "sqrt", Math_sqrt);
11644#endif
11645#if V7_ENABLE__Math__tan
11646 set_cfunc_prop(v7, math, "tan", Math_tan);
11647#endif
11648
11649#if V7_ENABLE__Math__constants
11650 v7_set(v7, math, "E", 1, v7_mk_number(v7, M_E));
11651 v7_set(v7, math, "PI", 2, v7_mk_number(v7, M_PI));
11652 v7_set(v7, math, "LN2", 3, v7_mk_number(v7, M_LN2));
11653 v7_set(v7, math, "LN10", 4, v7_mk_number(v7, M_LN10));
11654 v7_set(v7, math, "LOG2E", 5, v7_mk_number(v7, M_LOG2E));
11655 v7_set(v7, math, "LOG10E", 6, v7_mk_number(v7, M_LOG10E));
11656 v7_set(v7, math, "SQRT1_2", 7, v7_mk_number(v7, M_SQRT1_2));
11657 v7_set(v7, math, "SQRT2", 5, v7_mk_number(v7, M_SQRT2));
11658#endif
11659
11660 v7_set(v7, v7->vals.global_object, "Math", 4, math);
11661}
11662
11663#if defined(__cplusplus)
11664}
11665#endif /* __cplusplus */
11666
11667#endif /* V7_ENABLE__Math */
11668#ifdef V7_MODULE_LINES
11669#line 1 "v7/src/std_string.c"
11670#endif
11671/*
11672 * Copyright (c) 2014 Cesanta Software Limited
11673 * All rights reserved
11674 */
11675
11676/* Amalgamated: #include "common/utf.h" */
11677/* Amalgamated: #include "v7/src/internal.h" */
11678/* Amalgamated: #include "v7/src/std_string.h" */
11679/* Amalgamated: #include "v7/src/core.h" */
11680/* Amalgamated: #include "v7/src/function.h" */
11681/* Amalgamated: #include "v7/src/string.h" */
11682/* Amalgamated: #include "v7/src/slre.h" */
11683/* Amalgamated: #include "v7/src/std_regex.h" */
11684/* Amalgamated: #include "v7/src/std_object.h" */
11685/* Amalgamated: #include "v7/src/eval.h" */
11686/* Amalgamated: #include "v7/src/conversion.h" */
11687/* Amalgamated: #include "v7/src/array.h" */
11688/* Amalgamated: #include "v7/src/object.h" */
11689/* Amalgamated: #include "v7/src/regexp.h" */
11690/* Amalgamated: #include "v7/src/exceptions.h" */
11691
11692/* Substring implementations: RegExp-based and String-based {{{ */
11693
11694/*
11695 * Substring context: currently, used in Str_split() only, but will probably
11696 * be used in Str_replace() and other functions as well.
11697 *
11698 * Needed to provide different implementation for RegExp or String arguments,
11699 * keeping common parts reusable.
11700 */
11701struct _str_split_ctx {
11702 /* implementation-specific data */
11703 union {
11704#if V7_ENABLE__RegExp
11705 struct {
11706 struct slre_prog *prog;
11707 struct slre_loot loot;
11708 } regexp;
11709#endif
11710
11711 struct {
11712 val_t sep;
11713 } string;
11714 } impl;
11715
11716 struct v7 *v7;
11717
11718 /* start and end of previous match (set by `p_exec()`) */
11719 const char *match_start;
11720 const char *match_end;
11721
11722 /* pointers to implementation functions */
11723
11724 /*
11725 * Initialize context
11726 */
11727 void (*p_init)(struct _str_split_ctx *ctx, struct v7 *v7, val_t sep);
11728
11729 /*
11730 * Look for the next match, set `match_start` and `match_end` to appropriate
11731 * values.
11732 *
11733 * Returns 0 if match found, 1 otherwise (in accordance with `slre_exec()`)
11734 */
11735 int (*p_exec)(struct _str_split_ctx *ctx, const char *start, const char *end);
11736
11737#if V7_ENABLE__RegExp
11738 /*
11739 * Add captured data to resulting array (for RegExp-based implementation only)
11740 *
11741 * Returns updated `elem` value
11742 */
11743 long (*p_add_caps)(struct _str_split_ctx *ctx, val_t res, long elem,
11744 long limit);
11745#endif
11746};
11747
11748#if V7_ENABLE__RegExp
11749/* RegExp-based implementation of `p_init` in `struct _str_split_ctx` */
11750static void subs_regexp_init(struct _str_split_ctx *ctx, struct v7 *v7,
11751 val_t sep) {
11752 ctx->v7 = v7;
11753 ctx->impl.regexp.prog = v7_get_regexp_struct(v7, sep)->compiled_regexp;
11754}
11755
11756/* RegExp-based implementation of `p_exec` in `struct _str_split_ctx` */
11757static int subs_regexp_exec(struct _str_split_ctx *ctx, const char *start,
11758 const char *end) {
11759 int ret =
11760 slre_exec(ctx->impl.regexp.prog, 0, start, end, &ctx->impl.regexp.loot);
11761
11762 ctx->match_start = ctx->impl.regexp.loot.caps[0].start;
11763 ctx->match_end = ctx->impl.regexp.loot.caps[0].end;
11764
11765 return ret;
11766}
11767
11768/* RegExp-based implementation of `p_add_caps` in `struct _str_split_ctx` */
11769static long subs_regexp_split_add_caps(struct _str_split_ctx *ctx, val_t res,
11770 long elem, long limit) {
11771 int i;
11772 for (i = 1; i < ctx->impl.regexp.loot.num_captures && elem < limit; i++) {
11773 size_t cap_len =
11774 ctx->impl.regexp.loot.caps[i].end - ctx->impl.regexp.loot.caps[i].start;
11775 v7_array_push(
11776 ctx->v7, res,
11777 (ctx->impl.regexp.loot.caps[i].start != NULL)
11778 ? v7_mk_string(ctx->v7, ctx->impl.regexp.loot.caps[i].start,
11779 cap_len, 1)
11780 : V7_UNDEFINED);
11781 elem++;
11782 }
11783 return elem;
11784}
11785#endif
11786
11787/* String-based implementation of `p_init` in `struct _str_split_ctx` */
11788static void subs_string_init(struct _str_split_ctx *ctx, struct v7 *v7,
11789 val_t sep) {
11790 ctx->v7 = v7;
11791 ctx->impl.string.sep = sep;
11792}
11793
11794/* String-based implementation of `p_exec` in `struct _str_split_ctx` */
11795static int subs_string_exec(struct _str_split_ctx *ctx, const char *start,
11796 const char *end) {
11797 int ret = 1;
11798 size_t sep_len;
11799 const char *psep = v7_get_string(ctx->v7, &ctx->impl.string.sep, &sep_len);
11800
11801 if (sep_len == 0) {
11802 /* separator is an empty string: match empty string */
11803 ctx->match_start = start;
11804 ctx->match_end = start;
11805 ret = 0;
11806 } else {
11807 size_t i;
11808 for (i = 0; start <= (end - sep_len); ++i, start = utfnshift(start, 1)) {
11809 if (memcmp(start, psep, sep_len) == 0) {
11810 ret = 0;
11811 ctx->match_start = start;
11812 ctx->match_end = start + sep_len;
11813 break;
11814 }
11815 }
11816 }
11817
11818 return ret;
11819}
11820
11821#if V7_ENABLE__RegExp
11822/* String-based implementation of `p_add_caps` in `struct _str_split_ctx` */
11823static long subs_string_split_add_caps(struct _str_split_ctx *ctx, val_t res,
11824 long elem, long limit) {
11825 /* this is a stub function */
11826 (void) ctx;
11827 (void) res;
11828 (void) limit;
11829 return elem;
11830}
11831#endif
11832
11833/* }}} */
11834
11835WARN_UNUSED_RESULT
11836V7_PRIVATE enum v7_err String_ctor(struct v7 *v7, v7_val_t *res) {
11837 enum v7_err rcode = V7_OK;
11838 val_t this_obj = v7_get_this(v7);
11839 val_t arg0 = v7_arg(v7, 0);
11840
11841 *res = arg0;
11842
11843 if (v7_argc(v7) == 0) {
11844 *res = v7_mk_string(v7, NULL, 0, 1);
11845 } else if (!v7_is_string(arg0)) {
11846 rcode = to_string(v7, arg0, res, NULL, 0, NULL);
11847 if (rcode != V7_OK) {
11848 goto clean;
11849 }
11850 }
11851
11852 if (v7_is_generic_object(this_obj) && this_obj != v7->vals.global_object) {
11853 obj_prototype_set(v7, get_object_struct(this_obj),
11854 get_object_struct(v7->vals.string_prototype));
11855 v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), *res);
11856 /*
11857 * implicitly returning `this`: `call_cfunction()` in bcode.c will do
11858 * that for us
11859 */
11860 goto clean;
11861 }
11862
11863clean:
11864 return rcode;
11865}
11866
11867WARN_UNUSED_RESULT
11868V7_PRIVATE enum v7_err Str_fromCharCode(struct v7 *v7, v7_val_t *res) {
11869 enum v7_err rcode = V7_OK;
11870 int i, num_args = v7_argc(v7);
11871
11872 *res = v7_mk_string(v7, "", 0, 1); /* Empty string */
11873
11874 for (i = 0; i < num_args; i++) {
11875 char buf[10];
11876 val_t arg = v7_arg(v7, i);
11877 double d = v7_get_double(v7, arg);
11878 Rune r = (Rune)((int32_t)(isnan(d) || isinf(d) ? 0 : d) & 0xffff);
11879 int n = runetochar(buf, &r);
11880 val_t s = v7_mk_string(v7, buf, n, 1);
11881 *res = s_concat(v7, *res, s);
11882 }
11883
11884 return rcode;
11885}
11886
11887WARN_UNUSED_RESULT
11888static enum v7_err s_charCodeAt(struct v7 *v7, double *res) {
11889 return v7_char_code_at(v7, v7_get_this(v7), v7_arg(v7, 0), res);
11890}
11891
11892WARN_UNUSED_RESULT
11893V7_PRIVATE enum v7_err Str_charCodeAt(struct v7 *v7, v7_val_t *res) {
11894 enum v7_err rcode = V7_OK;
11895 double dnum = 0;
11896
11897 rcode = s_charCodeAt(v7, &dnum);
11898 if (rcode != V7_OK) {
11899 goto clean;
11900 }
11901
11902 *res = v7_mk_number(v7, dnum);
11903
11904clean:
11905 return rcode;
11906}
11907
11908WARN_UNUSED_RESULT
11909V7_PRIVATE enum v7_err Str_charAt(struct v7 *v7, v7_val_t *res) {
11910 enum v7_err rcode = V7_OK;
11911 double code = 0;
11912 char buf[10] = {0};
11913 int len = 0;
11914
11915 rcode = s_charCodeAt(v7, &code);
11916 if (rcode != V7_OK) {
11917 goto clean;
11918 }
11919
11920 if (!isnan(code)) {
11921 Rune r = (Rune) code;
11922 len = runetochar(buf, &r);
11923 }
11924 *res = v7_mk_string(v7, buf, len, 1);
11925
11926clean:
11927 return rcode;
11928}
11929
11930WARN_UNUSED_RESULT
11931V7_PRIVATE enum v7_err Str_concat(struct v7 *v7, v7_val_t *res) {
11932 enum v7_err rcode = V7_OK;
11933 val_t this_obj = v7_get_this(v7);
11934 int i, num_args = v7_argc(v7);
11935
11936 rcode = to_string(v7, this_obj, res, NULL, 0, NULL);
11937 if (rcode != V7_OK) {
11938 goto clean;
11939 }
11940
11941 for (i = 0; i < num_args; i++) {
11942 val_t str = V7_UNDEFINED;
11943
11944 rcode = to_string(v7, v7_arg(v7, i), &str, NULL, 0, NULL);
11945 if (rcode != V7_OK) {
11946 goto clean;
11947 }
11948
11949 *res = s_concat(v7, *res, str);
11950 }
11951
11952clean:
11953 return rcode;
11954}
11955
11956WARN_UNUSED_RESULT
11957static enum v7_err s_index_of(struct v7 *v7, int last, val_t *res) {
11958 enum v7_err rcode = V7_OK;
11959 val_t this_obj = v7_get_this(v7);
11960 val_t arg0 = v7_arg(v7, 0);
11961 size_t fromIndex = 0;
11962 double dres = -1;
11963
11964 if (!v7_is_undefined(arg0)) {
11965 const char *p1, *p2, *end;
11966 size_t i, len1, len2, bytecnt1, bytecnt2;
11967 val_t sub = V7_UNDEFINED;
11968
11969 rcode = to_string(v7, arg0, &sub, NULL, 0, NULL);
11970 if (rcode != V7_OK) {
11971 goto clean;
11972 }
11973
11974 rcode = to_string(v7, this_obj, &this_obj, NULL, 0, NULL);
11975 if (rcode != V7_OK) {
11976 goto clean;
11977 }
11978
11979 p1 = v7_get_string(v7, &this_obj, &bytecnt1);
11980 p2 = v7_get_string(v7, &sub, &bytecnt2);
11981
11982 if (bytecnt2 <= bytecnt1) {
11983 end = p1 + bytecnt1;
11984 len1 = utfnlen(p1, bytecnt1);
11985 len2 = utfnlen(p2, bytecnt2);
11986
11987 if (v7_argc(v7) > 1) {
11988 /* `fromIndex` was provided. Normalize it */
11989 double d = 0;
11990 {
11991 val_t arg = v7_arg(v7, 1);
11992 rcode = to_number_v(v7, arg, &arg);
11993 if (rcode != V7_OK) {
11994 goto clean;
11995 }
11996 d = v7_get_double(v7, arg);
11997 }
11998 if (isnan(d) || d < 0) {
11999 d = 0.0;
12000 } else if (isinf(d) || d > len1) {
12001 d = len1;
12002 }
12003 fromIndex = d;
12004
12005 /* adjust pointers accordingly to `fromIndex` */
12006 if (last) {
12007 const char *end_tmp = utfnshift(p1, fromIndex + len2);
12008 end = (end_tmp < end) ? end_tmp : end;
12009 } else {
12010 p1 = utfnshift(p1, fromIndex);
12011 }
12012 }
12013
12014 /*
12015 * TODO(dfrank): when `last` is set, start from the end and look
12016 * backward. We'll need to improve `utfnshift()` for that, so that it can
12017 * handle negative offsets.
12018 */
12019 for (i = 0; p1 <= (end - bytecnt2); i++, p1 = utfnshift(p1, 1)) {
12020 if (memcmp(p1, p2, bytecnt2) == 0) {
12021 dres = i;
12022 if (!last) break;
12023 }
12024 }
12025 }
12026 }
12027 if (!last && dres >= 0) dres += fromIndex;
12028 *res = v7_mk_number(v7, dres);
12029
12030clean:
12031 return rcode;
12032}
12033
12034WARN_UNUSED_RESULT
12035V7_PRIVATE enum v7_err Str_valueOf(struct v7 *v7, v7_val_t *res) {
12036 enum v7_err rcode = V7_OK;
12037 val_t this_obj = v7_get_this(v7);
12038
12039 if (!v7_is_string(this_obj) &&
12040 (v7_is_object(this_obj) &&
12041 v7_get_proto(v7, this_obj) != v7->vals.string_prototype)) {
12042 rcode =
12043 v7_throwf(v7, TYPE_ERROR, "String.valueOf called on non-string object");
12044 goto clean;
12045 }
12046
12047 rcode = Obj_valueOf(v7, res);
12048 goto clean;
12049
12050clean:
12051 return rcode;
12052}
12053
12054WARN_UNUSED_RESULT
12055V7_PRIVATE enum v7_err Str_indexOf(struct v7 *v7, v7_val_t *res) {
12056 return s_index_of(v7, 0, res);
12057}
12058
12059WARN_UNUSED_RESULT
12060V7_PRIVATE enum v7_err Str_lastIndexOf(struct v7 *v7, v7_val_t *res) {
12061 return s_index_of(v7, 1, res);
12062}
12063
12064#if V7_ENABLE__String__localeCompare
12065WARN_UNUSED_RESULT
12066V7_PRIVATE enum v7_err Str_localeCompare(struct v7 *v7, v7_val_t *res) {
12067 enum v7_err rcode = V7_OK;
12068 val_t this_obj = v7_get_this(v7);
12069 val_t arg0 = V7_UNDEFINED;
12070 val_t s = V7_UNDEFINED;
12071
12072 rcode = to_string(v7, v7_arg(v7, 0), &arg0, NULL, 0, NULL);
12073 if (rcode != V7_OK) {
12074 goto clean;
12075 }
12076
12077 rcode = to_string(v7, this_obj, &s, NULL, 0, NULL);
12078 if (rcode != V7_OK) {
12079 goto clean;
12080 }
12081
12082 *res = v7_mk_number(v7, s_cmp(v7, s, arg0));
12083
12084clean:
12085 return rcode;
12086}
12087#endif
12088
12089WARN_UNUSED_RESULT
12090V7_PRIVATE enum v7_err Str_toString(struct v7 *v7, v7_val_t *res) {
12091 enum v7_err rcode = V7_OK;
12092 val_t this_obj = v7_get_this(v7);
12093
12094 if (this_obj == v7->vals.string_prototype) {
12095 *res = v7_mk_string(v7, "false", 5, 1);
12096 goto clean;
12097 }
12098
12099 if (!v7_is_string(this_obj) &&
12100 !(v7_is_generic_object(this_obj) &&
12101 is_prototype_of(v7, this_obj, v7->vals.string_prototype))) {
12102 rcode = v7_throwf(v7, TYPE_ERROR,
12103 "String.toString called on non-string object");
12104 goto clean;
12105 }
12106
12107 rcode = obj_value_of(v7, this_obj, &this_obj);
12108 if (rcode != V7_OK) {
12109 goto clean;
12110 }
12111
12112 rcode = to_string(v7, this_obj, res, NULL, 0, NULL);
12113 if (rcode != V7_OK) {
12114 goto clean;
12115 }
12116
12117clean:
12118 return rcode;
12119}
12120
12121#if V7_ENABLE__RegExp
12122WARN_UNUSED_RESULT
12123enum v7_err call_regex_ctor(struct v7 *v7, val_t arg, val_t *res) {
12124 /* TODO(mkm): make general helper out of this */
12125 enum v7_err rcode = V7_OK;
12126 val_t saved_args = v7->vals.arguments, args = v7_mk_dense_array(v7);
12127 v7_array_push(v7, args, arg);
12128 v7->vals.arguments = args;
12129
12130 rcode = Regex_ctor(v7, res);
12131 if (rcode != V7_OK) {
12132 goto clean;
12133 }
12134 v7->vals.arguments = saved_args;
12135
12136clean:
12137 return rcode;
12138}
12139
12140WARN_UNUSED_RESULT
12141V7_PRIVATE enum v7_err Str_match(struct v7 *v7, v7_val_t *res) {
12142 enum v7_err rcode = V7_OK;
12143 val_t this_obj = v7_get_this(v7);
12144 val_t so = V7_UNDEFINED, ro = V7_UNDEFINED;
12145 long previousLastIndex = 0;
12146 int lastMatch = 1, n = 0, flag_g;
12147 struct v7_regexp *rxp;
12148
12149 *res = V7_NULL;
12150
12151 rcode = to_string(v7, this_obj, &so, NULL, 0, NULL);
12152 if (rcode != V7_OK) {
12153 goto clean;
12154 }
12155
12156 if (v7_argc(v7) == 0) {
12157 rcode = v7_mk_regexp(v7, "", 0, "", 0, &ro);
12158 if (rcode != V7_OK) {
12159 goto clean;
12160 }
12161 } else {
12162 rcode = obj_value_of(v7, v7_arg(v7, 0), &ro);
12163 if (rcode != V7_OK) {
12164 goto clean;
12165 }
12166 }
12167
12168 if (!v7_is_regexp(v7, ro)) {
12169 rcode = call_regex_ctor(v7, ro, &ro);
12170 if (rcode != V7_OK) {
12171 goto clean;
12172 }
12173 }
12174
12175 rxp = v7_get_regexp_struct(v7, ro);
12176 flag_g = slre_get_flags(rxp->compiled_regexp) & SLRE_FLAG_G;
12177 if (!flag_g) {
12178 rcode = rx_exec(v7, ro, so, 0, res);
12179 goto clean;
12180 }
12181
12182 rxp->lastIndex = 0;
12183 *res = v7_mk_dense_array(v7);
12184 while (lastMatch) {
12185 val_t result;
12186
12187 rcode = rx_exec(v7, ro, so, 1, &result);
12188 if (rcode != V7_OK) {
12189 goto clean;
12190 }
12191
12192 if (v7_is_null(result)) {
12193 lastMatch = 0;
12194 } else {
12195 long thisIndex = rxp->lastIndex;
12196 if (thisIndex == previousLastIndex) {
12197 previousLastIndex = thisIndex + 1;
12198 rxp->lastIndex = previousLastIndex;
12199 } else {
12200 previousLastIndex = thisIndex;
12201 }
12202 rcode =
12203 v7_array_push_throwing(v7, *res, v7_array_get(v7, result, 0), NULL);
12204 if (rcode != V7_OK) {
12205 goto clean;
12206 }
12207 n++;
12208 }
12209 }
12210
12211 if (n == 0) {
12212 *res = V7_NULL;
12213 goto clean;
12214 }
12215
12216clean:
12217 return rcode;
12218}
12219
12220WARN_UNUSED_RESULT
12221V7_PRIVATE enum v7_err Str_replace(struct v7 *v7, v7_val_t *res) {
12222 enum v7_err rcode = V7_OK;
12223 val_t this_obj = v7_get_this(v7);
12224 const char *s;
12225 size_t s_len;
12226 /*
12227 * Buffer of temporary strings returned by the replacement funciton. Will be
12228 * allocated below if only the replacement is a function. We need to store
12229 * each string in a separate `val_t`, because string data of length <= 5 is
12230 * stored right in `val_t`, so if there's more than one replacement,
12231 * each subsequent replacement will overwrite the previous one.
12232 */
12233 val_t *tmp_str_buf = NULL;
12234 val_t out_str_o;
12235 char *old_owned_mbuf_base = v7->owned_strings.buf;
12236 char *old_owned_mbuf_end = v7->owned_strings.buf + v7->owned_strings.len;
12237
12238 rcode = to_string(v7, this_obj, &this_obj, NULL, 0, NULL);
12239 if (rcode != V7_OK) {
12240 goto clean;
12241 }
12242
12243 s = v7_get_string(v7, &this_obj, &s_len);
12244
12245 if (s_len != 0 && v7_argc(v7) > 1) {
12246 const char *const str_end = s + s_len;
12247 char *p = (char *) s;
12248 uint32_t out_sub_num = 0;
12249 val_t ro = V7_UNDEFINED, str_func = V7_UNDEFINED;
12250 struct slre_prog *prog;
12251 struct slre_cap out_sub[V7_RE_MAX_REPL_SUB], *ptok = out_sub;
12252 struct slre_loot loot;
12253 int flag_g;
12254
12255 rcode = obj_value_of(v7, v7_arg(v7, 0), &ro);
12256 if (rcode != V7_OK) {
12257 goto clean;
12258 }
12259 rcode = obj_value_of(v7, v7_arg(v7, 1), &str_func);
12260 if (rcode != V7_OK) {
12261 goto clean;
12262 }
12263
12264 if (!v7_is_regexp(v7, ro)) {
12265 rcode = call_regex_ctor(v7, ro, &ro);
12266 if (rcode != V7_OK) {
12267 goto clean;
12268 }
12269 }
12270 prog = v7_get_regexp_struct(v7, ro)->compiled_regexp;
12271 flag_g = slre_get_flags(prog) & SLRE_FLAG_G;
12272
12273 if (!v7_is_callable(v7, str_func)) {
12274 rcode = to_string(v7, str_func, &str_func, NULL, 0, NULL);
12275 if (rcode != V7_OK) {
12276 goto clean;
12277 }
12278 }
12279
12280 do {
12281 int i;
12282 if (slre_exec(prog, 0, p, str_end, &loot)) break;
12283 if (p != loot.caps->start) {
12284 ptok->start = p;
12285 ptok->end = loot.caps->start;
12286 ptok++;
12287 out_sub_num++;
12288 }
12289
12290 if (v7_is_callable(v7, str_func)) { /* replace function */
12291 const char *rez_str;
12292 size_t rez_len;
12293 val_t arr = v7_mk_dense_array(v7);
12294
12295 for (i = 0; i < loot.num_captures; i++) {
12296 rcode = v7_array_push_throwing(
12297 v7, arr, v7_mk_string(v7, loot.caps[i].start,
12298 loot.caps[i].end - loot.caps[i].start, 1),
12299 NULL);
12300 if (rcode != V7_OK) {
12301 goto clean;
12302 }
12303 }
12304 rcode = v7_array_push_throwing(
12305 v7, arr, v7_mk_number(v7, utfnlen(s, loot.caps[0].start - s)),
12306 NULL);
12307 if (rcode != V7_OK) {
12308 goto clean;
12309 }
12310
12311 rcode = v7_array_push_throwing(v7, arr, this_obj, NULL);
12312 if (rcode != V7_OK) {
12313 goto clean;
12314 }
12315
12316 {
12317 val_t val = V7_UNDEFINED;
12318
12319 rcode = b_apply(v7, str_func, this_obj, arr, 0, &val);
12320 if (rcode != V7_OK) {
12321 goto clean;
12322 }
12323
12324 if (tmp_str_buf == NULL) {
12325 tmp_str_buf = (val_t *) calloc(sizeof(val_t), V7_RE_MAX_REPL_SUB);
12326 }
12327
12328 rcode = to_string(v7, val, &tmp_str_buf[out_sub_num], NULL, 0, NULL);
12329 if (rcode != V7_OK) {
12330 goto clean;
12331 }
12332 }
12333 rez_str = v7_get_string(v7, &tmp_str_buf[out_sub_num], &rez_len);
12334 if (rez_len) {
12335 ptok->start = rez_str;
12336 ptok->end = rez_str + rez_len;
12337 ptok++;
12338 out_sub_num++;
12339 }
12340 } else { /* replace string */
12341 struct slre_loot newsub;
12342 size_t f_len;
12343 const char *f_str = v7_get_string(v7, &str_func, &f_len);
12344 slre_replace(&loot, s, s_len, f_str, f_len, &newsub);
12345 for (i = 0; i < newsub.num_captures; i++) {
12346 ptok->start = newsub.caps[i].start;
12347 ptok->end = newsub.caps[i].end;
12348 ptok++;
12349 out_sub_num++;
12350 }
12351 }
12352 p = (char *) loot.caps[0].end;
12353 } while (flag_g && p < str_end);
12354 if (p <= str_end) {
12355 ptok->start = p;
12356 ptok->end = str_end;
12357 ptok++;
12358 out_sub_num++;
12359 }
12360 out_str_o = v7_mk_string(v7, NULL, 0, 1);
12361 ptok = out_sub;
12362 do {
12363 size_t ln = ptok->end - ptok->start;
12364 const char *ps = ptok->start;
12365 if (ptok->start >= old_owned_mbuf_base &&
12366 ptok->start < old_owned_mbuf_end) {
12367 ps += v7->owned_strings.buf - old_owned_mbuf_base;
12368 }
12369 out_str_o = s_concat(v7, out_str_o, v7_mk_string(v7, ps, ln, 1));
12370 p += ln;
12371 ptok++;
12372 } while (--out_sub_num);
12373
12374 *res = out_str_o;
12375 goto clean;
12376 }
12377
12378 *res = this_obj;
12379
12380clean:
12381 if (tmp_str_buf != NULL) {
12382 free(tmp_str_buf);
12383 tmp_str_buf = NULL;
12384 }
12385 return rcode;
12386}
12387
12388WARN_UNUSED_RESULT
12389V7_PRIVATE enum v7_err Str_search(struct v7 *v7, v7_val_t *res) {
12390 enum v7_err rcode = V7_OK;
12391 val_t this_obj = v7_get_this(v7);
12392 long utf_shift = -1;
12393
12394 if (v7_argc(v7) > 0) {
12395 size_t s_len;
12396 struct slre_loot sub;
12397 val_t so = V7_UNDEFINED, ro = V7_UNDEFINED;
12398 const char *s;
12399
12400 rcode = obj_value_of(v7, v7_arg(v7, 0), &ro);
12401 if (rcode != V7_OK) {
12402 goto clean;
12403 }
12404
12405 if (!v7_is_regexp(v7, ro)) {
12406 rcode = call_regex_ctor(v7, ro, &ro);
12407 if (rcode != V7_OK) {
12408 goto clean;
12409 }
12410 }
12411
12412 rcode = to_string(v7, this_obj, &so, NULL, 0, NULL);
12413 if (rcode != V7_OK) {
12414 goto clean;
12415 }
12416
12417 s = v7_get_string(v7, &so, &s_len);
12418
12419 if (!slre_exec(v7_get_regexp_struct(v7, ro)->compiled_regexp, 0, s,
12420 s + s_len, &sub))
12421 utf_shift = utfnlen(s, sub.caps[0].start - s); /* calc shift for UTF-8 */
12422 } else {
12423 utf_shift = 0;
12424 }
12425
12426 *res = v7_mk_number(v7, utf_shift);
12427
12428clean:
12429 return rcode;
12430}
12431
12432#endif /* V7_ENABLE__RegExp */
12433
12434WARN_UNUSED_RESULT
12435V7_PRIVATE enum v7_err Str_slice(struct v7 *v7, v7_val_t *res) {
12436 enum v7_err rcode = V7_OK;
12437 val_t this_obj = v7_get_this(v7);
12438 long from = 0, to = 0;
12439 size_t len;
12440 val_t so = V7_UNDEFINED;
12441 const char *begin, *end;
12442 int num_args = v7_argc(v7);
12443
12444 rcode = to_string(v7, this_obj, &so, NULL, 0, NULL);
12445 if (rcode != V7_OK) {
12446 goto clean;
12447 }
12448
12449 begin = v7_get_string(v7, &so, &len);
12450
12451 to = len = utfnlen(begin, len);
12452 if (num_args > 0) {
12453 rcode = to_long(v7, v7_arg(v7, 0), 0, &from);
12454 if (rcode != V7_OK) {
12455 goto clean;
12456 }
12457
12458 if (from < 0) {
12459 from += len;
12460 if (from < 0) from = 0;
12461 } else if ((size_t) from > len)
12462 from = len;
12463 if (num_args > 1) {
12464 rcode = to_long(v7, v7_arg(v7, 1), 0, &to);
12465 if (rcode != V7_OK) {
12466 goto clean;
12467 }
12468
12469 if (to < 0) {
12470 to += len;
12471 if (to < 0) to = 0;
12472 } else if ((size_t) to > len)
12473 to = len;
12474 }
12475 }
12476
12477 if (from > to) to = from;
12478 end = utfnshift(begin, to);
12479 begin = utfnshift(begin, from);
12480
12481 *res = v7_mk_string(v7, begin, end - begin, 1);
12482
12483clean:
12484 return rcode;
12485}
12486
12487WARN_UNUSED_RESULT
12488static enum v7_err s_transform(struct v7 *v7, val_t obj, Rune (*func)(Rune),
12489 val_t *res) {
12490 enum v7_err rcode = V7_OK;
12491 val_t s = V7_UNDEFINED;
12492 size_t i, n, len;
12493 const char *p2, *p;
12494
12495 rcode = to_string(v7, obj, &s, NULL, 0, NULL);
12496 if (rcode != V7_OK) {
12497 goto clean;
12498 }
12499
12500 p = v7_get_string(v7, &s, &len);
12501
12502 /* Pass NULL to make sure we're not creating dictionary value */
12503 *res = v7_mk_string(v7, NULL, len, 1);
12504
12505 {
12506 Rune r;
12507 p2 = v7_get_string(v7, res, &len);
12508 for (i = 0; i < len; i += n) {
12509 n = chartorune(&r, p + i);
12510 r = func(r);
12511 runetochar((char *) p2 + i, &r);
12512 }
12513 }
12514
12515clean:
12516 return rcode;
12517}
12518
12519WARN_UNUSED_RESULT
12520V7_PRIVATE enum v7_err Str_toLowerCase(struct v7 *v7, v7_val_t *res) {
12521 val_t this_obj = v7_get_this(v7);
12522 return s_transform(v7, this_obj, tolowerrune, res);
12523}
12524
12525WARN_UNUSED_RESULT
12526V7_PRIVATE enum v7_err Str_toUpperCase(struct v7 *v7, v7_val_t *res) {
12527 val_t this_obj = v7_get_this(v7);
12528 return s_transform(v7, this_obj, toupperrune, res);
12529}
12530
12531static int s_isspace(Rune c) {
12532 return isspacerune(c) || isnewline(c);
12533}
12534
12535WARN_UNUSED_RESULT
12536V7_PRIVATE enum v7_err Str_trim(struct v7 *v7, v7_val_t *res) {
12537 enum v7_err rcode = V7_OK;
12538 val_t this_obj = v7_get_this(v7);
12539 val_t s = V7_UNDEFINED;
12540 size_t i, n, len, start = 0, end, state = 0;
12541 const char *p;
12542 Rune r;
12543
12544 rcode = to_string(v7, this_obj, &s, NULL, 0, NULL);
12545 if (rcode != V7_OK) {
12546 goto clean;
12547 }
12548 p = v7_get_string(v7, &s, &len);
12549
12550 end = len;
12551 for (i = 0; i < len; i += n) {
12552 n = chartorune(&r, p + i);
12553 if (!s_isspace(r)) {
12554 if (state++ == 0) start = i;
12555 end = i + n;
12556 }
12557 }
12558
12559 *res = v7_mk_string(v7, p + start, end - start, 1);
12560
12561clean:
12562 return rcode;
12563}
12564
12565WARN_UNUSED_RESULT
12566V7_PRIVATE enum v7_err Str_length(struct v7 *v7, v7_val_t *res) {
12567 enum v7_err rcode = V7_OK;
12568 val_t this_obj = v7_get_this(v7);
12569 size_t len = 0;
12570 val_t s = V7_UNDEFINED;
12571
12572 rcode = obj_value_of(v7, this_obj, &s);
12573 if (rcode != V7_OK) {
12574 goto clean;
12575 }
12576
12577 if (v7_is_string(s)) {
12578 const char *p = v7_get_string(v7, &s, &len);
12579 len = utfnlen(p, len);
12580 }
12581
12582 *res = v7_mk_number(v7, len);
12583clean:
12584 return rcode;
12585}
12586
12587WARN_UNUSED_RESULT
12588V7_PRIVATE enum v7_err Str_at(struct v7 *v7, v7_val_t *res) {
12589 enum v7_err rcode = V7_OK;
12590 val_t this_obj = v7_get_this(v7);
12591 long arg0;
12592 val_t s = V7_UNDEFINED;
12593
12594 rcode = to_long(v7, v7_arg(v7, 0), -1, &arg0);
12595 if (rcode != V7_OK) {
12596 goto clean;
12597 }
12598
12599 rcode = obj_value_of(v7, this_obj, &s);
12600 if (rcode != V7_OK) {
12601 goto clean;
12602 }
12603
12604 if (v7_is_string(s)) {
12605 size_t n;
12606 const unsigned char *p = (unsigned char *) v7_get_string(v7, &s, &n);
12607 if (arg0 >= 0 && (size_t) arg0 < n) {
12608 *res = v7_mk_number(v7, p[arg0]);
12609 goto clean;
12610 }
12611 }
12612
12613 *res = v7_mk_number(v7, NAN);
12614
12615clean:
12616 return rcode;
12617}
12618
12619WARN_UNUSED_RESULT
12620V7_PRIVATE enum v7_err Str_blen(struct v7 *v7, v7_val_t *res) {
12621 enum v7_err rcode = V7_OK;
12622 val_t this_obj = v7_get_this(v7);
12623 size_t len = 0;
12624 val_t s = V7_UNDEFINED;
12625
12626 rcode = obj_value_of(v7, this_obj, &s);
12627 if (rcode != V7_OK) {
12628 goto clean;
12629 }
12630
12631 if (v7_is_string(s)) {
12632 v7_get_string(v7, &s, &len);
12633 }
12634
12635 *res = v7_mk_number(v7, len);
12636
12637clean:
12638 return rcode;
12639}
12640
12641WARN_UNUSED_RESULT
12642static enum v7_err s_substr(struct v7 *v7, val_t s, long start, long len,
12643 val_t *res) {
12644 enum v7_err rcode = V7_OK;
12645 size_t n;
12646 const char *p;
12647
12648 rcode = to_string(v7, s, &s, NULL, 0, NULL);
12649 if (rcode != V7_OK) {
12650 goto clean;
12651 }
12652
12653 p = v7_get_string(v7, &s, &n);
12654 n = utfnlen(p, n);
12655
12656 if (start < (long) n && len > 0) {
12657 if (start < 0) start = (long) n + start;
12658 if (start < 0) start = 0;
12659
12660 if (start > (long) n) start = n;
12661 if (len < 0) len = 0;
12662 if (len > (long) n - start) len = n - start;
12663 p = utfnshift(p, start);
12664 } else {
12665 len = 0;
12666 }
12667
12668 *res = v7_mk_string(v7, p, len, 1);
12669
12670clean:
12671 return rcode;
12672}
12673
12674WARN_UNUSED_RESULT
12675V7_PRIVATE enum v7_err Str_substr(struct v7 *v7, v7_val_t *res) {
12676 enum v7_err rcode = V7_OK;
12677 val_t this_obj = v7_get_this(v7);
12678 long start, len;
12679
12680 rcode = to_long(v7, v7_arg(v7, 0), 0, &start);
12681 if (rcode != V7_OK) {
12682 goto clean;
12683 }
12684
12685 rcode = to_long(v7, v7_arg(v7, 1), LONG_MAX, &len);
12686 if (rcode != V7_OK) {
12687 goto clean;
12688 }
12689
12690 rcode = s_substr(v7, this_obj, start, len, res);
12691 if (rcode != V7_OK) {
12692 goto clean;
12693 }
12694
12695clean:
12696 return rcode;
12697}
12698
12699WARN_UNUSED_RESULT
12700V7_PRIVATE enum v7_err Str_substring(struct v7 *v7, v7_val_t *res) {
12701 enum v7_err rcode = V7_OK;
12702 val_t this_obj = v7_get_this(v7);
12703 long start, end;
12704
12705 rcode = to_long(v7, v7_arg(v7, 0), 0, &start);
12706 if (rcode != V7_OK) {
12707 goto clean;
12708 }
12709
12710 rcode = to_long(v7, v7_arg(v7, 1), LONG_MAX, &end);
12711 if (rcode != V7_OK) {
12712 goto clean;
12713 }
12714
12715 if (start < 0) start = 0;
12716 if (end < 0) end = 0;
12717 if (start > end) {
12718 long tmp = start;
12719 start = end;
12720 end = tmp;
12721 }
12722
12723 rcode = s_substr(v7, this_obj, start, end - start, res);
12724 goto clean;
12725
12726clean:
12727 return rcode;
12728}
12729
12730WARN_UNUSED_RESULT
12731V7_PRIVATE enum v7_err Str_split(struct v7 *v7, v7_val_t *res) {
12732 enum v7_err rcode = V7_OK;
12733 val_t this_obj = v7_get_this(v7);
12734 const char *s, *s_end;
12735 size_t s_len;
12736 long num_args = v7_argc(v7);
12737 rcode = to_string(v7, this_obj, &this_obj, NULL, 0, NULL);
12738 if (rcode != V7_OK) {
12739 goto clean;
12740 }
12741 s = v7_get_string(v7, &this_obj, &s_len);
12742 s_end = s + s_len;
12743
12744 *res = v7_mk_dense_array(v7);
12745
12746 if (num_args == 0) {
12747 /*
12748 * No arguments were given: resulting array will contain just a single
12749 * element: the source string
12750 */
12751 rcode = v7_array_push_throwing(v7, *res, this_obj, NULL);
12752 if (rcode != V7_OK) {
12753 goto clean;
12754 }
12755 } else {
12756 val_t ro = V7_UNDEFINED;
12757 long elem, limit;
12758 size_t lookup_idx = 0, substr_idx = 0;
12759 struct _str_split_ctx ctx;
12760
12761 rcode = to_long(v7, v7_arg(v7, 1), LONG_MAX, &limit);
12762 if (rcode != V7_OK) {
12763 goto clean;
12764 }
12765
12766 rcode = obj_value_of(v7, v7_arg(v7, 0), &ro);
12767 if (rcode != V7_OK) {
12768 goto clean;
12769 }
12770
12771 /* Initialize substring context depending on the argument type */
12772 if (v7_is_regexp(v7, ro)) {
12773/* use RegExp implementation */
12774#if V7_ENABLE__RegExp
12775 ctx.p_init = subs_regexp_init;
12776 ctx.p_exec = subs_regexp_exec;
12777 ctx.p_add_caps = subs_regexp_split_add_caps;
12778#else
12779 assert(0);
12780#endif
12781 } else {
12782 /*
12783 * use String implementation: first of all, convert to String (if it's
12784 * not already a String)
12785 */
12786 rcode = to_string(v7, ro, &ro, NULL, 0, NULL);
12787 if (rcode != V7_OK) {
12788 goto clean;
12789 }
12790
12791 ctx.p_init = subs_string_init;
12792 ctx.p_exec = subs_string_exec;
12793#if V7_ENABLE__RegExp
12794 ctx.p_add_caps = subs_string_split_add_caps;
12795#endif
12796 }
12797 /* initialize context */
12798 ctx.p_init(&ctx, v7, ro);
12799
12800 if (s_len == 0) {
12801 /*
12802 * if `this` is (or converts to) an empty string, resulting array should
12803 * contain empty string if only separator does not match an empty string.
12804 * Otherwise, the array is left empty
12805 */
12806 int matches_empty = !ctx.p_exec(&ctx, s, s);
12807 if (!matches_empty) {
12808 rcode = v7_array_push_throwing(v7, *res, this_obj, NULL);
12809 if (rcode != V7_OK) {
12810 goto clean;
12811 }
12812 }
12813 } else {
12814 size_t last_match_len = 0;
12815
12816 for (elem = 0; elem < limit && lookup_idx < s_len;) {
12817 size_t substr_len;
12818 /* find next match, and break if there's no match */
12819 if (ctx.p_exec(&ctx, s + lookup_idx, s_end)) break;
12820
12821 last_match_len = ctx.match_end - ctx.match_start;
12822 substr_len = ctx.match_start - s - substr_idx;
12823
12824 /* add next substring to the resulting array, if needed */
12825 if (substr_len > 0 || last_match_len > 0) {
12826 rcode = v7_array_push_throwing(
12827 v7, *res, v7_mk_string(v7, s + substr_idx, substr_len, 1), NULL);
12828 if (rcode != V7_OK) {
12829 goto clean;
12830 }
12831 elem++;
12832
12833#if V7_ENABLE__RegExp
12834 /* Add captures (for RegExp only) */
12835 elem = ctx.p_add_caps(&ctx, *res, elem, limit);
12836#endif
12837 }
12838
12839 /* advance lookup_idx appropriately */
12840 if (last_match_len == 0) {
12841 /* empty match: advance to the next char */
12842 const char *next = utfnshift((s + lookup_idx), 1);
12843 lookup_idx += (next - (s + lookup_idx));
12844 } else {
12845 /* non-empty match: advance to the end of match */
12846 lookup_idx = ctx.match_end - s;
12847 }
12848
12849 /*
12850 * always remember the end of the match, so that next time we will take
12851 * substring from that position
12852 */
12853 substr_idx = ctx.match_end - s;
12854 }
12855
12856 /* add the last substring to the resulting array, if needed */
12857 if (elem < limit) {
12858 size_t substr_len = s_len - substr_idx;
12859 if (substr_len > 0 || last_match_len > 0) {
12860 rcode = v7_array_push_throwing(
12861 v7, *res, v7_mk_string(v7, s + substr_idx, substr_len, 1), NULL);
12862 if (rcode != V7_OK) {
12863 goto clean;
12864 }
12865 }
12866 }
12867 }
12868 }
12869
12870clean:
12871 return rcode;
12872}
12873
12874V7_PRIVATE void init_string(struct v7 *v7) {
12875 val_t str = mk_cfunction_obj_with_proto(v7, String_ctor, 1,
12876 v7->vals.string_prototype);
12877 v7_def(v7, v7->vals.global_object, "String", 6, V7_DESC_ENUMERABLE(0), str);
12878
12879 set_cfunc_prop(v7, str, "fromCharCode", Str_fromCharCode);
12880 set_cfunc_prop(v7, v7->vals.string_prototype, "charCodeAt", Str_charCodeAt);
12881 set_cfunc_prop(v7, v7->vals.string_prototype, "charAt", Str_charAt);
12882 set_cfunc_prop(v7, v7->vals.string_prototype, "concat", Str_concat);
12883 set_cfunc_prop(v7, v7->vals.string_prototype, "indexOf", Str_indexOf);
12884 set_cfunc_prop(v7, v7->vals.string_prototype, "substr", Str_substr);
12885 set_cfunc_prop(v7, v7->vals.string_prototype, "substring", Str_substring);
12886 set_cfunc_prop(v7, v7->vals.string_prototype, "valueOf", Str_valueOf);
12887 set_cfunc_prop(v7, v7->vals.string_prototype, "lastIndexOf", Str_lastIndexOf);
12888#if V7_ENABLE__String__localeCompare
12889 set_cfunc_prop(v7, v7->vals.string_prototype, "localeCompare",
12890 Str_localeCompare);
12891#endif
12892#if V7_ENABLE__RegExp
12893 set_cfunc_prop(v7, v7->vals.string_prototype, "match", Str_match);
12894 set_cfunc_prop(v7, v7->vals.string_prototype, "replace", Str_replace);
12895 set_cfunc_prop(v7, v7->vals.string_prototype, "search", Str_search);
12896#endif
12897 set_cfunc_prop(v7, v7->vals.string_prototype, "split", Str_split);
12898 set_cfunc_prop(v7, v7->vals.string_prototype, "slice", Str_slice);
12899 set_cfunc_prop(v7, v7->vals.string_prototype, "trim", Str_trim);
12900 set_cfunc_prop(v7, v7->vals.string_prototype, "toLowerCase", Str_toLowerCase);
12901#if V7_ENABLE__String__localeLowerCase
12902 set_cfunc_prop(v7, v7->vals.string_prototype, "toLocaleLowerCase",
12903 Str_toLowerCase);
12904#endif
12905 set_cfunc_prop(v7, v7->vals.string_prototype, "toUpperCase", Str_toUpperCase);
12906#if V7_ENABLE__String__localeUpperCase
12907 set_cfunc_prop(v7, v7->vals.string_prototype, "toLocaleUpperCase",
12908 Str_toUpperCase);
12909#endif
12910 set_cfunc_prop(v7, v7->vals.string_prototype, "toString", Str_toString);
12911
12912 v7_def(v7, v7->vals.string_prototype, "length", 6, V7_DESC_GETTER(1),
12913 v7_mk_cfunction(Str_length));
12914
12915 /* Non-standard Cesanta extension */
12916 set_cfunc_prop(v7, v7->vals.string_prototype, "at", Str_at);
12917 v7_def(v7, v7->vals.string_prototype, "blen", 4, V7_DESC_GETTER(1),
12918 v7_mk_cfunction(Str_blen));
12919}
12920#ifdef V7_MODULE_LINES
12921#line 1 "v7/src/std_date.c"
12922#endif
12923/*
12924 * Copyright (c) 2015 Cesanta Software Limited
12925 * All rights reserved
12926 */
12927
12928/* Amalgamated: #include "v7/src/internal.h" */
12929/* Amalgamated: #include "common/str_util.h" */
12930/* Amalgamated: #include "v7/src/std_object.h" */
12931/* Amalgamated: #include "v7/src/core.h" */
12932/* Amalgamated: #include "v7/src/util.h" */
12933/* Amalgamated: #include "v7/src/function.h" */
12934/* Amalgamated: #include "v7/src/object.h" */
12935/* Amalgamated: #include "v7/src/conversion.h" */
12936/* Amalgamated: #include "v7/src/exceptions.h" */
12937/* Amalgamated: #include "v7/src/primitive.h" */
12938/* Amalgamated: #include "v7/src/string.h" */
12939
12940#if V7_ENABLE__Date
12941
12942#include <locale.h>
12943#include <time.h>
12944
12945#ifndef _WIN32
12946extern long timezone;
12947#include <sys/time.h>
12948#endif
12949
12950#if defined(_MSC_VER)
12951#define timezone _timezone
12952#define tzname _tzname
12953#if _MSC_VER >= 1800
12954#define tzset _tzset
12955#endif
12956#endif
12957
12958#if defined(__cplusplus)
12959extern "C" {
12960#endif /* __cplusplus */
12961
12962typedef double etime_t; /* double is suitable type for ECMA time */
12963/* inernally we have to use 64-bit integer for some operations */
12964typedef int64_t etimeint_t;
12965#define INVALID_TIME NAN
12966
12967#define msPerDay 86400000
12968#define HoursPerDay 24
12969#define MinutesPerHour 60
12970#define SecondsPerMinute 60
12971#define SecondsPerHour 3600
12972#define msPerSecond 1000
12973#define msPerMinute 60000
12974#define msPerHour 3600000
12975#define MonthsInYear 12
12976
12977/* ECMA alternative to struct tm */
12978struct timeparts {
12979 int year; /* can be negative, up to +-282000 */
12980 int month; /* 0-11 */
12981 int day; /* 1-31 */
12982 int hour; /* 0-23 */
12983 int min; /* 0-59 */
12984 int sec; /* 0-59 */
12985 int msec;
12986 int dayofweek; /* 0-6 */
12987};
12988
12989static etimeint_t g_gmtoffms; /* timezone offset, ms, no DST */
12990static const char *g_tzname; /* current timezone name */
12991
12992/* Leap year formula copied from ECMA 5.1 standart as is */
12993static int ecma_DaysInYear(int y) {
12994 if (y % 4 != 0) {
12995 return 365;
12996 } else if (y % 4 == 0 && y % 100 != 0) {
12997 return 366;
12998 } else if (y % 100 == 0 && y % 400 != 0) {
12999 return 365;
13000 } else if (y % 400 == 0) {
13001 return 366;
13002 } else {
13003 return 365;
13004 }
13005}
13006
13007static etimeint_t ecma_DayFromYear(etimeint_t y) {
13008 return 365 * (y - 1970) + floor((y - 1969) / 4) - floor((y - 1901) / 100) +
13009 floor((y - 1601) / 400);
13010}
13011
13012static etimeint_t ecma_TimeFromYear(etimeint_t y) {
13013 return msPerDay * ecma_DayFromYear(y);
13014}
13015
13016static int ecma_IsLeapYear(int year) {
13017 return ecma_DaysInYear(year) == 366;
13018}
13019
13020static int *ecma_getfirstdays(int isleap) {
13021 static int sdays[2][MonthsInYear + 1] = {
13022 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
13023 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
13024
13025 return sdays[isleap];
13026}
13027
13028static int ecma_DaylightSavingTA(etime_t t) {
13029 time_t time = t / 1000;
13030 /*
13031 * Win32 doesn't have locatime_r
13032 * nixes don't have localtime_s
13033 * as result using localtime
13034 */
13035 struct tm *tm = localtime(&time);
13036 if (tm == NULL) {
13037 /* doesn't work on windows for times before epoch */
13038 return 0;
13039 }
13040 if (tm->tm_isdst > 0) {
13041 return msPerHour;
13042 } else {
13043 return 0;
13044 }
13045}
13046
13047static int ecma_LocalTZA(void) {
13048 return (int) -g_gmtoffms;
13049}
13050
13051static etimeint_t ecma_UTC(etime_t t) {
13052 return t - ecma_LocalTZA() - ecma_DaylightSavingTA(t - ecma_LocalTZA());
13053}
13054
13055#if V7_ENABLE__Date__toString || V7_ENABLE__Date__toLocaleString || \
13056 V7_ENABLE__Date__toJSON || V7_ENABLE__Date__getters || \
13057 V7_ENABLE__Date__setters
13058static int ecma_YearFromTime_s(etime_t t) {
13059 int first = floor((t / msPerDay) / 366) + 1970,
13060 last = floor((t / msPerDay) / 365) + 1970, middle = 0;
13061
13062 if (last < first) {
13063 int temp = first;
13064 first = last;
13065 last = temp;
13066 }
13067
13068 while (last > first) {
13069 middle = (last + first) / 2;
13070 if (ecma_TimeFromYear(middle) > t) {
13071 last = middle - 1;
13072 } else {
13073 if (ecma_TimeFromYear(middle) <= t) {
13074 if (ecma_TimeFromYear(middle + 1) > t) {
13075 first = middle;
13076 break;
13077 }
13078 first = middle + 1;
13079 }
13080 }
13081 }
13082
13083 return first;
13084}
13085
13086static etimeint_t ecma_Day(etime_t t) {
13087 return floor(t / msPerDay);
13088}
13089
13090static int ecma_DayWithinYear(etime_t t, int year) {
13091 return (int) (ecma_Day(t) - ecma_DayFromYear(year));
13092}
13093
13094static int ecma_MonthFromTime(etime_t t, int year) {
13095 int *days, i;
13096 etimeint_t dwy = ecma_DayWithinYear(t, year);
13097
13098 days = ecma_getfirstdays(ecma_IsLeapYear(year));
13099
13100 for (i = 0; i < MonthsInYear; i++) {
13101 if (dwy >= days[i] && dwy < days[i + 1]) {
13102 return i;
13103 }
13104 }
13105
13106 return -1;
13107}
13108
13109static int ecma_DateFromTime(etime_t t, int year) {
13110 int *days, mft = ecma_MonthFromTime(t, year),
13111 dwy = ecma_DayWithinYear(t, year);
13112
13113 if (mft > 11) {
13114 return -1;
13115 }
13116
13117 days = ecma_getfirstdays(ecma_IsLeapYear(year));
13118
13119 return dwy - days[mft] + 1;
13120}
13121
13122#define DEF_EXTRACT_TIMEPART(funcname, c1, c2) \
13123 static int ecma_##funcname(etime_t t) { \
13124 int ret = (etimeint_t) floor(t / c1) % c2; \
13125 if (ret < 0) { \
13126 ret += c2; \
13127 } \
13128 return ret; \
13129 }
13130
13131DEF_EXTRACT_TIMEPART(HourFromTime, msPerHour, HoursPerDay)
13132DEF_EXTRACT_TIMEPART(MinFromTime, msPerMinute, MinutesPerHour)
13133DEF_EXTRACT_TIMEPART(SecFromTime, msPerSecond, SecondsPerMinute)
13134DEF_EXTRACT_TIMEPART(msFromTime, 1, msPerSecond)
13135
13136static int ecma_WeekDay(etime_t t) {
13137 int ret = (ecma_Day(t) + 4) % 7;
13138 if (ret < 0) {
13139 ret += 7;
13140 }
13141
13142 return ret;
13143}
13144
13145static void d_gmtime(const etime_t *t, struct timeparts *tp) {
13146 tp->year = ecma_YearFromTime_s(*t);
13147 tp->month = ecma_MonthFromTime(*t, tp->year);
13148 tp->day = ecma_DateFromTime(*t, tp->year);
13149 tp->hour = ecma_HourFromTime(*t);
13150 tp->min = ecma_MinFromTime(*t);
13151 tp->sec = ecma_SecFromTime(*t);
13152 tp->msec = ecma_msFromTime(*t);
13153 tp->dayofweek = ecma_WeekDay(*t);
13154}
13155#endif /* V7_ENABLE__Date__toString || V7_ENABLE__Date__toLocaleString || \
13156 V7_ENABLE__Date__getters || V7_ENABLE__Date__setters */
13157
13158#if V7_ENABLE__Date__toString || V7_ENABLE__Date__toLocaleString || \
13159 V7_ENABLE__Date__getters || V7_ENABLE__Date__setters
13160static etimeint_t ecma_LocalTime(etime_t t) {
13161 return t + ecma_LocalTZA() + ecma_DaylightSavingTA(t);
13162}
13163
13164static void d_localtime(const etime_t *time, struct timeparts *tp) {
13165 etime_t local_time = ecma_LocalTime(*time);
13166 d_gmtime(&local_time, tp);
13167}
13168#endif
13169
13170static etimeint_t ecma_MakeTime(etimeint_t hour, etimeint_t min, etimeint_t sec,
13171 etimeint_t ms) {
13172 return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) *
13173 msPerSecond +
13174 ms;
13175}
13176
13177static etimeint_t ecma_MakeDay(int year, int month, int date) {
13178 int *days;
13179 etimeint_t yday, mday;
13180
13181 year += floor(month / 12);
13182 month = month % 12;
13183 yday = floor(ecma_TimeFromYear(year) / msPerDay);
13184 days = ecma_getfirstdays(ecma_IsLeapYear(year));
13185 mday = days[month];
13186
13187 return yday + mday + date - 1;
13188}
13189
13190static etimeint_t ecma_MakeDate(etimeint_t day, etimeint_t time) {
13191 return (day * msPerDay + time);
13192}
13193
13194static void d_gettime(etime_t *t) {
13195#ifndef _WIN32
13196 struct timeval tv;
13197 gettimeofday(&tv, NULL);
13198 *t = (etime_t) tv.tv_sec * 1000 + (etime_t) tv.tv_usec / 1000;
13199#else
13200 /* TODO(mkm): use native windows API in order to get ms granularity */
13201 *t = time(NULL) * 1000.0;
13202#endif
13203}
13204
13205static etime_t d_mktime_impl(const struct timeparts *tp) {
13206 return ecma_MakeDate(ecma_MakeDay(tp->year, tp->month, tp->day),
13207 ecma_MakeTime(tp->hour, tp->min, tp->sec, tp->msec));
13208}
13209
13210#if V7_ENABLE__Date__setters
13211static etime_t d_lmktime(const struct timeparts *tp) {
13212 return ecma_UTC(d_mktime_impl(tp));
13213}
13214#endif
13215
13216static etime_t d_gmktime(const struct timeparts *tp) {
13217 return d_mktime_impl(tp);
13218}
13219
13220typedef etime_t (*fmaketime_t)(const struct timeparts *);
13221typedef void (*fbreaktime_t)(const etime_t *, struct timeparts *);
13222
13223#if V7_ENABLE__Date__toString || V7_ENABLE__Date__toLocaleString || \
13224 V7_ENABLE__Date__toJSON
13225static val_t d_trytogetobjforstring(struct v7 *v7, val_t obj) {
13226 enum v7_err rcode = V7_OK;
13227 val_t ret = V7_UNDEFINED;
13228
13229 rcode = obj_value_of(v7, obj, &ret);
13230 if (rcode != V7_OK) {
13231 goto clean;
13232 }
13233
13234 if (ret == V7_TAG_NAN) {
13235 rcode = v7_throwf(v7, TYPE_ERROR, "Date is invalid (for string)");
13236 goto clean;
13237 }
13238
13239clean:
13240 (void) rcode;
13241 return ret;
13242}
13243#endif
13244
13245#if V7_ENABLE__Date__parse || V7_ENABLE__Date__UTC
13246static int d_iscalledasfunction(struct v7 *v7, val_t this_obj) {
13247 /* TODO(alashkin): verify this statement */
13248 return is_prototype_of(v7, this_obj, v7->vals.date_prototype);
13249}
13250#endif
13251
13252static const char *mon_name[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
13253 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
13254
13255int d_getnumbyname(const char **arr, int arr_size, const char *str) {
13256 int i;
13257 for (i = 0; i < arr_size; i++) {
13258 if (strncmp(arr[i], str, 3) == 0) {
13259 return i + 1;
13260 }
13261 }
13262
13263 return -1;
13264}
13265
13266int date_parse(const char *str, int *a1, int *a2, int *a3, char sep,
13267 char *rest) {
13268 char frmDate[] = " %d/%d/%d%[^\0]";
13269 frmDate[3] = frmDate[6] = sep;
13270 return sscanf(str, frmDate, a1, a2, a3, rest);
13271}
13272
13273#define NO_TZ 0x7FFFFFFF
13274
13275/*
13276 * not very smart but simple, and working according
13277 * to ECMA5.1 StringToDate function
13278 */
13279static int d_parsedatestr(const char *jstr, size_t len, struct timeparts *tp,
13280 int *tz) {
13281 char gmt[4];
13282 char buf1[100] = {0}, buf2[100] = {0};
13283 int res = 0;
13284 char str[101];
13285 memcpy(str, jstr, len);
13286 str[len] = '\0';
13287 memset(tp, 0, sizeof(*tp));
13288 *tz = NO_TZ;
13289
13290 /* trying toISOSrting() format */
13291 {
13292 const char *frmISOString = " %d-%02d-%02dT%02d:%02d:%02d.%03dZ";
13293 res = sscanf(str, frmISOString, &tp->year, &tp->month, &tp->day, &tp->hour,
13294 &tp->min, &tp->sec, &tp->msec);
13295 if (res == 7) {
13296 *tz = 0;
13297 return 1;
13298 }
13299 }
13300
13301 /* trying toString()/toUTCString()/toDateFormat() formats */
13302 {
13303 char month[4];
13304 int dowlen;
13305 const char *frmString = " %*s%n %03s %02d %d %02d:%02d:%02d %03s%d";
13306 res = sscanf(str, frmString, &dowlen, month, &tp->day, &tp->year, &tp->hour,
13307 &tp->min, &tp->sec, gmt, tz);
13308 if ((res == 3 || (res >= 6 && res <= 8)) && dowlen == 3) {
13309 if ((tp->month = d_getnumbyname(mon_name, ARRAY_SIZE(mon_name), month)) !=
13310 -1) {
13311 if (res == 7 && strncmp(gmt, "GMT", 3) == 0) {
13312 *tz = 0;
13313 }
13314 return 1;
13315 }
13316 }
13317 }
13318
13319 /* trying the rest */
13320
13321 /* trying date */
13322
13323 if (!(date_parse(str, &tp->month, &tp->day, &tp->year, '/', buf1) >= 3 ||
13324 date_parse(str, &tp->day, &tp->month, &tp->year, '.', buf1) >= 3 ||
13325 date_parse(str, &tp->year, &tp->month, &tp->day, '-', buf1) >= 3)) {
13326 return 0;
13327 }
13328
13329 /* there is date, trying time; from here return 0 only on errors */
13330
13331 /* trying HH:mm */
13332 {
13333 const char *frmMMhh = " %d:%d%[^\0]";
13334 res = sscanf(buf1, frmMMhh, &tp->hour, &tp->min, buf2);
13335 /* can't get time, but have some symbols, assuming error */
13336 if (res < 2) {
13337 return (strlen(buf2) == 0);
13338 }
13339 }
13340
13341 /* trying seconds */
13342 {
13343 const char *frmss = ":%d%[^\0]";
13344 memset(buf1, 0, sizeof(buf1));
13345 res = sscanf(buf2, frmss, &tp->sec, buf1);
13346 }
13347
13348 /* even if we don't get seconds we gonna try to get tz */
13349 {
13350 char *rest = res ? buf1 : buf2;
13351 char *buf = res ? buf2 : buf1;
13352 const char *frmtz = " %03s%d%[^\0]";
13353
13354 res = sscanf(rest, frmtz, gmt, tz, buf);
13355 if (res == 1 && strncmp(gmt, "GMT", 3) == 0) {
13356 *tz = 0;
13357 }
13358 }
13359
13360 /* return OK if we are at the end of string */
13361 return res <= 2;
13362}
13363
13364static int d_timeFromString(etime_t *time, const char *str, size_t str_len) {
13365 struct timeparts tp;
13366 int tz;
13367
13368 *time = INVALID_TIME;
13369
13370 if (str_len > 100) {
13371 /* too long for valid date string */
13372 return 0;
13373 }
13374
13375 if (d_parsedatestr(str, str_len, &tp, &tz)) {
13376 /* check results */
13377 int valid = 0;
13378
13379 tp.month--;
13380 valid = tp.day >= 1 && tp.day <= 31;
13381 valid &= tp.month >= 0 && tp.month <= 11;
13382 valid &= tp.hour >= 0 && tp.hour <= 23;
13383 valid &= tp.min >= 0 && tp.min <= 59;
13384 valid &= tp.sec >= 0 && tp.sec <= 59;
13385
13386 if (tz != NO_TZ && tz > 12) {
13387 tz /= 100;
13388 }
13389
13390 valid &= (abs(tz) <= 12 || tz == NO_TZ);
13391
13392 if (valid) {
13393 *time = d_gmktime(&tp);
13394
13395 if (tz != NO_TZ) {
13396 /* timezone specified, use it */
13397 *time -= (tz * msPerHour);
13398 } else if (tz != 0) {
13399 /* assuming local timezone and moving back to UTC */
13400 *time = ecma_UTC(*time);
13401 }
13402 }
13403 }
13404
13405 return !isnan(*time);
13406}
13407
13408/* notice: holding month in calendar format (1-12, not 0-11) */
13409struct dtimepartsarr {
13410 etime_t args[7];
13411};
13412
13413enum detimepartsarr {
13414 tpyear = 0,
13415 tpmonth,
13416 tpdate,
13417 tphours,
13418 tpminutes,
13419 tpseconds,
13420 tpmsec,
13421 tpmax
13422};
13423
13424static etime_t d_changepartoftime(const etime_t *current,
13425 struct dtimepartsarr *a,
13426 fbreaktime_t breaktimefunc,
13427 fmaketime_t maketimefunc) {
13428 /*
13429 * 0 = year, 1 = month , 2 = date , 3 = hours,
13430 * 4 = minutes, 5 = seconds, 6 = ms
13431 */
13432 struct timeparts tp;
13433 unsigned long i;
13434 int *tp_arr[7];
13435 /*
13436 * C89 doesn't allow initialization
13437 * like x = {&tp.year, &tp.month, .... }
13438 */
13439 tp_arr[0] = &tp.year;
13440 tp_arr[1] = &tp.month;
13441 tp_arr[2] = &tp.day;
13442 tp_arr[3] = &tp.hour;
13443 tp_arr[4] = &tp.min;
13444 tp_arr[5] = &tp.sec;
13445 tp_arr[6] = &tp.msec;
13446
13447 memset(&tp, 0, sizeof(tp));
13448
13449 if (breaktimefunc != NULL) {
13450 breaktimefunc(current, &tp);
13451 }
13452
13453 for (i = 0; i < ARRAY_SIZE(tp_arr); i++) {
13454 if (!isnan(a->args[i]) && !isinf(a->args[i])) {
13455 *tp_arr[i] = (int) a->args[i];
13456 }
13457 }
13458
13459 return maketimefunc(&tp);
13460}
13461
13462#if V7_ENABLE__Date__setters || V7_ENABLE__Date__UTC
13463static etime_t d_time_number_from_arr(struct v7 *v7, int start_pos,
13464 fbreaktime_t breaktimefunc,
13465 fmaketime_t maketimefunc) {
13466 enum v7_err rcode = V7_OK;
13467 val_t this_obj = v7_get_this(v7);
13468 etime_t ret_time = INVALID_TIME;
13469 long cargs;
13470
13471 val_t objtime = V7_UNDEFINED;
13472 rcode = obj_value_of(v7, this_obj, &objtime);
13473 if (rcode != V7_OK) {
13474 goto clean;
13475 }
13476
13477 if ((cargs = v7_argc(v7)) >= 1 && objtime != V7_TAG_NAN) {
13478 int i;
13479 etime_t new_part = INVALID_TIME;
13480 struct dtimepartsarr a;
13481 for (i = 0; i < 7; i++) {
13482 a.args[i] = INVALID_TIME;
13483 }
13484
13485 for (i = 0; i < cargs && (i + start_pos < tpmax); i++) {
13486 {
13487 val_t arg = v7_arg(v7, i);
13488 rcode = to_number_v(v7, arg, &arg);
13489 if (rcode != V7_OK) {
13490 goto clean;
13491 }
13492 new_part = v7_get_double(v7, arg);
13493 }
13494
13495 if (isnan(new_part)) {
13496 break;
13497 }
13498
13499 a.args[i + start_pos] = new_part;
13500 }
13501
13502 if (!isnan(new_part)) {
13503 etime_t current_time = v7_get_double(v7, objtime);
13504 ret_time =
13505 d_changepartoftime(¤t_time, &a, breaktimefunc, maketimefunc);
13506 }
13507 }
13508
13509clean:
13510 (void) rcode;
13511 return ret_time;
13512}
13513#endif /* V7_ENABLE__Date__setters */
13514
13515#if V7_ENABLE__Date__toString
13516static int d_tptostr(const struct timeparts *tp, char *buf, int addtz);
13517#endif
13518
13519/* constructor */
13520WARN_UNUSED_RESULT
13521V7_PRIVATE enum v7_err Date_ctor(struct v7 *v7, v7_val_t *res) {
13522 enum v7_err rcode = V7_OK;
13523 val_t this_obj = v7_get_this(v7);
13524 etime_t ret_time = INVALID_TIME;
13525 if (v7_is_generic_object(this_obj) && this_obj != v7->vals.global_object) {
13526 long cargs = v7_argc(v7);
13527 if (cargs <= 0) {
13528 /* no parameters - return current date & time */
13529 d_gettime(&ret_time);
13530 } else if (cargs == 1) {
13531 /* one parameter */
13532 val_t arg = v7_arg(v7, 0);
13533 if (v7_is_string(arg)) { /* it could be string */
13534 size_t str_size;
13535 const char *str = v7_get_string(v7, &arg, &str_size);
13536 d_timeFromString(&ret_time, str, str_size);
13537 }
13538 if (isnan(ret_time)) {
13539 /*
13540 * if cannot be parsed or
13541 * not string at all - trying to convert to number
13542 */
13543 ret_time = 0;
13544 rcode = to_number_v(v7, arg, &arg);
13545 if (rcode != V7_OK) {
13546 goto clean;
13547 }
13548 ret_time = v7_get_double(v7, arg);
13549 if (rcode != V7_OK) {
13550 goto clean;
13551 }
13552 }
13553 } else {
13554 /* 2+ paramaters - should be parts of a date */
13555 struct dtimepartsarr a;
13556 int i;
13557
13558 memset(&a, 0, sizeof(a));
13559
13560 for (i = 0; i < cargs; i++) {
13561 val_t arg = v7_arg(v7, i);
13562 rcode = to_number_v(v7, arg, &arg);
13563 if (rcode != V7_OK) {
13564 goto clean;
13565 }
13566 a.args[i] = v7_get_double(v7, arg);
13567 if (isnan(a.args[i])) {
13568 break;
13569 }
13570 }
13571
13572 if (i >= cargs) {
13573 /*
13574 * If date is supplied then let
13575 * dt be ToNumber(date); else let dt be 1.
13576 */
13577 if (a.args[tpdate] == 0) {
13578 a.args[tpdate] = 1;
13579 }
13580
13581 if (a.args[tpyear] >= 0 && a.args[tpyear] <= 99) {
13582 /*
13583 * If y is not NaN and 0 <= ToInteger(y) <= 99,
13584 * then let yr be 1900+ToInteger(y); otherwise, let yr be y.
13585 */
13586 a.args[tpyear] += 1900;
13587 }
13588
13589 ret_time = ecma_UTC(d_changepartoftime(0, &a, 0, d_gmktime));
13590 }
13591 }
13592
13593 obj_prototype_set(v7, get_object_struct(this_obj),
13594 get_object_struct(v7->vals.date_prototype));
13595
13596 v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), v7_mk_number(v7, ret_time));
13597 /*
13598 * implicitly returning `this`: `call_cfunction()` in bcode.c will do
13599 * that for us
13600 */
13601 goto clean;
13602 } else {
13603 /*
13604 * according to 15.9.2.1 we should ignore all
13605 * parameters in case of function-call
13606 */
13607 char buf[50];
13608 int len;
13609
13610#if V7_ENABLE__Date__toString
13611 struct timeparts tp;
13612 d_gettime(&ret_time);
13613 d_localtime(&ret_time, &tp);
13614 len = d_tptostr(&tp, buf, 1);
13615#else
13616 len = 0;
13617#endif /* V7_ENABLE__Date__toString */
13618
13619 *res = v7_mk_string(v7, buf, len, 1);
13620 goto clean;
13621 }
13622
13623clean:
13624 return rcode;
13625}
13626
13627#if V7_ENABLE__Date__toString || V7_ENABLE__Date__toJSON
13628static int d_timetoISOstr(const etime_t *time, char *buf, size_t buf_size) {
13629 /* ISO format: "+XXYYYY-MM-DDTHH:mm:ss.sssZ"; */
13630 struct timeparts tp;
13631 char use_ext = 0;
13632 const char *ey_frm = "%06d-%02d-%02dT%02d:%02d:%02d.%03dZ";
13633 const char *simpl_frm = "%d-%02d-%02dT%02d:%02d:%02d.%03dZ";
13634
13635 d_gmtime(time, &tp);
13636
13637 if (abs(tp.year) > 9999 || tp.year < 0) {
13638 *buf = (tp.year > 0) ? '+' : '-';
13639 use_ext = 1;
13640 }
13641
13642 return c_snprintf(buf + use_ext, buf_size - use_ext,
13643 use_ext ? ey_frm : simpl_frm, abs(tp.year), tp.month + 1,
13644 tp.day, tp.hour, tp.min, tp.sec, tp.msec) +
13645 use_ext;
13646}
13647
13648WARN_UNUSED_RESULT
13649V7_PRIVATE enum v7_err Date_toISOString(struct v7 *v7, v7_val_t *res) {
13650 enum v7_err rcode = V7_OK;
13651 val_t this_obj = v7_get_this(v7);
13652 char buf[30];
13653 etime_t time;
13654 int len;
13655
13656 if (val_type(v7, this_obj) != V7_TYPE_DATE_OBJECT) {
13657 rcode = v7_throwf(v7, TYPE_ERROR, "This is not a Date object");
13658 goto clean;
13659 }
13660
13661 time = v7_get_double(v7, d_trytogetobjforstring(v7, this_obj));
13662 len = d_timetoISOstr(&time, buf, sizeof(buf));
13663 if (len > (int) (sizeof(buf) - 1 /*null-term*/)) {
13664 len = (int) (sizeof(buf) - 1 /*null-term*/);
13665 }
13666
13667 *res = v7_mk_string(v7, buf, len, 1);
13668
13669clean:
13670 return rcode;
13671}
13672#endif /* V7_ENABLE__Date__toString || V7_ENABLE__Date__toJSON */
13673
13674#if V7_ENABLE__Date__toString
13675typedef int (*ftostring_t)(const struct timeparts *, char *, int);
13676
13677WARN_UNUSED_RESULT
13678static enum v7_err d_tostring(struct v7 *v7, val_t obj,
13679 fbreaktime_t breaktimefunc,
13680 ftostring_t tostringfunc, int addtz,
13681 v7_val_t *res) {
13682 enum v7_err rcode = V7_OK;
13683 struct timeparts tp;
13684 int len;
13685 char buf[100];
13686 etime_t time;
13687
13688 time = v7_get_double(v7, d_trytogetobjforstring(v7, obj));
13689
13690 breaktimefunc(&time, &tp);
13691 len = tostringfunc(&tp, buf, addtz);
13692
13693 *res = v7_mk_string(v7, buf, len, 1);
13694 return rcode;
13695}
13696
13697/* using macros to avoid copy-paste technic */
13698#define DEF_TOSTR(funcname, breaktimefunc, tostrfunc, addtz) \
13699 WARN_UNUSED_RESULT \
13700 V7_PRIVATE enum v7_err Date_to##funcname(struct v7 *v7, v7_val_t *res) { \
13701 val_t this_obj = v7_get_this(v7); \
13702 return d_tostring(v7, this_obj, breaktimefunc, tostrfunc, addtz, res); \
13703 }
13704
13705/* non-locale function should always return in english and 24h-format */
13706static const char *wday_name[] = {"Sun", "Mon", "Tue", "Wed",
13707 "Thu", "Fri", "Sat"};
13708
13709static int d_tptodatestr(const struct timeparts *tp, char *buf, int addtz) {
13710 (void) addtz;
13711
13712 return sprintf(buf, "%s %s %02d %d", wday_name[tp->dayofweek],
13713 mon_name[tp->month], tp->day, tp->year);
13714}
13715
13716DEF_TOSTR(DateString, d_localtime, d_tptodatestr, 1)
13717
13718static const char *d_gettzname(void) {
13719 return g_tzname;
13720}
13721
13722static int d_tptotimestr(const struct timeparts *tp, char *buf, int addtz) {
13723 int len;
13724
13725 len = sprintf(buf, "%02d:%02d:%02d GMT", tp->hour, tp->min, tp->sec);
13726
13727 if (addtz && g_gmtoffms != 0) {
13728 len = sprintf(buf + len, "%c%02d00 (%s)", g_gmtoffms > 0 ? '-' : '+',
13729 abs((int) g_gmtoffms / msPerHour), d_gettzname());
13730 }
13731
13732 return (int) strlen(buf);
13733}
13734
13735DEF_TOSTR(TimeString, d_localtime, d_tptotimestr, 1)
13736
13737static int d_tptostr(const struct timeparts *tp, char *buf, int addtz) {
13738 int len = d_tptodatestr(tp, buf, addtz);
13739 *(buf + len) = ' ';
13740 return d_tptotimestr(tp, buf + len + 1, addtz) + len + 1;
13741}
13742
13743DEF_TOSTR(String, d_localtime, d_tptostr, 1)
13744DEF_TOSTR(UTCString, d_gmtime, d_tptostr, 0)
13745#endif /* V7_ENABLE__Date__toString */
13746
13747#if V7_ENABLE__Date__toLocaleString
13748struct d_locale {
13749 char locale[50];
13750};
13751
13752static void d_getcurrentlocale(struct d_locale *loc) {
13753 strcpy(loc->locale, setlocale(LC_TIME, 0));
13754}
13755
13756static void d_setlocale(const struct d_locale *loc) {
13757 setlocale(LC_TIME, loc ? loc->locale : "");
13758}
13759
13760/* TODO(alashkin): check portability */
13761WARN_UNUSED_RESULT
13762static enum v7_err d_tolocalestr(struct v7 *v7, val_t obj, const char *frm,
13763 v7_val_t *res) {
13764 enum v7_err rcode = V7_OK;
13765 char buf[250];
13766 size_t len;
13767 struct tm t;
13768 etime_t time;
13769 struct d_locale prev_locale;
13770 struct timeparts tp;
13771
13772 time = v7_get_double(v7, d_trytogetobjforstring(v7, obj));
13773
13774 d_getcurrentlocale(&prev_locale);
13775 d_setlocale(0);
13776 d_localtime(&time, &tp);
13777
13778 memset(&t, 0, sizeof(t));
13779 t.tm_year = tp.year - 1900;
13780 t.tm_mon = tp.month;
13781 t.tm_mday = tp.day;
13782 t.tm_hour = tp.hour;
13783 t.tm_min = tp.min;
13784 t.tm_sec = tp.sec;
13785 t.tm_wday = tp.dayofweek;
13786
13787 len = strftime(buf, sizeof(buf), frm, &t);
13788
13789 d_setlocale(&prev_locale);
13790
13791 *res = v7_mk_string(v7, buf, len, 1);
13792 return rcode;
13793}
13794
13795#define DEF_TOLOCALESTR(funcname, frm) \
13796 WARN_UNUSED_RESULT \
13797 V7_PRIVATE enum v7_err Date_to##funcname(struct v7 *v7, v7_val_t *res) { \
13798 val_t this_obj = v7_get_this(v7); \
13799 return d_tolocalestr(v7, this_obj, frm, res); \
13800 }
13801
13802DEF_TOLOCALESTR(LocaleString, "%c")
13803DEF_TOLOCALESTR(LocaleDateString, "%x")
13804DEF_TOLOCALESTR(LocaleTimeString, "%X")
13805#endif /* V7_ENABLE__Date__toLocaleString */
13806
13807WARN_UNUSED_RESULT
13808V7_PRIVATE enum v7_err Date_valueOf(struct v7 *v7, v7_val_t *res) {
13809 enum v7_err rcode = V7_OK;
13810 val_t this_obj = v7_get_this(v7);
13811 if (!v7_is_generic_object(this_obj) ||
13812 (v7_is_generic_object(this_obj) &&
13813 v7_get_proto(v7, this_obj) != v7->vals.date_prototype)) {
13814 rcode = v7_throwf(v7, TYPE_ERROR, "Date.valueOf called on non-Date object");
13815 goto clean;
13816 }
13817
13818 rcode = Obj_valueOf(v7, res);
13819 if (rcode != V7_OK) {
13820 goto clean;
13821 }
13822
13823clean:
13824 return rcode;
13825}
13826
13827#if V7_ENABLE__Date__getters
13828static struct timeparts *d_getTimePart(struct v7 *v7, val_t val,
13829 struct timeparts *tp,
13830 fbreaktime_t breaktimefunc) {
13831 etime_t time;
13832 time = v7_get_double(v7, val);
13833 breaktimefunc(&time, tp);
13834 return tp;
13835}
13836
13837#define DEF_GET_TP_FUNC(funcName, tpmember, breaktimefunc) \
13838 WARN_UNUSED_RESULT \
13839 V7_PRIVATE enum v7_err Date_get##funcName(struct v7 *v7, v7_val_t *res) { \
13840 enum v7_err rcode = V7_OK; \
13841 val_t v = V7_UNDEFINED; \
13842 struct timeparts tp; \
13843 val_t this_obj = v7_get_this(v7); \
13844 \
13845 rcode = obj_value_of(v7, this_obj, &v); \
13846 if (rcode != V7_OK) { \
13847 goto clean; \
13848 } \
13849 *res = v7_mk_number( \
13850 v7, v == V7_TAG_NAN ? NAN : d_getTimePart(v7, v, &tp, breaktimefunc) \
13851 ->tpmember); \
13852 clean: \
13853 return rcode; \
13854 }
13855
13856#define DEF_GET_TP(funcName, tpmember) \
13857 DEF_GET_TP_FUNC(UTC##funcName, tpmember, d_gmtime) \
13858 DEF_GET_TP_FUNC(funcName, tpmember, d_localtime)
13859
13860DEF_GET_TP(Date, day)
13861DEF_GET_TP(FullYear, year)
13862DEF_GET_TP(Month, month)
13863DEF_GET_TP(Hours, hour)
13864DEF_GET_TP(Minutes, min)
13865DEF_GET_TP(Seconds, sec)
13866DEF_GET_TP(Milliseconds, msec)
13867DEF_GET_TP(Day, dayofweek)
13868
13869WARN_UNUSED_RESULT
13870V7_PRIVATE enum v7_err Date_getTime(struct v7 *v7, v7_val_t *res) {
13871 return Date_valueOf(v7, res);
13872}
13873
13874WARN_UNUSED_RESULT
13875V7_PRIVATE enum v7_err Date_getTimezoneOffset(struct v7 *v7, v7_val_t *res) {
13876 (void) v7;
13877 *res = v7_mk_number(v7, g_gmtoffms / msPerMinute);
13878 return V7_OK;
13879}
13880#endif /* V7_ENABLE__Date__getters */
13881
13882#if V7_ENABLE__Date__setters
13883WARN_UNUSED_RESULT
13884static enum v7_err d_setTimePart(struct v7 *v7, int start_pos,
13885 fbreaktime_t breaktimefunc,
13886 fmaketime_t maketimefunc, v7_val_t *res) {
13887 enum v7_err rcode = V7_OK;
13888 val_t this_obj = v7_get_this(v7);
13889 etime_t ret_time =
13890 d_time_number_from_arr(v7, start_pos, breaktimefunc, maketimefunc);
13891
13892 *res = v7_mk_number(v7, ret_time);
13893 v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), *res);
13894
13895 return rcode;
13896}
13897
13898#define DEF_SET_TP(name, start_pos) \
13899 WARN_UNUSED_RESULT \
13900 V7_PRIVATE enum v7_err Date_setUTC##name(struct v7 *v7, v7_val_t *res) { \
13901 return d_setTimePart(v7, start_pos, d_gmtime, d_gmktime, res); \
13902 } \
13903 WARN_UNUSED_RESULT \
13904 V7_PRIVATE enum v7_err Date_set##name(struct v7 *v7, v7_val_t *res) { \
13905 return d_setTimePart(v7, start_pos, d_localtime, d_lmktime, res); \
13906 }
13907
13908DEF_SET_TP(Milliseconds, tpmsec)
13909DEF_SET_TP(Seconds, tpseconds)
13910DEF_SET_TP(Minutes, tpminutes)
13911DEF_SET_TP(Hours, tphours)
13912DEF_SET_TP(Date, tpdate)
13913DEF_SET_TP(Month, tpmonth)
13914DEF_SET_TP(FullYear, tpyear)
13915
13916WARN_UNUSED_RESULT
13917V7_PRIVATE enum v7_err Date_setTime(struct v7 *v7, v7_val_t *res) {
13918 enum v7_err rcode = V7_OK;
13919 val_t this_obj = v7_get_this(v7);
13920
13921 if (v7_argc(v7) >= 1) {
13922 rcode = to_number_v(v7, v7_arg(v7, 0), res);
13923 if (rcode != V7_OK) {
13924 goto clean;
13925 }
13926 }
13927
13928 v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), *res);
13929
13930clean:
13931 return rcode;
13932}
13933#endif /* V7_ENABLE__Date__setters */
13934
13935#if V7_ENABLE__Date__toJSON
13936WARN_UNUSED_RESULT
13937V7_PRIVATE enum v7_err Date_toJSON(struct v7 *v7, v7_val_t *res) {
13938 return Date_toISOString(v7, res);
13939}
13940#endif /* V7_ENABLE__Date__toJSON */
13941
13942#if V7_ENABLE__Date__now
13943WARN_UNUSED_RESULT
13944V7_PRIVATE enum v7_err Date_now(struct v7 *v7, v7_val_t *res) {
13945 etime_t ret_time;
13946 (void) v7;
13947
13948 d_gettime(&ret_time);
13949
13950 *res = v7_mk_number(v7, ret_time);
13951 return V7_OK;
13952}
13953#endif /* V7_ENABLE__Date__now */
13954
13955#if V7_ENABLE__Date__parse
13956WARN_UNUSED_RESULT
13957V7_PRIVATE enum v7_err Date_parse(struct v7 *v7, v7_val_t *res) {
13958 enum v7_err rcode = V7_OK;
13959 val_t this_obj = v7_get_this(v7);
13960 etime_t ret_time = INVALID_TIME;
13961
13962 if (!d_iscalledasfunction(v7, this_obj)) {
13963 rcode = v7_throwf(v7, TYPE_ERROR, "Date.parse() called on object");
13964 goto clean;
13965 }
13966
13967 if (v7_argc(v7) >= 1) {
13968 val_t arg0 = v7_arg(v7, 0);
13969 if (v7_is_string(arg0)) {
13970 size_t size;
13971 const char *time_str = v7_get_string(v7, &arg0, &size);
13972
13973 d_timeFromString(&ret_time, time_str, size);
13974 }
13975 }
13976
13977 *res = v7_mk_number(v7, ret_time);
13978
13979clean:
13980 return rcode;
13981}
13982#endif /* V7_ENABLE__Date__parse */
13983
13984#if V7_ENABLE__Date__UTC
13985WARN_UNUSED_RESULT
13986V7_PRIVATE enum v7_err Date_UTC(struct v7 *v7, v7_val_t *res) {
13987 enum v7_err rcode = V7_OK;
13988 val_t this_obj = v7_get_this(v7);
13989 etime_t ret_time;
13990
13991 if (!d_iscalledasfunction(v7, this_obj)) {
13992 rcode = v7_throwf(v7, TYPE_ERROR, "Date.now() called on object");
13993 goto clean;
13994 }
13995
13996 ret_time = d_time_number_from_arr(v7, tpyear, 0, d_gmktime);
13997 *res = v7_mk_number(v7, ret_time);
13998
13999clean:
14000 return rcode;
14001}
14002#endif /* V7_ENABLE__Date__UTC */
14003
14004/****** Initialization *******/
14005
14006/*
14007 * We should clear V7_PROPERTY_ENUMERABLE for all Date props
14008 * TODO(mkm): check other objects
14009*/
14010static int d_set_cfunc_prop(struct v7 *v7, val_t o, const char *name,
14011 v7_cfunction_t *f) {
14012 return v7_def(v7, o, name, strlen(name), V7_DESC_ENUMERABLE(0),
14013 v7_mk_cfunction(f));
14014}
14015
14016#define DECLARE_GET(func) \
14017 d_set_cfunc_prop(v7, v7->vals.date_prototype, "getUTC" #func, \
14018 Date_getUTC##func); \
14019 d_set_cfunc_prop(v7, v7->vals.date_prototype, "get" #func, Date_get##func);
14020
14021#define DECLARE_SET(func) \
14022 d_set_cfunc_prop(v7, v7->vals.date_prototype, "setUTC" #func, \
14023 Date_setUTC##func); \
14024 d_set_cfunc_prop(v7, v7->vals.date_prototype, "set" #func, Date_set##func);
14025
14026V7_PRIVATE void init_date(struct v7 *v7) {
14027 val_t date =
14028 mk_cfunction_obj_with_proto(v7, Date_ctor, 7, v7->vals.date_prototype);
14029 v7_def(v7, v7->vals.global_object, "Date", 4, V7_DESC_ENUMERABLE(0), date);
14030 d_set_cfunc_prop(v7, v7->vals.date_prototype, "valueOf", Date_valueOf);
14031
14032#if V7_ENABLE__Date__getters
14033 DECLARE_GET(Date);
14034 DECLARE_GET(FullYear);
14035 DECLARE_GET(Month);
14036 DECLARE_GET(Hours);
14037 DECLARE_GET(Minutes);
14038 DECLARE_GET(Seconds);
14039 DECLARE_GET(Milliseconds);
14040 DECLARE_GET(Day);
14041 d_set_cfunc_prop(v7, v7->vals.date_prototype, "getTime", Date_getTime);
14042#endif
14043
14044#if V7_ENABLE__Date__setters
14045 DECLARE_SET(Date);
14046 DECLARE_SET(FullYear);
14047 DECLARE_SET(Month);
14048 DECLARE_SET(Hours);
14049 DECLARE_SET(Minutes);
14050 DECLARE_SET(Seconds);
14051 DECLARE_SET(Milliseconds);
14052 d_set_cfunc_prop(v7, v7->vals.date_prototype, "setTime", Date_setTime);
14053 d_set_cfunc_prop(v7, v7->vals.date_prototype, "getTimezoneOffset",
14054 Date_getTimezoneOffset);
14055#endif
14056
14057#if V7_ENABLE__Date__now
14058 d_set_cfunc_prop(v7, date, "now", Date_now);
14059#endif
14060#if V7_ENABLE__Date__parse
14061 d_set_cfunc_prop(v7, date, "parse", Date_parse);
14062#endif
14063#if V7_ENABLE__Date__UTC
14064 d_set_cfunc_prop(v7, date, "UTC", Date_UTC);
14065#endif
14066
14067#if V7_ENABLE__Date__toString
14068 d_set_cfunc_prop(v7, v7->vals.date_prototype, "toString", Date_toString);
14069 d_set_cfunc_prop(v7, v7->vals.date_prototype, "toISOString",
14070 Date_toISOString);
14071 d_set_cfunc_prop(v7, v7->vals.date_prototype, "toUTCString",
14072 Date_toUTCString);
14073 d_set_cfunc_prop(v7, v7->vals.date_prototype, "toDateString",
14074 Date_toDateString);
14075 d_set_cfunc_prop(v7, v7->vals.date_prototype, "toTimeString",
14076 Date_toTimeString);
14077#endif
14078#if V7_ENABLE__Date__toLocaleString
14079 d_set_cfunc_prop(v7, v7->vals.date_prototype, "toLocaleString",
14080 Date_toLocaleString);
14081 d_set_cfunc_prop(v7, v7->vals.date_prototype, "toLocaleDateString",
14082 Date_toLocaleDateString);
14083 d_set_cfunc_prop(v7, v7->vals.date_prototype, "toLocaleTimeString",
14084 Date_toLocaleTimeString);
14085#endif
14086#if V7_ENABLE__Date__toJSON
14087 d_set_cfunc_prop(v7, v7->vals.date_prototype, "toJSON", Date_toJSON);
14088#endif
14089
14090 /*
14091 * GTM offset without DST
14092 * TODO(alashkin): check this
14093 * Could be changed to tm::tm_gmtoff,
14094 * but tm_gmtoff includes DST, so
14095 * side effects are possible
14096 */
14097 tzset();
14098 g_gmtoffms = timezone * msPerSecond;
14099 /*
14100 * tzname could be changed by localtime_r call,
14101 * so we have to store pointer
14102 * TODO(alashkin): need restart on tz change???
14103 */
14104 g_tzname = tzname[0];
14105}
14106
14107#if defined(__cplusplus)
14108}
14109#endif /* __cplusplus */
14110
14111#endif /* V7_ENABLE__Date */
14112#ifdef V7_MODULE_LINES
14113#line 1 "v7/src/std_function.c"
14114#endif
14115/*
14116 * Copyright (c) 2014 Cesanta Software Limited
14117 * All rights reserved
14118 */
14119
14120/* Amalgamated: #include "common/str_util.h" */
14121/* Amalgamated: #include "v7/src/internal.h" */
14122/* Amalgamated: #include "v7/src/core.h" */
14123/* Amalgamated: #include "v7/src/function.h" */
14124/* Amalgamated: #include "v7/src/bcode.h" */
14125/* Amalgamated: #include "v7/src/eval.h" */
14126/* Amalgamated: #include "v7/src/conversion.h" */
14127/* Amalgamated: #include "v7/src/object.h" */
14128/* Amalgamated: #include "v7/src/exec.h" */
14129/* Amalgamated: #include "v7/src/exceptions.h" */
14130
14131#if defined(__cplusplus)
14132extern "C" {
14133#endif /* __cplusplus */
14134
14135WARN_UNUSED_RESULT
14136V7_PRIVATE enum v7_err Function_ctor(struct v7 *v7, v7_val_t *res) {
14137 enum v7_err rcode = V7_OK;
14138 long i, num_args = v7_argc(v7);
14139 size_t size;
14140 const char *s;
14141 struct mbuf m;
14142
14143 mbuf_init(&m, 0);
14144
14145 if (num_args <= 0) {
14146 goto clean;
14147 }
14148
14149 mbuf_append(&m, "(function(", 10);
14150
14151 for (i = 0; i < num_args - 1; i++) {
14152 rcode = obj_value_of(v7, v7_arg(v7, i), res);
14153 if (rcode != V7_OK) {
14154 goto clean;
14155 }
14156 if (v7_is_string(*res)) {
14157 if (i > 0) mbuf_append(&m, ",", 1);
14158 s = v7_get_string(v7, res, &size);
14159 mbuf_append(&m, s, size);
14160 }
14161 }
14162 mbuf_append(&m, "){", 2);
14163 rcode = obj_value_of(v7, v7_arg(v7, num_args - 1), res);
14164 if (rcode != V7_OK) {
14165 goto clean;
14166 }
14167 if (v7_is_string(*res)) {
14168 s = v7_get_string(v7, res, &size);
14169 mbuf_append(&m, s, size);
14170 }
14171 mbuf_append(&m, "})\0", 3);
14172
14173 rcode = v7_exec(v7, m.buf, res);
14174 if (rcode != V7_OK) {
14175 rcode = v7_throwf(v7, SYNTAX_ERROR, "Invalid function body");
14176 goto clean;
14177 }
14178
14179clean:
14180 mbuf_free(&m);
14181 return rcode;
14182}
14183
14184WARN_UNUSED_RESULT
14185V7_PRIVATE enum v7_err Function_length(struct v7 *v7, v7_val_t *res) {
14186 enum v7_err rcode = V7_OK;
14187 v7_val_t this_obj = v7_get_this(v7);
14188 struct v7_js_function *func;
14189
14190 rcode = obj_value_of(v7, this_obj, &this_obj);
14191 if (rcode != V7_OK) {
14192 goto clean;
14193 }
14194 if (!is_js_function(this_obj)) {
14195 *res = v7_mk_number(v7, 0);
14196 goto clean;
14197 }
14198
14199 func = get_js_function_struct(this_obj);
14200
14201 *res = v7_mk_number(v7, func->bcode->args_cnt);
14202
14203clean:
14204 return rcode;
14205}
14206
14207WARN_UNUSED_RESULT
14208V7_PRIVATE enum v7_err Function_name(struct v7 *v7, v7_val_t *res) {
14209 enum v7_err rcode = V7_OK;
14210 v7_val_t this_obj = v7_get_this(v7);
14211 struct v7_js_function *func;
14212
14213 rcode = obj_value_of(v7, this_obj, &this_obj);
14214 if (rcode != V7_OK) {
14215 goto clean;
14216 }
14217 if (!is_js_function(this_obj)) {
14218 goto clean;
14219 }
14220
14221 func = get_js_function_struct(this_obj);
14222
14223 assert(func->bcode != NULL);
14224
14225 assert(func->bcode->names_cnt >= 1);
14226 bcode_next_name_v(v7, func->bcode, func->bcode->ops.p, res);
14227
14228clean:
14229 return rcode;
14230}
14231
14232WARN_UNUSED_RESULT
14233V7_PRIVATE enum v7_err Function_apply(struct v7 *v7, v7_val_t *res) {
14234 enum v7_err rcode = V7_OK;
14235 val_t this_obj = v7_get_this(v7);
14236 val_t this_arg = v7_arg(v7, 0);
14237 val_t func_args = v7_arg(v7, 1);
14238
14239 rcode = obj_value_of(v7, this_obj, &this_obj);
14240 if (rcode != V7_OK) {
14241 goto clean;
14242 }
14243
14244 if (is_js_function(this_obj)) {
14245 /*
14246 * `Function_apply` is a cfunction, so, GC is inhibited before calling it.
14247 * But the given function to call is a JS function, so we should enable GC;
14248 * otherwise, it will be inhibited during the whole execution of the given
14249 * JS function
14250 */
14251 v7_set_gc_enabled(v7, 1);
14252 }
14253
14254 rcode = b_apply(v7, this_obj, this_arg, func_args, 0, res);
14255 if (rcode != V7_OK) {
14256 goto clean;
14257 }
14258
14259clean:
14260 return rcode;
14261}
14262
14263WARN_UNUSED_RESULT
14264V7_PRIVATE enum v7_err Function_toString(struct v7 *v7, v7_val_t *res) {
14265 enum v7_err rcode = V7_OK;
14266 char *ops;
14267 char *name;
14268 size_t name_len;
14269 char buf[50];
14270 char *b = buf;
14271 struct v7_js_function *func = get_js_function_struct(v7_get_this(v7));
14272 int i;
14273
14274 b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "[function");
14275
14276 assert(func->bcode != NULL);
14277 ops = func->bcode->ops.p;
14278
14279 /* first entry in name list */
14280 ops = bcode_next_name(ops, &name, &name_len);
14281
14282 if (name_len > 0) {
14283 b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), " %.*s", (int) name_len,
14284 name);
14285 }
14286 b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "(");
14287 for (i = 0; i < func->bcode->args_cnt; i++) {
14288 ops = bcode_next_name(ops, &name, &name_len);
14289
14290 b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "%.*s", (int) name_len,
14291 name);
14292 if (i < func->bcode->args_cnt - 1) {
14293 b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), ",");
14294 }
14295 }
14296 b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), ")");
14297
14298 {
14299 uint8_t loc_cnt =
14300 func->bcode->names_cnt - func->bcode->args_cnt - 1 /*func name*/;
14301
14302 if (loc_cnt > 0) {
14303 b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "{var ");
14304 for (i = 0; i < loc_cnt; ++i) {
14305 ops = bcode_next_name(ops, &name, &name_len);
14306
14307 b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "%.*s",
14308 (int) name_len, name);
14309 if (i < (loc_cnt - 1)) {
14310 b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), ",");
14311 }
14312 }
14313
14314 b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "}");
14315 }
14316 }
14317
14318 b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "]");
14319
14320 *res = v7_mk_string(v7, buf, strlen(buf), 1);
14321
14322 return rcode;
14323}
14324
14325V7_PRIVATE void init_function(struct v7 *v7) {
14326 val_t ctor = mk_cfunction_obj(v7, Function_ctor, 1);
14327
14328 v7_set(v7, ctor, "prototype", 9, v7->vals.function_prototype);
14329 v7_set(v7, v7->vals.global_object, "Function", 8, ctor);
14330 set_method(v7, v7->vals.function_prototype, "apply", Function_apply, 1);
14331 set_method(v7, v7->vals.function_prototype, "toString", Function_toString, 0);
14332 v7_def(v7, v7->vals.function_prototype, "length", 6,
14333 (V7_DESC_ENUMERABLE(0) | V7_DESC_GETTER(1)),
14334 v7_mk_cfunction(Function_length));
14335 v7_def(v7, v7->vals.function_prototype, "name", 4,
14336 (V7_DESC_ENUMERABLE(0) | V7_DESC_GETTER(1)),
14337 v7_mk_cfunction(Function_name));
14338}
14339
14340#if defined(__cplusplus)
14341}
14342#endif /* __cplusplus */
14343#ifdef V7_MODULE_LINES
14344#line 1 "v7/src/std_regex.c"
14345#endif
14346/*
14347 * Copyright (c) 2014 Cesanta Software Limited
14348 * All rights reserved
14349 */
14350
14351/* Amalgamated: #include "common/utf.h" */
14352/* Amalgamated: #include "common/str_util.h" */
14353/* Amalgamated: #include "v7/src/internal.h" */
14354/* Amalgamated: #include "v7/src/std_regex.h" */
14355/* Amalgamated: #include "v7/src/std_string.h" */
14356/* Amalgamated: #include "v7/src/slre.h" */
14357/* Amalgamated: #include "v7/src/core.h" */
14358/* Amalgamated: #include "v7/src/function.h" */
14359/* Amalgamated: #include "v7/src/conversion.h" */
14360/* Amalgamated: #include "v7/src/array.h" */
14361/* Amalgamated: #include "v7/src/object.h" */
14362/* Amalgamated: #include "v7/src/regexp.h" */
14363/* Amalgamated: #include "v7/src/exceptions.h" */
14364/* Amalgamated: #include "v7/src/string.h" */
14365/* Amalgamated: #include "v7/src/primitive.h" */
14366
14367#if V7_ENABLE__RegExp
14368
14369WARN_UNUSED_RESULT
14370V7_PRIVATE enum v7_err Regex_ctor(struct v7 *v7, v7_val_t *res) {
14371 enum v7_err rcode = V7_OK;
14372 long argnum = v7_argc(v7);
14373
14374 if (argnum > 0) {
14375 val_t arg = v7_arg(v7, 0);
14376 val_t ro, fl;
14377 size_t re_len, flags_len = 0;
14378 const char *re, *flags = NULL;
14379
14380 if (v7_is_regexp(v7, arg)) {
14381 if (argnum > 1) {
14382 /* ch15/15.10/15.10.3/S15.10.3.1_A2_T1.js */
14383 rcode = v7_throwf(v7, TYPE_ERROR, "invalid flags");
14384 goto clean;
14385 }
14386 *res = arg;
14387 goto clean;
14388 }
14389 rcode = to_string(v7, arg, &ro, NULL, 0, NULL);
14390 if (rcode != V7_OK) {
14391 goto clean;
14392 }
14393
14394 if (argnum > 1) {
14395 rcode = to_string(v7, v7_arg(v7, 1), &fl, NULL, 0, NULL);
14396 if (rcode != V7_OK) {
14397 goto clean;
14398 }
14399
14400 flags = v7_get_string(v7, &fl, &flags_len);
14401 }
14402 re = v7_get_string(v7, &ro, &re_len);
14403 rcode = v7_mk_regexp(v7, re, re_len, flags, flags_len, res);
14404 if (rcode != V7_OK) {
14405 goto clean;
14406 }
14407
14408 } else {
14409 rcode = v7_mk_regexp(v7, "(?:)", 4, NULL, 0, res);
14410 if (rcode != V7_OK) {
14411 goto clean;
14412 }
14413 }
14414
14415clean:
14416 return rcode;
14417}
14418
14419WARN_UNUSED_RESULT
14420V7_PRIVATE enum v7_err Regex_global(struct v7 *v7, v7_val_t *res) {
14421 enum v7_err rcode = V7_OK;
14422 int flags = 0;
14423 val_t this_obj = v7_get_this(v7);
14424 val_t r = V7_UNDEFINED;
14425 rcode = obj_value_of(v7, this_obj, &r);
14426 if (rcode != V7_OK) {
14427 goto clean;
14428 }
14429
14430 if (v7_is_regexp(v7, r)) {
14431 flags = slre_get_flags(v7_get_regexp_struct(v7, r)->compiled_regexp);
14432 }
14433
14434 *res = v7_mk_boolean(v7, flags & SLRE_FLAG_G);
14435
14436clean:
14437 return rcode;
14438}
14439
14440WARN_UNUSED_RESULT
14441V7_PRIVATE enum v7_err Regex_ignoreCase(struct v7 *v7, v7_val_t *res) {
14442 enum v7_err rcode = V7_OK;
14443 int flags = 0;
14444 val_t this_obj = v7_get_this(v7);
14445 val_t r = V7_UNDEFINED;
14446 rcode = obj_value_of(v7, this_obj, &r);
14447 if (rcode != V7_OK) {
14448 goto clean;
14449 }
14450
14451 if (v7_is_regexp(v7, r)) {
14452 flags = slre_get_flags(v7_get_regexp_struct(v7, r)->compiled_regexp);
14453 }
14454
14455 *res = v7_mk_boolean(v7, flags & SLRE_FLAG_I);
14456
14457clean:
14458 return rcode;
14459}
14460
14461WARN_UNUSED_RESULT
14462V7_PRIVATE enum v7_err Regex_multiline(struct v7 *v7, v7_val_t *res) {
14463 enum v7_err rcode = V7_OK;
14464 int flags = 0;
14465 val_t this_obj = v7_get_this(v7);
14466 val_t r = V7_UNDEFINED;
14467 rcode = obj_value_of(v7, this_obj, &r);
14468 if (rcode != V7_OK) {
14469 goto clean;
14470 }
14471
14472 if (v7_is_regexp(v7, r)) {
14473 flags = slre_get_flags(v7_get_regexp_struct(v7, r)->compiled_regexp);
14474 }
14475
14476 *res = v7_mk_boolean(v7, flags & SLRE_FLAG_M);
14477
14478clean:
14479 return rcode;
14480}
14481
14482WARN_UNUSED_RESULT
14483V7_PRIVATE enum v7_err Regex_source(struct v7 *v7, v7_val_t *res) {
14484 enum v7_err rcode = V7_OK;
14485 val_t this_obj = v7_get_this(v7);
14486 val_t r = V7_UNDEFINED;
14487 const char *buf = 0;
14488 size_t len = 0;
14489
14490 rcode = obj_value_of(v7, this_obj, &r);
14491 if (rcode != V7_OK) {
14492 goto clean;
14493 }
14494
14495 if (v7_is_regexp(v7, r)) {
14496 buf = v7_get_string(v7, &v7_get_regexp_struct(v7, r)->regexp_string, &len);
14497 }
14498
14499 *res = v7_mk_string(v7, buf, len, 1);
14500
14501clean:
14502 return rcode;
14503}
14504
14505WARN_UNUSED_RESULT
14506V7_PRIVATE enum v7_err Regex_get_lastIndex(struct v7 *v7, v7_val_t *res) {
14507 enum v7_err rcode = V7_OK;
14508 long lastIndex = 0;
14509 val_t this_obj = v7_get_this(v7);
14510
14511 if (v7_is_regexp(v7, this_obj)) {
14512 lastIndex = v7_get_regexp_struct(v7, this_obj)->lastIndex;
14513 }
14514
14515 *res = v7_mk_number(v7, lastIndex);
14516
14517 return rcode;
14518}
14519
14520WARN_UNUSED_RESULT
14521V7_PRIVATE enum v7_err Regex_set_lastIndex(struct v7 *v7, v7_val_t *res) {
14522 enum v7_err rcode = V7_OK;
14523 long lastIndex = 0;
14524 val_t this_obj = v7_get_this(v7);
14525
14526 if (v7_is_regexp(v7, this_obj)) {
14527 rcode = to_long(v7, v7_arg(v7, 0), 0, &lastIndex);
14528 if (rcode != V7_OK) {
14529 goto clean;
14530 }
14531 v7_get_regexp_struct(v7, this_obj)->lastIndex = lastIndex;
14532 }
14533
14534 *res = v7_mk_number(v7, lastIndex);
14535
14536clean:
14537 return rcode;
14538}
14539
14540WARN_UNUSED_RESULT
14541V7_PRIVATE enum v7_err rx_exec(struct v7 *v7, val_t rx, val_t vstr, int lind,
14542 val_t *res) {
14543 enum v7_err rcode = V7_OK;
14544 if (v7_is_regexp(v7, rx)) {
14545 val_t s = V7_UNDEFINED;
14546 size_t len;
14547 struct slre_loot sub;
14548 struct slre_cap *ptok = sub.caps;
14549 const char *str = NULL;
14550 const char *end = NULL;
14551 const char *begin = NULL;
14552 struct v7_regexp *rp = v7_get_regexp_struct(v7, rx);
14553 int flag_g = slre_get_flags(rp->compiled_regexp) & SLRE_FLAG_G;
14554
14555 rcode = to_string(v7, vstr, &s, NULL, 0, NULL);
14556 if (rcode != V7_OK) {
14557 goto clean;
14558 }
14559 str = v7_get_string(v7, &s, &len);
14560 end = str + len;
14561 begin = str;
14562
14563 if (rp->lastIndex < 0) rp->lastIndex = 0;
14564 if (flag_g || lind) begin = utfnshift(str, rp->lastIndex);
14565
14566 if (!slre_exec(rp->compiled_regexp, 0, begin, end, &sub)) {
14567 int i;
14568 val_t arr = v7_mk_array(v7);
14569 char *old_mbuf_base = v7->owned_strings.buf;
14570 ptrdiff_t rel = 0; /* creating strings might relocate the mbuf */
14571
14572 for (i = 0; i < sub.num_captures; i++, ptok++) {
14573 rel = v7->owned_strings.buf - old_mbuf_base;
14574 v7_array_push(v7, arr, v7_mk_string(v7, ptok->start + rel,
14575 ptok->end - ptok->start, 1));
14576 }
14577 if (flag_g) rp->lastIndex = utfnlen(str, sub.caps->end + rel - str);
14578 v7_def(v7, arr, "index", 5, V7_DESC_WRITABLE(0),
14579 v7_mk_number(v7, utfnlen(str + rel, sub.caps->start - str)));
14580 *res = arr;
14581 goto clean;
14582 } else {
14583 rp->lastIndex = 0;
14584 }
14585 }
14586
14587 *res = V7_NULL;
14588
14589clean:
14590 return rcode;
14591}
14592
14593WARN_UNUSED_RESULT
14594V7_PRIVATE enum v7_err Regex_exec(struct v7 *v7, v7_val_t *res) {
14595 enum v7_err rcode = V7_OK;
14596 val_t this_obj = v7_get_this(v7);
14597
14598 if (v7_argc(v7) > 0) {
14599 rcode = rx_exec(v7, this_obj, v7_arg(v7, 0), 0, res);
14600 if (rcode != V7_OK) {
14601 goto clean;
14602 }
14603 } else {
14604 *res = V7_NULL;
14605 }
14606
14607clean:
14608 return rcode;
14609}
14610
14611WARN_UNUSED_RESULT
14612V7_PRIVATE enum v7_err Regex_test(struct v7 *v7, v7_val_t *res) {
14613 enum v7_err rcode = V7_OK;
14614 val_t tmp = V7_UNDEFINED;
14615
14616 rcode = Regex_exec(v7, &tmp);
14617 if (rcode != V7_OK) {
14618 goto clean;
14619 }
14620
14621 *res = v7_mk_boolean(v7, !v7_is_null(tmp));
14622
14623clean:
14624 return rcode;
14625}
14626
14627WARN_UNUSED_RESULT
14628V7_PRIVATE enum v7_err Regex_flags(struct v7 *v7, v7_val_t *res) {
14629 enum v7_err rcode = V7_OK;
14630 char buf[3] = {0};
14631 val_t this_obj = v7_get_this(v7);
14632 struct v7_regexp *rp = v7_get_regexp_struct(v7, this_obj);
14633 size_t n = get_regexp_flags_str(v7, rp, buf);
14634 *res = v7_mk_string(v7, buf, n, 1);
14635
14636 return rcode;
14637}
14638
14639WARN_UNUSED_RESULT
14640V7_PRIVATE enum v7_err Regex_toString(struct v7 *v7, v7_val_t *res) {
14641 enum v7_err rcode = V7_OK;
14642 size_t n1, n2 = 0;
14643 char s2[3] = {0};
14644 char buf[50];
14645 val_t this_obj = v7_get_this(v7);
14646 struct v7_regexp *rp;
14647 const char *s1;
14648
14649 rcode = obj_value_of(v7, this_obj, &this_obj);
14650 if (rcode != V7_OK) {
14651 goto clean;
14652 }
14653
14654 if (!v7_is_regexp(v7, this_obj)) {
14655 rcode = v7_throwf(v7, TYPE_ERROR, "Not a regexp");
14656 goto clean;
14657 }
14658
14659 rp = v7_get_regexp_struct(v7, this_obj);
14660 s1 = v7_get_string(v7, &rp->regexp_string, &n1);
14661 n2 = get_regexp_flags_str(v7, rp, s2);
14662
14663 c_snprintf(buf, sizeof(buf), "/%.*s/%.*s", (int) n1, s1, (int) n2, s2);
14664
14665 *res = v7_mk_string(v7, buf, strlen(buf), 1);
14666
14667clean:
14668 return rcode;
14669}
14670
14671V7_PRIVATE void init_regex(struct v7 *v7) {
14672 val_t ctor =
14673 mk_cfunction_obj_with_proto(v7, Regex_ctor, 1, v7->vals.regexp_prototype);
14674 val_t lastIndex = v7_mk_dense_array(v7);
14675
14676 v7_def(v7, v7->vals.global_object, "RegExp", 6, V7_DESC_ENUMERABLE(0), ctor);
14677
14678 set_cfunc_prop(v7, v7->vals.regexp_prototype, "exec", Regex_exec);
14679 set_cfunc_prop(v7, v7->vals.regexp_prototype, "test", Regex_test);
14680 set_method(v7, v7->vals.regexp_prototype, "toString", Regex_toString, 0);
14681
14682 v7_def(v7, v7->vals.regexp_prototype, "global", 6, V7_DESC_GETTER(1),
14683 v7_mk_cfunction(Regex_global));
14684 v7_def(v7, v7->vals.regexp_prototype, "ignoreCase", 10, V7_DESC_GETTER(1),
14685 v7_mk_cfunction(Regex_ignoreCase));
14686 v7_def(v7, v7->vals.regexp_prototype, "multiline", 9, V7_DESC_GETTER(1),
14687 v7_mk_cfunction(Regex_multiline));
14688 v7_def(v7, v7->vals.regexp_prototype, "source", 6, V7_DESC_GETTER(1),
14689 v7_mk_cfunction(Regex_source));
14690 v7_def(v7, v7->vals.regexp_prototype, "flags", 5, V7_DESC_GETTER(1),
14691 v7_mk_cfunction(Regex_flags));
14692
14693 v7_array_set(v7, lastIndex, 0, v7_mk_cfunction(Regex_get_lastIndex));
14694 v7_array_set(v7, lastIndex, 1, v7_mk_cfunction(Regex_set_lastIndex));
14695 v7_def(v7, v7->vals.regexp_prototype, "lastIndex", 9,
14696 (V7_DESC_GETTER(1) | V7_DESC_SETTER(1)), lastIndex);
14697}
14698
14699#endif /* V7_ENABLE__RegExp */
14700#ifdef V7_MODULE_LINES
14701#line 1 "v7/src/std_proxy.c"
14702#endif
14703/*
14704 * Copyright (c) 2014 Cesanta Software Limited
14705 * All rights reserved
14706 */
14707
14708/* Amalgamated: #include "v7/src/internal.h" */
14709/* Amalgamated: #include "v7/src/std_object.h" */
14710/* Amalgamated: #include "v7/src/std_proxy.h" */
14711/* Amalgamated: #include "v7/src/conversion.h" */
14712/* Amalgamated: #include "v7/src/core.h" */
14713/* Amalgamated: #include "v7/src/function.h" */
14714/* Amalgamated: #include "v7/src/object.h" */
14715/* Amalgamated: #include "v7/src/primitive.h" */
14716/* Amalgamated: #include "v7/src/string.h" */
14717/* Amalgamated: #include "v7/src/exceptions.h" */
14718
14719#if defined(__cplusplus)
14720extern "C" {
14721#endif /* __cplusplus */
14722
14723#if V7_ENABLE__Proxy
14724
14725WARN_UNUSED_RESULT
14726V7_PRIVATE enum v7_err Proxy_ctor(struct v7 *v7, v7_val_t *res) {
14727 enum v7_err rcode = V7_OK;
14728 val_t this_obj = v7_get_this(v7);
14729 val_t target_v = v7_arg(v7, 0);
14730 val_t handler_v = v7_arg(v7, 1);
14731 struct v7_object *t = NULL;
14732 v7_prop_attr_desc_t attrs_desc =
14733 (V7_DESC_WRITABLE(0) | V7_DESC_ENUMERABLE(0) | V7_DESC_CONFIGURABLE(0));
14734
14735 if (this_obj == v7_get_global(v7) || !v7_is_object(this_obj)) {
14736 rcode = v7_throwf(v7, TYPE_ERROR, "Wrong 'this' object for Proxy ctor");
14737 goto clean;
14738 }
14739
14740 if (!v7_is_object(target_v) || !v7_is_object(handler_v)) {
14741 rcode =
14742 v7_throwf(v7, TYPE_ERROR,
14743 "Cannot create proxy with a non-object as target or handler");
14744 goto clean;
14745 }
14746
14747 t = get_object_struct(this_obj);
14748 t->attributes |= V7_OBJ_PROXY;
14749
14750 v7_def(v7, this_obj, _V7_PROXY_TARGET_NAME, ~0, attrs_desc, target_v);
14751 v7_def(v7, this_obj, _V7_PROXY_HANDLER_NAME, ~0, attrs_desc, handler_v);
14752
14753 (void) res;
14754
14755clean:
14756 return rcode;
14757}
14758
14759V7_PRIVATE void init_proxy(struct v7 *v7) {
14760 /*v7_prop_attr_desc_t attrs_desc =*/
14761 /*(V7_DESC_WRITABLE(0) | V7_DESC_ENUMERABLE(0) | V7_DESC_CONFIGURABLE(0));*/
14762 val_t proxy =
14763 mk_cfunction_obj_with_proto(v7, Proxy_ctor, 1, v7->vals.proxy_prototype);
14764
14765 v7_def(v7, v7->vals.global_object, "Proxy", ~0, V7_DESC_ENUMERABLE(0), proxy);
14766}
14767
14768V7_PRIVATE int is_special_proxy_name(const char *name, size_t name_len) {
14769 int ret = 0;
14770 if (name_len == (size_t) ~0) {
14771 name_len = strlen(name);
14772 }
14773 if (name_len == 5 && (memcmp(name, _V7_PROXY_TARGET_NAME, name_len) == 0 ||
14774 memcmp(name, _V7_PROXY_HANDLER_NAME, name_len) == 0)) {
14775 ret = 1;
14776 }
14777 return ret;
14778}
14779
14780#endif /* V7_ENABLE__Proxy */
14781
14782#if defined(__cplusplus)
14783}
14784#endif /* __cplusplus */
14785#ifdef V7_MODULE_LINES
14786#line 1 "v7/src/main.c"
14787#endif
14788/*
14789 * Copyright (c) 2014 Cesanta Software Limited
14790 * All rights reserved
14791 */
14792
14793/* Amalgamated: #include "v7/src/internal.h" */
14794/* Amalgamated: #include "v7/src/gc.h" */
14795/* Amalgamated: #include "v7/src/freeze.h" */
14796/* Amalgamated: #include "v7/src/main.h" */
14797/* Amalgamated: #include "v7/src/primitive.h" */
14798/* Amalgamated: #include "v7/src/exec.h" */
14799/* Amalgamated: #include "v7/src/util.h" */
14800/* Amalgamated: #include "v7/src/conversion.h" */
14801/* Amalgamated: #include "common/platform.h" */
14802/* Amalgamated: #include "common/cs_file.h" */
14803
14804#if defined(_MSC_VER) && _MSC_VER >= 1800
14805#define fileno _fileno
14806#endif
14807
14808#ifdef V7_EXE
14809#define V7_MAIN
14810#endif
14811
14812#ifdef V7_MAIN
14813
14814#include <sys/stat.h>
14815
14816static void show_usage(char *argv[]) {
14817 fprintf(stderr, "V7 version %s (c) Cesanta Software, built on %s\n",
14818 V7_VERSION, __DATE__);
14819 fprintf(stderr, "Usage: %s [OPTIONS] js_file ...\n", argv[0]);
14820 fprintf(stderr, "%s\n", "OPTIONS:");
14821 fprintf(stderr, "%s\n", " -e <expr> execute expression");
14822 fprintf(stderr, "%s\n", " -t dump generated text AST");
14823 fprintf(stderr, "%s\n", " -b dump generated binary AST");
14824 fprintf(stderr, "%s\n", " -c dump compiled binary bcode");
14825 fprintf(stderr, "%s\n", " -mm dump memory stats");
14826 fprintf(stderr, "%s\n", " -vo <n> object arena size");
14827 fprintf(stderr, "%s\n", " -vf <n> function arena size");
14828 fprintf(stderr, "%s\n", " -vp <n> property arena size");
14829#ifdef V7_FREEZE
14830 fprintf(stderr, "%s\n", " -freeze filename dump JS heap into a file");
14831#endif
14832 exit(EXIT_FAILURE);
14833}
14834
14835#if V7_ENABLE__Memory__stats
14836static void dump_mm_arena_stats(const char *msg, struct gc_arena *a) {
14837 printf("%s: total allocations %lu, total garbage %lu, max %" SIZE_T_FMT
14838 ", alive %lu\n",
14839 msg, a->allocations, a->garbage, gc_arena_size(a), a->alive);
14840 printf(
14841 "%s: (bytes: total allocations %lu, total garbage %lu, max %" SIZE_T_FMT
14842 ", alive %lu)\n",
14843 msg, a->allocations * a->cell_size, a->garbage * a->cell_size,
14844 gc_arena_size(a) * a->cell_size, a->alive * a->cell_size);
14845}
14846
14847static void dump_mm_stats(struct v7 *v7) {
14848 dump_mm_arena_stats("object: ", &v7->generic_object_arena);
14849 dump_mm_arena_stats("function: ", &v7->function_arena);
14850 dump_mm_arena_stats("property: ", &v7->property_arena);
14851 printf("string arena len: %" SIZE_T_FMT "\n", v7->owned_strings.len);
14852 printf("Total heap size: %" SIZE_T_FMT "\n",
14853 v7->owned_strings.len +
14854 gc_arena_size(&v7->generic_object_arena) *
14855 v7->generic_object_arena.cell_size +
14856 gc_arena_size(&v7->function_arena) * v7->function_arena.cell_size +
14857 gc_arena_size(&v7->property_arena) * v7->property_arena.cell_size);
14858}
14859#endif
14860
14861int v7_main(int argc, char *argv[], void (*pre_freeze_init)(struct v7 *),
14862 void (*pre_init)(struct v7 *), void (*post_init)(struct v7 *)) {
14863 int exit_rcode = EXIT_SUCCESS;
14864 struct v7 *v7;
14865 struct v7_create_opts opts;
14866 int as_json = 0;
14867 int i, j, show_ast = 0, binary_ast = 0, dump_bcode = 0, dump_stats = 0;
14868 val_t res;
14869 int nexprs = 0;
14870 const char *exprs[16];
14871
14872 memset(&opts, 0, sizeof(opts));
14873
14874 (void) show_ast;
14875 (void) binary_ast;
14876 (void) dump_bcode;
14877
14878 /* Execute inline code */
14879 for (i = 1; i < argc && argv[i][0] == '-'; i++) {
14880 if (strcmp(argv[i], "-e") == 0 && i + 1 < argc) {
14881 exprs[nexprs++] = argv[i + 1];
14882 i++;
14883 } else if (strcmp(argv[i], "-t") == 0) {
14884 show_ast = 1;
14885 } else if (strcmp(argv[i], "-b") == 0) {
14886 show_ast = 1;
14887 binary_ast = 1;
14888 } else if (strcmp(argv[i], "-c") == 0) {
14889 binary_ast = 1;
14890 dump_bcode = 1;
14891 } else if (strcmp(argv[i], "-h") == 0) {
14892 show_usage(argv);
14893 } else if (strcmp(argv[i], "-j") == 0) {
14894 as_json = 1;
14895#if V7_ENABLE__Memory__stats
14896 } else if (strcmp(argv[i], "-mm") == 0) {
14897 dump_stats = 1;
14898#endif
14899 } else if (strcmp(argv[i], "-vo") == 0 && i + 1 < argc) {
14900 opts.object_arena_size = atoi(argv[i + 1]);
14901 i++;
14902 } else if (strcmp(argv[i], "-vf") == 0 && i + 1 < argc) {
14903 opts.function_arena_size = atoi(argv[i + 1]);
14904 i++;
14905 } else if (strcmp(argv[i], "-vp") == 0 && i + 1 < argc) {
14906 opts.property_arena_size = atoi(argv[i + 1]);
14907 i++;
14908 }
14909#ifdef V7_FREEZE
14910 else if (strcmp(argv[i], "-freeze") == 0 && i + 1 < argc) {
14911 opts.freeze_file = argv[i + 1];
14912 i++;
14913 }
14914#endif
14915 }
14916
14917#ifndef V7_ALLOW_ARGLESS_MAIN
14918 if (argc == 1) {
14919 show_usage(argv);
14920 }
14921#endif
14922
14923 v7 = v7_create_opt(opts);
14924 res = V7_UNDEFINED;
14925
14926 if (pre_freeze_init != NULL) {
14927 pre_freeze_init(v7);
14928 }
14929
14930#ifdef V7_FREEZE
14931 /*
14932 * Skip pre_init if freezing, but still execute cmdline expressions.
14933 * This makes it easier to add custom code when freezing from cmdline.
14934 */
14935 if (opts.freeze_file == NULL) {
14936#endif
14937
14938 if (pre_init != NULL) {
14939 pre_init(v7);
14940 }
14941
14942#ifdef V7_FREEZE
14943 }
14944#endif
14945
14946#if V7_ENABLE__Memory__stats > 0 && !V7_DISABLE_GC
14947 if (dump_stats) {
14948 printf("Memory stats during init:\n");
14949 dump_mm_stats(v7);
14950 v7_gc(v7, 0);
14951 printf("Memory stats before run:\n");
14952 dump_mm_stats(v7);
14953 }
14954#else
14955 (void) dump_stats;
14956#endif
14957
14958 /* Execute inline expressions */
14959 for (j = 0; j < nexprs; j++) {
14960 enum v7_err (*exec)(struct v7 *, const char *, v7_val_t *);
14961 exec = v7_exec;
14962
14963 if (show_ast || dump_bcode) {
14964#if !defined(V7_NO_COMPILER)
14965 if (v7_compile(exprs[j], binary_ast, dump_bcode, stdout) != V7_OK) {
14966 exit_rcode = EXIT_FAILURE;
14967 fprintf(stderr, "%s\n", "parse error");
14968 }
14969#else /* V7_NO_COMPILER */
14970 exit_rcode = EXIT_FAILURE;
14971 fprintf(stderr, "%s\n", "Parsing is disabled by V7_NO_COMPILER");
14972#endif /* V7_NO_COMPILER */
14973 } else if (exec(v7, exprs[j], &res) != V7_OK) {
14974 v7_print_error(stderr, v7, exprs[j], res);
14975 exit_rcode = EXIT_FAILURE;
14976 res = V7_UNDEFINED;
14977 }
14978 }
14979
14980 /* Execute files */
14981 for (; i < argc; i++) {
14982 if (show_ast || dump_bcode) {
14983#if !defined(V7_NO_COMPILER)
14984 size_t size;
14985 char *source_code;
14986 if ((source_code = cs_read_file(argv[i], &size)) == NULL) {
14987 exit_rcode = EXIT_FAILURE;
14988 fprintf(stderr, "Cannot read [%s]\n", argv[i]);
14989 } else {
14990 if (_v7_compile(source_code, size, binary_ast, dump_bcode, stdout) !=
14991 V7_OK) {
14992 fprintf(stderr, "error: %s\n", v7->error_msg);
14993 exit_rcode = EXIT_FAILURE;
14994 exit(exit_rcode);
14995 }
14996 free(source_code);
14997 }
14998#else /* V7_NO_COMPILER */
14999 exit_rcode = EXIT_FAILURE;
15000 fprintf(stderr, "%s\n", "Parsing is disabled by V7_NO_COMPILER");
15001#endif /* V7_NO_COMPILER */
15002 } else if (v7_exec_file(v7, argv[i], &res) != V7_OK) {
15003 v7_print_error(stderr, v7, argv[i], res);
15004 res = V7_UNDEFINED;
15005 }
15006 }
15007
15008#ifdef V7_FREEZE
15009 if (opts.freeze_file != NULL) {
15010 freeze(v7, opts.freeze_file);
15011 exit(0);
15012 }
15013#endif
15014
15015 if (!(show_ast || dump_bcode)) {
15016 char buf[2000];
15017 char *s = v7_stringify(v7, res, buf, sizeof(buf),
15018 as_json ? V7_STRINGIFY_JSON : V7_STRINGIFY_DEBUG);
15019 printf("%s\n", s);
15020 if (s != buf) {
15021 free(s);
15022 }
15023 }
15024
15025 if (post_init != NULL) {
15026 post_init(v7);
15027 }
15028
15029#if V7_ENABLE__Memory__stats
15030 if (dump_stats) {
15031 printf("Memory stats after run:\n");
15032 dump_mm_stats(v7);
15033 }
15034#else
15035 (void) dump_stats;
15036#endif
15037
15038 v7_destroy(v7);
15039 return exit_rcode;
15040}
15041#endif
15042
15043#ifdef V7_EXE
15044int main(int argc, char *argv[]) {
15045 return v7_main(argc, argv, NULL, NULL, NULL);
15046}
15047#endif
15048#endif /* V7_EXPORT_INTERNAL_HEADERS */