Cesanta / v7 Featured

Dependents:   DISCO-F469NI_javascript_blinker

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers v7.c Source File

v7.c

00001 #include "v7.h"
00002 #ifdef V7_MODULE_LINES
00003 #line 1 "v7/src/license.h"
00004 #endif
00005 /*
00006  * Copyright (c) 2013-2014 Cesanta Software Limited
00007  * All rights reserved
00008  *
00009  * This software is dual-licensed: you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License version 2 as
00011  * published by the Free Software Foundation. For the terms of this
00012  * license, see <http://www.gnu.org/licenses/>.
00013  *
00014  * You are free to use this software under the terms of the GNU General
00015  * Public License, but WITHOUT ANY WARRANTY; without even the implied
00016  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017  * See the GNU General Public License for more details.
00018  *
00019  * Alternatively, you can license this software under a commercial
00020  * license, as set out in <https://www.cesanta.com/license>.
00021  */
00022 
00023 #ifdef V7_EXPOSE_PRIVATE
00024 #define V7_PRIVATE
00025 #define V7_EXTERN extern
00026 #else
00027 #define V7_PRIVATE static
00028 #define V7_EXTERN static
00029 #endif /* CS_V7_SRC_LICENSE_H_ */
00030 #ifdef V7_MODULE_LINES
00031 #line 1 "common/platform.h"
00032 #endif
00033 #ifndef CS_COMMON_PLATFORM_H_
00034 #define CS_COMMON_PLATFORM_H_
00035 
00036 /*
00037  * For the "custom" platform, includes and dependencies can be
00038  * provided through mg_locals.h.
00039  */
00040 #define CS_P_CUSTOM 0
00041 #define CS_P_UNIX 1
00042 #define CS_P_WINDOWS 2
00043 #define CS_P_ESP_LWIP 3
00044 #define CS_P_CC3200 4
00045 #define CS_P_MSP432 5
00046 #define CS_P_CC3100 6
00047 #define CS_P_MBED 7
00048 
00049 /* If not specified explicitly, we guess platform by defines. */
00050 #ifndef CS_PLATFORM
00051 
00052 #if defined(TARGET_IS_MSP432P4XX) || defined(__MSP432P401R__)
00053 
00054 #define CS_PLATFORM CS_P_MSP432
00055 #elif defined(cc3200)
00056 #define CS_PLATFORM CS_P_CC3200
00057 #elif defined(__unix__) || defined(__APPLE__)
00058 #define CS_PLATFORM CS_P_UNIX
00059 #elif defined(_WIN32)
00060 #define CS_PLATFORM CS_P_WINDOWS
00061 #elif defined(__MBED__)
00062 #define CS_PLATFORM CS_P_MBED
00063 #endif
00064 
00065 #ifndef CS_PLATFORM
00066 #error "CS_PLATFORM is not specified and we couldn't guess it."
00067 #endif
00068 
00069 #endif /* !defined(CS_PLATFORM) */
00070 
00071 /* Amalgamated: #include "common/platforms/platform_unix.h" */
00072 /* Amalgamated: #include "common/platforms/platform_windows.h" */
00073 /* Amalgamated: #include "common/platforms/platform_esp_lwip.h" */
00074 /* Amalgamated: #include "common/platforms/platform_cc3200.h" */
00075 /* Amalgamated: #include "common/platforms/platform_cc3100.h" */
00076 /* Amalgamated: #include "common/platforms/platform_mbed.h" */
00077 
00078 /* Common stuff */
00079 
00080 #ifdef __GNUC__
00081 #define NORETURN __attribute__((noreturn))
00082 #define NOINLINE __attribute__((noinline))
00083 #define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
00084 #define NOINSTR __attribute__((no_instrument_function))
00085 #else
00086 #define NORETURN
00087 #define NOINLINE
00088 #define WARN_UNUSED_RESULT
00089 #define NOINSTR
00090 #endif /* __GNUC__ */
00091 
00092 #ifndef ARRAY_SIZE
00093 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
00094 #endif
00095 
00096 #endif /* CS_COMMON_PLATFORM_H_ */
00097 #ifdef V7_MODULE_LINES
00098 #line 1 "common/platforms/platform_windows.h"
00099 #endif
00100 #ifndef CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_
00101 #define CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_
00102 #if CS_PLATFORM == CS_P_WINDOWS
00103 
00104 /*
00105  * MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
00106  * MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
00107  * MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
00108  * MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
00109  * MSVC++ 9.0  _MSC_VER == 1500 (Visual Studio 2008)
00110  * MSVC++ 8.0  _MSC_VER == 1400 (Visual Studio 2005)
00111  * MSVC++ 7.1  _MSC_VER == 1310 (Visual Studio 2003)
00112  * MSVC++ 7.0  _MSC_VER == 1300
00113  * MSVC++ 6.0  _MSC_VER == 1200
00114  * MSVC++ 5.0  _MSC_VER == 1100
00115  */
00116 #ifdef _MSC_VER
00117 #pragma warning(disable : 4127) /* FD_SET() emits warning, disable it */
00118 #pragma warning(disable : 4204) /* missing c99 support */
00119 #endif
00120 
00121 #define _WINSOCK_DEPRECATED_NO_WARNINGS 1
00122 #define _CRT_SECURE_NO_WARNINGS
00123 
00124 #include <assert.h>
00125 #include <direct.h>
00126 #include <errno.h>
00127 #include <fcntl.h>
00128 #include <io.h>
00129 #include <limits.h>
00130 #include <signal.h>
00131 #include <stddef.h>
00132 #include <stdio.h>
00133 #include <stdlib.h>
00134 #include <sys/stat.h>
00135 #include <time.h>
00136 
00137 #ifdef _MSC_VER
00138 #pragma comment(lib, "ws2_32.lib") /* Linking with winsock library */
00139 #endif
00140 
00141 #include <winsock2.h>
00142 #include <ws2tcpip.h>
00143 #include <windows.h>
00144 #include <process.h>
00145 
00146 #if defined(_MSC_VER) && _MSC_VER >= 1800
00147 #define strdup _strdup
00148 #endif
00149 
00150 #ifndef EINPROGRESS
00151 #define EINPROGRESS WSAEINPROGRESS
00152 #endif
00153 #ifndef EWOULDBLOCK
00154 #define EWOULDBLOCK WSAEWOULDBLOCK
00155 #endif
00156 #ifndef __func__
00157 #define STRX(x) #x
00158 #define STR(x) STRX(x)
00159 #define __func__ __FILE__ ":" STR(__LINE__)
00160 #endif
00161 #define snprintf _snprintf
00162 #define fileno _fileno
00163 #define vsnprintf _vsnprintf
00164 #define sleep(x) Sleep((x) *1000)
00165 #define to64(x) _atoi64(x)
00166 #if !defined(__MINGW32__) && !defined(__MINGW64__)
00167 #define popen(x, y) _popen((x), (y))
00168 #define pclose(x) _pclose(x)
00169 #endif
00170 #define rmdir _rmdir
00171 #if defined(_MSC_VER) && _MSC_VER >= 1400
00172 #define fseeko(x, y, z) _fseeki64((x), (y), (z))
00173 #else
00174 #define fseeko(x, y, z) fseek((x), (y), (z))
00175 #endif
00176 #if defined(_MSC_VER) && _MSC_VER <= 1200
00177 typedef unsigned long uintptr_t;
00178 typedef long intptr_t;
00179 #endif
00180 typedef int socklen_t;
00181 #if _MSC_VER >= 1700
00182 #include <stdint.h>
00183 #else
00184 typedef signed char int8_t;
00185 typedef unsigned char uint8_t;
00186 typedef int int32_t;
00187 typedef unsigned int uint32_t;
00188 typedef short int16_t;
00189 typedef unsigned short uint16_t;
00190 typedef __int64 int64_t;
00191 typedef unsigned __int64 uint64_t;
00192 #endif
00193 typedef SOCKET sock_t;
00194 typedef uint32_t in_addr_t;
00195 #ifndef UINT16_MAX
00196 #define UINT16_MAX 65535
00197 #endif
00198 #ifndef UINT32_MAX
00199 #define UINT32_MAX 4294967295
00200 #endif
00201 #ifndef pid_t
00202 #define pid_t HANDLE
00203 #endif
00204 #define INT64_FMT "I64d"
00205 #define INT64_X_FMT "I64x"
00206 #define SIZE_T_FMT "Iu"
00207 #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
00208 typedef struct stat cs_stat_t;
00209 #else
00210 typedef struct _stati64 cs_stat_t;
00211 #endif
00212 #ifndef S_ISDIR
00213 #define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
00214 #endif
00215 #ifndef S_ISREG
00216 #define S_ISREG(x) (((x) &_S_IFMT) == _S_IFREG)
00217 #endif
00218 #define DIRSEP '\\'
00219 
00220 #ifndef va_copy
00221 #ifdef __va_copy
00222 #define va_copy __va_copy
00223 #else
00224 #define va_copy(x, y) (x) = (y)
00225 #endif
00226 #endif
00227 
00228 #ifndef MG_MAX_HTTP_REQUEST_SIZE
00229 #define MG_MAX_HTTP_REQUEST_SIZE 8192
00230 #endif
00231 
00232 #ifndef MG_MAX_HTTP_SEND_MBUF
00233 #define MG_MAX_HTTP_SEND_MBUF 4096
00234 #endif
00235 
00236 #ifndef MG_MAX_HTTP_HEADERS
00237 #define MG_MAX_HTTP_HEADERS 40
00238 #endif
00239 
00240 #endif /* CS_PLATFORM == CS_P_WINDOWS */
00241 #endif /* CS_COMMON_PLATFORMS_PLATFORM_WINDOWS_H_ */
00242 #ifdef V7_MODULE_LINES
00243 #line 1 "common/platforms/platform_unix.h"
00244 #endif
00245 #ifndef CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_
00246 #define CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_
00247 #if CS_PLATFORM == CS_P_UNIX
00248 
00249 #ifndef _XOPEN_SOURCE
00250 #define _XOPEN_SOURCE 600
00251 #endif
00252 
00253 /* <inttypes.h> wants this for C++ */
00254 #ifndef __STDC_FORMAT_MACROS
00255 #define __STDC_FORMAT_MACROS
00256 #endif
00257 
00258 /* C++ wants that for INT64_MAX */
00259 #ifndef __STDC_LIMIT_MACROS
00260 #define __STDC_LIMIT_MACROS
00261 #endif
00262 
00263 /* Enable fseeko() and ftello() functions */
00264 #ifndef _LARGEFILE_SOURCE
00265 #define _LARGEFILE_SOURCE
00266 #endif
00267 
00268 /* Enable 64-bit file offsets */
00269 #ifndef _FILE_OFFSET_BITS
00270 #define _FILE_OFFSET_BITS 64
00271 #endif
00272 
00273 #include <arpa/inet.h>
00274 #include <assert.h>
00275 #include <ctype.h>
00276 #include <dirent.h>
00277 #include <errno.h>
00278 #include <fcntl.h>
00279 #include <inttypes.h>
00280 #include <stdint.h>
00281 #include <limits.h>
00282 #include <math.h>
00283 #include <netdb.h>
00284 #include <netinet/in.h>
00285 #include <pthread.h>
00286 #include <signal.h>
00287 #include <stdarg.h>
00288 #include <stdio.h>
00289 #include <stdlib.h>
00290 #include <string.h>
00291 #include <sys/socket.h>
00292 #include <sys/select.h>
00293 #include <sys/stat.h>
00294 #include <sys/time.h>
00295 #include <sys/types.h>
00296 #include <unistd.h>
00297 
00298 /*
00299  * osx correctly avoids defining strtoll when compiling in strict ansi mode.
00300  * We require strtoll, and if your embedded pre-c99 compiler lacks one, please
00301  * implement a shim.
00302  */
00303 #if !(defined(__DARWIN_C_LEVEL) && __DARWIN_C_LEVEL >= 200809L)
00304 long long strtoll(const char *, char **, int);
00305 #endif
00306 
00307 typedef int sock_t;
00308 #define INVALID_SOCKET (-1)
00309 #define SIZE_T_FMT "zu"
00310 typedef struct stat cs_stat_t;
00311 #define DIRSEP '/'
00312 #define to64(x) strtoll(x, NULL, 10)
00313 #define INT64_FMT PRId64
00314 #define INT64_X_FMT PRIx64
00315 
00316 #ifndef __cdecl
00317 #define __cdecl
00318 #endif
00319 
00320 #ifndef va_copy
00321 #ifdef __va_copy
00322 #define va_copy __va_copy
00323 #else
00324 #define va_copy(x, y) (x) = (y)
00325 #endif
00326 #endif
00327 
00328 #define closesocket(x) close(x)
00329 
00330 #ifndef MG_MAX_HTTP_REQUEST_SIZE
00331 #define MG_MAX_HTTP_REQUEST_SIZE 8192
00332 #endif
00333 
00334 #ifndef MG_MAX_HTTP_SEND_MBUF
00335 #define MG_MAX_HTTP_SEND_MBUF 4096
00336 #endif
00337 
00338 #ifndef MG_MAX_HTTP_HEADERS
00339 #define MG_MAX_HTTP_HEADERS 40
00340 #endif
00341 
00342 #endif /* CS_PLATFORM == CS_P_UNIX */
00343 #endif /* CS_COMMON_PLATFORMS_PLATFORM_UNIX_H_ */
00344 #ifdef V7_MODULE_LINES
00345 #line 1 "common/platforms/platform_esp_lwip.h"
00346 #endif
00347 #ifndef CS_COMMON_PLATFORMS_PLATFORM_ESP_LWIP_H_
00348 #define CS_COMMON_PLATFORMS_PLATFORM_ESP_LWIP_H_
00349 #if CS_PLATFORM == CS_P_ESP_LWIP
00350 
00351 #include <assert.h>
00352 #include <ctype.h>
00353 #include <fcntl.h>
00354 #include <inttypes.h>
00355 #include <string.h>
00356 #include <sys/stat.h>
00357 #include <sys/time.h>
00358 
00359 #include <lwip/err.h>
00360 #include <lwip/ip_addr.h>
00361 #include <lwip/inet.h>
00362 #include <lwip/netdb.h>
00363 #include <lwip/dns.h>
00364 
00365 #ifndef LWIP_PROVIDE_ERRNO
00366 #include <errno.h>
00367 #endif
00368 
00369 #define LWIP_TIMEVAL_PRIVATE 0
00370 
00371 #if LWIP_SOCKET
00372 #include <lwip/sockets.h>
00373 #define SOMAXCONN 10
00374 #else
00375 /* We really need the definitions from sockets.h. */
00376 #undef LWIP_SOCKET
00377 #define LWIP_SOCKET 1
00378 #include <lwip/sockets.h>
00379 #undef LWIP_SOCKET
00380 #define LWIP_SOCKET 0
00381 #endif
00382 
00383 typedef int sock_t;
00384 #define INVALID_SOCKET (-1)
00385 #define SIZE_T_FMT "u"
00386 typedef struct stat cs_stat_t;
00387 #define DIRSEP '/'
00388 #define to64(x) strtoll(x, NULL, 10)
00389 #define INT64_FMT PRId64
00390 #define INT64_X_FMT PRIx64
00391 #define __cdecl
00392 
00393 unsigned long os_random(void);
00394 #define random os_random
00395 
00396 #endif /* CS_PLATFORM == CS_P_ESP_LWIP */
00397 #endif /* CS_COMMON_PLATFORMS_PLATFORM_ESP_LWIP_H_ */
00398 #ifdef V7_MODULE_LINES
00399 #line 1 "common/mbuf.h"
00400 #endif
00401 /*
00402  * Copyright (c) 2015 Cesanta Software Limited
00403  * All rights reserved
00404  */
00405 
00406 /*
00407  * === Memory Buffers
00408  *
00409  * Mbufs are mutable/growing memory buffers, like C++ strings.
00410  * Mbuf can append data to the end of a buffer or insert data into arbitrary
00411  * position in the middle of a buffer. The buffer grows automatically when
00412  * needed.
00413  */
00414 
00415 #ifndef CS_COMMON_MBUF_H_
00416 #define CS_COMMON_MBUF_H_
00417 
00418 #if defined(__cplusplus)
00419 extern "C" {
00420 #endif
00421 
00422 #include <stdlib.h>
00423 
00424 #ifndef MBUF_SIZE_MULTIPLIER
00425 #define MBUF_SIZE_MULTIPLIER 1.5
00426 #endif
00427 
00428 /* Memory buffer descriptor */
00429 struct mbuf {
00430   char *buf;   /* Buffer pointer */
00431   size_t len;  /* Data length. Data is located between offset 0 and len. */
00432   size_t size; /* Buffer size allocated by realloc(1). Must be >= len */
00433 };
00434 
00435 /*
00436  * Initialises an Mbuf.
00437  * `initial_capacity` specifies the initial capacity of the mbuf.
00438  */
00439 void mbuf_init(struct mbuf *, size_t initial_capacity);
00440 
00441 /* Frees the space allocated for the mbuffer and resets the mbuf structure. */
00442 void mbuf_free(struct mbuf *);
00443 
00444 /*
00445  * Appends data to the Mbuf.
00446  *
00447  * Returns the number of bytes appended or 0 if out of memory.
00448  */
00449 size_t mbuf_append(struct mbuf *, const void *data, size_t data_size);
00450 
00451 /*
00452  * Inserts data at a specified offset in the Mbuf.
00453  *
00454  * Existing data will be shifted forwards and the buffer will
00455  * be grown if necessary.
00456  * Returns the number of bytes inserted.
00457  */
00458 size_t mbuf_insert(struct mbuf *, size_t, const void *, size_t);
00459 
00460 /* Removes `data_size` bytes from the beginning of the buffer. */
00461 void mbuf_remove(struct mbuf *, size_t data_size);
00462 
00463 /*
00464  * Resizes an Mbuf.
00465  *
00466  * If `new_size` is smaller than buffer's `len`, the
00467  * resize is not performed.
00468  */
00469 void mbuf_resize(struct mbuf *, size_t new_size);
00470 
00471 /* Shrinks an Mbuf by resizing its `size` to `len`. */
00472 void mbuf_trim(struct mbuf *);
00473 
00474 #if defined(__cplusplus)
00475 }
00476 #endif /* __cplusplus */
00477 
00478 #endif /* CS_COMMON_MBUF_H_ */
00479 #ifdef V7_MODULE_LINES
00480 #line 1 "common/platforms/simplelink/cs_simplelink.h"
00481 #endif
00482 /*
00483  * Copyright (c) 2014-2016 Cesanta Software Limited
00484  * All rights reserved
00485  */
00486 
00487 #ifndef CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_
00488 #define CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_
00489 
00490 /* If simplelink.h is already included, all bets are off. */
00491 #if defined(MG_SOCKET_SIMPLELINK) && !defined(__SIMPLELINK_H__)
00492 
00493 #include <stdbool.h>
00494 
00495 #ifndef __TI_COMPILER_VERSION__
00496 #undef __CONCAT
00497 #undef FD_CLR
00498 #undef FD_ISSET
00499 #undef FD_SET
00500 #undef FD_SETSIZE
00501 #undef FD_ZERO
00502 #undef fd_set
00503 #endif
00504 
00505 /* We want to disable SL_INC_STD_BSD_API_NAMING, so we include user.h ourselves
00506  * and undef it. */
00507 #define PROVISIONING_API_H_
00508 #include <simplelink/user.h>
00509 #undef PROVISIONING_API_H_
00510 #undef SL_INC_STD_BSD_API_NAMING
00511 
00512 #include <simplelink/include/simplelink.h>
00513 #include <simplelink/include/netapp.h>
00514 
00515 /* Now define only the subset of the BSD API that we use.
00516  * Notably, close(), read() and write() are not defined. */
00517 #define AF_INET SL_AF_INET
00518 
00519 #define socklen_t SlSocklen_t
00520 #define sockaddr SlSockAddr_t
00521 #define sockaddr_in SlSockAddrIn_t
00522 #define in_addr SlInAddr_t
00523 
00524 #define SOCK_STREAM SL_SOCK_STREAM
00525 #define SOCK_DGRAM SL_SOCK_DGRAM
00526 
00527 #define htonl sl_Htonl
00528 #define ntohl sl_Ntohl
00529 #define htons sl_Htons
00530 #define ntohs sl_Ntohs
00531 
00532 #ifndef EACCES
00533 #define EACCES SL_EACCES
00534 #endif
00535 #ifndef EAFNOSUPPORT
00536 #define EAFNOSUPPORT SL_EAFNOSUPPORT
00537 #endif
00538 #ifndef EAGAIN
00539 #define EAGAIN SL_EAGAIN
00540 #endif
00541 #ifndef EBADF
00542 #define EBADF SL_EBADF
00543 #endif
00544 #ifndef EINVAL
00545 #define EINVAL SL_EINVAL
00546 #endif
00547 #ifndef ENOMEM
00548 #define ENOMEM SL_ENOMEM
00549 #endif
00550 #ifndef EWOULDBLOCK
00551 #define EWOULDBLOCK SL_EWOULDBLOCK
00552 #endif
00553 
00554 #define SOMAXCONN 8
00555 
00556 #ifdef __cplusplus
00557 extern "C" {
00558 #endif
00559 
00560 const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
00561 char *inet_ntoa(struct in_addr in);
00562 int inet_pton(int af, const char *src, void *dst);
00563 
00564 struct mg_mgr;
00565 struct mg_connection;
00566 
00567 typedef void (*mg_init_cb)(struct mg_mgr *mgr);
00568 bool mg_start_task(int priority, int stack_size, mg_init_cb mg_init);
00569 
00570 void mg_run_in_task(void (*cb)(struct mg_mgr *mgr, void *arg), void *cb_arg);
00571 
00572 int sl_fs_init(void);
00573 
00574 void sl_restart_cb(struct mg_mgr *mgr);
00575 
00576 int sl_set_ssl_opts(struct mg_connection *nc);
00577 
00578 #ifdef __cplusplus
00579 }
00580 #endif
00581 
00582 #endif /* defined(MG_SOCKET_SIMPLELINK) && !defined(__SIMPLELINK_H__) */
00583 
00584 #endif /* CS_COMMON_PLATFORMS_SIMPLELINK_CS_SIMPLELINK_H_ */
00585 #ifdef V7_MODULE_LINES
00586 #line 1 "common/platforms/platform_cc3200.h"
00587 #endif
00588 /*
00589  * Copyright (c) 2014-2016 Cesanta Software Limited
00590  * All rights reserved
00591  */
00592 
00593 #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_
00594 #define CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_
00595 #if CS_PLATFORM == CS_P_CC3200
00596 
00597 #include <assert.h>
00598 #include <ctype.h>
00599 #include <errno.h>
00600 #include <inttypes.h>
00601 #include <stdint.h>
00602 #include <string.h>
00603 #include <time.h>
00604 
00605 #ifndef __TI_COMPILER_VERSION__
00606 #include <fcntl.h>
00607 #include <sys/time.h>
00608 #endif
00609 
00610 #define MG_SOCKET_SIMPLELINK 1
00611 #define MG_DISABLE_SOCKETPAIR 1
00612 #define MG_DISABLE_SYNC_RESOLVER 1
00613 #define MG_DISABLE_POPEN 1
00614 #define MG_DISABLE_CGI 1
00615 /* Only SPIFFS supports directories, SLFS does not. */
00616 #ifndef CC3200_FS_SPIFFS
00617 #define MG_DISABLE_DAV 1
00618 #define MG_DISABLE_DIRECTORY_LISTING 1
00619 #endif
00620 
00621 /* Amalgamated: #include "common/platforms/simplelink/cs_simplelink.h" */
00622 
00623 typedef int sock_t;
00624 #define INVALID_SOCKET (-1)
00625 #define SIZE_T_FMT "u"
00626 typedef struct stat cs_stat_t;
00627 #define DIRSEP '/'
00628 #define to64(x) strtoll(x, NULL, 10)
00629 #define INT64_FMT PRId64
00630 #define INT64_X_FMT PRIx64
00631 #define __cdecl
00632 
00633 #define fileno(x) -1
00634 
00635 /* Some functions we implement for Mongoose. */
00636 
00637 #ifdef __cplusplus
00638 extern "C" {
00639 #endif
00640 
00641 #ifdef __TI_COMPILER_VERSION__
00642 struct SlTimeval_t;
00643 #define timeval SlTimeval_t
00644 int gettimeofday(struct timeval *t, void *tz);
00645 
00646 int asprintf(char **strp, const char *fmt, ...);
00647 
00648 #endif
00649 
00650 /* TI's libc does not have stat & friends, add them. */
00651 #ifdef __TI_COMPILER_VERSION__
00652 
00653 #include <file.h>
00654 
00655 typedef unsigned int mode_t;
00656 typedef size_t _off_t;
00657 typedef long ssize_t;
00658 
00659 struct stat {
00660   int st_ino;
00661   mode_t st_mode;
00662   int st_nlink;
00663   time_t st_mtime;
00664   off_t st_size;
00665 };
00666 
00667 int _stat(const char *pathname, struct stat *st);
00668 #define stat(a, b) _stat(a, b)
00669 
00670 #define __S_IFMT 0170000
00671 
00672 #define __S_IFDIR 0040000
00673 #define __S_IFCHR 0020000
00674 #define __S_IFREG 0100000
00675 
00676 #define __S_ISTYPE(mode, mask) (((mode) &__S_IFMT) == (mask))
00677 
00678 #define S_IFDIR __S_IFDIR
00679 #define S_IFCHR __S_IFCHR
00680 #define S_IFREG __S_IFREG
00681 #define S_ISDIR(mode) __S_ISTYPE((mode), __S_IFDIR)
00682 #define S_ISREG(mode) __S_ISTYPE((mode), __S_IFREG)
00683 
00684 /* As of 5.2.7, TI compiler does not support va_copy() yet. */
00685 #define va_copy(apc, ap) ((apc) = (ap))
00686 
00687 #endif /* __TI_COMPILER_VERSION__ */
00688 
00689 #ifdef CC3200_FS_SPIFFS
00690 #include <common/spiffs/spiffs.h>
00691 
00692 typedef struct {
00693   spiffs_DIR dh;
00694   struct spiffs_dirent de;
00695 } DIR;
00696 
00697 #define d_name name
00698 #define dirent spiffs_dirent
00699 
00700 DIR *opendir(const char *dir_name);
00701 int closedir(DIR *dir);
00702 struct dirent *readdir(DIR *dir);
00703 #endif /* CC3200_FS_SPIFFS */
00704 
00705 #ifdef CC3200_FS_SLFS
00706 #define MG_FS_SLFS
00707 #endif
00708 
00709 #ifdef __cplusplus
00710 }
00711 #endif
00712 
00713 #endif /* CS_PLATFORM == CS_P_CC3200 */
00714 #endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3200_H_ */
00715 #ifdef V7_MODULE_LINES
00716 #line 1 "common/platforms/platform_cc3100.h"
00717 #endif
00718 /*
00719  * Copyright (c) 2014-2016 Cesanta Software Limited
00720  * All rights reserved
00721  */
00722 
00723 #ifndef CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_
00724 #define CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_
00725 #if CS_PLATFORM == CS_P_CC3100
00726 
00727 #include <assert.h>
00728 #include <ctype.h>
00729 #include <errno.h>
00730 #include <inttypes.h>
00731 #include <stdint.h>
00732 #include <string.h>
00733 #include <time.h>
00734 
00735 #define MG_SOCKET_SIMPLELINK 1
00736 #define MG_DISABLE_SOCKETPAIR 1
00737 #define MG_DISABLE_SYNC_RESOLVER 1
00738 #define MG_DISABLE_POPEN 1
00739 #define MG_DISABLE_CGI 1
00740 #define MG_DISABLE_DAV 1
00741 #define MG_DISABLE_DIRECTORY_LISTING 1
00742 #define MG_DISABLE_FILESYSTEM 1
00743 
00744 /*
00745  * CC3100 SDK and STM32 SDK include headers w/out path, just like
00746  * #include "simplelink.h". As result, we have to add all required directories
00747  * into Makefile IPATH and do the same thing (include w/out path)
00748  */
00749 
00750 #include <simplelink.h>
00751 #include <netapp.h>
00752 #undef timeval 
00753 
00754 typedef int sock_t;
00755 #define INVALID_SOCKET (-1)
00756 
00757 #define to64(x) strtoll(x, NULL, 10)
00758 #define INT64_FMT PRId64
00759 #define INT64_X_FMT PRIx64
00760 #define SIZE_T_FMT "u"
00761 
00762 #define SOMAXCONN 8
00763 
00764 const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
00765 char *inet_ntoa(struct in_addr in);
00766 int inet_pton(int af, const char *src, void *dst);
00767 
00768 #endif /* CS_PLATFORM == CS_P_CC3100 */
00769 #endif /* CS_COMMON_PLATFORMS_PLATFORM_CC3100_H_ */
00770 #ifdef V7_MODULE_LINES
00771 #line 1 "common/platforms/platform_mbed.h"
00772 #endif
00773 /*
00774  * Copyright (c) 2014-2016 Cesanta Software Limited
00775  * All rights reserved
00776  */
00777 
00778 #ifndef CS_COMMON_PLATFORMS_PLATFORM_MBED_H_
00779 #define CS_COMMON_PLATFORMS_PLATFORM_MBED_H_
00780 #if CS_PLATFORM == CS_P_MBED
00781 
00782 /* Amalgamated: #include "mbed.h" */
00783 
00784 #endif /* CS_PLATFORM == CS_P_MBED */
00785 #endif /* CS_COMMON_PLATFORMS_PLATFORM_MBED_H_ */
00786 #ifdef V7_MODULE_LINES
00787 #line 1 "common/str_util.h"
00788 #endif
00789 /*
00790  * Copyright (c) 2015 Cesanta Software Limited
00791  * All rights reserved
00792  */
00793 
00794 #ifndef CS_COMMON_STR_UTIL_H_
00795 #define CS_COMMON_STR_UTIL_H_
00796 
00797 #include <stdarg.h>
00798 #include <stdlib.h>
00799 
00800 #ifdef __cplusplus
00801 extern "C" {
00802 #endif
00803 
00804 size_t c_strnlen(const char *s, size_t maxlen);
00805 int c_snprintf(char *buf, size_t buf_size, const char *format, ...);
00806 int c_vsnprintf(char *buf, size_t buf_size, const char *format, va_list ap);
00807 /*
00808  * Find the first occurrence of find in s, where the search is limited to the
00809  * first slen characters of s.
00810  */
00811 const char *c_strnstr(const char *s, const char *find, size_t slen);
00812 
00813 #ifdef __cplusplus
00814 }
00815 #endif
00816 
00817 #endif /* CS_COMMON_STR_UTIL_H_ */
00818 #ifdef V7_MODULE_LINES
00819 #line 1 "common/utf.h"
00820 #endif
00821 /*
00822  * Copyright (c) 2014 Cesanta Software Limited
00823  * All rights reserved
00824  */
00825 
00826 #ifndef CS_COMMON_UTF_H_
00827 #define CS_COMMON_UTF_H_
00828 
00829 #if defined(__cplusplus)
00830 extern "C" {
00831 #endif /* __cplusplus */
00832 
00833 typedef unsigned char uchar;
00834 
00835 typedef unsigned short Rune; /* 16 bits */
00836 
00837 #define nelem(a) (sizeof(a) / sizeof(a)[0])
00838 
00839 enum {
00840   UTFmax = 3,               /* maximum bytes per rune */
00841   Runesync = 0x80,          /* cannot represent part of a UTF sequence (<) */
00842   Runeself = 0x80,          /* rune and UTF sequences are the same (<) */
00843   Runeerror = 0xFFFD        /* decoding error in UTF */
00844   /* Runemax    = 0xFFFC */ /* maximum rune value */
00845 };
00846 
00847 /* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/utf/?*.c | grep -v static |grep -v __ */
00848 int chartorune(Rune *rune, const char *str);
00849 int fullrune(const char *str, int n);
00850 int isdigitrune(Rune c);
00851 int isnewline(Rune c);
00852 int iswordchar(Rune c);
00853 int isalpharune(Rune c);
00854 int islowerrune(Rune c);
00855 int isspacerune(Rune c);
00856 int isupperrune(Rune c);
00857 int runetochar(char *str, Rune *rune);
00858 Rune tolowerrune(Rune c);
00859 Rune toupperrune(Rune c);
00860 int utfnlen(const char *s, long m);
00861 const char *utfnshift(const char *s, long m);
00862 
00863 #if 0 /* Not implemented. */
00864 int istitlerune(Rune c);
00865 int runelen(Rune c);
00866 int runenlen(Rune *r, int nrune);
00867 Rune *runestrcat(Rune *s1, Rune *s2);
00868 Rune *runestrchr(Rune *s, Rune c);
00869 Rune *runestrcpy(Rune *s1, Rune *s2);
00870 Rune *runestrdup(Rune *s);
00871 Rune *runestrecpy(Rune *s1, Rune *es1, Rune *s2);
00872 int runestrcmp(Rune *s1, Rune *s2);
00873 long runestrlen(Rune *s);
00874 Rune *runestrncat(Rune *s1, Rune *s2, long n);
00875 int runestrncmp(Rune *s1, Rune *s2, long n);
00876 Rune *runestrncpy(Rune *s1, Rune *s2, long n);
00877 Rune *runestrrchr(Rune *s, Rune c);
00878 Rune *runestrstr(Rune *s1, Rune *s2);
00879 Rune totitlerune(Rune c);
00880 char *utfecpy(char *to, char *e, char *from);
00881 int utflen(char *s);
00882 char *utfrrune(char *s, long c);
00883 char *utfrune(char *s, long c);
00884 char *utfutf(char *s1, char *s2);
00885 #endif
00886 
00887 #if defined(__cplusplus)
00888 }
00889 #endif /* __cplusplus */
00890 #endif /* CS_COMMON_UTF_H_ */
00891 #ifdef V7_MODULE_LINES
00892 #line 1 "common/base64.h"
00893 #endif
00894 /*
00895  * Copyright (c) 2014 Cesanta Software Limited
00896  * All rights reserved
00897  */
00898 
00899 #ifndef CS_COMMON_BASE64_H_
00900 #define CS_COMMON_BASE64_H_
00901 
00902 #ifndef DISABLE_BASE64
00903 
00904 #include <stdio.h>
00905 
00906 #ifdef __cplusplus
00907 extern "C" {
00908 #endif
00909 
00910 typedef void (*cs_base64_putc_t)(char, void *);
00911 
00912 struct cs_base64_ctx {
00913   /* cannot call it putc because it's a macro on some environments */
00914   cs_base64_putc_t b64_putc;
00915   unsigned char chunk[3];
00916   int chunk_size;
00917   void *user_data;
00918 };
00919 
00920 void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t putc,
00921                     void *user_data);
00922 void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len);
00923 void cs_base64_finish(struct cs_base64_ctx *ctx);
00924 
00925 void cs_base64_encode(const unsigned char *src, int src_len, char *dst);
00926 void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len);
00927 int cs_base64_decode(const unsigned char *s, int len, char *dst);
00928 
00929 #ifdef __cplusplus
00930 }
00931 #endif
00932 
00933 #endif /* DISABLE_BASE64 */
00934 
00935 #endif /* CS_COMMON_BASE64_H_ */
00936 #ifdef V7_MODULE_LINES
00937 #line 1 "common/md5.h"
00938 #endif
00939 /*
00940  * Copyright (c) 2014 Cesanta Software Limited
00941  * All rights reserved
00942  */
00943 
00944 #ifndef CS_COMMON_MD5_H_
00945 #define CS_COMMON_MD5_H_
00946 
00947 /* Amalgamated: #include "common/platform.h" */
00948 
00949 #ifdef __cplusplus
00950 extern "C" {
00951 #endif /* __cplusplus */
00952 
00953 typedef struct MD5Context {
00954   uint32_t buf[4];
00955   uint32_t bits[2];
00956   unsigned char in[64];
00957 } MD5_CTX;
00958 
00959 void MD5_Init(MD5_CTX *c);
00960 void MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len);
00961 void MD5_Final(unsigned char *md, MD5_CTX *c);
00962 
00963 /*
00964  * Return stringified MD5 hash for NULL terminated list of pointer/length pairs.
00965  * A length should be specified as size_t variable.
00966  * Example:
00967  *
00968  *    char buf[33];
00969  *    cs_md5(buf, "foo", (size_t) 3, "bar", (size_t) 3, NULL);
00970  */
00971 char *cs_md5(char buf[33], ...);
00972 
00973 /*
00974  * Stringify binary data. Output buffer size must be 2 * size_of_input + 1
00975  * because each byte of input takes 2 bytes in string representation
00976  * plus 1 byte for the terminating \0 character.
00977  */
00978 void cs_to_hex(char *to, const unsigned char *p, size_t len);
00979 
00980 #ifdef __cplusplus
00981 }
00982 #endif /* __cplusplus */
00983 
00984 #endif /* CS_COMMON_MD5_H_ */
00985 #ifdef V7_MODULE_LINES
00986 #line 1 "common/sha1.h"
00987 #endif
00988 /*
00989  * Copyright (c) 2014 Cesanta Software Limited
00990  * All rights reserved
00991  */
00992 
00993 #ifndef CS_COMMON_SHA1_H_
00994 #define CS_COMMON_SHA1_H_
00995 
00996 #ifndef DISABLE_SHA1
00997 
00998 /* Amalgamated: #include "common/platform.h" */
00999 
01000 #ifdef __cplusplus
01001 extern "C" {
01002 #endif /* __cplusplus */
01003 
01004 typedef struct {
01005   uint32_t state[5];
01006   uint32_t count[2];
01007   unsigned char buffer[64];
01008 } cs_sha1_ctx;
01009 
01010 void cs_sha1_init(cs_sha1_ctx *);
01011 void cs_sha1_update(cs_sha1_ctx *, const unsigned char *data, uint32_t len);
01012 void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *);
01013 void cs_hmac_sha1(const unsigned char *key, size_t key_len,
01014                   const unsigned char *text, size_t text_len,
01015                   unsigned char out[20]);
01016 #ifdef __cplusplus
01017 }
01018 #endif /* __cplusplus */
01019 
01020 #endif /* DISABLE_SHA1 */
01021 
01022 #endif /* CS_COMMON_SHA1_H_ */
01023 #ifdef V7_MODULE_LINES
01024 #line 1 "common/cs_dirent.h"
01025 #endif
01026 /*
01027  * Copyright (c) 2014-2016 Cesanta Software Limited
01028  * All rights reserved
01029  */
01030 
01031 #ifndef CS_COMMON_CS_DIRENT_H_
01032 #define CS_COMMON_CS_DIRENT_H_
01033 
01034 #ifdef __cplusplus
01035 extern "C" {
01036 #endif /* __cplusplus */
01037 
01038 #ifdef CS_ENABLE_SPIFFS
01039 
01040 #include <spiffs.h>
01041 
01042 typedef struct {
01043   spiffs_DIR dh;
01044   struct spiffs_dirent de;
01045 } DIR;
01046 
01047 #define d_name name
01048 #define dirent spiffs_dirent
01049 
01050 int rmdir(const char *path);
01051 int mkdir(const char *path, mode_t mode);
01052 
01053 #endif
01054 
01055 #if defined(_WIN32)
01056 struct dirent {
01057   char d_name[MAX_PATH];
01058 };
01059 
01060 typedef struct DIR {
01061   HANDLE handle;
01062   WIN32_FIND_DATAW info;
01063   struct dirent result;
01064 } DIR;
01065 #endif
01066 
01067 #if defined(_WIN32) || defined(CS_ENABLE_SPIFFS)
01068 DIR *opendir(const char *dir_name);
01069 int closedir(DIR *dir);
01070 struct dirent *readdir(DIR *dir);
01071 #endif
01072 
01073 #ifdef __cplusplus
01074 }
01075 #endif /* __cplusplus */
01076 
01077 #endif /* CS_COMMON_CS_DIRENT_H_ */
01078 #ifdef V7_MODULE_LINES
01079 #line 1 "common/cs_file.h"
01080 #endif
01081 /*
01082  * Copyright (c) 2015 Cesanta Software Limited
01083  * All rights reserved
01084  */
01085 
01086 #ifndef CS_COMMON_CS_FILE_H_
01087 #define CS_COMMON_CS_FILE_H_
01088 
01089 /* Amalgamated: #include "common/platform.h" */
01090 
01091 #ifdef __cplusplus
01092 extern "C" {
01093 #endif /* __cplusplus */
01094 
01095 /*
01096  * Read whole file `path` in memory. It is responsibility of the caller
01097  * to `free()` allocated memory. File content is guaranteed to be
01098  * '\0'-terminated. File size is returned in `size` variable, which does not
01099  * count terminating `\0`.
01100  * Return: allocated memory, or NULL on error.
01101  */
01102 char *cs_read_file(const char *path, size_t *size);
01103 
01104 #ifdef CS_MMAP
01105 char *cs_mmap_file(const char *path, size_t *size);
01106 #endif
01107 
01108 #ifdef __cplusplus
01109 }
01110 #endif /* __cplusplus */
01111 
01112 #endif /* CS_COMMON_CS_FILE_H_ */
01113 #ifdef V7_MODULE_LINES
01114 #line 1 "common/coroutine.h"
01115 #endif
01116 /*
01117  * Copyright (c) 2015 Cesanta Software Limited
01118  * All rights reserved
01119  */
01120 
01121 /*
01122  * Module that provides generic macros and functions to implement "coroutines",
01123  * i.e. C code that uses `mbuf` as a stack for function calls.
01124  *
01125  * More info: see the design doc: https://goo.gl/kfcG61
01126  */
01127 
01128 #ifndef CS_COMMON_COROUTINE_H_
01129 #define CS_COMMON_COROUTINE_H_
01130 
01131 /* Amalgamated: #include "common/mbuf.h" */
01132 /* Amalgamated: #include "common/platform.h" */
01133 
01134 /* user-defined union, this module only operates on the pointer */
01135 union user_arg_ret;
01136 
01137 /*
01138  * Type that represents size of local function variables. We assume we'll never
01139  * need more than 255 bytes of stack frame.
01140  */
01141 typedef uint8_t cr_locals_size_t;
01142 
01143 /*
01144  * Descriptor of a single function; const array of such descriptors should
01145  * be given to `cr_context_init()`
01146  */
01147 struct cr_func_desc {
01148   /*
01149    * Size of the function's data that should be stored on stack.
01150    *
01151    * NOTE: you should use `CR_LOCALS_SIZEOF(your_type)` instead of `sizeof()`,
01152    * since this value should be aligned by the word boundary, and
01153    * `CR_LOCALS_SIZEOF()` takes care of this.
01154    */
01155   cr_locals_size_t locals_size;
01156 };
01157 
01158 enum cr_status {
01159   CR_RES__OK,
01160   CR_RES__OK_YIELDED,
01161 
01162   CR_RES__ERR_STACK_OVERFLOW,
01163 
01164   /* Underflow can only be caused by memory corruption or bug in CR */
01165   CR_RES__ERR_STACK_DATA_UNDERFLOW,
01166   /* Underflow can only be caused by memory corruption or bug in CR */
01167   CR_RES__ERR_STACK_CALL_UNDERFLOW,
01168 
01169   CR_RES__ERR_UNCAUGHT_EXCEPTION,
01170 };
01171 
01172 /* Context of the coroutine engine */
01173 struct cr_ctx {
01174   /*
01175    * id of the next "function" to call. If no function is going to be called,
01176    * it's CR_FID__NONE.
01177    */
01178   uint8_t called_fid;
01179 
01180   /*
01181    * when `called_fid` is not `CR_FID__NONE`, this field holds called
01182    * function's stack frame size
01183    */
01184   size_t call_locals_size;
01185 
01186   /*
01187    * when `called_fid` is not `CR_FID__NONE`, this field holds called
01188    * function's arguments size
01189    */
01190   size_t call_arg_size;
01191 
01192   /*
01193    * pointer to the current function's locals.
01194    * Needed to make `CR_CUR_LOCALS_PT()` fast.
01195    */
01196   uint8_t *p_cur_func_locals;
01197 
01198   /* data stack */
01199   struct mbuf stack_data;
01200 
01201   /* return stack */
01202   struct mbuf stack_ret;
01203 
01204   /* index of the current fid + 1 in return stack */
01205   size_t cur_fid_idx;
01206 
01207   /* pointer to the array of function descriptors */
01208   const struct cr_func_desc *p_func_descrs;
01209 
01210   /* thrown exception. If nothing is currently thrown, it's `CR_EXC_ID__NONE` */
01211   uint8_t thrown_exc;
01212 
01213   /* status: normally, it's `CR_RES__OK` */
01214   enum cr_status status;
01215 
01216   /*
01217    * pointer to user-dependent union of arguments for all functions, as well as
01218    * return values, yielded and resumed values.
01219    */
01220   union user_arg_ret *p_arg_retval;
01221 
01222   /* true if currently running function returns */
01223   unsigned need_return : 1;
01224 
01225   /* true if currently running function yields */
01226   unsigned need_yield : 1;
01227 
01228 #if defined(CR_TRACK_MAX_STACK_LEN)
01229   size_t stack_data_max_len;
01230   size_t stack_ret_max_len;
01231 #endif
01232 };
01233 
01234 /*
01235  * User's enum with function ids should use items of this one like this:
01236  *
01237  *   enum my_func_id {
01238  *     my_func_none = CR_FID__NONE,
01239  *
01240  *     my_foo = CR_FID__USER,
01241  *     my_foo1,
01242  *     my_foo2,
01243  *
01244  *     my_bar,
01245  *     my_bar1,
01246  *   };
01247  *
01248  */
01249 enum cr_fid {
01250   CR_FID__NONE,
01251   CR_FID__USER,
01252 
01253   /* for internal usage only */
01254   CR_FID__TRY_MARKER = 0xff,
01255 };
01256 
01257 /*
01258  * User's enum with exception ids should use items of this one like this:
01259  *
01260  *   enum my_exc_id {
01261  *     MY_EXC_ID__FIRST = CR_EXC_ID__USER,
01262  *     MY_EXC_ID__SECOND,
01263  *     MY_EXC_ID__THIRD,
01264  *   };
01265  */
01266 enum cr_exc_id {
01267   CR_EXC_ID__NONE,
01268   CR_EXC_ID__USER,
01269 };
01270 
01271 /*
01272  * A type whose size is a special case for macros `CR_LOCALS_SIZEOF()` and
01273  * `CR_ARG_SIZEOF()` : it is assumed as zero size.
01274  *
01275  * This hackery is needed because empty structs (that would yield sizeof 0) are
01276  * illegal in plain C.
01277  */
01278 typedef struct { uint8_t _dummy[((cr_locals_size_t) -1)]; } cr_zero_size_type_t;
01279 
01280 /*
01281  * To be used in dispatcher switch: depending on the "fid" (function id), we
01282  * jump to the appropriate label.
01283  */
01284 #define CR_DEFINE_ENTRY_POINT(fid) \
01285   case fid:                        \
01286     goto fid
01287 
01288 /*
01289  * Returns lvalue: id of the currently active "function". It just takes the id
01290  * from the appropriate position of the "stack".
01291  *
01292  * Client code only needs it in dispatcher switch.
01293  */
01294 #define CR_CURR_FUNC_C(p_ctx) \
01295   *(((cr_locals_size_t *) (p_ctx)->stack_ret.buf) + (p_ctx)->cur_fid_idx - 1)
01296 
01297 /*
01298  * Prepare context for calling first function.
01299  *
01300  * Should be used outside of the exec loop, right after initializing
01301  * context with `cr_context_init()`
01302  *
01303  * `call_fid`: id of the function to be called
01304  */
01305 #define CR_FIRST_CALL_PREPARE_C(p_ctx, call_fid)                           \
01306   _CR_CALL_PREPARE(p_ctx, call_fid, CR_LOCALS_SIZEOF(call_fid##_locals_t), \
01307                    CR_ARG_SIZEOF(call_fid##_arg_t), CR_FID__NONE)
01308 
01309 /*
01310  * Call "function" with id `call_fid`: uses `_CR_CALL_PREPARE()` to prepare
01311  * stuff, and then jumps to the `_cr_iter_begin`, which will perform all
01312  * necessary bookkeeping.
01313  *
01314  * Should be used from eval loop only.
01315  *
01316  * `local_ret_fid`: id of the label right after the function call (where
01317  * currently running function will be resumed later)
01318  */
01319 #define CR_CALL_C(p_ctx, call_fid, local_ret_fid)                            \
01320   do {                                                                       \
01321     _CR_CALL_PREPARE(p_ctx, call_fid, CR_LOCALS_SIZEOF(call_fid##_locals_t), \
01322                      CR_ARG_SIZEOF(call_fid##_arg_t), local_ret_fid);        \
01323     goto _cr_iter_begin;                                                     \
01324   local_ret_fid:                                                             \
01325     /* we'll get here when called function returns */                        \
01326     ;                                                                        \
01327   } while (0)
01328 
01329 /*
01330  * "Return" the value `retval` from the current "function" with id `cur_fid`.
01331  * You have to specify `cur_fid` since different functions may have different
01332  * return types.
01333  *
01334  * Should be used from eval loop only.
01335  */
01336 #define CR_RETURN_C(p_ctx, cur_fid, retval)         \
01337   do {                                              \
01338     /* copy ret to arg_retval */                    \
01339     CR_ARG_RET_PT_C(p_ctx)->ret.cur_fid = (retval); \
01340     /* set need_return flag */                      \
01341     (p_ctx)->need_return = 1;                       \
01342     goto _cr_iter_begin;                            \
01343   } while (0)
01344 
01345 /*
01346  * Same as `CR_RETURN_C`, but without any return value
01347  */
01348 #define CR_RETURN_VOID_C(p_ctx) \
01349   do {                          \
01350     /* set need_return flag */  \
01351     (p_ctx)->need_return = 1;   \
01352     goto _cr_iter_begin;        \
01353   } while (0)
01354 
01355 /*
01356  * Yield with the value `value`. It will be set just by the assigment operator
01357  * in the `yielded` field of the `union user_arg_ret`.
01358  *
01359  * `local_ret_fid`: id of the label right after the yielding (where currently
01360  * running function will be resumed later)
01361  *
01362  */
01363 #define CR_YIELD_C(p_ctx, value, local_ret_fid)           \
01364   do {                                                    \
01365     /* copy ret to arg_retval */                          \
01366     CR_ARG_RET_PT_C(p_ctx)->yielded = (value);            \
01367     /* set need_yield flag */                             \
01368     (p_ctx)->need_yield = 1;                              \
01369                                                           \
01370     /* adjust return func id */                           \
01371     CR_CURR_FUNC_C(p_ctx) = (local_ret_fid);              \
01372                                                           \
01373     goto _cr_iter_begin;                                  \
01374   local_ret_fid:                                          \
01375     /* we'll get here when the machine will be resumed */ \
01376     ;                                                     \
01377   } while (0)
01378 
01379 /*
01380  * Prepare context for resuming with the given value. After using this
01381  * macro, you need to call your user-dependent exec function.
01382  */
01383 #define CR_RESUME_C(p_ctx, value)                \
01384   do {                                           \
01385     if ((p_ctx)->status == CR_RES__OK_YIELDED) { \
01386       CR_ARG_RET_PT_C(p_ctx)->resumed = (value); \
01387       (p_ctx)->status = CR_RES__OK;              \
01388     }                                            \
01389   } while (0)
01390 
01391 /*
01392  * Evaluates to the yielded value (value given to `CR_YIELD_C()`)
01393  */
01394 #define CR_YIELDED_C(p_ctx) (CR_ARG_RET_PT_C(p_ctx)->yielded)
01395 
01396 /*
01397  * Evaluates to the value given to `CR_RESUME_C()`
01398  */
01399 #define CR_RESUMED_C(p_ctx) (CR_ARG_RET_PT_C(p_ctx)->resumed)
01400 
01401 /*
01402  * Beginning of the try-catch block.
01403  *
01404  * Should be used in eval loop only.
01405  *
01406  * `first_catch_fid`: function id of the first catch block.
01407  */
01408 #define CR_TRY_C(p_ctx, first_catch_fid)                                   \
01409   do {                                                                     \
01410     _CR_STACK_RET_ALLOC((p_ctx), _CR_TRY_SIZE);                            \
01411     /* update pointer to current function's locals (may be invalidated) */ \
01412     _CR_CUR_FUNC_LOCALS_UPD(p_ctx);                                        \
01413     /*  */                                                                 \
01414     _CR_TRY_MARKER(p_ctx) = CR_FID__TRY_MARKER;                            \
01415     _CR_TRY_CATCH_FID(p_ctx) = (first_catch_fid);                          \
01416   } while (0)
01417 
01418 /*
01419  * Beginning of the individual catch block (and the end of the previous one, if
01420  * any)
01421  *
01422  * Should be used in eval loop only.
01423  *
01424  * `exc_id`: exception id to catch
01425  *
01426  * `catch_fid`: function id of this catch block.
01427  *
01428  * `next_catch_fid`: function id of the next catch block (or of the
01429  * `CR_ENDCATCH()`)
01430  */
01431 #define CR_CATCH_C(p_ctx, exc_id, catch_fid, next_catch_fid) \
01432   catch_fid:                                                 \
01433   do {                                                       \
01434     if ((p_ctx)->thrown_exc != (exc_id)) {                   \
01435       goto next_catch_fid;                                   \
01436     }                                                        \
01437     (p_ctx)->thrown_exc = CR_EXC_ID__NONE;                   \
01438   } while (0)
01439 
01440 /*
01441  * End of all catch blocks.
01442  *
01443  * Should be used in eval loop only.
01444  *
01445  * `endcatch_fid`: function id of this endcatch.
01446  */
01447 #define CR_ENDCATCH_C(p_ctx, endcatch_fid)                                   \
01448   endcatch_fid:                                                              \
01449   do {                                                                       \
01450     (p_ctx)->stack_ret.len -= _CR_TRY_SIZE;                                  \
01451     /* if we still have non-handled exception, continue unwinding "stack" */ \
01452     if ((p_ctx)->thrown_exc != CR_EXC_ID__NONE) {                            \
01453       goto _cr_iter_begin;                                                   \
01454     }                                                                        \
01455   } while (0)
01456 
01457 /*
01458  * Throw exception.
01459  *
01460  * Should be used from eval loop only.
01461  *
01462  * `exc_id`: exception id to throw
01463  */
01464 #define CR_THROW_C(p_ctx, exc_id)                        \
01465   do {                                                   \
01466     assert((enum cr_exc_id)(exc_id) != CR_EXC_ID__NONE); \
01467     /* clear need_return flag */                         \
01468     (p_ctx)->thrown_exc = (exc_id);                      \
01469     goto _cr_iter_begin;                                 \
01470   } while (0)
01471 
01472 /*
01473  * Get latest returned value from the given "function".
01474  *
01475  * `fid`: id of the function which returned value. Needed to ret value value
01476  * from the right field in the `(p_ctx)->arg_retval.ret` (different functions
01477  * may have different return types)
01478  */
01479 #define CR_RETURNED_C(p_ctx, fid) (CR_ARG_RET_PT_C(p_ctx)->ret.fid)
01480 
01481 /*
01482  * Get currently thrown exception id. If nothing is being thrown at the moment,
01483  * `CR_EXC_ID__NONE` is returned
01484  */
01485 #define CR_THROWN_C(p_ctx) ((p_ctx)->thrown_exc)
01486 
01487 /*
01488  * Like `sizeof()`, but it always evaluates to the multiple of `sizeof(void *)`
01489  *
01490  * It should be used for (struct cr_func_desc)::locals_size
01491  *
01492  * NOTE: instead of checking `sizeof(type) <= ((cr_locals_size_t) -1)`, I'd
01493  * better put the calculated value as it is, and if it overflows, then compiler
01494  * will generate warning, and this would help us to reveal our mistake. But
01495  * unfortunately, clang *always* generates this warning (even if the whole
01496  * expression yields 0), so we have to apply a bit more of dirty hacks here.
01497  */
01498 #define CR_LOCALS_SIZEOF(type)                                                \
01499   ((sizeof(type) == sizeof(cr_zero_size_type_t))                              \
01500        ? 0                                                                    \
01501        : (sizeof(type) <= ((cr_locals_size_t) -1)                             \
01502               ? ((cr_locals_size_t)(((sizeof(type)) + (sizeof(void *) - 1)) & \
01503                                     (~(sizeof(void *) - 1))))                 \
01504               : ((cr_locals_size_t) -1)))
01505 
01506 #define CR_ARG_SIZEOF(type) \
01507   ((sizeof(type) == sizeof(cr_zero_size_type_t)) ? 0 : sizeof(type))
01508 
01509 /*
01510  * Returns pointer to the current function's stack locals, and casts to given
01511  * type.
01512  *
01513  * Typical usage might look as follows:
01514  *
01515  *    #undef L
01516  *    #define L CR_CUR_LOCALS_PT(p_ctx, struct my_foo_locals)
01517  *
01518  * Then, assuming `struct my_foo_locals` has the field `bar`, we can access it
01519  * like this:
01520  *
01521  *    L->bar
01522  */
01523 #define CR_CUR_LOCALS_PT_C(p_ctx, type) ((type *) ((p_ctx)->p_cur_func_locals))
01524 
01525 /*
01526  * Returns pointer to the user-defined union of arguments and return values:
01527  * `union user_arg_ret`
01528  */
01529 #define CR_ARG_RET_PT_C(p_ctx) ((p_ctx)->p_arg_retval)
01530 
01531 #define CR_ARG_RET_PT() CR_ARG_RET_PT_C(p_ctx)
01532 
01533 #define CR_CUR_LOCALS_PT(type) CR_CUR_LOCALS_PT_C(p_ctx, type)
01534 
01535 #define CR_CURR_FUNC() CR_CURR_FUNC_C(p_ctx)
01536 
01537 #define CR_CALL(call_fid, local_ret_fid) \
01538   CR_CALL_C(p_ctx, call_fid, local_ret_fid)
01539 
01540 #define CR_RETURN(cur_fid, retval) CR_RETURN_C(p_ctx, cur_fid, retval)
01541 
01542 #define CR_RETURN_VOID() CR_RETURN_VOID_C(p_ctx)
01543 
01544 #define CR_RETURNED(fid) CR_RETURNED_C(p_ctx, fid)
01545 
01546 #define CR_YIELD(value, local_ret_fid) CR_YIELD_C(p_ctx, value, local_ret_fid)
01547 
01548 #define CR_YIELDED() CR_YIELDED_C(p_ctx)
01549 
01550 #define CR_RESUME(value) CR_RESUME_C(p_ctx, value)
01551 
01552 #define CR_RESUMED() CR_RESUMED_C(p_ctx)
01553 
01554 #define CR_TRY(catch_name) CR_TRY_C(p_ctx, catch_name)
01555 
01556 #define CR_CATCH(exc_id, catch_name, next_catch_name) \
01557   CR_CATCH_C(p_ctx, exc_id, catch_name, next_catch_name)
01558 
01559 #define CR_ENDCATCH(endcatch_name) CR_ENDCATCH_C(p_ctx, endcatch_name)
01560 
01561 #define CR_THROW(exc_id) CR_THROW_C(p_ctx, exc_id)
01562 
01563 /* Private macros {{{ */
01564 
01565 #define _CR_CUR_FUNC_LOCALS_UPD(p_ctx)                                 \
01566   do {                                                                 \
01567     (p_ctx)->p_cur_func_locals = (uint8_t *) (p_ctx)->stack_data.buf + \
01568                                  (p_ctx)->stack_data.len -             \
01569                                  _CR_CURR_FUNC_LOCALS_SIZE(p_ctx);     \
01570   } while (0)
01571 
01572 /*
01573  * Size of the stack needed for each try-catch block.
01574  * Use `_CR_TRY_MARKER()` and `_CR_TRY_CATCH_FID()` to get/set parts.
01575  */
01576 #define _CR_TRY_SIZE 2 /*CR_FID__TRY_MARKER, catch_fid*/
01577 
01578 /*
01579  * Evaluates to lvalue where `CR_FID__TRY_MARKER` should be stored
01580  */
01581 #define _CR_TRY_MARKER(p_ctx) \
01582   *(((uint8_t *) (p_ctx)->stack_ret.buf) + (p_ctx)->stack_ret.len - 1)
01583 
01584 /*
01585  * Evaluates to lvalue where `catch_fid` should be stored
01586  */
01587 #define _CR_TRY_CATCH_FID(p_ctx) \
01588   *(((uint8_t *) (p_ctx)->stack_ret.buf) + (p_ctx)->stack_ret.len - 2)
01589 
01590 #define _CR_CURR_FUNC_LOCALS_SIZE(p_ctx) \
01591   ((p_ctx)->p_func_descrs[CR_CURR_FUNC_C(p_ctx)].locals_size)
01592 
01593 /*
01594  * Prepare context for calling next function.
01595  *
01596  * See comments for `CR_CALL()` macro.
01597  */
01598 #define _CR_CALL_PREPARE(p_ctx, _call_fid, _locals_size, _arg_size, \
01599                          local_ret_fid)                             \
01600   do {                                                              \
01601     /* adjust return func id */                                     \
01602     CR_CURR_FUNC_C(p_ctx) = (local_ret_fid);                        \
01603                                                                     \
01604     /* set called_fid */                                            \
01605     (p_ctx)->called_fid = (_call_fid);                              \
01606                                                                     \
01607     /* set sizes: locals and arg */                                 \
01608     (p_ctx)->call_locals_size = (_locals_size);                     \
01609     (p_ctx)->call_arg_size = (_arg_size);                           \
01610   } while (0)
01611 
01612 #define _CR_STACK_DATA_OVF_CHECK(p_ctx, inc) (0)
01613 
01614 #define _CR_STACK_DATA_UND_CHECK(p_ctx, dec) ((p_ctx)->stack_data.len < (dec))
01615 
01616 #define _CR_STACK_RET_OVF_CHECK(p_ctx, inc) (0)
01617 
01618 #define _CR_STACK_RET_UND_CHECK(p_ctx, dec) ((p_ctx)->stack_ret.len < (dec))
01619 
01620 #define _CR_STACK_FID_OVF_CHECK(p_ctx, inc) (0)
01621 
01622 #define _CR_STACK_FID_UND_CHECK(p_ctx, dec) ((p_ctx)->cur_fid_idx < (dec))
01623 
01624 #if defined(CR_TRACK_MAX_STACK_LEN)
01625 
01626 #define _CR_STACK_DATA_ALLOC(p_ctx, inc)                         \
01627   do {                                                           \
01628     mbuf_append(&((p_ctx)->stack_data), NULL, (inc));            \
01629     if ((p_ctx)->stack_data_max_len < (p_ctx)->stack_data.len) { \
01630       (p_ctx)->stack_data_max_len = (p_ctx)->stack_data.len;     \
01631     }                                                            \
01632   } while (0)
01633 
01634 #define _CR_STACK_RET_ALLOC(p_ctx, inc)                        \
01635   do {                                                         \
01636     mbuf_append(&((p_ctx)->stack_ret), NULL, (inc));           \
01637     if ((p_ctx)->stack_ret_max_len < (p_ctx)->stack_ret.len) { \
01638       (p_ctx)->stack_ret_max_len = (p_ctx)->stack_ret.len;     \
01639     }                                                          \
01640   } while (0)
01641 
01642 #else
01643 
01644 #define _CR_STACK_DATA_ALLOC(p_ctx, inc)              \
01645   do {                                                \
01646     mbuf_append(&((p_ctx)->stack_data), NULL, (inc)); \
01647   } while (0)
01648 
01649 #define _CR_STACK_RET_ALLOC(p_ctx, inc)              \
01650   do {                                               \
01651     mbuf_append(&((p_ctx)->stack_ret), NULL, (inc)); \
01652   } while (0)
01653 
01654 #endif
01655 
01656 #define _CR_STACK_DATA_FREE(p_ctx, dec) \
01657   do {                                  \
01658     (p_ctx)->stack_data.len -= (dec);   \
01659   } while (0)
01660 
01661 #define _CR_STACK_RET_FREE(p_ctx, dec) \
01662   do {                                 \
01663     (p_ctx)->stack_ret.len -= (dec);   \
01664   } while (0)
01665 
01666 #define _CR_STACK_FID_ALLOC(p_ctx, inc) \
01667   do {                                  \
01668     (p_ctx)->cur_fid_idx += (inc);      \
01669   } while (0)
01670 
01671 #define _CR_STACK_FID_FREE(p_ctx, dec) \
01672   do {                                 \
01673     (p_ctx)->cur_fid_idx -= (dec);     \
01674   } while (0)
01675 
01676 /* }}} */
01677 
01678 /*
01679  * Should be used in eval loop right after `_cr_iter_begin:` label
01680  */
01681 enum cr_status cr_on_iter_begin(struct cr_ctx *p_ctx);
01682 
01683 /*
01684  * Initialize context `p_ctx`.
01685  *
01686  * `p_arg_retval`: pointer to the user-defined `union user_arg_ret`
01687  *
01688  * `p_func_descrs`: array of all user function descriptors
01689  */
01690 void cr_context_init(struct cr_ctx *p_ctx, union user_arg_ret *p_arg_retval,
01691                      size_t arg_retval_size,
01692                      const struct cr_func_desc *p_func_descrs);
01693 
01694 /*
01695  * free resources occupied by context (at least, "stack" arrays)
01696  */
01697 void cr_context_free(struct cr_ctx *p_ctx);
01698 
01699 #endif /* CS_COMMON_COROUTINE_H_ */
01700 #ifdef V7_MODULE_LINES
01701 #line 1 "v7/src/features_profiles.h"
01702 #endif
01703 /*
01704  * Copyright (c) 2014 Cesanta Software Limited
01705  * All rights reserved
01706  */
01707 
01708 #ifndef CS_V7_SRC_FEATURES_PROFILES_H_
01709 #define CS_V7_SRC_FEATURES_PROFILES_H_
01710 
01711 #define V7_BUILD_PROFILE_MINIMAL 1
01712 #define V7_BUILD_PROFILE_MEDIUM 2
01713 #define V7_BUILD_PROFILE_FULL 3
01714 
01715 #ifndef V7_BUILD_PROFILE
01716 #define V7_BUILD_PROFILE V7_BUILD_PROFILE_FULL
01717 #endif
01718 
01719 #endif /* CS_V7_SRC_FEATURES_PROFILES_H_ */
01720 #ifdef V7_MODULE_LINES
01721 #line 1 "v7/src/features_minimal.h"
01722 #endif
01723 /*
01724  * Copyright (c) 2014 Cesanta Software Limited
01725  * All rights reserved
01726  */
01727 
01728 /* Amalgamated: #include "v7/src/features_profiles.h" */
01729 
01730 #if V7_BUILD_PROFILE == V7_BUILD_PROFILE_MINIMAL
01731 
01732 /* This space is intentionally left blank. */
01733 
01734 #endif /* CS_V7_SRC_FEATURES_MINIMAL_H_ */
01735 #ifdef V7_MODULE_LINES
01736 #line 1 "v7/src/features_medium.h"
01737 #endif
01738 /*
01739  * Copyright (c) 2014 Cesanta Software Limited
01740  * All rights reserved
01741  */
01742 
01743 /* Amalgamated: #include "v7/src/features_profiles.h" */
01744 
01745 #if V7_BUILD_PROFILE == V7_BUILD_PROFILE_MEDIUM
01746 
01747 #define V7_ENABLE__Date 1
01748 #define V7_ENABLE__Date__now 1
01749 #define V7_ENABLE__Date__UTC 1
01750 #define V7_ENABLE__Math 1
01751 #define V7_ENABLE__Math__atan2 1
01752 #define V7_ENABLE__RegExp 1
01753 
01754 #endif /* CS_V7_SRC_FEATURES_MEDIUM_H_ */
01755 #ifdef V7_MODULE_LINES
01756 #line 1 "v7/src/features_full.h"
01757 #endif
01758 /*
01759  * Copyright (c) 2014 Cesanta Software Limited
01760  * All rights reserved
01761  */
01762 
01763 #ifndef CS_V7_SRC_FEATURES_FULL_H_
01764 #define CS_V7_SRC_FEATURES_FULL_H_
01765 
01766 /* Amalgamated: #include "v7/src/features_profiles.h" */
01767 
01768 #if V7_BUILD_PROFILE == V7_BUILD_PROFILE_FULL
01769 /*
01770  * DO NOT EDIT.
01771  * This file is generated by scripts/gen-features-full.pl.
01772  */
01773 #ifndef CS_ENABLE_UTF8
01774 #define CS_ENABLE_UTF8 1
01775 #endif
01776 
01777 #define V7_ENABLE__Array__reduce 1
01778 #define V7_ENABLE__Blob 1
01779 #define V7_ENABLE__Date 1
01780 #define V7_ENABLE__Date__UTC 1
01781 #define V7_ENABLE__Date__getters 1
01782 #define V7_ENABLE__Date__now 1
01783 #define V7_ENABLE__Date__parse 1
01784 #define V7_ENABLE__Date__setters 1
01785 #define V7_ENABLE__Date__toJSON 1
01786 #define V7_ENABLE__Date__toLocaleString 1
01787 #define V7_ENABLE__Date__toString 1
01788 #define V7_ENABLE__File__list 1
01789 #define V7_ENABLE__File__require 1
01790 #define V7_ENABLE__Function__bind 1
01791 #define V7_ENABLE__Function__call 1
01792 #define V7_ENABLE__Math 1
01793 #define V7_ENABLE__Math__abs 1
01794 #define V7_ENABLE__Math__acos 1
01795 #define V7_ENABLE__Math__asin 1
01796 #define V7_ENABLE__Math__atan 1
01797 #define V7_ENABLE__Math__atan2 1
01798 #define V7_ENABLE__Math__ceil 1
01799 #define V7_ENABLE__Math__constants 1
01800 #define V7_ENABLE__Math__cos 1
01801 #define V7_ENABLE__Math__exp 1
01802 #define V7_ENABLE__Math__floor 1
01803 #define V7_ENABLE__Math__log 1
01804 #define V7_ENABLE__Math__max 1
01805 #define V7_ENABLE__Math__min 1
01806 #define V7_ENABLE__Math__pow 1
01807 #define V7_ENABLE__Math__random 1
01808 #define V7_ENABLE__Math__round 1
01809 #define V7_ENABLE__Math__sin 1
01810 #define V7_ENABLE__Math__sqrt 1
01811 #define V7_ENABLE__Math__tan 1
01812 #define V7_ENABLE__Memory__stats 1
01813 #define V7_ENABLE__NUMBER__NEGATIVE_INFINITY 1
01814 #define V7_ENABLE__NUMBER__POSITIVE_INFINITY 1
01815 #define V7_ENABLE__Object__create 1
01816 #define V7_ENABLE__Object__defineProperties 1
01817 #define V7_ENABLE__Object__getOwnPropertyDescriptor 1
01818 #define V7_ENABLE__Object__getOwnPropertyNames 1
01819 #define V7_ENABLE__Object__getPrototypeOf 1
01820 #define V7_ENABLE__Object__hasOwnProperty 1
01821 #define V7_ENABLE__Object__isExtensible 1
01822 #define V7_ENABLE__Object__isFrozen 1
01823 #define V7_ENABLE__Object__isPrototypeOf 1
01824 #define V7_ENABLE__Object__isSealed 1
01825 #define V7_ENABLE__Object__keys 1
01826 #define V7_ENABLE__Object__preventExtensions 1
01827 #define V7_ENABLE__Object__propertyIsEnumerable 1
01828 #define V7_ENABLE__Proxy 1
01829 #define V7_ENABLE__RegExp 1
01830 #define V7_ENABLE__StackTrace 1
01831 #define V7_ENABLE__String__localeCompare 1
01832 #define V7_ENABLE__String__localeLowerCase 1
01833 #define V7_ENABLE__String__localeUpperCase 1
01834 
01835 #endif /* V7_BUILD_PROFILE == V7_BUILD_PROFILE_FULL */
01836 
01837 #endif /* CS_V7_SRC_FEATURES_FULL_H_ */
01838 #ifdef V7_MODULE_LINES
01839 #line 1 "v7/src/v7_features.h"
01840 #endif
01841 /*
01842  * Copyright (c) 2014 Cesanta Software Limited
01843  * All rights reserved
01844  */
01845 
01846 #ifndef CS_V7_SRC_V7_FEATURES_H_
01847 #define CS_V7_SRC_V7_FEATURES_H_
01848 
01849 /* Only one will actually be used based on V7_BUILD_PROFILE. */
01850 /* Amalgamated: #include "v7/src/features_minimal.h" */
01851 /* Amalgamated: #include "v7/src/features_medium.h" */
01852 /* Amalgamated: #include "v7/src/features_full.h" */
01853 
01854 #endif /* CS_V7_SRC_V7_FEATURES_H_ */
01855 #ifdef V7_MODULE_LINES
01856 #line 1 "v7/src/platform.h"
01857 #endif
01858 /*
01859  * Copyright (c) 2014 Cesanta Software Limited
01860  * All rights reserved
01861  */
01862 
01863 #ifndef CS_V7_SRC_PLATFORM_H_
01864 #define CS_V7_SRC_PLATFORM_H_
01865 
01866 #ifdef __arm
01867 #undef V7_ENABLE__Date
01868 #define V7_ENABLE__Date 0
01869 #endif
01870 
01871 #endif /* CS_V7_SRC_PLATFORM_H_ */
01872 #ifdef V7_MODULE_LINES
01873 #line 1 "v7/src/internal.h"
01874 #endif
01875 /*
01876  * Copyright (c) 2014 Cesanta Software Limited
01877  * All rights reserved
01878  */
01879 
01880 #ifndef CS_V7_SRC_INTERNAL_H_
01881 #define CS_V7_SRC_INTERNAL_H_
01882 
01883 /* Amalgamated: #include "v7/src/license.h" */
01884 
01885 /* Check whether we're compiling in an environment with no filesystem */
01886 #if defined(ARDUINO) && (ARDUINO == 106)
01887 #define V7_NO_FS
01888 #endif
01889 
01890 #ifndef FAST
01891 #define FAST
01892 #endif
01893 
01894 #ifndef STATIC
01895 #define STATIC
01896 #endif
01897 
01898 #ifndef ENDL
01899 #define ENDL "\n"
01900 #endif
01901 
01902 /*
01903  * In some compilers (watcom) NAN == NAN (and other comparisons) don't follow
01904  * the rules of IEEE 754. Since we don't know a priori which compilers
01905  * will generate correct code, we disable the fallback on selected platforms.
01906  * TODO(mkm): selectively disable on clang/gcc once we test this out.
01907  */
01908 #define V7_BROKEN_NAN
01909 
01910 #undef _POSIX_C_SOURCE
01911 #define _POSIX_C_SOURCE 200809L
01912 
01913 #include <assert.h>
01914 #ifndef NO_LIBC
01915 #include <ctype.h>
01916 #endif
01917 #include <errno.h>
01918 #include <float.h>
01919 #include <limits.h>
01920 #include <math.h>
01921 #include <stdarg.h>
01922 #include <stddef.h>
01923 #include <stdio.h>
01924 #include <stdlib.h>
01925 #include <string.h>
01926 #include <setjmp.h>
01927 
01928 /* Public API. Implemented in api.c */
01929 /* Amalgamated: #include "common/platform.h" */
01930 
01931 #ifdef V7_WINDOWS
01932 #define vsnprintf _vsnprintf
01933 #define snprintf _snprintf
01934 
01935 /* VS2015 Update 1 has ISO C99 `isnan` and `isinf` defined in math.h */
01936 #if _MSC_FULL_VER < 190023506
01937 #define isnan(x) _isnan(x)
01938 #define isinf(x) (!_finite(x))
01939 #endif
01940 
01941 #define __unused __pragma(warning(suppress : 4100))
01942 typedef __int64 int64_t;
01943 typedef int int32_t;
01944 typedef unsigned int uint32_t;
01945 typedef unsigned short uint16_t;
01946 typedef unsigned char uint8_t;
01947 
01948 /* For 64bit VisualStudio 2010 */
01949 #ifndef _UINTPTR_T_DEFINED
01950 typedef unsigned long uintptr_t;
01951 #endif
01952 
01953 #ifndef __func__
01954 #define __func__ ""
01955 #endif
01956 
01957 #else
01958 #include <stdint.h>
01959 #endif
01960 
01961 /* Amalgamated: #include "v7/src/v7_features.h" */
01962 /* Amalgamated: #include "v7/src/platform.h" */
01963 
01964 /* MSVC6 doesn't have standard C math constants defined */
01965 #ifndef M_E
01966 #define M_E 2.71828182845904523536028747135266250
01967 #endif
01968 
01969 #ifndef M_LOG2E
01970 #define M_LOG2E 1.44269504088896340735992468100189214
01971 #endif
01972 
01973 #ifndef M_LOG10E
01974 #define M_LOG10E 0.434294481903251827651128918916605082
01975 #endif
01976 
01977 #ifndef M_LN2
01978 #define M_LN2 0.693147180559945309417232121458176568
01979 #endif
01980 
01981 #ifndef M_LN10
01982 #define M_LN10 2.30258509299404568401799145468436421
01983 #endif
01984 
01985 #ifndef M_PI
01986 #define M_PI 3.14159265358979323846264338327950288
01987 #endif
01988 
01989 #ifndef M_SQRT2
01990 #define M_SQRT2 1.41421356237309504880168872420969808
01991 #endif
01992 
01993 #ifndef M_SQRT1_2
01994 #define M_SQRT1_2 0.707106781186547524400844362104849039
01995 #endif
01996 
01997 #ifndef NAN
01998 extern double _v7_nan;
01999 #define HAS_V7_NAN
02000 #define NAN (_v7_nan)
02001 #endif
02002 
02003 #ifndef INFINITY
02004 extern double _v7_infinity;
02005 #define HAS_V7_INFINITY
02006 #define INFINITY (_v7_infinity)
02007 #endif
02008 
02009 #ifndef EXIT_SUCCESS
02010 #define EXIT_SUCCESS 0
02011 #endif
02012 
02013 #ifndef EXIT_FAILURE
02014 #define EXIT_FAILURE 1
02015 #endif
02016 
02017 #if defined(V7_ENABLE_GC_CHECK) || defined(V7_STACK_GUARD_MIN_SIZE) || \
02018     defined(V7_ENABLE_STACK_TRACKING) || defined(V7_ENABLE_CALL_TRACE)
02019 /* Need to enable GCC/clang instrumentation */
02020 #define V7_CYG_PROFILE_ON
02021 #endif
02022 
02023 #if defined(V7_CYG_PROFILE_ON)
02024 extern struct v7 *v7_head;
02025 
02026 #if defined(V7_STACK_GUARD_MIN_SIZE)
02027 extern void *v7_sp_limit;
02028 #endif
02029 #endif
02030 
02031 #ifndef ARRAY_SIZE
02032 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
02033 #endif
02034 
02035 #define V7_STATIC_ASSERT(COND, MSG) \
02036   typedef char static_assertion_##MSG[2 * (!!(COND)) - 1]
02037 
02038 #define BUF_LEFT(size, used) (((size_t)(used) < (size)) ? ((size) - (used)) : 0)
02039 
02040 #endif /* CS_V7_SRC_INTERNAL_H_ */
02041 #ifdef V7_MODULE_LINES
02042 #line 1 "v7/src/core_public.h"
02043 #endif
02044 /*
02045  * Copyright (c) 2014 Cesanta Software Limited
02046  * All rights reserved
02047  */
02048 
02049 /*
02050  * === Core
02051  */
02052 
02053 #ifndef CS_V7_SRC_CORE_PUBLIC_H_
02054 #define CS_V7_SRC_CORE_PUBLIC_H_
02055 
02056 #ifndef _POSIX_C_SOURCE
02057 #define _POSIX_C_SOURCE 200809L
02058 #endif
02059 
02060 /* Amalgamated: #include "v7/src/license.h" */
02061 /* Amalgamated: #include "v7/src/v7_features.h" */
02062 /* Amalgamated: #include "v7/src/platform.h" */
02063 
02064 #include <stddef.h> /* For size_t */
02065 #include <stdio.h>  /* For FILE */
02066 
02067 #if defined(__cplusplus)
02068 extern "C" {
02069 #endif /* __cplusplus */
02070 
02071 /*
02072  * TODO(dfrank) : improve amalgamation, so that we'll be able to include
02073  * files here, and include common/platform.h
02074  *
02075  * For now, copy-pasting `WARN_UNUSED_RESULT` here
02076  */
02077 #ifdef __GNUC__
02078 #define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
02079 #define NOINSTR __attribute__((no_instrument_function))
02080 #else
02081 #define WARN_UNUSED_RESULT
02082 #define NOINSTR
02083 #endif
02084 
02085 #define V7_VERSION "1.0"
02086 
02087 #if (defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__)) || \
02088     (defined(_MSC_VER) && _MSC_VER <= 1200)
02089 #define V7_WINDOWS
02090 #endif
02091 
02092 #ifdef V7_WINDOWS
02093 typedef unsigned __int64 uint64_t;
02094 #else
02095 #include <inttypes.h>
02096 #endif
02097 /* 64-bit value, used to store JS values */
02098 typedef uint64_t v7_val_t;
02099 
02100 /* JavaScript `null` value */
02101 #define V7_NULL ((uint64_t) 0xfffe << 48)
02102 
02103 /* JavaScript `undefined` value */
02104 #define V7_UNDEFINED ((uint64_t) 0xfffd << 48)
02105 
02106 /* This if-0 is a dirty workaround to force etags to pick `struct v7` */
02107 #if 0
02108 /* Opaque structure. V7 engine context. */
02109 struct v7 {
02110   /* ... */
02111 };
02112 #endif
02113 
02114 struct v7;
02115 
02116 /*
02117  * Code which is returned by some of the v7 functions. If something other than
02118  * `V7_OK` is returned from some function, the caller function typically should
02119  * either immediately cleanup and return the code further, or handle the error.
02120  */
02121 enum v7_err {
02122   V7_OK,
02123   V7_SYNTAX_ERROR,
02124   V7_EXEC_EXCEPTION,
02125   V7_AST_TOO_LARGE,
02126   V7_INTERNAL_ERROR,
02127 };
02128 
02129 /* JavaScript -> C call interface */
02130 WARN_UNUSED_RESULT
02131 typedef enum v7_err(v7_cfunction_t)(struct v7 *v7, v7_val_t *res);
02132 
02133 /* Create V7 instance */
02134 struct v7 *v7_create(void);
02135 
02136 /*
02137  * Customizations of initial V7 state; used by `v7_create_opt()`.
02138  */
02139 struct v7_create_opts {
02140   size_t object_arena_size;
02141   size_t function_arena_size;
02142   size_t property_arena_size;
02143 #ifdef V7_STACK_SIZE
02144   void *c_stack_base;
02145 #endif
02146 #ifdef V7_FREEZE
02147   /* if not NULL, dump JS heap after init */
02148   char *freeze_file;
02149 #endif
02150 };
02151 
02152 /*
02153  * Like `v7_create()`, but allows to customize initial v7 state, see `struct
02154  * v7_create_opts`.
02155  */
02156 struct v7 *v7_create_opt(struct v7_create_opts opts);
02157 
02158 /* Destroy V7 instance */
02159 void v7_destroy(struct v7 *v7);
02160 
02161 /* Return root level (`global`) object of the given V7 instance. */
02162 v7_val_t v7_get_global(struct v7 *v);
02163 
02164 /* Return current `this` object. */
02165 v7_val_t v7_get_this(struct v7 *v);
02166 
02167 /* Return current `arguments` array */
02168 v7_val_t v7_get_arguments(struct v7 *v);
02169 
02170 /* Return i-th argument */
02171 v7_val_t v7_arg(struct v7 *v, unsigned long i);
02172 
02173 /* Return the length of `arguments` */
02174 unsigned long v7_argc(struct v7 *v7);
02175 
02176 /*
02177  * Tells the GC about a JS value variable/field owned
02178  * by C code.
02179  *
02180  * User C code should own v7_val_t variables
02181  * if the value's lifetime crosses any invocation
02182  * to the v7 runtime that creates new objects or new
02183  * properties and thus can potentially trigger GC.
02184  *
02185  * The registration of the variable prevents the GC from mistakenly treat
02186  * the object as garbage. The GC might be triggered potentially
02187  * allows the GC to update pointers
02188  *
02189  * User code should also explicitly disown the variables with v7_disown once
02190  * it goes out of scope or the structure containing the v7_val_t field is freed.
02191  *
02192  * Example:
02193  *
02194  *  ```
02195  *    struct v7_val cb;
02196  *    v7_own(v7, &cb);
02197  *    cb = v7_array_get(v7, args, 0);
02198  *    // do something with cb
02199  *    v7_disown(v7, &cb);
02200  *  ```
02201  */
02202 void v7_own(struct v7 *v7, v7_val_t *v);
02203 
02204 /*
02205  * Returns 1 if value is found, 0 otherwise
02206  */
02207 int v7_disown(struct v7 *v7, v7_val_t *v);
02208 
02209 /*
02210  * Enable or disable GC.
02211  *
02212  * Must be called before invoking v7_exec or v7_apply
02213  * from within a cfunction unless you know what you're doing.
02214  *
02215  * GC is disabled during execution of cfunctions in order to simplify
02216  * memory management of simple cfunctions.
02217  * However executing even small snippets of JS code causes a lot of memory
02218  * pressure. Enabling GC solves that but forces you to take care of the
02219  * reachability of your temporary V7 v7_val_t variables, as the GC needs
02220  * to know where they are since objects and strings can be either reclaimed
02221  * or relocated during a GC pass.
02222  */
02223 void v7_set_gc_enabled(struct v7 *v7, int enabled);
02224 
02225 /*
02226  * Set an optional C stack limit.
02227  *
02228  * It sets a flag that will cause the interpreter
02229  * to throw an InterruptedError.
02230  * It's safe to call it from signal handlers and ISRs
02231  * on single threaded environments.
02232  */
02233 void v7_interrupt(struct v7 *v7);
02234 
02235 /* Returns last parser error message. TODO: rename it to `v7_get_error()` */
02236 const char *v7_get_parser_error(struct v7 *v7);
02237 
02238 #if defined(V7_ENABLE_STACK_TRACKING)
02239 /*
02240  * Available if only `V7_ENABLE_STACK_TRACKING` is defined.
02241  *
02242  * Stack metric id. See `v7_stack_stat()`
02243  */
02244 enum v7_stack_stat_what {
02245   /* max stack size consumed by `i_exec()` */
02246   V7_STACK_STAT_EXEC,
02247   /* max stack size consumed by `parse()` (which is called from `i_exec()`) */
02248   V7_STACK_STAT_PARSER,
02249 
02250   V7_STACK_STATS_CNT
02251 };
02252 
02253 /*
02254  * Available if only `V7_ENABLE_STACK_TRACKING` is defined.
02255  *
02256  * Returns stack metric specified by the metric id `what`. See
02257  * `v7_stack_stat_clean()`
02258  */
02259 int v7_stack_stat(struct v7 *v7, enum v7_stack_stat_what what);
02260 
02261 /*
02262  * Available if only `V7_ENABLE_STACK_TRACKING` is defined.
02263  *
02264  * Clean all stack statistics gathered so far. See `v7_stack_stat()`
02265  */
02266 void v7_stack_stat_clean(struct v7 *v7);
02267 #endif
02268 
02269 #if defined(__cplusplus)
02270 }
02271 #endif /* __cplusplus */
02272 
02273 #endif /* CS_V7_SRC_CORE_PUBLIC_H_ */
02274 #ifdef V7_MODULE_LINES
02275 #line 1 "v7/src/std_error.h"
02276 #endif
02277 /*
02278  * Copyright (c) 2014 Cesanta Software Limited
02279  * All rights reserved
02280  */
02281 
02282 #ifndef CS_V7_SRC_STD_ERROR_H_
02283 #define CS_V7_SRC_STD_ERROR_H_
02284 
02285 /* Amalgamated: #include "v7/src/license.h" */
02286 
02287 struct v7;
02288 
02289 /*
02290  * JavaScript error types
02291  */
02292 #define TYPE_ERROR "TypeError"
02293 #define SYNTAX_ERROR "SyntaxError"
02294 #define REFERENCE_ERROR "ReferenceError"
02295 #define INTERNAL_ERROR "InternalError"
02296 #define RANGE_ERROR "RangeError"
02297 #define EVAL_ERROR "EvalError"
02298 #define ERROR_CTOR_MAX 6
02299 /*
02300  * TODO(mkm): EvalError is not so important, we should guard it behind
02301  * something like `V7_ENABLE__EvalError`. However doing so makes it hard to
02302  * keep ERROR_CTOR_MAX up to date; perhaps let's find a better way of doing it.
02303  *
02304  * EvalError is useful mostly because we now have ecma tests failing:
02305  *
02306  * 8129 FAIL ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-7-c-iii-24.js (tail -c
02307  * +7600043 tests/ecmac.db|head -c 496): [{"message":"[EvalError] is not
02308  * defined"}]
02309  *
02310  * Those tests are not EvalError specific, and they do test that the exception
02311  * handling machinery works as intended.
02312  */
02313 
02314 #if defined(__cplusplus)
02315 extern "C" {
02316 #endif /* __cplusplus */
02317 
02318 V7_PRIVATE void init_error(struct v7 *v7);
02319 
02320 #if defined(__cplusplus)
02321 }
02322 #endif /* __cplusplus */
02323 
02324 #endif /* CS_V7_SRC_STD_ERROR_H_ */
02325 #ifdef V7_MODULE_LINES
02326 #line 1 "v7/src/mm.h"
02327 #endif
02328 /*
02329  * Copyright (c) 2014 Cesanta Software Limited
02330  * All rights reserved
02331  */
02332 
02333 #ifndef CS_V7_SRC_MM_H_
02334 #define CS_V7_SRC_MM_H_
02335 
02336 /* Amalgamated: #include "v7/src/internal.h" */
02337 
02338 typedef void (*gc_cell_destructor_t)(struct v7 *v7, void *);
02339 
02340 struct gc_block {
02341   struct gc_block *next;
02342   struct gc_cell *base;
02343   size_t size;
02344 };
02345 
02346 struct gc_arena {
02347   struct gc_block *blocks;
02348   size_t size_increment;
02349   struct gc_cell *free; /* head of free list */
02350   size_t cell_size;
02351 
02352 #if V7_ENABLE__Memory__stats
02353   unsigned long allocations; /* cumulative counter of allocations */
02354   unsigned long garbage;     /* cumulative counter of garbage */
02355   unsigned long alive;       /* number of living cells */
02356 #endif
02357 
02358   gc_cell_destructor_t destructor;
02359 
02360   int verbose;
02361   const char *name; /* for debugging purposes */
02362 };
02363 
02364 #endif /* CS_V7_SRC_MM_H_ */
02365 #ifdef V7_MODULE_LINES
02366 #line 1 "v7/src/parser.h"
02367 #endif
02368 /*
02369  * Copyright (c) 2014 Cesanta Software Limited
02370  * All rights reserved
02371  */
02372 
02373 #ifndef CS_V7_SRC_PARSER_H_
02374 #define CS_V7_SRC_PARSER_H_
02375 
02376 /* Amalgamated: #include "v7/src/internal.h" */
02377 /* Amalgamated: #include "v7/src/core_public.h" */
02378 
02379 #if !defined(V7_NO_COMPILER)
02380 
02381 struct v7;
02382 struct ast;
02383 
02384 #if defined(__cplusplus)
02385 extern "C" {
02386 #endif /* __cplusplus */
02387 
02388 struct v7_pstate {
02389   const char *file_name;
02390   const char *source_code;
02391   const char *pc;      /* Current parsing position */
02392   const char *src_end; /* End of source code */
02393   int line_no;         /* Line number */
02394   int prev_line_no;    /* Line number of previous token */
02395   int inhibit_in;      /* True while `in` expressions are inhibited */
02396   int in_function;     /* True if in a function */
02397   int in_loop;         /* True if in a loop */
02398   int in_switch;       /* True if in a switch block */
02399   int in_strict;       /* True if in strict mode */
02400 };
02401 
02402 V7_PRIVATE enum v7_err parse(struct v7 *v7, struct ast *a, const char *src,
02403                              size_t src_len, int is_json);
02404 
02405 #if defined(__cplusplus)
02406 }
02407 #endif /* __cplusplus */
02408 
02409 #endif /* V7_NO_COMPILER */
02410 
02411 #endif /* CS_V7_SRC_PARSER_H_ */
02412 #ifdef V7_MODULE_LINES
02413 #line 1 "v7/src/object_public.h"
02414 #endif
02415 /*
02416  * Copyright (c) 2014 Cesanta Software Limited
02417  * All rights reserved
02418  */
02419 
02420 /*
02421  * === Objects
02422  */
02423 
02424 #ifndef CS_V7_SRC_OBJECT_PUBLIC_H_
02425 #define CS_V7_SRC_OBJECT_PUBLIC_H_
02426 
02427 /* Amalgamated: #include "v7/src/core_public.h" */
02428 
02429 #if defined(__cplusplus)
02430 extern "C" {
02431 #endif /* __cplusplus */
02432 
02433 /*
02434  * Property attributes bitmask
02435  */
02436 typedef unsigned short v7_prop_attr_t;
02437 #define V7_PROPERTY_NON_WRITABLE (1 << 0)
02438 #define V7_PROPERTY_NON_ENUMERABLE (1 << 1)
02439 #define V7_PROPERTY_NON_CONFIGURABLE (1 << 2)
02440 #define V7_PROPERTY_GETTER (1 << 3)
02441 #define V7_PROPERTY_SETTER (1 << 4)
02442 #define _V7_PROPERTY_HIDDEN (1 << 5)
02443 /* property not managed by V7 HEAP */
02444 #define _V7_PROPERTY_OFF_HEAP (1 << 6)
02445 /* special property holding user data and destructor cb */
02446 #define _V7_PROPERTY_USER_DATA_AND_DESTRUCTOR (1 << 7)
02447 /*
02448  * not a property attribute, but a flag for `v7_def()`. It's here in order to
02449  * keep all offsets in one place
02450  */
02451 #define _V7_DESC_PRESERVE_VALUE (1 << 8)
02452 
02453 #define V7_PROP_ATTR_IS_WRITABLE(a) (!(a & V7_PROPERTY_NON_WRITABLE))
02454 #define V7_PROP_ATTR_IS_ENUMERABLE(a) (!(a & V7_PROPERTY_NON_ENUMERABLE))
02455 #define V7_PROP_ATTR_IS_CONFIGURABLE(a) (!(a & V7_PROPERTY_NON_CONFIGURABLE))
02456 
02457 /*
02458  * Internal helpers for `V7_DESC_...` macros
02459  */
02460 #define _V7_DESC_SHIFT 16
02461 #define _V7_DESC_MASK ((1 << _V7_DESC_SHIFT) - 1)
02462 #define _V7_MK_DESC(v, n) \
02463   (((v7_prop_attr_desc_t)(n)) << _V7_DESC_SHIFT | ((v) ? (n) : 0))
02464 #define _V7_MK_DESC_INV(v, n) _V7_MK_DESC(!(v), (n))
02465 
02466 /*
02467  * Property attribute descriptors that may be given to `v7_def()`: for each
02468  * attribute (`v7_prop_attr_t`), there is a corresponding macro, which takes
02469  * param: either 1 (set attribute) or 0 (clear attribute). If some particular
02470  * attribute isn't mentioned at all, it's left unchanged (or default, if the
02471  * property is being created)
02472  *
02473  * There is additional flag: `V7_DESC_PRESERVE_VALUE`. If it is set, the
02474  * property value isn't changed (or set to `undefined` if the property is being
02475  * created)
02476  */
02477 typedef unsigned long v7_prop_attr_desc_t;
02478 #define V7_DESC_WRITABLE(v) _V7_MK_DESC_INV(v, V7_PROPERTY_NON_WRITABLE)
02479 #define V7_DESC_ENUMERABLE(v) _V7_MK_DESC_INV(v, V7_PROPERTY_NON_ENUMERABLE)
02480 #define V7_DESC_CONFIGURABLE(v) _V7_MK_DESC_INV(v, V7_PROPERTY_NON_CONFIGURABLE)
02481 #define V7_DESC_GETTER(v) _V7_MK_DESC(v, V7_PROPERTY_GETTER)
02482 #define V7_DESC_SETTER(v) _V7_MK_DESC(v, V7_PROPERTY_SETTER)
02483 #define V7_DESC_PRESERVE_VALUE _V7_DESC_PRESERVE_VALUE
02484 
02485 #define _V7_DESC_HIDDEN(v) _V7_MK_DESC(v, _V7_PROPERTY_HIDDEN)
02486 #define _V7_DESC_OFF_HEAP(v) _V7_MK_DESC(v, _V7_PROPERTY_OFF_HEAP)
02487 
02488 /* See `v7_set_destructor_cb` */
02489 typedef void(v7_destructor_cb_t)(struct v7 *v7, void *ud);
02490 
02491 /* Make an empty object */
02492 v7_val_t v7_mk_object(struct v7 *v7);
02493 
02494 /*
02495  * Returns true if the given value is an object or function.
02496  * i.e. it returns true if the value holds properties and can be
02497  * used as argument to `v7_get`, `v7_set` and `v7_def`.
02498  */
02499 int v7_is_object(v7_val_t v);
02500 
02501 /* Set object's prototype. Return old prototype or undefined on error. */
02502 v7_val_t v7_set_proto(struct v7 *v7, v7_val_t obj, v7_val_t proto);
02503 
02504 /* Get object's prototype. */
02505 v7_val_t v7_get_proto(struct v7 *v7, v7_val_t obj);
02506 
02507 /*
02508  * Lookup property `name` in object `obj`. If `obj` holds no such property,
02509  * an `undefined` value is returned.
02510  *
02511  * If `name_len` is ~0, `name` is assumed to be NUL-terminated and
02512  * `strlen(name)` is used.
02513  */
02514 v7_val_t v7_get(struct v7 *v7, v7_val_t obj, const char *name, size_t name_len);
02515 
02516 /*
02517  * Like `v7_get()`, but "returns" value through `res` pointer argument.
02518  * `res` must not be `NULL`.
02519  *
02520  * Caller should check the error code returned, and if it's something other
02521  * than `V7_OK`, perform cleanup and return this code further.
02522  */
02523 WARN_UNUSED_RESULT
02524 enum v7_err v7_get_throwing(struct v7 *v7, v7_val_t obj, const char *name,
02525                             size_t name_len, v7_val_t *res);
02526 
02527 /*
02528  * Define object property, similar to JavaScript `Object.defineProperty()`.
02529  *
02530  * `name`, `name_len` specify property name, `val` is a property value.
02531  * `attrs_desc` is a set of flags which can affect property's attributes,
02532  * see comment of `v7_prop_attr_desc_t` for details.
02533  *
02534  * If `name_len` is ~0, `name` is assumed to be NUL-terminated and
02535  * `strlen(name)` is used.
02536  *
02537  * Returns non-zero on success, 0 on error (e.g. out of memory).
02538  *
02539  * See also `v7_set()`.
02540  */
02541 int v7_def(struct v7 *v7, v7_val_t obj, const char *name, size_t name_len,
02542            v7_prop_attr_desc_t attrs_desc, v7_val_t v);
02543 
02544 /*
02545  * Set object property. Behaves just like JavaScript assignment.
02546  *
02547  * See also `v7_def()`.
02548  */
02549 int v7_set(struct v7 *v7, v7_val_t obj, const char *name, size_t len,
02550            v7_val_t val);
02551 
02552 /*
02553  * A helper function to define object's method backed by a C function `func`.
02554  * `name` must be NUL-terminated.
02555  *
02556  * Return value is the same as for `v7_set()`.
02557  */
02558 int v7_set_method(struct v7 *, v7_val_t obj, const char *name,
02559                   v7_cfunction_t *func);
02560 
02561 /*
02562  * Delete own property `name` of the object `obj`. Does not follow the
02563  * prototype chain.
02564  *
02565  * If `name_len` is ~0, `name` is assumed to be NUL-terminated and
02566  * `strlen(name)` is used.
02567  *
02568  * Returns 0 on success, -1 on error.
02569  */
02570 int v7_del(struct v7 *v7, v7_val_t obj, const char *name, size_t name_len);
02571 
02572 #if V7_ENABLE__Proxy
02573 struct prop_iter_proxy_ctx;
02574 #endif
02575 
02576 /*
02577  * Context for property iteration, see `v7_next_prop()`.
02578  *
02579  * Clients should not interpret contents of this structure, it's here merely to
02580  * allow clients to allocate it not from the heap.
02581  */
02582 struct prop_iter_ctx {
02583 #if V7_ENABLE__Proxy
02584   struct prop_iter_proxy_ctx *proxy_ctx;
02585 #endif
02586   struct v7_property *cur_prop;
02587 
02588   unsigned init : 1;
02589 };
02590 
02591 /*
02592  * Initialize the property iteration context `ctx`, see `v7_next_prop()` for
02593  * usage example.
02594  */
02595 enum v7_err v7_init_prop_iter_ctx(struct v7 *v7, v7_val_t obj,
02596                                   struct prop_iter_ctx *ctx);
02597 
02598 /*
02599  * Destruct the property iteration context `ctx`, see `v7_next_prop()` for
02600  * usage example
02601  */
02602 void v7_destruct_prop_iter_ctx(struct v7 *v7, struct prop_iter_ctx *ctx);
02603 
02604 /*
02605  * Iterate over the `obj`'s properties.
02606  *
02607  * Usage example (here we assume we have some `v7_val_t obj`):
02608  *
02609  *     struct prop_iter_ctx ctx;
02610  *     v7_val_t name, val;
02611  *     v7_prop_attr_t attrs;
02612  *
02613  *     v7_init_prop_iter_ctx(v7, obj, &ctx);
02614  *     while (v7_next_prop(v7, &ctx, &name, &val, &attrs)) {
02615  *       if (V7_PROP_ATTR_IS_ENUMERABLE(attrs)) continue;
02616  *       ...
02617  *     }
02618  *     v7_destruct_prop_iter_ctx(v7, &ctx);
02619  *
02620  * As you see, v7_next_prop will iterate through all properties, including
02621  * non-enumerable ones, and it's your responsibility to test the attributes
02622  * with the provided `V7_PROP_ATTR_*` macros and proceed as you see fit.
02623  */
02624 int v7_next_prop(struct v7 *v7, struct prop_iter_ctx *ctx, v7_val_t *name,
02625                  v7_val_t *value, v7_prop_attr_t *attrs);
02626 
02627 /* Returns true if the object is an instance of a given constructor. */
02628 int v7_is_instanceof(struct v7 *v7, v7_val_t o, const char *c);
02629 
02630 /* Returns true if the object is an instance of a given constructor. */
02631 int v7_is_instanceof_v(struct v7 *v7, v7_val_t o, v7_val_t c);
02632 
02633 /*
02634  * Associates an opaque C value (anything that can be casted to a `void * )
02635  * with an object.
02636  *
02637  * You can achieve a similar effect by just setting a special property with
02638  * a foreign value (see `v7_mk_foreign`), except user data offers the following
02639  * advantages:
02640  *
02641  * 1. You don't have to come up with some arbitrary "special" property name.
02642  * 2. JS scripts cannot access user data by mistake via property lookup.
02643  * 3. The user data is available to the destructor. When the desctructor is
02644  *    invoked you cannot access any of its properties.
02645  * 4. Allows the implementation to use a more compact encoding
02646  *
02647  * Does nothing if `obj` is not a mutable object.
02648  */
02649 void v7_set_user_data(struct v7 *v7, v7_val_t obj, void *ud);
02650 
02651 /*
02652  * Get the opaque user data set with `v7_set_user_data`.
02653  *
02654  * Returns NULL if there is no user data set or if `obj` is not an object.
02655  */
02656 void *v7_get_user_data(struct v7 *v7, v7_val_t obj);
02657 
02658 /*
02659  * Register a callback which will be invoked when a given object gets
02660  * reclaimed by the garbage collector.
02661  *
02662  * The callback will be invoked while garbage collection is still in progress
02663  * and hence the internal state of the JS heap is in an undefined state.
02664  *
02665  * The only v7 API which is safe to use in this callback is `v7_disown()`,
02666  * that's why `v7` pointer is given to it. *Calls to any other v7 functions are
02667  * illegal here*.
02668  *
02669  * The intended use case is to reclaim resources allocated by C code.
02670  */
02671 void v7_set_destructor_cb(struct v7 *v7, v7_val_t obj, v7_destructor_cb_t *d);
02672 
02673 #if defined(__cplusplus)
02674 }
02675 #endif /* __cplusplus */
02676 
02677 #endif /* CS_V7_SRC_OBJECT_PUBLIC_H_ */
02678 #ifdef V7_MODULE_LINES
02679 #line 1 "v7/src/tokenizer.h"
02680 #endif
02681 /*
02682  * Copyright (c) 2014 Cesanta Software Limited
02683  * All rights reserved
02684  */
02685 
02686 #ifndef CS_V7_SRC_TOKENIZER_H_
02687 #define CS_V7_SRC_TOKENIZER_H_
02688 
02689 /* Amalgamated: #include "v7/src/internal.h" */
02690 
02691 #if !defined(V7_NO_COMPILER)
02692 
02693 enum v7_tok {
02694   TOK_END_OF_INPUT,
02695   TOK_NUMBER,
02696   TOK_STRING_LITERAL,
02697   TOK_REGEX_LITERAL,
02698   TOK_IDENTIFIER,
02699 
02700   /* Punctuators */
02701   TOK_OPEN_CURLY,
02702   TOK_CLOSE_CURLY,
02703   TOK_OPEN_PAREN,
02704   TOK_CLOSE_PAREN,
02705   TOK_COMMA,
02706   TOK_OPEN_BRACKET,
02707   TOK_CLOSE_BRACKET,
02708   TOK_DOT,
02709   TOK_COLON,
02710   TOK_SEMICOLON,
02711 
02712   /* Equality ops, in this order */
02713   TOK_EQ,
02714   TOK_EQ_EQ,
02715   TOK_NE,
02716   TOK_NE_NE,
02717 
02718   /* Assigns */
02719   TOK_ASSIGN,
02720   TOK_REM_ASSIGN,
02721   TOK_MUL_ASSIGN,
02722   TOK_DIV_ASSIGN,
02723   TOK_XOR_ASSIGN,
02724   TOK_PLUS_ASSIGN,
02725   TOK_MINUS_ASSIGN,
02726   TOK_OR_ASSIGN,
02727   TOK_AND_ASSIGN,
02728   TOK_LSHIFT_ASSIGN,
02729   TOK_RSHIFT_ASSIGN,
02730   TOK_URSHIFT_ASSIGN,
02731   TOK_AND,
02732   TOK_LOGICAL_OR,
02733   TOK_PLUS,
02734   TOK_MINUS,
02735   TOK_PLUS_PLUS,
02736   TOK_MINUS_MINUS,
02737   TOK_LOGICAL_AND,
02738   TOK_OR,
02739   TOK_QUESTION,
02740   TOK_TILDA,
02741   TOK_REM,
02742   TOK_MUL,
02743   TOK_DIV,
02744   TOK_XOR,
02745 
02746   /* Relational ops, must go in this order */
02747   TOK_LE,
02748   TOK_LT,
02749   TOK_GE,
02750   TOK_GT,
02751   TOK_LSHIFT,
02752   TOK_RSHIFT,
02753   TOK_URSHIFT,
02754   TOK_NOT,
02755 
02756   /* Keywords. must be in the same order as tokenizer.c::s_keywords array */
02757   TOK_BREAK,
02758   TOK_CASE,
02759   TOK_CATCH,
02760   TOK_CONTINUE,
02761   TOK_DEBUGGER,
02762   TOK_DEFAULT,
02763   TOK_DELETE,
02764   TOK_DO,
02765   TOK_ELSE,
02766   TOK_FALSE,
02767   TOK_FINALLY,
02768   TOK_FOR,
02769   TOK_FUNCTION,
02770   TOK_IF,
02771   TOK_IN,
02772   TOK_INSTANCEOF,
02773   TOK_NEW,
02774   TOK_NULL,
02775   TOK_RETURN,
02776   TOK_SWITCH,
02777   TOK_THIS,
02778   TOK_THROW,
02779   TOK_TRUE,
02780   TOK_TRY,
02781   TOK_TYPEOF,
02782   TOK_VAR,
02783   TOK_VOID,
02784   TOK_WHILE,
02785   TOK_WITH,
02786 
02787   /* TODO(lsm): process these reserved words too */
02788   TOK_CLASS,
02789   TOK_ENUM,
02790   TOK_EXTENDS,
02791   TOK_SUPER,
02792   TOK_CONST,
02793   TOK_EXPORT,
02794   TOK_IMPORT,
02795   TOK_IMPLEMENTS,
02796   TOK_LET,
02797   TOK_PRIVATE,
02798   TOK_PUBLIC,
02799   TOK_INTERFACE,
02800   TOK_PACKAGE,
02801   TOK_PROTECTED,
02802   TOK_STATIC,
02803   TOK_YIELD,
02804 
02805   NUM_TOKENS
02806 };
02807 
02808 #if defined(__cplusplus)
02809 extern "C" {
02810 #endif /* __cplusplus */
02811 
02812 V7_PRIVATE int skip_to_next_tok(const char **ptr, const char *src_end);
02813 V7_PRIVATE enum v7_tok get_tok(const char **s, const char *src_end, double *n,
02814                                enum v7_tok prev_tok);
02815 V7_PRIVATE int is_reserved_word_token(enum v7_tok tok);
02816 
02817 #if defined(__cplusplus)
02818 }
02819 #endif /* __cplusplus */
02820 
02821 #endif /* V7_NO_COMPILER */
02822 
02823 #endif /* CS_V7_SRC_TOKENIZER_H_ */
02824 #ifdef V7_MODULE_LINES
02825 #line 1 "v7/src/opcodes.h"
02826 #endif
02827 /*
02828  * Copyright (c) 2014 Cesanta Software Limited
02829  * All rights reserved
02830  */
02831 
02832 #ifndef CS_V7_SRC_OPCODES_H_
02833 #define CS_V7_SRC_OPCODES_H_
02834 
02835 /*
02836  * ==== Instructions
02837  *
02838  * Bytecode instructions consist of 1-byte opcode, optionally followed by N
02839  * bytes of arguments.
02840  *
02841  * Opcodes that accept an index in the literal table (PUSH_LIT, GET_VAR,
02842  * SET_VAR, ...) also accept inline literals. In order to distinguish indices in
02843  * the literals table and the inline literals, indices 0 and 1 are reserved as
02844  * type tags for inline literals:
02845  *
02846  * if 0, the following bytes encode a string literal
02847  * if 1, they encode a number (textual, like in the AST)
02848  *
02849  * (see enum bcode_inline_lit_type_tag)
02850  *
02851  *
02852  * Stack diagrams follow the syntax and semantics of:
02853  *
02854  * http://everything2.com/title/Forth+stack+diagrams[Forth stack diagrams].
02855  *
02856  * We use the following extension in the terminology:
02857  *
02858  * `T`: "Try stack".
02859  * `A`: opcode arguments.
02860  * `S`: stash register (one element stack).
02861  *
02862  */
02863 enum opcode {
02864   /*
02865    * Removes an item from the top of the stack. It is undefined what happens if
02866    * the stack is empty.
02867    *
02868    * `( a -- )`
02869   */
02870   OP_DROP,
02871   /*
02872    * Duplicates a value on top of the stack.
02873    *
02874    * `( a -- a a)`
02875   */
02876   OP_DUP,
02877   /*
02878    * Duplicates 2 values from the top of the stack in the same order.
02879    *
02880    * `( a b -- a b a b)`
02881   */
02882   OP_2DUP,
02883   /*
02884    * Swap the top two items on the stack.
02885    *
02886    * `( a b -- b a )`
02887    */
02888   OP_SWAP,
02889   /*
02890    * Copy current top of the stack to the temporary stash register.
02891    *
02892    * The content of the stash register will be cleared in the event of an
02893    * exception.
02894    *
02895    * `( a S: b -- a S: a)` saves TOS to stash reg
02896    */
02897   OP_STASH,
02898   /*
02899    * Replace the top of the stack with the content of the temporary stash
02900    * register.
02901    *
02902    * The stash register is cleared afterwards.
02903    *
02904    * `( a S: b -- b S: nil )` replaces tos with stash reg
02905    */
02906   OP_UNSTASH,
02907 
02908   /*
02909    * Effectively drops the last-but-one element from stack
02910    *
02911    * `( a b -- b )`
02912    */
02913   OP_SWAP_DROP,
02914 
02915   /*
02916    * Pushes `undefined` onto the stack.
02917    *
02918    * `( -- undefined )`
02919    */
02920   OP_PUSH_UNDEFINED,
02921   /*
02922    * Pushes `null` onto the stack.
02923    *
02924    * `( -- null )`
02925    */
02926   OP_PUSH_NULL,
02927   /*
02928    * Pushes current value of `this` onto the stack.
02929    *
02930    * `( -- this )`
02931    */
02932   OP_PUSH_THIS,
02933   /*
02934    * Pushes `true` onto the stack.
02935    *
02936    * `( -- true )`
02937    */
02938   OP_PUSH_TRUE,
02939   /*
02940    * Pushes `false` onto the stack.
02941    *
02942    * `( -- false )`
02943    */
02944   OP_PUSH_FALSE,
02945   /*
02946    * Pushes `0` onto the stack.
02947    *
02948    * `( -- 0 )`
02949    */
02950   OP_PUSH_ZERO,
02951   /*
02952    * Pushes `1` onto the stack.
02953    *
02954    * `( -- 1 )`
02955    */
02956   OP_PUSH_ONE,
02957 
02958   /*
02959    * Pushes a value from literals table onto the stack.
02960    *
02961    * The opcode takes a varint operand interpreted as an index in the current
02962    * literal table (see lit table).
02963    *
02964    * ( -- a )
02965    */
02966   OP_PUSH_LIT,
02967 
02968   OP_NOT,
02969   OP_LOGICAL_NOT,
02970 
02971   /*
02972    * Takes a number from the top of the stack, inverts the sign and pushes it
02973    * back.
02974    *
02975    * `( a -- -a )`
02976    */
02977   OP_NEG,
02978   /*
02979    * Takes a number from the top of the stack pushes the evaluation of
02980    * `Number()`.
02981    *
02982    * `( a -- Number(a) )`
02983    */
02984   OP_POS,
02985 
02986   /*
02987    * Takes 2 values from the top of the stack and performs addition operation:
02988    * If any of the two values is not `undefined`, number or boolean, both values
02989    * are converted into strings and concatenated.
02990    * Otherwise, both values are treated as numbers:
02991    * * `undefined` is converted into NaN
02992    * * `true` is converted into 1
02993    * * `false` is converted into 0
02994    *
02995    * Result is pushed back onto the stack.
02996    *
02997    * TODO: make it behave exactly like JavaScript's `+` operator.
02998    *
02999    * `( a b -- a+b )`
03000    */
03001   OP_ADD,
03002   OP_SUB,     /* ( a b -- a-b ) */
03003   OP_REM,     /* ( a b -- a%b ) */
03004   OP_MUL,     /* ( a b -- a*b ) */
03005   OP_DIV,     /* ( a b -- a/b ) */
03006   OP_LSHIFT,  /* ( a b -- a<<b ) */
03007   OP_RSHIFT,  /* ( a b -- a>>b ) */
03008   OP_URSHIFT, /* ( a b -- a>>>b ) */
03009   OP_OR,      /* ( a b -- a|b ) */
03010   OP_XOR,     /* ( a b -- a^b ) */
03011   OP_AND,     /* ( a b -- a&b ) */
03012 
03013   /*
03014    * Takes two numbers form the top of the stack and pushes `true` if they are
03015    * equal, or `false` if they are not equal.
03016    *
03017    * ( a b -- a===b )
03018    */
03019   OP_EQ_EQ,
03020   OP_EQ,    /* ( a b -- a==b ) */
03021   OP_NE,    /* ( a b -- a!=b ) */
03022   OP_NE_NE, /* ( a b -- a!==b ) */
03023   OP_LT,    /* ( a b -- a<b ) */
03024   OP_LE,    /* ( a b -- a<=b ) */
03025   OP_GT,    /* ( a b -- a>b ) */
03026   OP_GE,    /* ( a b -- a>=b ) */
03027   OP_INSTANCEOF,
03028 
03029   OP_TYPEOF,
03030 
03031   OP_IN,
03032   /*
03033    * Takes 2 values from the stack, treats the top of the stack as property name
03034    * and the next value must be an object, an array or a string.
03035    * If it's an object, pushes the value of its named property onto the stack.
03036    * If it's an array or a string, returns a value at a given position.
03037   */
03038   OP_GET,
03039   /*
03040    * Takes 3 items from the stack: value, property name, object. Sets the given
03041    * property of a given object to a given value, pushes value back onto the
03042    *stack.
03043    *
03044    * `( a b c -- a[b]=c )`
03045   */
03046   OP_SET,
03047   /*
03048    * Takes 1 value from the stack and a varint argument -- index of the var name
03049    * in the literals table. Tries to find the variable in the current scope
03050    * chain and assign the value to it. If the varialble is not found -- creates
03051    * a new one in the global scope. Pushes the value back to the stack.
03052    *
03053    * `( a -- a )`
03054    */
03055   OP_SET_VAR,
03056   /*
03057    * Takes a varint argument -- index of the var name in the literals table.
03058    * Looks up that variable in the scope chain and pushes its value onto the
03059    * stack.
03060    *
03061    * `( -- a )`
03062    */
03063   OP_GET_VAR,
03064 
03065   /*
03066    * Like OP_GET_VAR but returns undefined
03067    * instead of throwing reference error.
03068    *
03069    * `( -- a )`
03070    */
03071   OP_SAFE_GET_VAR,
03072 
03073   /*
03074    * ==== Jumps
03075    *
03076    * All jump instructions take one 4-byte argument: offset to jump to. Offset
03077    *is a
03078    * index of the byte in the instruction stream, starting with 0. No byte order
03079    * conversion is applied.
03080    *
03081    * TODO: specify byte order for the offset.
03082    */
03083 
03084   /*
03085    * Unconditiona jump.
03086    */
03087   OP_JMP,
03088   /*
03089    * Takes one value from the stack and performs a jump if conversion of that
03090    * value to boolean results in `true`.
03091    *
03092    * `( a -- )`
03093   */
03094   OP_JMP_TRUE,
03095   /*
03096    * Takes one value from the stack and performs a jump if conversion of that
03097    * value to boolean results in `false`.
03098    *
03099    * `( a -- )`
03100    */
03101   OP_JMP_FALSE,
03102   /*
03103    * Like OP_JMP_TRUE but if the branch
03104    * is taken it also drops another stack element:
03105    *
03106    * if `b` is true: `( a b -- )`
03107    * if `b` is false: `( a b -- a )`
03108    */
03109   OP_JMP_TRUE_DROP,
03110 
03111   /*
03112    * Conditional jump on the v7->is_continuing flag.
03113    * Clears the flag once executed.
03114    *
03115    * `( -- )`
03116    */
03117   OP_JMP_IF_CONTINUE,
03118 
03119   /*
03120    * Constructs a new empty object and pushes it onto the stack.
03121    *
03122    * `( -- {} )`
03123    */
03124   OP_CREATE_OBJ,
03125   /*
03126    * Constructs a new empty array and pushes it onto the stack.
03127    *
03128    * `( -- [] )`
03129    */
03130   OP_CREATE_ARR,
03131 
03132   /*
03133    * Allocates the iteration context (for `OP_NEXT_PROP`) from heap and pushes
03134    * a foreign pointer to it on stack. The allocated data is stored as "user
03135    * data" of the object, and it will be reclaimed automatically when the
03136    * object gets garbage-collected.
03137    *
03138    * `( -- ctx )`
03139    */
03140   OP_PUSH_PROP_ITER_CTX,
03141 
03142   /*
03143    * Yields the next property name.
03144    * Used in the for..in construct.
03145    *
03146    * The first evaluation must receive `null` as handle.
03147    * Subsequent evaluations will either:
03148    *
03149    * a) produce a new handle, the key and true value:
03150    *
03151    * `( o h -- o h' key true)`
03152    *
03153    * b) produce a false value only, indicating no more properties:
03154    *
03155    * `( o h -- false)`
03156    */
03157   OP_NEXT_PROP,
03158 
03159   /*
03160    * Copies the function object at TOS and assigns current scope
03161    * in func->scope.
03162    *
03163    * `( a -- a )`
03164    */
03165   OP_FUNC_LIT,
03166   /*
03167    * Takes the number of arguments as parameter.
03168    *
03169    * Pops N function arguments from stack, then pops function, then pops `this`.
03170    * Calls a function and populates TOS with the returned value.
03171    *
03172    * `( this f a0 a1 ... aN -- f(a0,a1,...) )`
03173    */
03174   OP_CALL,
03175   OP_NEW,
03176   /*
03177    * Checks that TOS is a callable and if not saves an exception
03178    * that will will be thrown by CALL after all arguments have been evaluated.
03179    */
03180   OP_CHECK_CALL,
03181   /*
03182    * Returns the current function.
03183    *
03184    * It has no stack side effects. The function upon return will leave the
03185    * return value on the stack. The return value must be pushed on the stack
03186    * prior to invoking a RET.
03187    *
03188    * `( -- )`
03189    */
03190   OP_RET,
03191 
03192   /*
03193    * Deletes the property of given name `p` from the given object `o`. Returns
03194    * boolean value `a`.
03195    *
03196    * `( o p -- a )`
03197    */
03198   OP_DELETE,
03199 
03200   /*
03201    * Like `OP_DELETE`, but uses the current scope as an object to delete
03202    * a property from.
03203    *
03204    * `( p -- a )`
03205    */
03206   OP_DELETE_VAR,
03207 
03208   /*
03209    * Pushes a value (bcode offset of `catch` block) from opcode argument to
03210    * "try stack".
03211    *
03212    * Used in the beginning of the `try` block.
03213    *
03214    * `( A: a -- T: a )`
03215    */
03216   OP_TRY_PUSH_CATCH,
03217 
03218   /*
03219    * Pushes a value (bcode offset of `finally` block) from opcode argument to
03220    * "try stack".
03221    *
03222    * Used in the beginning of the `try` block.
03223    *
03224    * `( A: a -- T: a )`
03225    *
03226    * TODO: implement me
03227    */
03228   OP_TRY_PUSH_FINALLY,
03229 
03230   /*
03231    * Pushes a value (bcode offset of a label) from opcode argument to
03232    * "try stack".
03233    *
03234    * Used at the beginning of loops that contain break or continue.
03235    * Possible optimisation: don't emit if we can ensure that no break or
03236    * continue statement is used.
03237    *
03238    * `( A: a -- T: a )`
03239    */
03240   OP_TRY_PUSH_LOOP,
03241 
03242   /*
03243    * Pushes a value (bcode offset of a label) from opcode argument to
03244    * "try stack".
03245    *
03246    * Used at the beginning of switch statements.
03247    *
03248    * `( A: a -- T: a )`
03249    */
03250   OP_TRY_PUSH_SWITCH,
03251 
03252   /*
03253    * Pops a value (bcode offset of `finally` or `catch` block) from "try
03254    * stack", and discards it
03255    *
03256    * Used in the end of the `try` block, as well as in the beginning of the
03257    * `catch` and `finally` blocks
03258    *
03259    * `( T: a -- T: )`
03260    */
03261   OP_TRY_POP,
03262 
03263   /*
03264    * Used in the end of the `finally` block:
03265    *
03266    * - if some value is currently being thrown, keep throwing it.
03267    *   If eventually we encounter `catch` block, the thrown value gets
03268    *   populated on TOS:
03269    *
03270    *   `( -- a )`
03271    *
03272    * - if there is some pending value to return, keep returning it.
03273    *   If we encounter no further `finally` blocks, then the returned value
03274    *   gets populated on TOS:
03275    *
03276    *   `( -- a )`
03277    *
03278    *   And return is performed.
03279    *
03280    * - otherwise, do nothing
03281    */
03282   OP_AFTER_FINALLY,
03283 
03284   /*
03285    * Throw value from TOS. First of all, it pops the value and saves it into
03286    * `v7->vals.thrown_error`:
03287    *
03288    * `( a -- )`
03289    *
03290    * Then unwinds stack looking for the first `catch` or `finally` blocks.
03291    *
03292    * - if `finally` is found, thrown value is kept into `v7->vals.thrown_error`.
03293    * - if `catch` is found, thrown value is pushed back to the stack:
03294    *   `( -- a )`
03295    * - otherwise, thrown value is kept into `v7->vals.thrown_error`
03296    */
03297   OP_THROW,
03298 
03299   /*
03300    * Unwind to next break entry in the try stack, evaluating
03301    * all finally blocks on its way up.
03302    *
03303    * `( -- )`
03304    */
03305   OP_BREAK,
03306 
03307   /*
03308    * Like OP_BREAK, but sets the v7->is_continuing flag
03309    * which will cause OP_JMP_IF_CONTINUE to restart the loop.
03310    *
03311    * `( -- )`
03312    */
03313   OP_CONTINUE,
03314 
03315   /*
03316    * Used when we enter the `catch` block. Takes a varint argument -- index of
03317    * the exception variable name in the literals table.
03318    *
03319    * Pops the exception value from the stack, creates a private frame,
03320    * sets exception property on it with the given name. pushes this
03321    * private frame to call stack.
03322    *
03323    * `( e -- )`
03324    */
03325   OP_ENTER_CATCH,
03326 
03327   /*
03328    * Ued when we exit from the `catch` block. Merely pops the private frame
03329    * from the call stack.
03330    *
03331    * `( -- )`
03332    */
03333   OP_EXIT_CATCH,
03334 
03335   OP_MAX,
03336 };
03337 
03338 #define _OP_LINE_NO 0x80
03339 
03340 #endif /* CS_V7_SRC_OPCODES_H_ */
03341 #ifdef V7_MODULE_LINES
03342 #line 1 "v7/src/core.h"
03343 #endif
03344 /*
03345  * Copyright (c) 2014 Cesanta Software Limited
03346  * All rights reserved
03347  */
03348 
03349 #ifndef CS_V7_SRC_CORE_H_
03350 #define CS_V7_SRC_CORE_H_
03351 
03352 /* Amalgamated: #include "v7/src/core_public.h" */
03353 
03354 /* Amalgamated: #include "common/mbuf.h" */
03355 /* Amalgamated: #include "v7/src/std_error.h" */
03356 /* Amalgamated: #include "v7/src/mm.h" */
03357 /* Amalgamated: #include "v7/src/parser.h" */
03358 /* Amalgamated: #include "v7/src/object_public.h" */
03359 /* Amalgamated: #include "v7/src/tokenizer.h" */
03360 /* Amalgamated: #include "v7/src/opcodes.h" */
03361 
03362 #if defined(__cplusplus)
03363 extern "C" {
03364 #endif /* __cplusplus */
03365 
03366 typedef uint64_t val_t;
03367 
03368 #if defined(V7_ENABLE_ENTITY_IDS)
03369 
03370 typedef unsigned short entity_id_t;
03371 typedef unsigned char entity_id_part_t;
03372 
03373 /*
03374  * Magic numbers that are stored in various objects in order to identify their
03375  * type in runtime
03376  */
03377 #define V7_ENTITY_ID_PROP 0xe9a1
03378 #define V7_ENTITY_ID_PART_OBJ 0x57
03379 #define V7_ENTITY_ID_PART_GEN_OBJ 0x31
03380 #define V7_ENTITY_ID_PART_JS_FUNC 0x0d
03381 
03382 #define V7_ENTITY_ID_NONE 0xa5a5
03383 #define V7_ENTITY_ID_PART_NONE 0xa5
03384 
03385 #endif
03386 
03387 /*
03388  *  Double-precision floating-point number, IEEE 754
03389  *
03390  *  64 bit (8 bytes) in total
03391  *  1  bit sign
03392  *  11 bits exponent
03393  *  52 bits mantissa
03394  *      7         6        5        4        3        2        1        0
03395  *  seeeeeee|eeeemmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm|mmmmmmmm
03396  *
03397  * If an exponent is all-1 and mantissa is all-0, then it is an INFINITY:
03398  *  11111111|11110000|00000000|00000000|00000000|00000000|00000000|00000000
03399  *
03400  * If an exponent is all-1 and mantissa's MSB is 1, it is a quiet NaN:
03401  *  11111111|11111000|00000000|00000000|00000000|00000000|00000000|00000000
03402  *
03403  *  V7 NaN-packing:
03404  *    sign and exponent is 0xfff
03405  *    4 bits specify type (tag), must be non-zero
03406  *    48 bits specify value
03407  *
03408  *  11111111|1111tttt|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv|vvvvvvvv
03409  *   NaN marker |type|  48-bit placeholder for values: pointers, strings
03410  *
03411  * On 64-bit platforms, pointers are really 48 bit only, so they can fit,
03412  * provided they are sign extended
03413  */
03414 
03415 /*
03416  * A tag is made of the sign bit and the 4 lower order bits of byte 6.
03417  * So in total we have 32 possible tags.
03418  *
03419  * Tag (1,0) however cannot hold a zero payload otherwise it's interpreted as an
03420  * INFINITY; for simplicity we're just not going to use that combination.
03421  */
03422 #define MAKE_TAG(s, t) \
03423   ((uint64_t)(s) << 63 | (uint64_t) 0x7ff0 << 48 | (uint64_t)(t) << 48)
03424 
03425 #define V7_TAG_OBJECT MAKE_TAG(1, 0xF)
03426 #define V7_TAG_FOREIGN MAKE_TAG(1, 0xE)
03427 #define V7_TAG_UNDEFINED MAKE_TAG(1, 0xD)
03428 #define V7_TAG_BOOLEAN MAKE_TAG(1, 0xC)
03429 #define V7_TAG_NAN MAKE_TAG(1, 0xB)
03430 #define V7_TAG_STRING_I MAKE_TAG(1, 0xA)  /* Inlined string len < 5 */
03431 #define V7_TAG_STRING_5 MAKE_TAG(1, 0x9)  /* Inlined string len 5 */
03432 #define V7_TAG_STRING_O MAKE_TAG(1, 0x8)  /* Owned string */
03433 #define V7_TAG_STRING_F MAKE_TAG(1, 0x7)  /* Foreign string */
03434 #define V7_TAG_STRING_C MAKE_TAG(1, 0x6)  /* String chunk */
03435 #define V7_TAG_FUNCTION MAKE_TAG(1, 0x5)  /* JavaScript function */
03436 #define V7_TAG_CFUNCTION MAKE_TAG(1, 0x4) /* C function */
03437 #define V7_TAG_STRING_D MAKE_TAG(1, 0x3)  /* Dictionary string  */
03438 #define V7_TAG_REGEXP MAKE_TAG(1, 0x2)    /* Regex */
03439 #define V7_TAG_NOVALUE MAKE_TAG(1, 0x1)   /* Sentinel for no value */
03440 #define V7_TAG_MASK MAKE_TAG(1, 0xF)
03441 
03442 #define _V7_NULL V7_TAG_FOREIGN
03443 #define _V7_UNDEFINED V7_TAG_UNDEFINED
03444 
03445 V7_STATIC_ASSERT(_V7_NULL == V7_NULL, public_V7_NULL_is_wrong);
03446 V7_STATIC_ASSERT(_V7_UNDEFINED == V7_UNDEFINED, public_V7_UNDEFINED_is_wrong);
03447 
03448 /*
03449  * Object attributes bitmask
03450  */
03451 typedef unsigned char v7_obj_attr_t;
03452 #define V7_OBJ_NOT_EXTENSIBLE (1 << 0) /* TODO(lsm): store this in LSB */
03453 #define V7_OBJ_DENSE_ARRAY (1 << 1)    /* TODO(mkm): store in some tag */
03454 #define V7_OBJ_FUNCTION (1 << 2)       /* function object */
03455 #define V7_OBJ_OFF_HEAP (1 << 3)       /* object not managed by V7 HEAP */
03456 #define V7_OBJ_HAS_DESTRUCTOR (1 << 4) /* has user data */
03457 #define V7_OBJ_PROXY (1 << 5)          /* it's a Proxy object */
03458 
03459 /*
03460  * JavaScript value is either a primitive, or an object.
03461  * There are 5 primitive types: Undefined, Null, Boolean, Number, String.
03462  * Non-primitive type is an Object type. There are several classes of Objects,
03463  * see description of `struct v7_generic_object` below for more details.
03464  * This enumeration combines types and object classes in one enumeration.
03465  * NOTE(lsm): compile with `-fshort-enums` to reduce sizeof(enum v7_type) to 1.
03466  */
03467 enum v7_type {
03468   /* Primitive types */
03469   V7_TYPE_UNDEFINED,
03470   V7_TYPE_NULL,
03471   V7_TYPE_BOOLEAN,
03472   V7_TYPE_NUMBER,
03473   V7_TYPE_STRING,
03474   V7_TYPE_FOREIGN,
03475   V7_TYPE_CFUNCTION,
03476 
03477   /* Different classes of Object type */
03478   V7_TYPE_GENERIC_OBJECT,
03479   V7_TYPE_BOOLEAN_OBJECT,
03480   V7_TYPE_STRING_OBJECT,
03481   V7_TYPE_NUMBER_OBJECT,
03482   V7_TYPE_FUNCTION_OBJECT,
03483   V7_TYPE_CFUNCTION_OBJECT,
03484   V7_TYPE_REGEXP_OBJECT,
03485   V7_TYPE_ARRAY_OBJECT,
03486   V7_TYPE_DATE_OBJECT,
03487   V7_TYPE_ERROR_OBJECT,
03488   V7_TYPE_MAX_OBJECT_TYPE,
03489   V7_NUM_TYPES
03490 };
03491 
03492 /*
03493  * Call frame type mask: we have a "class hierarchy" of the call frames, see
03494  * `struct v7_call_frame_base`, and the `type_mask` field represents the exact
03495  * frame type.
03496  *
03497  * Possible values are:
03498  *
03499  * - `V7_CALL_FRAME_MASK_PRIVATE | V7_CALL_FRAME_MASK_BCODE`: the most popular
03500  *   frame type: call frame for bcode execution, either top-level code or JS
03501  *   function.
03502  * - `V7_CALL_FRAME_MASK_PRIVATE`: used for `catch` clauses only: the variables
03503  *   we create in `catch` clause should not be visible from the outside of the
03504  *   clause, so we have to create a separate scope object for it.
03505  * - `V7_CALL_FRAME_MASK_CFUNC`: call frame for C function.
03506  */
03507 typedef uint8_t v7_call_frame_mask_t;
03508 #define V7_CALL_FRAME_MASK_BCODE (1 << 0)
03509 #define V7_CALL_FRAME_MASK_PRIVATE (1 << 1)
03510 #define V7_CALL_FRAME_MASK_CFUNC (1 << 2)
03511 
03512 /*
03513  * Base of the call frame; includes the pointer to the previous frame,
03514  * and the frame type.
03515  *
03516  * In order to save memory, it also contains some bitfields which actually
03517  * belong to some "sub-structures".
03518  *
03519  * The hierarchy is as follows:
03520  *
03521  *   - v7_call_frame_base
03522  *     - v7_call_frame_private
03523  *       - v7_call_frame_bcode
03524  *     - v7_call_frame_cfunc
03525  */
03526 struct v7_call_frame_base {
03527   struct v7_call_frame_base *prev;
03528 
03529   /* See comment for `v7_call_frame_mask_t` */
03530   v7_call_frame_mask_t type_mask : 3;
03531 
03532   /* Belongs to `struct v7_call_frame_private` */
03533   unsigned int line_no : 16;
03534 
03535   /* Belongs to `struct v7_call_frame_bcode` */
03536   unsigned is_constructor : 1;
03537 
03538   /* Belongs to `struct v7_call_frame_bcode` */
03539   unsigned int is_thrown : 1;
03540 };
03541 
03542 /*
03543  * "private" call frame, used in `catch` blocks, merely for using a separate
03544  * scope object there. It is also a "base class" for the bcode call frame,
03545  * see `struct v7_call_frame_bcode`.
03546  *
03547  * TODO(dfrank): probably implement it differently, so that we can get rid of
03548  * the separate "private" frames whatsoever (and just include it into struct
03549  * v7_call_frame_bcode )
03550  */
03551 struct v7_call_frame_private {
03552   struct v7_call_frame_base base;
03553   size_t stack_size;
03554   struct {
03555     /*
03556      * Current execution scope. Initially, it is equal to the `global_object`;
03557      * and at each function call, it is augmented by the new scope object, which
03558      * has the previous value as a prototype.
03559      */
03560     val_t scope;
03561 
03562     val_t try_stack;
03563   } vals;
03564 };
03565 
03566 /*
03567  * "bcode" call frame, augments "private" frame with `bcode` and the position
03568  * in it, and `this` object. It is the primary frame type, used when executing
03569  * a bcode script or calling a function.
03570  */
03571 struct v7_call_frame_bcode {
03572   struct v7_call_frame_private base;
03573   struct {
03574     val_t this_obj;
03575     val_t thrown_error;
03576   } vals;
03577   struct bcode *bcode;
03578   char *bcode_ops;
03579 };
03580 
03581 /*
03582  * "cfunc" call frame, used when calling cfunctions.
03583  */
03584 struct v7_call_frame_cfunc {
03585   struct v7_call_frame_base base;
03586 
03587   struct {
03588     val_t this_obj;
03589   } vals;
03590 
03591   v7_cfunction_t *cfunc;
03592 };
03593 
03594 /*
03595  * This structure groups together all val_t logical members
03596  * of struct v7 so that GC and freeze logic can easily access all
03597  * of them together. This structure must contain only val_t members.
03598  */
03599 struct v7_vals {
03600   val_t global_object;
03601 
03602   val_t arguments; /* arguments of current call */
03603 
03604   val_t object_prototype;
03605   val_t array_prototype;
03606   val_t boolean_prototype;
03607   val_t error_prototype;
03608   val_t string_prototype;
03609   val_t regexp_prototype;
03610   val_t number_prototype;
03611   val_t date_prototype;
03612   val_t function_prototype;
03613   val_t proxy_prototype;
03614 
03615   /*
03616    * temporary register for `OP_STASH` and `OP_UNSTASH` instructions. Valid if
03617    * `v7->is_stashed` is non-zero
03618    */
03619   val_t stash;
03620 
03621   val_t error_objects[ERROR_CTOR_MAX];
03622 
03623   /*
03624    * Value that is being thrown. Valid if `is_thrown` is non-zero (see below)
03625    */
03626   val_t thrown_error;
03627 
03628   /*
03629    * value that is going to be returned. Needed when some `finally` block needs
03630    * to be executed after `return my_value;` was issued. Used in bcode.
03631    * See also `is_returned` below
03632    */
03633   val_t returned_value;
03634 
03635   val_t last_name[2]; /* used for error reporting */
03636   /* most recent OP_CHECK_CALL exceptions, to be thrown by OP_CALL|OP_NEW */
03637   val_t call_check_ex;
03638 };
03639 
03640 struct v7 {
03641   struct v7_vals vals;
03642 
03643   /*
03644    * Stack of call frames.
03645    *
03646    * Execution contexts are contained in two chains:
03647    * - Stack of call frames: to allow returning, throwing, and stack trace
03648    *   generation;
03649    * - In the lexical scope via their prototype chain (to allow variable
03650    *   lookup), see `struct v7_call_frame_private::scope`.
03651    *
03652    * Execution contexts should be allocated on heap, because they might not be
03653    * on a call stack but still referenced (closures).
03654    *
03655    * New call frame is created every time some top-level code is evaluated,
03656    * or some code is being `eval`-d, or some function is called, either JS
03657    * function or C function (although the call frame types are different for
03658    * JS functions and cfunctions, see `struct v7_call_frame_base` and its
03659    * sub-structures)
03660    *
03661    * When no code is being evaluated at the moment, `call_stack` is `NULL`.
03662    *
03663    * See comment for `struct v7_call_frame_base` for some more details.
03664    */
03665   struct v7_call_frame_base *call_stack;
03666 
03667   /*
03668    * Bcode executes until it reaches `bottom_call_frame`. When some top-level
03669    * or `eval`-d code starts execution, the `bottom_call_frame` is set to the
03670    * call frame which was just created for the execution.
03671    */
03672   struct v7_call_frame_base *bottom_call_frame;
03673 
03674   struct mbuf stack; /* value stack for bcode interpreter */
03675 
03676   struct mbuf owned_strings;   /* Sequence of (varint len, char data[]) */
03677   struct mbuf foreign_strings; /* Sequence of (varint len, char *data) */
03678 
03679   struct mbuf tmp_stack; /* Stack of val_t* elements, used as root set */
03680   int need_gc;           /* Set to true to trigger GC when safe */
03681 
03682   struct gc_arena generic_object_arena;
03683   struct gc_arena function_arena;
03684   struct gc_arena property_arena;
03685 #if V7_ENABLE__Memory__stats
03686   size_t function_arena_ast_size;
03687   size_t bcode_ops_size;
03688   size_t bcode_lit_total_size;
03689   size_t bcode_lit_deser_size;
03690 #endif
03691   struct mbuf owned_values; /* buffer for GC roots owned by C code */
03692 
03693   /*
03694    * Stack of the root bcodes being executed at the moment. Note that when some
03695    * regular JS function is called inside `eval_bcode()`, the function's bcode
03696    * is NOT added here. Buf if some cfunction is called, which in turn calls
03697    * `b_exec()` (or `b_apply()`) recursively, the new bcode is added to this
03698    * stack.
03699    */
03700   struct mbuf act_bcodes;
03701 
03702   char error_msg[80]; /* Exception message */
03703 
03704   struct mbuf json_visited_stack; /* Detecting cycle in to_json */
03705 
03706 /* Parser state */
03707 #if !defined(V7_NO_COMPILER)
03708   struct v7_pstate pstate; /* Parsing state */
03709   enum v7_tok cur_tok;     /* Current token */
03710   const char *tok;         /* Parsed terminal token (ident, number, string) */
03711   unsigned long tok_len;   /* Length of the parsed terminal token */
03712   size_t last_var_node;    /* Offset of last var node or function/script node */
03713   int after_newline;       /* True if the cur_tok starts a new line */
03714   double cur_tok_dbl;      /* When tokenizing, parser stores TOK_NUMBER here */
03715 
03716   /*
03717    * Current linenumber. Currently it is used by parser, compiler and bcode
03718    * evaluator.
03719    *
03720    * - Parser: it's the last line_no emitted to AST
03721    * - Compiler: it's the last line_no emitted to bcode
03722    */
03723   int line_no;
03724 #endif /* V7_NO_COMPILER */
03725 
03726   /* singleton, pointer because of amalgamation */
03727   struct v7_property *cur_dense_prop;
03728 
03729   volatile int interrupted;
03730 #ifdef V7_STACK_SIZE
03731   void *sp_limit;
03732   void *sp_lwm;
03733 #endif
03734 
03735 #if defined(V7_CYG_PROFILE_ON)
03736   /* linked list of v7 contexts, needed by cyg_profile hooks */
03737   struct v7 *next_v7;
03738 
03739 #if defined(V7_ENABLE_STACK_TRACKING)
03740   /* linked list of stack tracking contexts */
03741   struct stack_track_ctx *stack_track_ctx;
03742 
03743   int stack_stat[V7_STACK_STATS_CNT];
03744 #endif
03745 
03746 #endif
03747 
03748 #ifdef V7_MALLOC_GC
03749   struct mbuf malloc_trace;
03750 #endif
03751 
03752 /*
03753  * TODO(imax): remove V7_DISABLE_STR_ALLOC_SEQ knob after 2015/12/01 if there
03754  * are no issues.
03755  */
03756 #ifndef V7_DISABLE_STR_ALLOC_SEQ
03757   uint16_t gc_next_asn; /* Next sequence number to use. */
03758   uint16_t gc_min_asn;  /* Minimal sequence number currently in use. */
03759 #endif
03760 
03761 #if defined(V7_TRACK_MAX_PARSER_STACK_SIZE)
03762   size_t parser_stack_data_max_size;
03763   size_t parser_stack_ret_max_size;
03764   size_t parser_stack_data_max_len;
03765   size_t parser_stack_ret_max_len;
03766 #endif
03767 
03768 #ifdef V7_FREEZE
03769   FILE *freeze_file;
03770 #endif
03771 
03772   /*
03773    * true if exception is currently being created. Needed to avoid recursive
03774    * exception creation
03775    */
03776   unsigned int creating_exception : 1;
03777   /* while true, GC is inhibited */
03778   unsigned int inhibit_gc : 1;
03779   /* true if `thrown_error` is valid */
03780   unsigned int is_thrown : 1;
03781   /* true if `returned_value` is valid */
03782   unsigned int is_returned : 1;
03783   /* true if a finally block is executing while breaking */
03784   unsigned int is_breaking : 1;
03785   /* true when a continue OP is executed, reset by `OP_JMP_IF_CONTINUE` */
03786   unsigned int is_continuing : 1;
03787   /* true if some value is currently stashed (`v7->vals.stash`) */
03788   unsigned int is_stashed : 1;
03789   /* true if last emitted statement does not affect data stack */
03790   unsigned int is_stack_neutral : 1;
03791   /* true if precompiling; affects compiler bcode choices */
03792   unsigned int is_precompiling : 1;
03793 
03794   enum opcode last_ops[2]; /* trace of last ops, used for error reporting */
03795 };
03796 
03797 struct v7_property {
03798   struct v7_property *
03799       next; /* Linkage in struct v7_generic_object::properties */
03800   v7_prop_attr_t attributes;
03801 #if defined(V7_ENABLE_ENTITY_IDS)
03802   entity_id_t entity_id;
03803 #endif
03804   val_t name;  /* Property name (a string) */
03805   val_t value; /* Property value */
03806 };
03807 
03808 /*
03809  * "base object": structure which is shared between objects and functions.
03810  */
03811 struct v7_object {
03812   /* First HIDDEN property in a chain is an internal object value */
03813   struct v7_property *properties;
03814   v7_obj_attr_t attributes;
03815 #if defined(V7_ENABLE_ENTITY_IDS)
03816   entity_id_part_t entity_id_base;
03817   entity_id_part_t entity_id_spec;
03818 #endif
03819 };
03820 
03821 /*
03822  * An object is an unordered collection of properties.
03823  * A function stored in a property of an object is called a method.
03824  * A property has a name, a value, and set of attributes.
03825  * Attributes are: ReadOnly, DontEnum, DontDelete, Internal.
03826  *
03827  * A constructor is a function that creates and initializes objects.
03828  * Each constructor has an associated prototype object that is used for
03829  * inheritance and shared properties. When a constructor creates an object,
03830  * the new object references the constructor’s prototype.
03831  *
03832  * Objects could be a "generic objects" which is a collection of properties,
03833  * or a "typed object" which also hold an internal value like String or Number.
03834  * Those values are implicit, unnamed properties of the respective types,
03835  * and can be coerced into primitive types by calling a respective constructor
03836  * as a function:
03837  *    var a = new Number(123);
03838  *    typeof(a) == 'object';
03839  *    typeof(Number(a)) == 'number';
03840  */
03841 struct v7_generic_object {
03842   /*
03843    * This has to be the first field so that objects can be managed by the GC.
03844    */
03845   struct v7_object base;
03846   struct v7_object *prototype;
03847 };
03848 
03849 /*
03850  * Variables are function-scoped and are hoisted.
03851  * Lexical scoping & closures: each function has a chain of scopes, defined
03852  * by the lexicographic order of function definitions.
03853  * Scope is different from the execution context.
03854  * Execution context carries "variable object" which is variable/value
03855  * mapping for all variables defined in a function, and `this` object.
03856  * If function is not called as a method, then `this` is a global object.
03857  * Otherwise, `this` is an object that contains called method.
03858  * New execution context is created each time a function call is performed.
03859  * Passing arguments through recursion is done using execution context, e.g.
03860  *
03861  *    var factorial = function(num) {
03862  *      return num < 2 ? 1 : num * factorial(num - 1);
03863  *    };
03864  *
03865  * Here, recursion calls the same function `factorial` several times. Execution
03866  * contexts for each call form a stack. Each context has different variable
03867  * object, `vars`, with different values of `num`.
03868  */
03869 
03870 struct v7_js_function {
03871   /*
03872    * Functions are objects. This has to be the first field so that function
03873    * objects can be managed by the GC.
03874    */
03875   struct v7_object base;
03876   struct v7_generic_object *scope; /* lexical scope of the closure */
03877 
03878   /* bytecode, might be shared between functions */
03879   struct bcode *bcode;
03880 };
03881 
03882 struct v7_regexp {
03883   val_t regexp_string;
03884   struct slre_prog *compiled_regexp;
03885   long lastIndex;
03886 };
03887 
03888 /* Vector, describes some memory location pointed by `p` with length `len` */
03889 struct v7_vec {
03890   char *p;
03891   size_t len;
03892 };
03893 
03894 /*
03895  * Constant vector, describes some const memory location pointed by `p` with
03896  * length `len`
03897  */
03898 struct v7_vec_const {
03899   const char *p;
03900   size_t len;
03901 };
03902 
03903 #define V7_VEC(str) \
03904   { (str), sizeof(str) - 1 }
03905 
03906 /*
03907  * Returns current execution scope.
03908  *
03909  * See comment for `struct v7_call_frame_private::vals::scope`
03910  */
03911 V7_PRIVATE v7_val_t get_scope(struct v7 *v7);
03912 
03913 /*
03914  * Returns 1 if currently executing bcode in the "strict mode", 0 otherwise
03915  */
03916 V7_PRIVATE uint8_t is_strict_mode(struct v7 *v7);
03917 
03918 #if defined(__cplusplus)
03919 }
03920 #endif /* __cplusplus */
03921 
03922 #endif /* CS_V7_SRC_CORE_H_ */
03923 #ifdef V7_MODULE_LINES
03924 #line 1 "v7/src/primitive_public.h"
03925 #endif
03926 /*
03927  * Copyright (c) 2014 Cesanta Software Limited
03928  * All rights reserved
03929  */
03930 
03931 /*
03932  * === Primitives
03933  *
03934  * All primitive values but strings.
03935  *
03936  * "foreign" values are also here, see `v7_mk_foreign()`.
03937  */
03938 
03939 #ifndef CS_V7_SRC_PRIMITIVE_PUBLIC_H_
03940 #define CS_V7_SRC_PRIMITIVE_PUBLIC_H_
03941 
03942 /* Amalgamated: #include "v7/src/core_public.h" */
03943 
03944 #if defined(__cplusplus)
03945 extern "C" {
03946 #endif /* __cplusplus */
03947 
03948 /* Make numeric primitive value */
03949 NOINSTR v7_val_t v7_mk_number(struct v7 *v7, double num);
03950 
03951 /*
03952  * Returns number value stored in `v7_val_t` as `double`.
03953  *
03954  * Returns NaN for non-numbers.
03955  */
03956 NOINSTR double v7_get_double(struct v7 *v7, v7_val_t v);
03957 
03958 /*
03959  * Returns number value stored in `v7_val_t` as `int`. If the number value is
03960  * not an integer, the fraction part will be discarded.
03961  *
03962  * If the given value is a non-number, or NaN, the result is undefined.
03963  */
03964 NOINSTR int v7_get_int(struct v7 *v7, v7_val_t v);
03965 
03966 /* Returns true if given value is a primitive number value */
03967 int v7_is_number(v7_val_t v);
03968 
03969 /* Make boolean primitive value (either `true` or `false`) */
03970 NOINSTR v7_val_t v7_mk_boolean(struct v7 *v7, int is_true);
03971 
03972 /*
03973  * Returns boolean stored in `v7_val_t`:
03974  *  0 for `false` or non-boolean, non-0 for `true`
03975  */
03976 NOINSTR int v7_get_bool(struct v7 *v7, v7_val_t v);
03977 
03978 /* Returns true if given value is a primitive boolean value */
03979 int v7_is_boolean(v7_val_t v);
03980 
03981 /*
03982  * Make `null` primitive value.
03983  *
03984  * NOTE: this function is deprecated and will be removed in future releases.
03985  * Use `V7_NULL` instead.
03986  */
03987 NOINSTR v7_val_t v7_mk_null(void);
03988 
03989 /* Returns true if given value is a primitive `null` value */
03990 int v7_is_null(v7_val_t v);
03991 
03992 /*
03993  * Make `undefined` primitive value.
03994  *
03995  * NOTE: this function is deprecated and will be removed in future releases.
03996  * Use `V7_UNDEFINED` instead.
03997  */
03998 NOINSTR v7_val_t v7_mk_undefined(void);
03999 
04000 /* Returns true if given value is a primitive `undefined` value */
04001 int v7_is_undefined(v7_val_t v);
04002 
04003 /*
04004  * Make JavaScript value that holds C/C++ `void *` pointer.
04005  *
04006  * A foreign value is completely opaque and JS code cannot do anything useful
04007  * with it except holding it in properties and passing it around.
04008  * It behaves like a sealed object with no properties.
04009  *
04010  * NOTE:
04011  * Only valid pointers (as defined by each supported architecture) will fully
04012  * preserved. In particular, all supported 64-bit architectures (x86_64, ARM-64)
04013  * actually define a 48-bit virtual address space.
04014  * Foreign values will be sign-extended as required, i.e creating a foreign
04015  * value of something like `(void *) -1` will work as expected. This is
04016  * important because in some 64-bit OSs (e.g. Solaris) the user stack grows
04017  * downwards from the end of the address space.
04018  *
04019  * If you need to store exactly sizeof(void*) bytes of raw data where
04020  * `sizeof(void*)` >= 8, please use byte arrays instead.
04021  */
04022 NOINSTR v7_val_t v7_mk_foreign(struct v7 *v7, void *ptr);
04023 
04024 /*
04025  * Returns `void *` pointer stored in `v7_val_t`.
04026  *
04027  * Returns NULL if the value is not a foreign pointer.
04028  */
04029 NOINSTR void *v7_get_ptr(struct v7 *v7, v7_val_t v);
04030 
04031 /* Returns true if given value holds `void *` pointer */
04032 int v7_is_foreign(v7_val_t v);
04033 
04034 #if defined(__cplusplus)
04035 }
04036 #endif /* __cplusplus */
04037 
04038 #endif /* CS_V7_SRC_PRIMITIVE_PUBLIC_H_ */
04039 #ifdef V7_MODULE_LINES
04040 #line 1 "v7/src/primitive.h"
04041 #endif
04042 /*
04043  * Copyright (c) 2014 Cesanta Software Limited
04044  * All rights reserved
04045  */
04046 
04047 #ifndef CS_V7_SRC_PRIMITIVE_H_
04048 #define CS_V7_SRC_PRIMITIVE_H_
04049 
04050 /* Amalgamated: #include "v7/src/primitive_public.h" */
04051 
04052 /* Amalgamated: #include "v7/src/core.h" */
04053 
04054 /* Returns true if given value is a number, not NaN and not Infinity. */
04055 V7_PRIVATE int is_finite(struct v7 *v7, v7_val_t v);
04056 
04057 V7_PRIVATE val_t pointer_to_value(void *p);
04058 V7_PRIVATE void *get_ptr(val_t v);
04059 
04060 #endif /* CS_V7_SRC_PRIMITIVE_H_ */
04061 #ifdef V7_MODULE_LINES
04062 #line 1 "v7/src/string_public.h"
04063 #endif
04064 /*
04065  * Copyright (c) 2014 Cesanta Software Limited
04066  * All rights reserved
04067  */
04068 
04069 /*
04070  * === Strings
04071  */
04072 
04073 #ifndef CS_V7_SRC_STRING_PUBLIC_H_
04074 #define CS_V7_SRC_STRING_PUBLIC_H_
04075 
04076 /* Amalgamated: #include "v7/src/core_public.h" */
04077 
04078 #if defined(__cplusplus)
04079 extern "C" {
04080 #endif /* __cplusplus */
04081 
04082 /*
04083  * Creates a string primitive value.
04084  * `str` must point to the utf8 string of length `len`.
04085  * If `len` is ~0, `str` is assumed to be NUL-terminated and `strlen(str)` is
04086  * used.
04087  *
04088  * If `copy` is non-zero, the string data is copied and owned by the GC. The
04089  * caller can free the string data afterwards. Otherwise (`copy` is zero), the
04090  * caller owns the string data, and is responsible for not freeing it while it
04091  * is used.
04092  */
04093 v7_val_t v7_mk_string(struct v7 *v7, const char *str, size_t len, int copy);
04094 
04095 /* Returns true if given value is a primitive string value */
04096 int v7_is_string(v7_val_t v);
04097 
04098 /*
04099  * Returns a pointer to the string stored in `v7_val_t`.
04100  *
04101  * String length returned in `len`, which is allowed to be NULL. Returns NULL
04102  * if the value is not a string.
04103  *
04104  * JS strings can contain embedded NUL chars and may or may not be NUL
04105  * terminated.
04106  *
04107  * CAUTION: creating new JavaScript object, array, or string may kick in a
04108  * garbage collector, which in turn may relocate string data and invalidate
04109  * pointer returned by `v7_get_string()`.
04110  *
04111  * Short JS strings are embedded inside the `v7_val_t` value itself. This is why
04112  * a pointer to a `v7_val_t` is required. It also means that the string data
04113  * will become invalid once that `v7_val_t` value goes out of scope.
04114  */
04115 const char *v7_get_string(struct v7 *v7, v7_val_t *v, size_t *len);
04116 
04117 /*
04118  * Returns a pointer to the string stored in `v7_val_t`.
04119  *
04120  * Returns NULL if the value is not a string or if the string is not compatible
04121  * with a C string.
04122  *
04123  * C compatible strings contain exactly one NUL char, in terminal position.
04124  *
04125  * All strings owned by the V7 engine (see `v7_mk_string()`) are guaranteed to
04126  * be NUL terminated. Out of these, those that don't include embedded NUL chars
04127  * are guaranteed to be C compatible.
04128  */
04129 const char *v7_get_cstring(struct v7 *v7, v7_val_t *v);
04130 
04131 #if defined(__cplusplus)
04132 }
04133 #endif /* __cplusplus */
04134 
04135 #endif /* CS_V7_SRC_STRING_PUBLIC_H_ */
04136 #ifdef V7_MODULE_LINES
04137 #line 1 "v7/src/string.h"
04138 #endif
04139 /*
04140  * Copyright (c) 2014 Cesanta Software Limited
04141  * All rights reserved
04142  */
04143 
04144 #ifndef CS_V7_SRC_STRING_H_
04145 #define CS_V7_SRC_STRING_H_
04146 
04147 /* Amalgamated: #include "v7/src/string_public.h" */
04148 
04149 /* Amalgamated: #include "v7/src/core.h" */
04150 
04151 /*
04152  * Size of the extra space for strings mbuf that is needed to avoid frequent
04153  * reallocations
04154  */
04155 #define _V7_STRING_BUF_RESERVE 500
04156 
04157 #if defined(__cplusplus)
04158 extern "C" {
04159 #endif /* __cplusplus */
04160 
04161 WARN_UNUSED_RESULT
04162 V7_PRIVATE enum v7_err v7_char_code_at(struct v7 *v7, v7_val_t s, v7_val_t at,
04163                                        double *res);
04164 V7_PRIVATE int s_cmp(struct v7 *, val_t a, val_t b);
04165 V7_PRIVATE val_t s_concat(struct v7 *, val_t, val_t);
04166 
04167 /*
04168  * Convert a C string to to an unsigned integer.
04169  * `ok` will be set to true if the string conforms to
04170  * an unsigned long.
04171  */
04172 WARN_UNUSED_RESULT
04173 V7_PRIVATE enum v7_err str_to_ulong(struct v7 *v7, val_t v, int *ok,
04174                                     unsigned long *res);
04175 
04176 /*
04177  * Convert a V7 string to to an unsigned integer.
04178  * `ok` will be set to true if the string conforms to
04179  * an unsigned long.
04180  *
04181  * Use it if only you need strong conformity of the value to an integer;
04182  * otherwise, use `to_long()` or `to_number_v()` instead.
04183  */
04184 V7_PRIVATE unsigned long cstr_to_ulong(const char *s, size_t len, int *ok);
04185 
04186 enum embstr_flags {
04187   EMBSTR_ZERO_TERM = (1 << 0),
04188   EMBSTR_UNESCAPE = (1 << 1),
04189 };
04190 
04191 V7_PRIVATE void embed_string(struct mbuf *m, size_t offset, const char *p,
04192                              size_t len, uint8_t /*enum embstr_flags*/ flags);
04193 
04194 V7_PRIVATE size_t unescape(const char *s, size_t len, char *to);
04195 
04196 #if defined(__cplusplus)
04197 }
04198 #endif /* __cplusplus */
04199 
04200 #endif /* CS_V7_SRC_STRING_H_ */
04201 #ifdef V7_MODULE_LINES
04202 #line 1 "v7/src/exceptions_public.h"
04203 #endif
04204 /*
04205  * Copyright (c) 2014 Cesanta Software Limited
04206  * All rights reserved
04207  */
04208 
04209 /*
04210  * === Exceptions
04211  */
04212 
04213 #ifndef CS_V7_SRC_EXCEPTIONS_PUBLIC_H_
04214 #define CS_V7_SRC_EXCEPTIONS_PUBLIC_H_
04215 
04216 /* Amalgamated: #include "v7/src/core_public.h" */
04217 
04218 #if defined(__cplusplus)
04219 extern "C" {
04220 #endif /* __cplusplus */
04221 
04222 /* Throw an exception with an already existing value. */
04223 WARN_UNUSED_RESULT
04224 enum v7_err v7_throw(struct v7 *v7, v7_val_t v);
04225 
04226 /*
04227  * Throw an exception with given formatted message.
04228  *
04229  * Pass "Error" as typ for a generic error.
04230  */
04231 WARN_UNUSED_RESULT
04232 enum v7_err v7_throwf(struct v7 *v7, const char *typ, const char *err_fmt, ...);
04233 
04234 /*
04235  * Rethrow the currently thrown object. In fact, it just returns
04236  * V7_EXEC_EXCEPTION.
04237  */
04238 WARN_UNUSED_RESULT
04239 enum v7_err v7_rethrow(struct v7 *v7);
04240 
04241 /*
04242  * Returns the value that is being thrown at the moment, or `undefined` if
04243  * nothing is being thrown. If `is_thrown` is not `NULL`, it will be set
04244  * to either 0 or 1, depending on whether something is thrown at the moment.
04245  */
04246 v7_val_t v7_get_thrown_value(struct v7 *v7, unsigned char *is_thrown);
04247 
04248 /* Clears currently thrown value, if any. */
04249 void v7_clear_thrown_value(struct v7 *v7);
04250 
04251 #if defined(__cplusplus)
04252 }
04253 #endif /* __cplusplus */
04254 
04255 #endif /* CS_V7_SRC_EXCEPTIONS_PUBLIC_H_ */
04256 #ifdef V7_MODULE_LINES
04257 #line 1 "v7/src/exceptions.h"
04258 #endif
04259 /*
04260  * Copyright (c) 2014 Cesanta Software Limited
04261  * All rights reserved
04262  */
04263 
04264 #ifndef CS_V7_SRC_EXCEPTIONS_H_
04265 #define CS_V7_SRC_EXCEPTIONS_H_
04266 
04267 /* Amalgamated: #include "v7/src/exceptions_public.h" */
04268 
04269 /* Amalgamated: #include "v7/src/core.h" */
04270 
04271 /*
04272  * Try to perform some arbitrary call, and if the result is other than `V7_OK`,
04273  * "throws" an error with `V7_THROW()`
04274  */
04275 #define V7_TRY2(call, clean_label)           \
04276   do {                                       \
04277     enum v7_err _e = call;                   \
04278     V7_CHECK2(_e == V7_OK, _e, clean_label); \
04279   } while (0)
04280 
04281 /*
04282  * Sets return value to the provided one, and `goto`s `clean`.
04283  *
04284  * For this to work, you should have local `enum v7_err rcode` variable,
04285  * and a `clean` label.
04286  */
04287 #define V7_THROW2(err_code, clean_label)                              \
04288   do {                                                                \
04289     (void) v7;                                                        \
04290     rcode = (err_code);                                               \
04291     assert(rcode != V7_OK);                                           \
04292     assert(!v7_is_undefined(v7->vals.thrown_error) && v7->is_thrown); \
04293     goto clean_label;                                                 \
04294   } while (0)
04295 
04296 /*
04297  * Checks provided condition `cond`, and if it's false, then "throws"
04298  * provided `err_code` (see `V7_THROW()`)
04299  */
04300 #define V7_CHECK2(cond, err_code, clean_label) \
04301   do {                                         \
04302     if (!(cond)) {                             \
04303       V7_THROW2(err_code, clean_label);        \
04304     }                                          \
04305   } while (0)
04306 
04307 /*
04308  * Checks provided condition `cond`, and if it's false, then "throws"
04309  * internal error
04310  *
04311  * TODO(dfrank): it would be good to have formatted string: then, we can
04312  * specify file and line.
04313  */
04314 #define V7_CHECK_INTERNAL2(cond, clean_label)                         \
04315   do {                                                                \
04316     if (!(cond)) {                                                    \
04317       enum v7_err __rcode = v7_throwf(v7, "Error", "Internal error"); \
04318       (void) __rcode;                                                 \
04319       V7_THROW2(V7_INTERNAL_ERROR, clean_label);                      \
04320     }                                                                 \
04321   } while (0)
04322 
04323 /*
04324  * Shortcuts for the macros above, but they assume the clean label `clean`.
04325  */
04326 
04327 #define V7_TRY(call) V7_TRY2(call, clean)
04328 #define V7_THROW(err_code) V7_THROW2(err_code, clean)
04329 #define V7_CHECK(cond, err_code) V7_CHECK2(cond, err_code, clean)
04330 #define V7_CHECK_INTERNAL(cond) V7_CHECK_INTERNAL2(cond, clean)
04331 
04332 #if defined(__cplusplus)
04333 extern "C" {
04334 #endif /* __cplusplus */
04335 
04336 /*
04337  * At the moment, most of the exception-related functions are public, and are
04338  * declared in `exceptions_public.h`
04339  */
04340 
04341 /*
04342  * Create an instance of the exception with type `typ` (see `TYPE_ERROR`,
04343  * `SYNTAX_ERROR`, etc), and message `msg`.
04344  */
04345 V7_PRIVATE enum v7_err create_exception(struct v7 *v7, const char *typ,
04346                                         const char *msg, val_t *res);
04347 
04348 #if defined(__cplusplus)
04349 }
04350 #endif /* __cplusplus */
04351 
04352 #endif /* CS_V7_SRC_EXCEPTIONS_H_ */
04353 #ifdef V7_MODULE_LINES
04354 #line 1 "v7/src/object.h"
04355 #endif
04356 /*
04357  * Copyright (c) 2014 Cesanta Software Limited
04358  * All rights reserved
04359  */
04360 
04361 #ifndef CS_V7_SRC_OBJECT_H_
04362 #define CS_V7_SRC_OBJECT_H_
04363 
04364 /* Amalgamated: #include "v7/src/object_public.h" */
04365 
04366 /* Amalgamated: #include "v7/src/internal.h" */
04367 /* Amalgamated: #include "v7/src/core.h" */
04368 
04369 V7_PRIVATE val_t mk_object(struct v7 *v7, val_t prototype);
04370 V7_PRIVATE val_t v7_object_to_value(struct v7_object *o);
04371 V7_PRIVATE struct v7_generic_object *get_generic_object_struct(val_t v);
04372 
04373 /*
04374  * Returns pointer to the struct representing an object.
04375  * Given value must be an object (the caller can verify it
04376  * by calling `v7_is_object()`)
04377  */
04378 V7_PRIVATE struct v7_object *get_object_struct(v7_val_t v);
04379 
04380 /*
04381  * Return true if given value is a JavaScript object (will return
04382  * false for function)
04383  */
04384 V7_PRIVATE int v7_is_generic_object(v7_val_t v);
04385 
04386 V7_PRIVATE struct v7_property *v7_mk_property(struct v7 *v7);
04387 
04388 V7_PRIVATE struct v7_property *v7_get_own_property2(struct v7 *v7, val_t obj,
04389                                                     const char *name,
04390                                                     size_t len,
04391                                                     v7_prop_attr_t attrs);
04392 
04393 V7_PRIVATE struct v7_property *v7_get_own_property(struct v7 *v7, val_t obj,
04394                                                    const char *name,
04395                                                    size_t len);
04396 
04397 /*
04398  * If `len` is -1/MAXUINT/~0, then `name` must be 0-terminated
04399  *
04400  * Returns a pointer to the property structure, given an object and a name of
04401  * the property as a pointer to string buffer and length.
04402  *
04403  * See also `v7_get_property_v`
04404  */
04405 V7_PRIVATE struct v7_property *v7_get_property(struct v7 *v7, val_t obj,
04406                                                const char *name, size_t len);
04407 
04408 /*
04409  * Just like `v7_get_property`, but takes name as a `v7_val_t`
04410  */
04411 V7_PRIVATE enum v7_err v7_get_property_v(struct v7 *v7, val_t obj,
04412                                          v7_val_t name,
04413                                          struct v7_property **res);
04414 
04415 WARN_UNUSED_RESULT
04416 V7_PRIVATE enum v7_err v7_get_throwing_v(struct v7 *v7, v7_val_t obj,
04417                                          v7_val_t name, v7_val_t *res);
04418 
04419 V7_PRIVATE void v7_destroy_property(struct v7_property **p);
04420 
04421 WARN_UNUSED_RESULT
04422 V7_PRIVATE enum v7_err v7_invoke_setter(struct v7 *v7, struct v7_property *prop,
04423                                         val_t obj, val_t val);
04424 
04425 /*
04426  * Like `set_property`, but takes property name as a `val_t`
04427  */
04428 WARN_UNUSED_RESULT
04429 V7_PRIVATE enum v7_err set_property_v(struct v7 *v7, val_t obj, val_t name,
04430                                       val_t val, struct v7_property **res);
04431 
04432 /*
04433  * Like JavaScript assignment: set a property with given `name` + `len` at
04434  * the object `obj` to value `val`. Returns a property through the `res`
04435  * (which may be `NULL` if return value is not required)
04436  */
04437 WARN_UNUSED_RESULT
04438 V7_PRIVATE enum v7_err set_property(struct v7 *v7, val_t obj, const char *name,
04439                                     size_t len, v7_val_t val,
04440                                     struct v7_property **res);
04441 
04442 /*
04443  * Like `def_property()`, but takes property name as a `val_t`
04444  */
04445 WARN_UNUSED_RESULT
04446 V7_PRIVATE enum v7_err def_property_v(struct v7 *v7, val_t obj, val_t name,
04447                                       v7_prop_attr_desc_t attrs_desc, val_t val,
04448                                       uint8_t as_assign,
04449                                       struct v7_property **res);
04450 
04451 /*
04452  * Define object property, similar to JavaScript `Object.defineProperty()`.
04453  *
04454  * Just like public `v7_def()`, but returns `enum v7_err`, and therefore can
04455  * throw.
04456  *
04457  * Additionally, takes param `as_assign`: if it is non-zero, it behaves
04458  * similarly to plain JavaScript assignment in terms of some exception-related
04459  * corner cases.
04460  *
04461  * `res` may be `NULL`.
04462  */
04463 WARN_UNUSED_RESULT
04464 V7_PRIVATE enum v7_err def_property(struct v7 *v7, val_t obj, const char *name,
04465                                     size_t len, v7_prop_attr_desc_t attrs_desc,
04466                                     v7_val_t val, uint8_t as_assign,
04467                                     struct v7_property **res);
04468 
04469 V7_PRIVATE int set_method(struct v7 *v7, val_t obj, const char *name,
04470                           v7_cfunction_t *func, int num_args);
04471 
04472 V7_PRIVATE int set_cfunc_prop(struct v7 *v7, val_t o, const char *name,
04473                               v7_cfunction_t *func);
04474 
04475 /* Return address of property value or NULL if the passed property is NULL */
04476 WARN_UNUSED_RESULT
04477 V7_PRIVATE enum v7_err v7_property_value(struct v7 *v7, val_t obj,
04478                                          struct v7_property *p, val_t *res);
04479 
04480 #if V7_ENABLE__Proxy
04481 /*
04482  * Additional context for property iteration of a proxied object, see
04483  * `v7_next_prop()`.
04484  */
04485 struct prop_iter_proxy_ctx {
04486   /* Proxy target object */
04487   v7_val_t target_obj;
04488   /* Proxy handler object */
04489   v7_val_t handler_obj;
04490 
04491   /*
04492    * array returned by the `ownKeys` callback, valid if only `has_own_keys` is
04493    * set
04494    */
04495   v7_val_t own_keys;
04496   /*
04497    * callback to get property descriptor, one of these:
04498    *   - a JS or cfunction `getOwnPropertyDescriptor`
04499    *     (if `has_get_own_prop_desc_C` is not set);
04500    *   - a C callback `v7_get_own_prop_desc_cb_t`.
04501    *     (if `has_get_own_prop_desc_C` is set);
04502    */
04503   v7_val_t get_own_prop_desc;
04504 
04505   /*
04506    * if `has_own_keys` is set, `own_key_idx` represents next index in the
04507    * `own_keys` array
04508    */
04509   unsigned own_key_idx : 29;
04510 
04511   /* if set, `own_keys` is valid */
04512   unsigned has_own_keys : 1;
04513   /* if set, `get_own_prop_desc` is valid */
04514   unsigned has_get_own_prop_desc : 1;
04515   /*
04516    * if set, `get_own_prop_desc` is a C callback `has_get_own_prop_desc_C`, not
04517    * a JS callback
04518    */
04519   unsigned has_get_own_prop_desc_C : 1;
04520 };
04521 #endif
04522 
04523 /*
04524  * Like public function `v7_init_prop_iter_ctx()`, but it takes additional
04525  * argument `proxy_transp`; if it is zero, and the given `obj` is a Proxy, it
04526  * will iterate the properties of the proxy itself, not the Proxy's target.
04527  */
04528 WARN_UNUSED_RESULT
04529 V7_PRIVATE enum v7_err init_prop_iter_ctx(struct v7 *v7, v7_val_t obj,
04530                                           int proxy_transp,
04531                                           struct prop_iter_ctx *ctx);
04532 
04533 WARN_UNUSED_RESULT
04534 V7_PRIVATE enum v7_err next_prop(struct v7 *v7, struct prop_iter_ctx *ctx,
04535                                  v7_val_t *name, v7_val_t *value,
04536                                  v7_prop_attr_t *attrs, int *ok);
04537 
04538 /*
04539  * Set new prototype `proto` for the given object `obj`. Returns `0` at
04540  * success, `-1` at failure (it may fail if given `obj` is a function object:
04541  * it's impossible to change function object's prototype)
04542  */
04543 V7_PRIVATE int obj_prototype_set(struct v7 *v7, struct v7_object *obj,
04544                                  struct v7_object *proto);
04545 
04546 /*
04547  * Given a pointer to the object structure, returns a
04548  * pointer to the prototype object, or `NULL` if there is
04549  * no prototype.
04550  */
04551 V7_PRIVATE struct v7_object *obj_prototype(struct v7 *v7,
04552                                            struct v7_object *obj);
04553 
04554 V7_PRIVATE int is_prototype_of(struct v7 *v7, val_t o, val_t p);
04555 
04556 /* Get the property holding user data and destructor, or NULL */
04557 V7_PRIVATE struct v7_property *get_user_data_property(v7_val_t obj);
04558 
04559 #endif /* CS_V7_SRC_OBJECT_H_ */
04560 #ifdef V7_MODULE_LINES
04561 #line 1 "v7/src/exec_public.h"
04562 #endif
04563 /*
04564  * Copyright (c) 2014 Cesanta Software Limited
04565  * All rights reserved
04566  */
04567 
04568 /*
04569  * === Execution of JavaScript code
04570  */
04571 
04572 #ifndef CS_V7_SRC_EXEC_PUBLIC_H_
04573 #define CS_V7_SRC_EXEC_PUBLIC_H_
04574 
04575 /* Amalgamated: #include "v7/src/core_public.h" */
04576 
04577 #if defined(__cplusplus)
04578 extern "C" {
04579 #endif /* __cplusplus */
04580 
04581 /*
04582  * Execute JavaScript `js_code`. The result of evaluation is stored in
04583  * the `result` variable.
04584  *
04585  * Return:
04586  *
04587  *  - V7_OK on success. `result` contains the result of execution.
04588  *  - V7_SYNTAX_ERROR if `js_code` in not a valid code. `result` is undefined.
04589  *  - V7_EXEC_EXCEPTION if `js_code` threw an exception. `result` stores
04590  *    an exception object.
04591  *  - V7_AST_TOO_LARGE if `js_code` contains an AST segment longer than 16 bit.
04592  *    `result` is undefined. To avoid this error, build V7 with V7_LARGE_AST.
04593  */
04594 WARN_UNUSED_RESULT
04595 enum v7_err v7_exec(struct v7 *v7, const char *js_code, v7_val_t *result);
04596 
04597 /*
04598  * Options for `v7_exec_opt()`. To get default options, like `v7_exec()` uses,
04599  * just zero out this struct.
04600  */
04601 struct v7_exec_opts {
04602   /* Filename, used for stack traces only */
04603   const char *filename;
04604 
04605   /*
04606    * Object to be used as `this`. Note: when it is zeroed out, i.e. it's a
04607    * number `0`, the `undefined` value is assumed. It means that it's
04608    * impossible to actually use the number `0` as `this` object, but it makes
04609    * little sense anyway.
04610    */
04611   v7_val_t this_obj;
04612 
04613   /* Whether the given `js_code` should be interpreted as JSON, not JS code */
04614   unsigned is_json : 1;
04615 };
04616 
04617 /*
04618  * Customizable version of `v7_exec()`: allows to specify various options, see
04619  * `struct v7_exec_opts`.
04620  */
04621 enum v7_err v7_exec_opt(struct v7 *v7, const char *js_code,
04622                         const struct v7_exec_opts *opts, v7_val_t *res);
04623 
04624 /*
04625  * Same as `v7_exec()`, but loads source code from `path` file.
04626  */
04627 WARN_UNUSED_RESULT
04628 enum v7_err v7_exec_file(struct v7 *v7, const char *path, v7_val_t *result);
04629 
04630 /*
04631  * Parse `str` and store corresponding JavaScript object in `res` variable.
04632  * String `str` should be '\0'-terminated.
04633  * Return value and semantic is the same as for `v7_exec()`.
04634  */
04635 WARN_UNUSED_RESULT
04636 enum v7_err v7_parse_json(struct v7 *v7, const char *str, v7_val_t *res);
04637 
04638 /*
04639  * Same as `v7_parse_json()`, but loads JSON string from `path`.
04640  */
04641 WARN_UNUSED_RESULT
04642 enum v7_err v7_parse_json_file(struct v7 *v7, const char *path, v7_val_t *res);
04643 
04644 #if !defined(V7_NO_COMPILER)
04645 
04646 /*
04647  * Compile JavaScript code `js_code` into the byte code and write generated
04648  * byte code into opened file stream `fp`. If `generate_binary_output` is 0,
04649  * then generated byte code is in human-readable text format. Otherwise, it is
04650  * in the binary format, suitable for execution by V7 instance.
04651  * NOTE: `fp` must be a valid, opened, writable file stream.
04652  */
04653 WARN_UNUSED_RESULT
04654 enum v7_err v7_compile(const char *js_code, int generate_binary_output,
04655                        int use_bcode, FILE *fp);
04656 
04657 #endif /* V7_NO_COMPILER */
04658 
04659 /*
04660  * Call function `func` with arguments `args`, using `this_obj` as `this`.
04661  * `args` should be an array containing arguments or `undefined`.
04662  *
04663  * `res` can be `NULL` if return value is not required.
04664  */
04665 WARN_UNUSED_RESULT
04666 enum v7_err v7_apply(struct v7 *v7, v7_val_t func, v7_val_t this_obj,
04667                      v7_val_t args, v7_val_t *res);
04668 
04669 #if defined(__cplusplus)
04670 }
04671 #endif /* __cplusplus */
04672 
04673 #endif /* CS_V7_SRC_EXEC_PUBLIC_H_ */
04674 #ifdef V7_MODULE_LINES
04675 #line 1 "v7/src/exec.h"
04676 #endif
04677 /*
04678  * Copyright (c) 2014 Cesanta Software Limited
04679  * All rights reserved
04680  */
04681 
04682 #ifndef CS_V7_SRC_EXEC_H_
04683 #define CS_V7_SRC_EXEC_H_
04684 
04685 /* Amalgamated: #include "v7/src/exec_public.h" */
04686 
04687 /* Amalgamated: #include "v7/src/core.h" */
04688 
04689 #if !defined(V7_NO_COMPILER)
04690 
04691 #if defined(__cplusplus)
04692 extern "C" {
04693 #endif /* __cplusplus */
04694 
04695 /*
04696  * At the moment, all exec-related functions are public, and are declared in
04697  * `exec_public.h`
04698  */
04699 
04700 WARN_UNUSED_RESULT
04701 enum v7_err _v7_compile(const char *js_code, size_t js_code_size,
04702                         int generate_binary_output, int use_bcode, FILE *fp);
04703 
04704 #if defined(__cplusplus)
04705 }
04706 #endif /* __cplusplus */
04707 
04708 #endif /* V7_NO_COMPILER */
04709 
04710 #endif /* CS_V7_SRC_EXEC_H_ */
04711 #ifdef V7_MODULE_LINES
04712 #line 1 "v7/src/array_public.h"
04713 #endif
04714 /*
04715  * Copyright (c) 2014 Cesanta Software Limited
04716  * All rights reserved
04717  */
04718 
04719 /*
04720  * === Arrays
04721  */
04722 
04723 #ifndef CS_V7_SRC_ARRAY_PUBLIC_H_
04724 #define CS_V7_SRC_ARRAY_PUBLIC_H_
04725 
04726 /* Amalgamated: #include "v7/src/core_public.h" */
04727 
04728 #if defined(__cplusplus)
04729 extern "C" {
04730 #endif /* __cplusplus */
04731 
04732 /* Make an empty array object */
04733 v7_val_t v7_mk_array(struct v7 *v7);
04734 
04735 /* Returns true if given value is an array object */
04736 int v7_is_array(struct v7 *v7, v7_val_t v);
04737 
04738 /* Returns length on an array. If `arr` is not an array, 0 is returned. */
04739 unsigned long v7_array_length(struct v7 *v7, v7_val_t arr);
04740 
04741 /* Insert value `v` in array `arr` at the end of the array. */
04742 int v7_array_push(struct v7 *, v7_val_t arr, v7_val_t v);
04743 
04744 /*
04745  * Like `v7_array_push()`, but "returns" value through the `res` pointer
04746  * argument. `res` is allowed to be `NULL`.
04747  *
04748  * Caller should check the error code returned, and if it's something other
04749  * than `V7_OK`, perform cleanup and return this code further.
04750  */
04751 WARN_UNUSED_RESULT
04752 enum v7_err v7_array_push_throwing(struct v7 *v7, v7_val_t arr, v7_val_t v,
04753                                    int *res);
04754 
04755 /*
04756  * Return array member at index `index`. If `index` is out of bounds, undefined
04757  * is returned.
04758  */
04759 v7_val_t v7_array_get(struct v7 *, v7_val_t arr, unsigned long index);
04760 
04761 /* Insert value `v` into `arr` at index `index`. */
04762 int v7_array_set(struct v7 *v7, v7_val_t arr, unsigned long index, v7_val_t v);
04763 
04764 /*
04765  * Like `v7_array_set()`, but "returns" value through the `res` pointer
04766  * argument. `res` is allowed to be `NULL`.
04767  *
04768  * Caller should check the error code returned, and if it's something other
04769  * than `V7_OK`, perform cleanup and return this code further.
04770  */
04771 WARN_UNUSED_RESULT
04772 enum v7_err v7_array_set_throwing(struct v7 *v7, v7_val_t arr,
04773                                   unsigned long index, v7_val_t v, int *res);
04774 
04775 /* Delete value in array `arr` at index `index`, if it exists. */
04776 void v7_array_del(struct v7 *v7, v7_val_t arr, unsigned long index);
04777 
04778 #if defined(__cplusplus)
04779 }
04780 #endif /* __cplusplus */
04781 
04782 #endif /* CS_V7_SRC_ARRAY_PUBLIC_H_ */
04783 #ifdef V7_MODULE_LINES
04784 #line 1 "v7/src/array.h"
04785 #endif
04786 /*
04787  * Copyright (c) 2014 Cesanta Software Limited
04788  * All rights reserved
04789  */
04790 
04791 #ifndef CS_V7_SRC_ARRAY_H_
04792 #define CS_V7_SRC_ARRAY_H_
04793 
04794 /* Amalgamated: #include "v7/src/array_public.h" */
04795 
04796 /* Amalgamated: #include "v7/src/core.h" */
04797 
04798 #if defined(__cplusplus)
04799 extern "C" {
04800 #endif /* __cplusplus */
04801 
04802 V7_PRIVATE v7_val_t v7_mk_dense_array(struct v7 *v7);
04803 V7_PRIVATE val_t
04804 v7_array_get2(struct v7 *v7, v7_val_t arr, unsigned long index, int *has);
04805 
04806 #if defined(__cplusplus)
04807 }
04808 #endif /* __cplusplus */
04809 
04810 #endif /* CS_V7_SRC_ARRAY_H_ */
04811 #ifdef V7_MODULE_LINES
04812 #line 1 "v7/src/conversion_public.h"
04813 #endif
04814 /*
04815  * Copyright (c) 2014 Cesanta Software Limited
04816  * All rights reserved
04817  */
04818 
04819 /*
04820  * === Conversion
04821  */
04822 
04823 #ifndef CS_V7_SRC_CONVERSION_PUBLIC_H_
04824 #define CS_V7_SRC_CONVERSION_PUBLIC_H_
04825 
04826 /* Amalgamated: #include "v7/src/core_public.h" */
04827 
04828 #if defined(__cplusplus)
04829 extern "C" {
04830 #endif /* __cplusplus */
04831 
04832 /* Stringify mode, see `v7_stringify()` and `v7_stringify_throwing()` */
04833 enum v7_stringify_mode {
04834   V7_STRINGIFY_DEFAULT,
04835   V7_STRINGIFY_JSON,
04836   V7_STRINGIFY_DEBUG,
04837 };
04838 
04839 /*
04840  * Generate string representation of the JavaScript value `val` into a buffer
04841  * `buf`, `len`. If `len` is too small to hold a generated string,
04842  * `v7_stringify()` allocates required memory. In that case, it is caller's
04843  * responsibility to free the allocated buffer. Generated string is guaranteed
04844  * to be 0-terminated.
04845  *
04846  * Available stringification modes are:
04847  *
04848  * - `V7_STRINGIFY_DEFAULT`:
04849  *   Convert JS value to string, using common JavaScript semantics:
04850  *   - If value is an object:
04851  *     - call `toString()`;
04852  *     - If `toString()` returned non-primitive value, call `valueOf()`;
04853  *     - If `valueOf()` returned non-primitive value, throw `TypeError`.
04854  *   - Now we have a primitive, and if it's not a string, then stringify it.
04855  *
04856  * - `V7_STRINGIFY_JSON`:
04857  *   Generate JSON output
04858  *
04859  * - `V7_STRINGIFY_DEBUG`:
04860  *   Mostly like JSON, but will not omit non-JSON objects like functions.
04861  *
04862  * Example code:
04863  *
04864  *     char buf[100], *p;
04865  *     p = v7_stringify(v7, obj, buf, sizeof(buf), V7_STRINGIFY_DEFAULT);
04866  *     printf("JSON string: [%s]\n", p);
04867  *     if (p != buf) {
04868  *       free(p);
04869  *     }
04870  */
04871 char *v7_stringify(struct v7 *v7, v7_val_t v, char *buf, size_t len,
04872                    enum v7_stringify_mode mode);
04873 
04874 /*
04875  * Like `v7_stringify()`, but "returns" value through the `res` pointer
04876  * argument. `res` must not be `NULL`.
04877  *
04878  * Caller should check the error code returned, and if it's something other
04879  * than `V7_OK`, perform cleanup and return this code further.
04880  */
04881 WARN_UNUSED_RESULT
04882 enum v7_err v7_stringify_throwing(struct v7 *v7, v7_val_t v, char *buf,
04883                                   size_t size, enum v7_stringify_mode mode,
04884                                   char **res);
04885 
04886 /*
04887  * A shortcut for `v7_stringify()` with `V7_STRINGIFY_JSON`
04888  */
04889 #define v7_to_json(a, b, c, d) v7_stringify(a, b, c, d, V7_STRINGIFY_JSON)
04890 
04891 /* Returns true if given value evaluates to true, as in `if (v)` statement. */
04892 int v7_is_truthy(struct v7 *v7, v7_val_t v);
04893 
04894 #if defined(__cplusplus)
04895 }
04896 #endif /* __cplusplus */
04897 
04898 #endif /* CS_V7_SRC_CONVERSION_PUBLIC_H_ */
04899 #ifdef V7_MODULE_LINES
04900 #line 1 "v7/src/conversion.h"
04901 #endif
04902 /*
04903  * Copyright (c) 2014 Cesanta Software Limited
04904  * All rights reserved
04905  */
04906 
04907 #ifndef CS_V7_SRC_CONVERSION_H_
04908 #define CS_V7_SRC_CONVERSION_H_
04909 
04910 /* Amalgamated: #include "v7/src/conversion_public.h" */
04911 
04912 /* Amalgamated: #include "v7/src/core.h" */
04913 
04914 #if defined(__cplusplus)
04915 extern "C" {
04916 #endif /* __cplusplus */
04917 
04918 /*
04919  * Conversion API
04920  * ==============
04921  *
04922  * - If you need to convert any JS value to string using common JavaScript
04923  *   semantics, use `to_string()`, which can convert to both `v7_val_t` or your
04924  *   C buffer.
04925  *
04926  * - If you need to convert any JS value to number using common JavaScript
04927  *   semantics, use `to_number_v()`;
04928  *
04929  * - If you need to convert any JS value to primitive, without forcing it to
04930  *   string or number, use `to_primitive()` (see comments for this function for
04931  *   details);
04932  *
04933  * - If you have a primitive value, and you want to convert it to either string
04934  *   or number, you can still use functions above: `to_string()` and
04935  *   `to_number_v()`. But if you want to save a bit of work, use:
04936  *   - `primitive_to_str()`
04937  *   - `primitive_to_number()`
04938  *
04939  *   In fact, these are a bit lower level functions, which are used by
04940  *   `to_string()` and `to_number_v()` after converting value to
04941  *   primitive.
04942  *
04943  * - If you want to call `valueOf()` on the object, use `obj_value_of()`;
04944  * - If you want to call `toString()` on the object, use `obj_to_string()`;
04945  *
04946  * - If you need to convert any JS value to boolean using common JavaScript
04947  *   semantics (as in the expression `if (v)` or `Boolean(v)`), use
04948  *   `to_boolean_v()`.
04949  *
04950  * - If you want to get the JSON representation of a value, use
04951  *   `to_json_or_debug()`, passing `0` as `is_debug` : writes data to your C
04952  *   buffer;
04953  *
04954  * - There is one more kind of representation: `DEBUG`. It's very similar to
04955  *   JSON, but it will not omit non-JSON values, such as functions. Again, use
04956  *   `to_json_or_debug()`, but pass `1` as `is_debug` this time: writes data to
04957  *   your C buffer;
04958  *
04959  * Additionally, for any kind of to-string conversion into C buffer, you can
04960  * use a convenience wrapper function (mostly for public API), which can
04961  * allocate the buffer for you:
04962  *
04963  *   - `v7_stringify_throwing()`;
04964  *   - `v7_stringify()` : the same as above, but doesn't throw.
04965  *
04966  * There are a couple of more specific conversions, which I'd like to probably
04967  * refactor or remove in the future:
04968  *
04969  * - `to_long()` : if given value is `undefined`, returns provided default
04970  *   value; otherwise, converts value to number, and then truncates to `long`.
04971  * - `str_to_ulong()` : converts the value to string, and tries to parse it as
04972  *   an integer. Use it if only you need strong conformity ov the value to an
04973  *   integer (currently, it's used only when examining keys of array object)
04974  *
04975  * ----------------------------------------------------------------------------
04976  *
04977  * TODO(dfrank):
04978  *   - Rename functions like `v7_get_double(v7, )`, `get_object_struct()` to
04979  *something
04980  *     that will clearly identify that they convert to some C entity, not
04981  *     `v7_val_t`
04982  *   - Maybe make `to_string()` private? But then, there will be no way
04983  *     in public API to convert value to `v7_val_t` string, so, for now
04984  *     it's here.
04985  *   - When we agree on what goes to public API, and what does not, write
04986  *     similar conversion guide for public API (in `conversion_public.h`)
04987  */
04988 
04989 /*
04990  * Convert any JS value to number, using common JavaScript semantics:
04991  *
04992  * - If value is an object:
04993  *   - call `valueOf()`;
04994  *   - If `valueOf()` returned non-primitive value, call `toString()`;
04995  *   - If `toString()` returned non-primitive value, throw `TypeError`.
04996  * - Now we have a primitive, and if it's not a number, then:
04997  *   - If `undefined`, return `NaN`
04998  *   - If `null`, return 0.0
04999  *   - If boolean, return either 1 or 0
05000  *   - If string, try to parse it.
05001  */
05002 WARN_UNUSED_RESULT
05003 V7_PRIVATE enum v7_err to_number_v(struct v7 *v7, v7_val_t v, v7_val_t *res);
05004 
05005 /*
05006  * Convert any JS value to string, using common JavaScript semantics,
05007  * see `v7_stringify()` and `V7_STRINGIFY_DEFAULT`.
05008  *
05009  * This function can return multiple things:
05010  *
05011  * - String as a `v7_val_t` (if `res` is not `NULL`)
05012  * - String copied to buffer `buf` with max size `buf_size` (if `buf` is not
05013  *   `NULL`)
05014  * - Length of actual string, independently of `buf_size` (if `res_len` is not
05015  *   `NULL`)
05016  *
05017  * The rationale of having multiple formats of returned value is the following:
05018  *
05019  * Initially, to-string conversion always returned `v7_val_t`. But it turned
05020  * out that there are situations where such an approach adds useless pressure
05021  * on GC: e.g. when converting `undefined` to string, and the caller actually
05022  * needs a C buffer, not a `v7_val_t`.
05023  *
05024  * Always returning string through `buf`+`buf_size` is bad as well: if we
05025  * convert from object to string, and either `toString()` or `valueOf()`
05026  * returned string, then we'd have to get string data from it, write to buffer,
05027  * and if caller actually need `v7_val_t`, then it will have to create new
05028  * instance of the same string: again, useless GC pressure.
05029  *
05030  * So, we have to use the combined approach. This function will make minimal
05031  * work depending on give `res` and `buf`.
05032  */
05033 WARN_UNUSED_RESULT
05034 V7_PRIVATE enum v7_err to_string(struct v7 *v7, v7_val_t v, v7_val_t *res,
05035                                  char *buf, size_t buf_size, size_t *res_len);
05036 
05037 /*
05038  * Convert value to primitive, if it's not already.
05039  *
05040  * For object-to-primitive conversion, each object in JavaScript has two
05041  * methods: `toString()` and `valueOf()`.
05042  *
05043  * When converting object to string, JavaScript does the following:
05044  *   - call `toString()`;
05045  *   - If `toString()` returned non-primitive value, call `valueOf()`;
05046  *   - If `valueOf()` returned non-primitive value, throw `TypeError`.
05047  *
05048  * When converting object to number, JavaScript calls the same functions,
05049  * but in reverse:
05050  *   - call `valueOf()`;
05051  *   - If `valueOf()` returned non-primitive value, call `toString()`;
05052  *   - If `toString()` returned non-primitive value, throw `TypeError`.
05053  *
05054  * This function `to_primitive()` performs either type of conversion,
05055  * depending on the `hint` argument (see `enum to_primitive_hint`).
05056  */
05057 enum to_primitive_hint {
05058   /* Call `valueOf()` first, then `toString()` if needed */
05059   V7_TO_PRIMITIVE_HINT_NUMBER,
05060 
05061   /* Call `toString()` first, then `valueOf()` if needed */
05062   V7_TO_PRIMITIVE_HINT_STRING,
05063 
05064   /* STRING for Date, NUMBER for everything else */
05065   V7_TO_PRIMITIVE_HINT_AUTO,
05066 };
05067 WARN_UNUSED_RESULT
05068 enum v7_err to_primitive(struct v7 *v7, v7_val_t v, enum to_primitive_hint hint,
05069                          v7_val_t *res);
05070 
05071 /*
05072  * Convert primitive value to string, using common JavaScript semantics. If
05073  * you need to convert any value to string (either object or primitive),
05074  * see `to_string()` or `v7_stringify_throwing()`.
05075  *
05076  * This function can return multiple things:
05077  *
05078  * - String as a `v7_val_t` (if `res` is not `NULL`)
05079  * - String copied to buffer `buf` with max size `buf_size` (if `buf` is not
05080  *   `NULL`)
05081  * - Length of actual string, independently of `buf_size` (if `res_len` is not
05082  *   `NULL`)
05083  */
05084 WARN_UNUSED_RESULT
05085 V7_PRIVATE enum v7_err primitive_to_str(struct v7 *v7, val_t v, val_t *res,
05086                                         char *buf, size_t buf_size,
05087                                         size_t *res_len);
05088 
05089 /*
05090  * Convert primitive value to number, using common JavaScript semantics. If you
05091  * need to convert any value to number (either object or primitive), see
05092  * `to_number_v()`
05093  */
05094 WARN_UNUSED_RESULT
05095 V7_PRIVATE enum v7_err primitive_to_number(struct v7 *v7, val_t v, val_t *res);
05096 
05097 /*
05098  * Convert value to JSON or "debug" representation, depending on whether
05099  * `is_debug` is non-zero. The "debug" is the same as JSON, but non-JSON values
05100  * (functions, `undefined`, etc) will not be omitted.
05101  *
05102  * See also `v7_stringify()`, `v7_stringify_throwing()`.
05103  */
05104 WARN_UNUSED_RESULT
05105 V7_PRIVATE enum v7_err to_json_or_debug(struct v7 *v7, val_t v, char *buf,
05106                                         size_t size, size_t *res_len,
05107                                         uint8_t is_debug);
05108 
05109 /*
05110  * Calls `valueOf()` on given object `v`
05111  */
05112 WARN_UNUSED_RESULT
05113 V7_PRIVATE enum v7_err obj_value_of(struct v7 *v7, val_t v, val_t *res);
05114 
05115 /*
05116  * Calls `toString()` on given object `v`
05117  */
05118 WARN_UNUSED_RESULT
05119 V7_PRIVATE enum v7_err obj_to_string(struct v7 *v7, val_t v, val_t *res);
05120 
05121 /*
05122  * If given value is `undefined`, returns `default_value`; otherwise,
05123  * converts value to number, and then truncates to `long`.
05124  */
05125 WARN_UNUSED_RESULT
05126 V7_PRIVATE enum v7_err to_long(struct v7 *v7, val_t v, long default_value,
05127                                long *res);
05128 
05129 /*
05130  * Converts value to boolean as in the expression `if (v)` or `Boolean(v)`.
05131  *
05132  * NOTE: it can't throw (even if the given value is an object with `valueOf()`
05133  * that throws), so it returns `val_t` directly.
05134  */
05135 WARN_UNUSED_RESULT
05136 V7_PRIVATE val_t to_boolean_v(struct v7 *v7, val_t v);
05137 
05138 #if defined(__cplusplus)
05139 }
05140 #endif /* __cplusplus */
05141 
05142 #endif /* CS_V7_SRC_CONVERSION_H_ */
05143 #ifdef V7_MODULE_LINES
05144 #line 1 "v7/src/varint.h"
05145 #endif
05146 /*
05147  * Copyright (c) 2014 Cesanta Software Limited
05148  * All rights reserved
05149  */
05150 
05151 #ifndef CS_V7_SRC_VARINT_H_
05152 #define CS_V7_SRC_VARINT_H_
05153 
05154 /* Amalgamated: #include "v7/src/internal.h" */
05155 
05156 #if defined(__cplusplus)
05157 extern "C" {
05158 #endif /* __cplusplus */
05159 
05160 V7_PRIVATE int encode_varint(size_t len, unsigned char *p);
05161 V7_PRIVATE size_t decode_varint(const unsigned char *p, int *llen);
05162 V7_PRIVATE int calc_llen(size_t len);
05163 
05164 #if defined(__cplusplus)
05165 }
05166 #endif /* __cplusplus */
05167 
05168 #endif /* CS_V7_SRC_VARINT_H_ */
05169 #ifdef V7_MODULE_LINES
05170 #line 1 "common/cs_strtod.h"
05171 #endif
05172 /*
05173  * Copyright (c) 2014-2016 Cesanta Software Limited
05174  * All rights reserved
05175  */
05176 
05177 #ifndef CS_COMMON_CS_STRTOD_H_
05178 #define CS_COMMON_CS_STRTOD_H_
05179 
05180 double cs_strtod(const char *str, char **endptr);
05181 
05182 #endif /* CS_COMMON_CS_STRTOD_H_ */
05183 #ifdef V7_MODULE_LINES
05184 #line 1 "v7/src/ast.h"
05185 #endif
05186 /*
05187  * Copyright (c) 2014 Cesanta Software Limited
05188  * All rights reserved
05189  */
05190 
05191 #ifndef CS_V7_SRC_AST_H_
05192 #define CS_V7_SRC_AST_H_
05193 
05194 #include <stdio.h>
05195 /* Amalgamated: #include "common/mbuf.h" */
05196 /* Amalgamated: #include "v7/src/internal.h" */
05197 /* Amalgamated: #include "v7/src/core.h" */
05198 
05199 #if !defined(V7_NO_COMPILER)
05200 
05201 #if defined(__cplusplus)
05202 extern "C" {
05203 #endif /* __cplusplus */
05204 
05205 #define BIN_AST_SIGNATURE "V\007ASTV10"
05206 
05207 enum ast_tag {
05208   AST_NOP,
05209   AST_SCRIPT,
05210   AST_VAR,
05211   AST_VAR_DECL,
05212   AST_FUNC_DECL,
05213   AST_IF,
05214   AST_FUNC,
05215 
05216   AST_ASSIGN,
05217   AST_REM_ASSIGN,
05218   AST_MUL_ASSIGN,
05219   AST_DIV_ASSIGN,
05220   AST_XOR_ASSIGN,
05221   AST_PLUS_ASSIGN,
05222   AST_MINUS_ASSIGN,
05223   AST_OR_ASSIGN,
05224   AST_AND_ASSIGN,
05225   AST_LSHIFT_ASSIGN,
05226   AST_RSHIFT_ASSIGN,
05227   AST_URSHIFT_ASSIGN,
05228 
05229   AST_NUM,
05230   AST_IDENT,
05231   AST_STRING,
05232   AST_REGEX,
05233   AST_LABEL,
05234 
05235   AST_SEQ,
05236   AST_WHILE,
05237   AST_DOWHILE,
05238   AST_FOR,
05239   AST_FOR_IN,
05240   AST_COND,
05241 
05242   AST_DEBUGGER,
05243   AST_BREAK,
05244   AST_LABELED_BREAK,
05245   AST_CONTINUE,
05246   AST_LABELED_CONTINUE,
05247   AST_RETURN,
05248   AST_VALUE_RETURN,
05249   AST_THROW,
05250 
05251   AST_TRY,
05252   AST_SWITCH,
05253   AST_CASE,
05254   AST_DEFAULT,
05255   AST_WITH,
05256 
05257   AST_LOGICAL_OR,
05258   AST_LOGICAL_AND,
05259   AST_OR,
05260   AST_XOR,
05261   AST_AND,
05262 
05263   AST_EQ,
05264   AST_EQ_EQ,
05265   AST_NE,
05266   AST_NE_NE,
05267 
05268   AST_LE,
05269   AST_LT,
05270   AST_GE,
05271   AST_GT,
05272   AST_IN,
05273   AST_INSTANCEOF,
05274 
05275   AST_LSHIFT,
05276   AST_RSHIFT,
05277   AST_URSHIFT,
05278 
05279   AST_ADD,
05280   AST_SUB,
05281 
05282   AST_REM,
05283   AST_MUL,
05284   AST_DIV,
05285 
05286   AST_POSITIVE,
05287   AST_NEGATIVE,
05288   AST_NOT,
05289   AST_LOGICAL_NOT,
05290   AST_VOID,
05291   AST_DELETE,
05292   AST_TYPEOF,
05293   AST_PREINC,
05294   AST_PREDEC,
05295 
05296   AST_POSTINC,
05297   AST_POSTDEC,
05298 
05299   AST_MEMBER,
05300   AST_INDEX,
05301   AST_CALL,
05302 
05303   AST_NEW,
05304 
05305   AST_ARRAY,
05306   AST_OBJECT,
05307   AST_PROP,
05308   AST_GETTER,
05309   AST_SETTER,
05310 
05311   AST_THIS,
05312   AST_TRUE,
05313   AST_FALSE,
05314   AST_NULL,
05315   AST_UNDEFINED,
05316 
05317   AST_USE_STRICT,
05318 
05319   AST_MAX_TAG
05320 };
05321 
05322 struct ast {
05323   struct mbuf mbuf;
05324   int refcnt;
05325   int has_overflow;
05326 };
05327 
05328 typedef unsigned long ast_off_t;
05329 
05330 #if __GNUC__ >= 4 && __GNUC_MINOR__ >= 8
05331 #define GCC_HAS_PRAGMA_DIAGNOSTIC
05332 #endif
05333 
05334 #ifdef GCC_HAS_PRAGMA_DIAGNOSTIC
05335 /*
05336  * TODO(mkm): GCC complains that bitfields on char are not standard
05337  */
05338 #pragma GCC diagnostic push
05339 #pragma GCC diagnostic ignored "-Wpedantic"
05340 #endif
05341 struct ast_node_def {
05342 #ifndef V7_DISABLE_AST_TAG_NAMES
05343   const char *name; /* tag name, for debugging and serialization */
05344 #endif
05345   unsigned char has_varint : 1;   /* has a varint body */
05346   unsigned char has_inlined : 1;  /* inlined data whose size is in varint fld */
05347   unsigned char num_skips : 3;    /* number of skips */
05348   unsigned char num_subtrees : 3; /* number of fixed subtrees */
05349 };
05350 extern const struct ast_node_def ast_node_defs[];
05351 #if V7_ENABLE_FOOTPRINT_REPORT
05352 extern const size_t ast_node_defs_size;
05353 extern const size_t ast_node_defs_count;
05354 #endif
05355 #ifdef GCC_HAS_PRAGMA_DIAGNOSTIC
05356 #pragma GCC diagnostic pop
05357 #endif
05358 
05359 enum ast_which_skip {
05360   AST_END_SKIP = 0,
05361   AST_VAR_NEXT_SKIP = 1,
05362   AST_SCRIPT_FIRST_VAR_SKIP = AST_VAR_NEXT_SKIP,
05363   AST_FOR_BODY_SKIP = 1,
05364   AST_DO_WHILE_COND_SKIP = 1,
05365   AST_END_IF_TRUE_SKIP = 1,
05366   AST_TRY_CATCH_SKIP = 1,
05367   AST_TRY_FINALLY_SKIP = 2,
05368   AST_FUNC_FIRST_VAR_SKIP = AST_VAR_NEXT_SKIP,
05369   AST_FUNC_BODY_SKIP = 2,
05370   AST_SWITCH_DEFAULT_SKIP = 1
05371 };
05372 
05373 V7_PRIVATE void ast_init(struct ast *, size_t);
05374 V7_PRIVATE void ast_optimize(struct ast *);
05375 V7_PRIVATE void ast_free(struct ast *);
05376 
05377 /*
05378  * Begins an AST node by inserting a tag to the AST at the given offset.
05379  *
05380  * It also allocates space for the fixed_size payload and the space for
05381  * the skips.
05382  *
05383  * The caller is responsible for appending children.
05384  *
05385  * Returns the offset of the node payload (one byte after the tag).
05386  * This offset can be passed to `ast_set_skip`.
05387  */
05388 V7_PRIVATE ast_off_t
05389 ast_insert_node(struct ast *a, ast_off_t pos, enum ast_tag tag);
05390 
05391 /*
05392  * Modify tag which is already added to buffer. Keeps `AST_TAG_LINENO_PRESENT`
05393  * flag.
05394  */
05395 V7_PRIVATE void ast_modify_tag(struct ast *a, ast_off_t tag_off,
05396                                enum ast_tag tag);
05397 
05398 #ifndef V7_DISABLE_LINE_NUMBERS
05399 /*
05400  * Add line_no varint after all skips of the tag at the offset `tag_off`, and
05401  * marks the tag byte.
05402  *
05403  * Byte at the offset `tag_off` should be a valid tag.
05404  */
05405 V7_PRIVATE void ast_add_line_no(struct ast *a, ast_off_t tag_off, int line_no);
05406 #endif
05407 
05408 /*
05409  * Patches a given skip slot for an already emitted node with the
05410  * current write cursor position (e.g. AST length).
05411  *
05412  * This is intended to be invoked when a node with a variable number
05413  * of child subtrees is closed, or when the consumers need a shortcut
05414  * to the next sibling.
05415  *
05416  * Each node type has a different number and semantic for skips,
05417  * all of them defined in the `ast_which_skip` enum.
05418  * All nodes having a variable number of child subtrees must define
05419  * at least the `AST_END_SKIP` skip, which effectively skips a node
05420  * boundary.
05421  *
05422  * Every tree reader can assume this and safely skip unknown nodes.
05423  *
05424  * `pos` should be an offset of the byte right after a tag.
05425  */
05426 V7_PRIVATE ast_off_t
05427 ast_set_skip(struct ast *a, ast_off_t pos, enum ast_which_skip skip);
05428 
05429 /*
05430  * Patches a given skip slot for an already emitted node with the value
05431  * (stored as delta relative to the `pos` node) of the `where` argument.
05432  */
05433 V7_PRIVATE ast_off_t ast_modify_skip(struct ast *a, ast_off_t pos,
05434                                      ast_off_t where, enum ast_which_skip skip);
05435 
05436 /*
05437  * Returns the offset in AST to which the given `skip` points.
05438  *
05439  * `pos` should be an offset of the byte right after a tag.
05440  */
05441 V7_PRIVATE ast_off_t
05442 ast_get_skip(struct ast *a, ast_off_t pos, enum ast_which_skip skip);
05443 
05444 /*
05445  * Returns the tag from the offset `ppos`, and shifts `ppos` by 1.
05446  */
05447 V7_PRIVATE enum ast_tag ast_fetch_tag(struct ast *a, ast_off_t *ppos);
05448 
05449 /*
05450  * Moves the cursor to the tag's varint and inlined data (if there are any, see
05451  * `struct ast_node_def::has_varint` and `struct ast_node_def::has_inlined`).
05452  *
05453  * Technically, it skips node's "skips" and line number data, if either is
05454  * present.
05455  *
05456  * Assumes a cursor (`ppos`) positioned right after a tag.
05457  */
05458 V7_PRIVATE void ast_move_to_inlined_data(struct ast *a, ast_off_t *ppos);
05459 
05460 /*
05461  * Moves the cursor to the tag's subtrees (if there are any,
05462  * see `struct ast_node_def::num_subtrees`), or to the next node in case the
05463  * current node has no subtrees.
05464  *
05465  * Technically, it skips node's "skips", line number data, and inlined data, if
05466  * either is present.
05467  *
05468  * Assumes a cursor (`ppos`) positioned right after a tag.
05469  */
05470 V7_PRIVATE void ast_move_to_children(struct ast *a, ast_off_t *ppos);
05471 
05472 /* Helper to add a node with inlined data. */
05473 V7_PRIVATE ast_off_t ast_insert_inlined_node(struct ast *a, ast_off_t pos,
05474                                              enum ast_tag tag, const char *name,
05475                                              size_t len);
05476 
05477 /*
05478  * Returns the line number encoded in the node, or `0` in case of none is
05479  * encoded.
05480  *
05481  * `pos` should be an offset of the byte right after a tag.
05482  */
05483 V7_PRIVATE int ast_get_line_no(struct ast *a, ast_off_t pos);
05484 
05485 /*
05486  * `pos` should be an offset of the byte right after a tag
05487  */
05488 V7_PRIVATE char *ast_get_inlined_data(struct ast *a, ast_off_t pos, size_t *n);
05489 
05490 /*
05491  * Returns the `double` number inlined in the node
05492  */
05493 V7_PRIVATE double ast_get_num(struct ast *a, ast_off_t pos);
05494 
05495 /*
05496  * Skips the node and all its subnodes.
05497  *
05498  * Cursor (`ppos`) should be at the tag byte
05499  */
05500 V7_PRIVATE void ast_skip_tree(struct ast *a, ast_off_t *ppos);
05501 
05502 V7_PRIVATE void ast_dump_tree(FILE *fp, struct ast *a, ast_off_t *ppos,
05503                               int depth);
05504 
05505 V7_PRIVATE void release_ast(struct v7 *v7, struct ast *a);
05506 
05507 #if defined(__cplusplus)
05508 }
05509 #endif /* __cplusplus */
05510 
05511 #endif /* V7_NO_COMPILER */
05512 
05513 #endif /* CS_V7_SRC_AST_H_ */
05514 #ifdef V7_MODULE_LINES
05515 #line 1 "v7/src/bcode.h"
05516 #endif
05517 /*
05518  * Copyright (c) 2014 Cesanta Software Limited
05519  * All rights reserved
05520  */
05521 
05522 #ifndef CS_V7_SRC_BCODE_H_
05523 #define CS_V7_SRC_BCODE_H_
05524 
05525 #define BIN_BCODE_SIGNATURE "V\007BCODE:"
05526 
05527 #if !defined(V7_NAMES_CNT_WIDTH)
05528 #define V7_NAMES_CNT_WIDTH 10
05529 #endif
05530 
05531 #if !defined(V7_ARGS_CNT_WIDTH)
05532 #define V7_ARGS_CNT_WIDTH 8
05533 #endif
05534 
05535 #define V7_NAMES_CNT_MAX ((1 << V7_NAMES_CNT_WIDTH) - 1)
05536 #define V7_ARGS_CNT_MAX ((1 << V7_ARGS_CNT_WIDTH) - 1)
05537 
05538 /* Amalgamated: #include "v7/src/internal.h" */
05539 /* Amalgamated: #include "v7/src/core.h" */
05540 /* Amalgamated: #include "v7/src/opcodes.h" */
05541 /* Amalgamated: #include "v7/src/string.h" */
05542 /* Amalgamated: #include "v7/src/object.h" */
05543 /* Amalgamated: #include "v7/src/primitive.h" */
05544 /* Amalgamated: #include "common/mbuf.h" */
05545 
05546 enum bcode_inline_lit_type_tag {
05547   BCODE_INLINE_STRING_TYPE_TAG = 0,
05548   BCODE_INLINE_NUMBER_TYPE_TAG,
05549   BCODE_INLINE_FUNC_TYPE_TAG,
05550   BCODE_INLINE_REGEXP_TYPE_TAG,
05551 
05552   BCODE_MAX_INLINE_TYPE_TAG
05553 };
05554 
05555 #if defined(__cplusplus)
05556 extern "C" {
05557 #endif /* __cplusplus */
05558 
05559 typedef uint32_t bcode_off_t;
05560 
05561 /*
05562  * Each JS function will have one bcode structure
05563  * containing the instruction stream, a literal table, and function
05564  * metadata.
05565  * Instructions contain references to literals (strings, constants, etc)
05566  *
05567  * The bcode struct can be shared between function instances
05568  * and keeps a reference count used to free it in the function destructor.
05569  */
05570 struct bcode {
05571   /*
05572    * Names + instruction opcode.
05573    * Names are null-terminates strings. For function's bcode, there are:
05574    *  - function name (for anonymous function, the name is still present: an
05575    *    empty string);
05576    *  - arg names (a number of args is determined by `args_cnt`, see below);
05577    *  - local names (a number or locals can be calculated:
05578    *    `(names_cnt - args_cnt - 1)`).
05579    *
05580    * For script's bcode, there are just local names.
05581    */
05582   struct v7_vec ops;
05583 
05584   /* Literal table */
05585   struct v7_vec lit;
05586 
05587 #ifndef V7_DISABLE_FILENAMES
05588   /* Name of the file from which this bcode was generated (used for debug) */
05589   void *filename;
05590 #endif
05591 
05592   /* Reference count */
05593   uint8_t refcnt;
05594 
05595   /* Total number of null-terminated strings in the beginning of `ops` */
05596   unsigned int names_cnt : V7_NAMES_CNT_WIDTH;
05597 
05598   /* Number of args (should be <= `(names_cnt + 1)`) */
05599   unsigned int args_cnt : V7_ARGS_CNT_WIDTH;
05600 
05601   unsigned int strict_mode : 1;
05602   /*
05603    * If true this structure lives on read only memory, either
05604    * mmapped or constant data section.
05605    */
05606   unsigned int frozen : 1;
05607 
05608   /* If set, `ops.buf` points to ROM, so we shouldn't free it */
05609   unsigned int ops_in_rom : 1;
05610   /* Set for deserialized bcode. Used for metrics only */
05611   unsigned int deserialized : 1;
05612 
05613   /* Set when `ops` contains function name as the first `name` */
05614   unsigned int func_name_present : 1;
05615 
05616 #ifndef V7_DISABLE_FILENAMES
05617   /* If set, `filename` points to ROM, so we shouldn't free it */
05618   unsigned int filename_in_rom : 1;
05619 #endif
05620 };
05621 
05622 /*
05623  * Bcode builder context: it contains mutable mbufs for opcodes and literals,
05624  * whereas the bcode itself contains just vectors (`struct v7_vec`).
05625  */
05626 struct bcode_builder {
05627   struct v7 *v7;
05628   struct bcode *bcode;
05629 
05630   struct mbuf ops; /* names + instruction opcode */
05631   struct mbuf lit; /* literal table */
05632 };
05633 
05634 V7_PRIVATE void bcode_builder_init(struct v7 *v7,
05635                                    struct bcode_builder *bbuilder,
05636                                    struct bcode *bcode);
05637 V7_PRIVATE void bcode_builder_finalize(struct bcode_builder *bbuilder);
05638 
05639 /*
05640  * Note: `filename` must be either:
05641  *
05642  * - `NULL`. In this case, `filename_in_rom` is ignored.
05643  * - A pointer to ROM (or to any other unmanaged memory). `filename_in_rom`
05644  *   must be set to 1.
05645  * - A pointer returned by `shdata_create()`, i.e. a pointer to shared data.
05646  *
05647  * If you need to copy filename from another bcode, just pass NULL initially,
05648  * and after bcode is initialized, call `bcode_copy_filename_from()`.
05649  *
05650  * To get later a proper null-terminated filename string from bcode, use
05651  * `bcode_get_filename()`.
05652  */
05653 V7_PRIVATE void bcode_init(struct bcode *bcode, uint8_t strict_mode,
05654                            void *filename, uint8_t filename_in_rom);
05655 V7_PRIVATE void bcode_free(struct v7 *v7, struct bcode *bcode);
05656 V7_PRIVATE void release_bcode(struct v7 *v7, struct bcode *bcode);
05657 V7_PRIVATE void retain_bcode(struct v7 *v7, struct bcode *bcode);
05658 
05659 #ifndef V7_DISABLE_FILENAMES
05660 /*
05661  * Return a pointer to null-terminated filename string
05662  */
05663 V7_PRIVATE const char *bcode_get_filename(struct bcode *bcode);
05664 #endif
05665 
05666 /*
05667  * Copy filename from `src` to `dst`. If source filename is a pointer to ROM,
05668  * then just the pointer is copied; otherwise, appropriate shdata pointer is
05669  * retained.
05670  */
05671 V7_PRIVATE void bcode_copy_filename_from(struct bcode *dst, struct bcode *src);
05672 
05673 /*
05674  * Serialize a bcode structure.
05675  *
05676  * All literals, including functions, are inlined into `ops` data; see
05677  * the serialization logic in `bcode_op_lit()`.
05678  *
05679  * The root bcode looks just like a regular function.
05680  *
05681  * This function is used only internally, but used in a complicated mix of
05682  * configurations, hence the commented V7_PRIVATE
05683  */
05684 /*V7_PRIVATE*/ void bcode_serialize(struct v7 *v7, struct bcode *bcode,
05685                                     FILE *f);
05686 
05687 V7_PRIVATE void bcode_deserialize(struct v7 *v7, struct bcode *bcode,
05688                                   const char *data);
05689 
05690 #ifdef V7_BCODE_DUMP
05691 V7_PRIVATE void dump_bcode(struct v7 *v7, FILE *, struct bcode *);
05692 #endif
05693 
05694 /* mode of literal storage: in literal table or inlined in `ops` */
05695 enum lit_mode {
05696   /* literal stored in table, index is in `lit_t::lit_idx` */
05697   LIT_MODE__TABLE,
05698   /* literal should be inlined in `ops`, value is in `lit_t::inline_val` */
05699   LIT_MODE__INLINED,
05700 };
05701 
05702 /*
05703  * Result of the addition of literal value to bcode (see `bcode_add_lit()`).
05704  * There are two possible cases:
05705  *
05706  * - Literal is added to the literal table. In this case, `mode ==
05707  *   LIT_MODE__TABLE`, and the index of the literal is stored in `lit_idx`
05708  * - Literal is not added anywhere, and should be inlined into `ops`. In this
05709  *   case, `mode == LIT_MODE__INLINED`, and the value to inline is stored in
05710  *   `inline_val`.
05711  *
05712  * It's `bcode_op_lit()` who handles both of these cases.
05713  */
05714 typedef struct {
05715   union {
05716     /*
05717      * index in literal table;
05718      * NOTE: valid if only `mode == LIT_MODE__TABLE`
05719      */
05720     size_t lit_idx;
05721 
05722     /*
05723      * value to be inlined into `ops`;
05724      * NOTE: valid if only `mode == LIT_MODE__INLINED`
05725      */
05726     v7_val_t inline_val;
05727   } v; /* anonymous unions are a c11 feature */
05728 
05729   /*
05730    * mode of literal storage (see `enum lit_mode`)
05731    * NOTE: we need one more bit, because enum can be signed
05732    * on some compilers (e.g. msvc) and thus will get signextended
05733    * when moved to a `enum lit_mode` variable basically corrupting
05734    * the value. See https://github.com/cesanta/v7/issues/551
05735    */
05736   enum lit_mode mode : 2;
05737 } lit_t;
05738 
05739 V7_PRIVATE void bcode_op(struct bcode_builder *bbuilder, uint8_t op);
05740 
05741 #ifndef V7_DISABLE_LINE_NUMBERS
05742 V7_PRIVATE void bcode_append_lineno(struct bcode_builder *bbuilder,
05743                                     int line_no);
05744 #endif
05745 
05746 /*
05747  * Add a literal to the bcode literal table, or just decide that the literal
05748  * should be inlined into `ops`. See `lit_t` for details.
05749  */
05750 V7_PRIVATE
05751 lit_t bcode_add_lit(struct bcode_builder *bbuilder, v7_val_t val);
05752 
05753 /* disabled because of short lits */
05754 #if 0
05755 V7_PRIVATE v7_val_t bcode_get_lit(struct bcode *bcode, size_t idx);
05756 #endif
05757 
05758 /*
05759  * Emit an opcode `op`, and handle the literal `lit` (see `bcode_add_lit()`,
05760  * `lit_t`). Depending on the literal storage mode (see `enum lit_mode`), this
05761  * function either emits literal table index or inlines the literal directly
05762  * into `ops.`
05763  */
05764 V7_PRIVATE void bcode_op_lit(struct bcode_builder *bbuilder, enum opcode op,
05765                              lit_t lit);
05766 
05767 /* Helper function, equivalent of `bcode_op_lit(bbuilder, OP_PUSH_LIT, lit)` */
05768 V7_PRIVATE void bcode_push_lit(struct bcode_builder *bbuilder, lit_t lit);
05769 
05770 /*
05771  * Add name to bcode. If `idx` is null, a name is appended to the end of the
05772  * `bcode->ops.buf`. If `idx` is provided, it should point to the index at
05773  * which new name should be inserted; and it is updated by the
05774  * `bcode_add_name()` to point right after newly added name.
05775  *
05776  * This function is used only internally, but used in a complicated mix of
05777  * configurations, hence the commented V7_PRIVATE
05778  */
05779 WARN_UNUSED_RESULT
05780     /*V7_PRIVATE*/ enum v7_err
05781     bcode_add_name(struct bcode_builder *bbuilder, const char *p, size_t len,
05782                    size_t *idx);
05783 
05784 /*
05785  * Takes a pointer to the beginning of `ops` buffer and names count, returns
05786  * a pointer where actual opcodes begin (i.e. skips names).
05787  *
05788  * It takes two distinct arguments instead of just `struct bcode` pointer,
05789  * because during bcode building `ops` is stored in builder.
05790  *
05791  * This function is used only internally, but used in a complicated mix of
05792  * configurations, hence the commented V7_PRIVATE
05793  */
05794 /*V7_PRIVATE*/ char *bcode_end_names(char *ops, size_t names_cnt);
05795 
05796 /*
05797  * Given a pointer to `ops` (which should be `bcode->ops` or a pointer returned
05798  * from previous invocation of `bcode_next_name()`), yields a name string via
05799  * arguments `pname`, `plen`.
05800  *
05801  * Returns a pointer that should be given to `bcode_next_name()` to get a next
05802  * string (Whether there is a next string should be determined via the
05803  * `names_cnt`; since if there are no more names, this function will return an
05804  * invalid non-null pointer as next name pointer)
05805  */
05806 V7_PRIVATE char *bcode_next_name(char *ops, char **pname, size_t *plen);
05807 
05808 /*
05809  * Like `bcode_next_name()`, but instead of yielding a C string, it yields a
05810  * `val_t` value (via `res`).
05811  */
05812 V7_PRIVATE char *bcode_next_name_v(struct v7 *v7, struct bcode *bcode,
05813                                    char *ops, val_t *res);
05814 
05815 V7_PRIVATE bcode_off_t bcode_pos(struct bcode_builder *bbuilder);
05816 
05817 V7_PRIVATE bcode_off_t bcode_add_target(struct bcode_builder *bbuilder);
05818 /*
05819  * This function is used only internally, but used in a complicated mix of
05820  * configurations, hence the commented V7_PRIVATE
05821  */
05822 /*V7_PRIVATE*/ bcode_off_t bcode_op_target(struct bcode_builder *bbuilder,
05823                                            uint8_t op);
05824 /*V7_PRIVATE*/ void bcode_patch_target(struct bcode_builder *bbuilder,
05825                                        bcode_off_t label, bcode_off_t target);
05826 
05827 V7_PRIVATE void bcode_add_varint(struct bcode_builder *bbuilder, size_t value);
05828 /*
05829  * Reads varint-encoded integer from the provided pointer, and adjusts
05830  * the pointer appropriately
05831  */
05832 V7_PRIVATE size_t bcode_get_varint(char **ops);
05833 
05834 /*
05835  * Decode a literal value from a string of opcodes and update the cursor to
05836  * point past it
05837  */
05838 V7_PRIVATE
05839 v7_val_t bcode_decode_lit(struct v7 *v7, struct bcode *bcode, char **ops);
05840 
05841 #if defined(V7_BCODE_DUMP) || defined(V7_BCODE_TRACE)
05842 V7_PRIVATE void dump_op(struct v7 *v7, FILE *f, struct bcode *bcode,
05843                         char **ops);
05844 #endif
05845 
05846 #if defined(__cplusplus)
05847 }
05848 #endif /* __cplusplus */
05849 
05850 #endif /* CS_V7_SRC_BCODE_H_ */
05851 #ifdef V7_MODULE_LINES
05852 #line 1 "v7/src/gc_public.h"
05853 #endif
05854 /*
05855  * Copyright (c) 2014 Cesanta Software Limited
05856  * All rights reserved
05857  */
05858 
05859 /*
05860  * === Garbage Collector
05861  */
05862 
05863 #ifndef CS_V7_SRC_GC_PUBLIC_H_
05864 #define CS_V7_SRC_GC_PUBLIC_H_
05865 
05866 /* Amalgamated: #include "v7/src/core_public.h" */
05867 
05868 #if defined(__cplusplus)
05869 extern "C" {
05870 #endif /* __cplusplus */
05871 
05872 #if V7_ENABLE__Memory__stats
05873 
05874 /* Heap metric id, see `v7_heap_stat()` */
05875 enum v7_heap_stat_what {
05876   V7_HEAP_STAT_HEAP_SIZE,
05877   V7_HEAP_STAT_HEAP_USED,
05878   V7_HEAP_STAT_STRING_HEAP_RESERVED,
05879   V7_HEAP_STAT_STRING_HEAP_USED,
05880   V7_HEAP_STAT_OBJ_HEAP_MAX,
05881   V7_HEAP_STAT_OBJ_HEAP_FREE,
05882   V7_HEAP_STAT_OBJ_HEAP_CELL_SIZE,
05883   V7_HEAP_STAT_FUNC_HEAP_MAX,
05884   V7_HEAP_STAT_FUNC_HEAP_FREE,
05885   V7_HEAP_STAT_FUNC_HEAP_CELL_SIZE,
05886   V7_HEAP_STAT_PROP_HEAP_MAX,
05887   V7_HEAP_STAT_PROP_HEAP_FREE,
05888   V7_HEAP_STAT_PROP_HEAP_CELL_SIZE,
05889   V7_HEAP_STAT_FUNC_AST_SIZE,
05890   V7_HEAP_STAT_BCODE_OPS_SIZE,
05891   V7_HEAP_STAT_BCODE_LIT_TOTAL_SIZE,
05892   V7_HEAP_STAT_BCODE_LIT_DESER_SIZE,
05893   V7_HEAP_STAT_FUNC_OWNED,
05894   V7_HEAP_STAT_FUNC_OWNED_MAX
05895 };
05896 
05897 /* Returns a given heap statistics */
05898 int v7_heap_stat(struct v7 *v7, enum v7_heap_stat_what what);
05899 #endif
05900 
05901 /*
05902  * Perform garbage collection.
05903  * Pass true to full in order to reclaim unused heap back to the OS.
05904  */
05905 void v7_gc(struct v7 *v7, int full);
05906 
05907 #if defined(__cplusplus)
05908 }
05909 #endif /* __cplusplus */
05910 
05911 #endif /* CS_V7_SRC_GC_PUBLIC_H_ */
05912 #ifdef V7_MODULE_LINES
05913 #line 1 "v7/src/gc.h"
05914 #endif
05915 /*
05916  * Copyright (c) 2014 Cesanta Software Limited
05917  * All rights reserved
05918  */
05919 
05920 #ifndef CS_V7_SRC_GC_H_
05921 #define CS_V7_SRC_GC_H_
05922 
05923 /* Amalgamated: #include "v7/src/gc_public.h" */
05924 
05925 /* Amalgamated: #include "v7/src/internal.h" */
05926 /* Amalgamated: #include "v7/src/core.h" */
05927 
05928 /*
05929  * Macros for marking reachable things: use bit 0.
05930  */
05931 #define MARK(p) (((struct gc_cell *) (p))->head.word |= 1)
05932 #define UNMARK(p) (((struct gc_cell *) (p))->head.word &= ~1)
05933 #define MARKED(p) (((struct gc_cell *) (p))->head.word & 1)
05934 
05935 /*
05936  * Similar to `MARK()` / `UNMARK()` / `MARKED()`, but `.._FREE` counterparts
05937  * are intended to mark free cells (as opposed to used ones), so they use
05938  * bit 1.
05939  */
05940 #define MARK_FREE(p) (((struct gc_cell *) (p))->head.word |= 2)
05941 #define UNMARK_FREE(p) (((struct gc_cell *) (p))->head.word &= ~2)
05942 #define MARKED_FREE(p) (((struct gc_cell *) (p))->head.word & 2)
05943 
05944 /*
05945  * performs arithmetics on gc_cell pointers as if they were arena->cell_size
05946  * bytes wide
05947  */
05948 #define GC_CELL_OP(arena, cell, op, arg) \
05949   ((struct gc_cell *) (((char *) (cell)) op((arg) * (arena)->cell_size)))
05950 
05951 struct gc_tmp_frame {
05952   struct v7 *v7;
05953   size_t pos;
05954 };
05955 
05956 struct gc_cell {
05957   union {
05958     struct gc_cell *link;
05959     uintptr_t word;
05960   } head;
05961 };
05962 
05963 #if defined(__cplusplus)
05964 extern "C" {
05965 #endif /* __cplusplus */
05966 
05967 V7_PRIVATE struct v7_generic_object *new_generic_object(struct v7 *);
05968 V7_PRIVATE struct v7_property *new_property(struct v7 *);
05969 V7_PRIVATE struct v7_js_function *new_function(struct v7 *);
05970 
05971 V7_PRIVATE void gc_mark(struct v7 *, val_t);
05972 
05973 V7_PRIVATE void gc_arena_init(struct gc_arena *, size_t, size_t, size_t,
05974                               const char *);
05975 V7_PRIVATE void gc_arena_destroy(struct v7 *, struct gc_arena *a);
05976 V7_PRIVATE void gc_sweep(struct v7 *, struct gc_arena *, size_t);
05977 V7_PRIVATE void *gc_alloc_cell(struct v7 *, struct gc_arena *);
05978 
05979 V7_PRIVATE struct gc_tmp_frame new_tmp_frame(struct v7 *);
05980 V7_PRIVATE void tmp_frame_cleanup(struct gc_tmp_frame *);
05981 V7_PRIVATE void tmp_stack_push(struct gc_tmp_frame *, val_t *);
05982 
05983 V7_PRIVATE void compute_need_gc(struct v7 *);
05984 /* perform gc if not inhibited */
05985 V7_PRIVATE int maybe_gc(struct v7 *);
05986 
05987 #ifndef V7_DISABLE_STR_ALLOC_SEQ
05988 V7_PRIVATE uint16_t
05989 gc_next_allocation_seqn(struct v7 *v7, const char *str, size_t len);
05990 V7_PRIVATE int gc_is_valid_allocation_seqn(struct v7 *v7, uint16_t n);
05991 V7_PRIVATE void gc_check_valid_allocation_seqn(struct v7 *v7, uint16_t n);
05992 #endif
05993 
05994 V7_PRIVATE uint64_t gc_string_val_to_offset(val_t v);
05995 
05996 /* return 0 if v is an object/function with a bad pointer */
05997 V7_PRIVATE int gc_check_val(struct v7 *v7, val_t v);
05998 
05999 /* checks whether a pointer is within the ranges of an arena */
06000 V7_PRIVATE int gc_check_ptr(const struct gc_arena *a, const void *p);
06001 
06002 #if V7_ENABLE__Memory__stats
06003 V7_PRIVATE size_t gc_arena_size(struct gc_arena *);
06004 #endif
06005 
06006 #if defined(__cplusplus)
06007 }
06008 #endif /* __cplusplus */
06009 
06010 #endif /* CS_V7_SRC_GC_H_ */
06011 #ifdef V7_MODULE_LINES
06012 #line 1 "v7/src/regexp_public.h"
06013 #endif
06014 /*
06015  * Copyright (c) 2014 Cesanta Software Limited
06016  * All rights reserved
06017  */
06018 
06019 /*
06020  * === RegExp
06021  */
06022 
06023 #ifndef CS_V7_SRC_REGEXP_PUBLIC_H_
06024 #define CS_V7_SRC_REGEXP_PUBLIC_H_
06025 
06026 /* Amalgamated: #include "v7/src/core_public.h" */
06027 
06028 #if defined(__cplusplus)
06029 extern "C" {
06030 #endif /* __cplusplus */
06031 
06032 /*
06033  * Make RegExp object.
06034  * `regex`, `regex_len` specify a pattern, `flags` and `flags_len` specify
06035  * flags. Both utf8 encoded. For example, `regex` is `(.+)`, `flags` is `gi`.
06036  * If `regex_len` is ~0, `regex` is assumed to be NUL-terminated and
06037  * `strlen(regex)` is used.
06038  */
06039 WARN_UNUSED_RESULT
06040 enum v7_err v7_mk_regexp(struct v7 *v7, const char *regex, size_t regex_len,
06041                          const char *flags, size_t flags_len, v7_val_t *res);
06042 
06043 /* Returns true if given value is a JavaScript RegExp object*/
06044 int v7_is_regexp(struct v7 *v7, v7_val_t v);
06045 
06046 #if defined(__cplusplus)
06047 }
06048 #endif /* __cplusplus */
06049 
06050 #endif /* CS_V7_SRC_REGEXP_PUBLIC_H_ */
06051 #ifdef V7_MODULE_LINES
06052 #line 1 "v7/src/regexp.h"
06053 #endif
06054 /*
06055  * Copyright (c) 2014 Cesanta Software Limited
06056  * All rights reserved
06057  */
06058 
06059 #ifndef CS_V7_SRC_REGEXP_H_
06060 #define CS_V7_SRC_REGEXP_H_
06061 
06062 /* Amalgamated: #include "v7/src/regexp_public.h" */
06063 
06064 /* Amalgamated: #include "v7/src/core.h" */
06065 
06066 #if V7_ENABLE__RegExp
06067 
06068 /*
06069  * Maximum number of flags returned by get_regexp_flags_str().
06070  * NOTE: does not include null-terminate byte.
06071  */
06072 #define _V7_REGEXP_MAX_FLAGS_LEN 3
06073 
06074 struct v7_regexp;
06075 
06076 V7_PRIVATE struct v7_regexp *v7_get_regexp_struct(struct v7 *, v7_val_t);
06077 
06078 /*
06079  * Generates a string containing regexp flags, e.g. "gi".
06080  *
06081  * `buf` should point to a buffer of minimum `_V7_REGEXP_MAX_FLAGS_LEN` bytes.
06082  * Returns length of the resulted string (saved into `buf`)
06083  */
06084 V7_PRIVATE size_t
06085 get_regexp_flags_str(struct v7 *v7, struct v7_regexp *rp, char *buf);
06086 #endif /* V7_ENABLE__RegExp */
06087 
06088 #endif /* CS_V7_SRC_REGEXP_H_ */
06089 #ifdef V7_MODULE_LINES
06090 #line 1 "v7/src/function_public.h"
06091 #endif
06092 /*
06093  * Copyright (c) 2014 Cesanta Software Limited
06094  * All rights reserved
06095  */
06096 
06097 /*
06098  * === Functions
06099  */
06100 
06101 #ifndef CS_V7_SRC_FUNCTION_PUBLIC_H_
06102 #define CS_V7_SRC_FUNCTION_PUBLIC_H_
06103 
06104 /* Amalgamated: #include "v7/src/core_public.h" */
06105 
06106 #if defined(__cplusplus)
06107 extern "C" {
06108 #endif /* __cplusplus */
06109 
06110 /*
06111  * Make a JS function object backed by a cfunction.
06112  *
06113  * `func` is a C callback.
06114  *
06115  * A function object is JS object having the Function prototype that holds a
06116  * cfunction value in a hidden property.
06117  *
06118  * The function object will have a `prototype` property holding an object that
06119  * will be used as the prototype of objects created when calling the function
06120  * with the `new` operator.
06121  */
06122 v7_val_t v7_mk_function(struct v7 *, v7_cfunction_t *func);
06123 
06124 /*
06125  * Make f a JS function with specified prototype `proto`, so that the resulting
06126  * function is better suited for the usage as a constructor.
06127  */
06128 v7_val_t v7_mk_function_with_proto(struct v7 *v7, v7_cfunction_t *f,
06129                                    v7_val_t proto);
06130 
06131 /*
06132  * Make a JS value that holds C/C++ callback pointer.
06133  *
06134  * CAUTION: This is a low-level function value. It's not a real object and
06135  * cannot hold user defined properties. You should use `v7_mk_function` unless
06136  * you know what you're doing.
06137  */
06138 v7_val_t v7_mk_cfunction(v7_cfunction_t *func);
06139 
06140 /*
06141  * Returns true if given value is callable (i.e. it's either a JS function or
06142  * cfunction)
06143  */
06144 int v7_is_callable(struct v7 *v7, v7_val_t v);
06145 
06146 #if defined(__cplusplus)
06147 }
06148 #endif /* __cplusplus */
06149 
06150 #endif /* CS_V7_SRC_FUNCTION_PUBLIC_H_ */
06151 #ifdef V7_MODULE_LINES
06152 #line 1 "v7/src/function.h"
06153 #endif
06154 /*
06155  * Copyright (c) 2014 Cesanta Software Limited
06156  * All rights reserved
06157  */
06158 
06159 #ifndef CS_V7_SRC_FUNCTION_H_
06160 #define CS_V7_SRC_FUNCTION_H_
06161 
06162 /* Amalgamated: #include "v7/src/function_public.h" */
06163 
06164 /* Amalgamated: #include "v7/src/internal.h" */
06165 /* Amalgamated: #include "v7/src/core.h" */
06166 
06167 #if defined(__cplusplus)
06168 extern "C" {
06169 #endif /* __cplusplus */
06170 
06171 V7_PRIVATE struct v7_js_function *get_js_function_struct(val_t v);
06172 V7_PRIVATE val_t
06173 mk_js_function(struct v7 *v7, struct v7_generic_object *scope, val_t proto);
06174 V7_PRIVATE int is_js_function(val_t v);
06175 V7_PRIVATE v7_val_t mk_cfunction_lite(v7_cfunction_t *f);
06176 
06177 /* Returns true if given value holds a pointer to C callback */
06178 V7_PRIVATE int is_cfunction_lite(v7_val_t v);
06179 
06180 /* Returns true if given value holds an object which represents C callback */
06181 V7_PRIVATE int is_cfunction_obj(struct v7 *v7, v7_val_t v);
06182 
06183 /*
06184  * Returns `v7_cfunction_t *` callback pointer stored in `v7_val_t`, or NULL
06185  * if given value is neither cfunction pointer nor cfunction object.
06186  */
06187 V7_PRIVATE v7_cfunction_t *get_cfunction_ptr(struct v7 *v7, v7_val_t v);
06188 
06189 /*
06190  * Like v7_mk_function but also sets the function's `length` property.
06191  *
06192  * The `length` property is useful for introspection and the stdlib defines it
06193  * for many core functions mostly because the ECMA test suite requires it and we
06194  * don't want to skip otherwise useful tests just because the `length` property
06195  * check fails early in the test. User defined functions don't need to specify
06196  * the length and passing -1 is a safe choice, as it will also reduce the
06197  * footprint.
06198  *
06199  * The subtle difference between set `length` explicitly to 0 rather than
06200  * just defaulting the `0` value from the prototype is that in the former case
06201  * the property cannot be change since it's read only. This again, is important
06202  * only for ecma compliance and your user code might or might not find this
06203  * relevant.
06204  *
06205  * NODO(lsm): please don't combine v7_mk_function_arg and v7_mk_function
06206  * into one function. Currently `num_args` is useful only internally. External
06207  * users can just use `v7_def` to set the length.
06208  */
06209 V7_PRIVATE
06210 v7_val_t mk_cfunction_obj(struct v7 *v7, v7_cfunction_t *func, int num_args);
06211 
06212 /*
06213  * Like v7_mk_function_with_proto but also sets the function's `length`
06214  *property.
06215  *
06216  * NODO(lsm): please don't combine mk_cfunction_obj_with_proto and
06217  * v7_mk_function_with_proto.
06218  * into one function. Currently `num_args` is useful only internally. External
06219  * users can just use `v7_def` to set the length.
06220  */
06221 V7_PRIVATE
06222 v7_val_t mk_cfunction_obj_with_proto(struct v7 *v7, v7_cfunction_t *f,
06223                                      int num_args, v7_val_t proto);
06224 
06225 #if defined(__cplusplus)
06226 }
06227 #endif /* __cplusplus */
06228 
06229 #endif /* CS_V7_SRC_FUNCTION_H_ */
06230 #ifdef V7_MODULE_LINES
06231 #line 1 "v7/src/util_public.h"
06232 #endif
06233 /*
06234  * Copyright (c) 2014 Cesanta Software Limited
06235  * All rights reserved
06236  */
06237 
06238 /*
06239  * === Utility functions
06240  */
06241 
06242 #ifndef CS_V7_SRC_UTIL_PUBLIC_H_
06243 #define CS_V7_SRC_UTIL_PUBLIC_H_
06244 
06245 /* Amalgamated: #include "v7/src/core_public.h" */
06246 
06247 #if defined(__cplusplus)
06248 extern "C" {
06249 #endif /* __cplusplus */
06250 
06251 /* Output a string representation of the value to stdout.
06252  * V7_STRINGIFY_DEBUG mode is used. */
06253 void v7_print(struct v7 *v7, v7_val_t v);
06254 
06255 /* Output a string representation of the value to stdout followed by a newline.
06256  * V7_STRINGIFY_DEBUG mode is used. */
06257 void v7_println(struct v7 *v7, v7_val_t v);
06258 
06259 /* Output a string representation of the value to a file.
06260  * V7_STRINGIFY_DEBUG mode is used. */
06261 void v7_fprint(FILE *f, struct v7 *v7, v7_val_t v);
06262 
06263 /* Output a string representation of the value to a file followed by a newline.
06264  * V7_STRINGIFY_DEBUG mode is used. */
06265 void v7_fprintln(FILE *f, struct v7 *v7, v7_val_t v);
06266 
06267 /* Output stack trace recorded in the exception `e` to file `f` */
06268 void v7_fprint_stack_trace(FILE *f, struct v7 *v7, v7_val_t e);
06269 
06270 /* Output error object message and possibly stack trace to f */
06271 void v7_print_error(FILE *f, struct v7 *v7, const char *ctx, v7_val_t e);
06272 
06273 #if V7_ENABLE__Proxy
06274 
06275 struct v7_property;
06276 
06277 /*
06278  * C callback, analogue of JS callback `getOwnPropertyDescriptor()`.
06279  * Callbacks of this type are used for C API only, see `m7_mk_proxy()`.
06280  *
06281  * `name` is the name of the property, and the function should fill `attrs` and
06282  * `value` with the property data. Before this callback is called, `attrs` is
06283  * set to 0, and `value` is `V7_UNDEFINED`.
06284  *
06285  * It should return non-zero if the property should be considered existing, or
06286  * zero otherwise.
06287  *
06288  * You can inspect the property attributes with the `V7_PROP_ATTR_IS_*` macros.
06289  */
06290 typedef int(v7_get_own_prop_desc_cb_t)(struct v7 *v7, v7_val_t target,
06291                                        v7_val_t name, v7_prop_attr_t *attrs,
06292                                        v7_val_t *value);
06293 
06294 /* Handler for `v7_mk_proxy()`; each item is a cfunction */
06295 typedef struct {
06296   v7_cfunction_t *get;
06297   v7_cfunction_t *set;
06298   v7_cfunction_t *own_keys;
06299   v7_get_own_prop_desc_cb_t *get_own_prop_desc;
06300 } v7_proxy_hnd_t;
06301 
06302 /*
06303  * Create a Proxy object, see:
06304  * https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy
06305  *
06306  * Only two traps are implemented so far: `get()` and `set()`. Note that
06307  * `Object.defineProperty()` bypasses the `set()` trap.
06308  *
06309  * If `target` is not an object, the empty object will be used, so it's safe
06310  * to pass `V7_UNDEFINED` as `target`.
06311  */
06312 v7_val_t v7_mk_proxy(struct v7 *v7, v7_val_t target,
06313                      const v7_proxy_hnd_t *handler);
06314 
06315 #endif /* V7_ENABLE__Proxy */
06316 
06317 #if defined(__cplusplus)
06318 }
06319 #endif /* __cplusplus */
06320 
06321 #endif /* CS_V7_SRC_UTIL_PUBLIC_H_ */
06322 #ifdef V7_MODULE_LINES
06323 #line 1 "v7/src/util.h"
06324 #endif
06325 /*
06326  * Copyright (c) 2014 Cesanta Software Limited
06327  * All rights reserved
06328  */
06329 
06330 #ifndef CS_V7_SRC_UTIL_H_
06331 #define CS_V7_SRC_UTIL_H_
06332 
06333 /* Amalgamated: #include "v7/src/core.h" */
06334 /* Amalgamated: #include "v7/src/util_public.h" */
06335 
06336 struct bcode;
06337 
06338 V7_PRIVATE enum v7_type val_type(struct v7 *v7, val_t v);
06339 
06340 #ifndef V7_DISABLE_LINE_NUMBERS
06341 V7_PRIVATE uint8_t msb_lsb_swap(uint8_t b);
06342 #endif
06343 
06344 /*
06345  * At the moment, all other utility functions are public, and are declared in
06346  * `util_public.h`
06347  */
06348 
06349 #endif /* CS_V7_SRC_UTIL_H_ */
06350 #ifdef V7_MODULE_LINES
06351 #line 1 "v7/src/shdata.h"
06352 #endif
06353 /*
06354  * Copyright (c) 2014 Cesanta Software Limited
06355  * All rights reserved
06356  */
06357 
06358 /*
06359  * shdata (stands for "shared data") is a simple module that allows to have
06360  * reference count for an arbitrary payload data, which will be freed as
06361  * necessary. A poor man's shared_ptr.
06362  */
06363 
06364 #ifndef CS_V7_SRC_SHDATA_H_
06365 #define CS_V7_SRC_SHDATA_H_
06366 
06367 /* Amalgamated: #include "v7/src/internal.h" */
06368 
06369 #if !defined(V7_DISABLE_FILENAMES) && !defined(V7_DISABLE_LINE_NUMBERS)
06370 struct shdata {
06371   /* Reference count */
06372   uint8_t refcnt;
06373 
06374   /*
06375    * Note: we'd use `unsigned char payload[];` here, but we can't, since this
06376    * feature was introduced in C99 only
06377    */
06378 };
06379 
06380 /*
06381  * Allocate memory chunk of appropriate size, copy given `payload` data there,
06382  * retain (`shdata_retain()`), and return it.
06383  */
06384 V7_PRIVATE struct shdata *shdata_create(const void *payload, size_t size);
06385 
06386 V7_PRIVATE struct shdata *shdata_create_from_string(const char *src);
06387 
06388 /*
06389  * Increment reference count for the given shared data
06390  */
06391 V7_PRIVATE void shdata_retain(struct shdata *p);
06392 
06393 /*
06394  * Decrement reference count for the given shared data
06395  */
06396 V7_PRIVATE void shdata_release(struct shdata *p);
06397 
06398 /*
06399  * Get payload data
06400  */
06401 V7_PRIVATE void *shdata_get_payload(struct shdata *p);
06402 
06403 #endif
06404 #endif /* CS_V7_SRC_SHDATA_H_ */
06405 #ifdef V7_MODULE_LINES
06406 #line 1 "v7/src/eval.h"
06407 #endif
06408 /*
06409  * Copyright (c) 2014 Cesanta Software Limited
06410  * All rights reserved
06411  */
06412 
06413 #ifndef CS_V7_SRC_EVAL_H_
06414 #define CS_V7_SRC_EVAL_H_
06415 
06416 /* Amalgamated: #include "v7/src/internal.h" */
06417 /* Amalgamated: #include "v7/src/bcode.h" */
06418 
06419 struct v7_call_frame_base;
06420 
06421 #if defined(__cplusplus)
06422 extern "C" {
06423 #endif /* __cplusplus */
06424 
06425 WARN_UNUSED_RESULT
06426 V7_PRIVATE enum v7_err eval_bcode(struct v7 *v7, struct bcode *bcode,
06427                                   val_t this_object, uint8_t reset_line_no,
06428                                   val_t *_res);
06429 
06430 WARN_UNUSED_RESULT
06431 V7_PRIVATE enum v7_err b_apply(struct v7 *v7, v7_val_t func, v7_val_t this_obj,
06432                                v7_val_t args, uint8_t is_constructor,
06433                                v7_val_t *res);
06434 
06435 WARN_UNUSED_RESULT
06436 V7_PRIVATE enum v7_err b_exec(struct v7 *v7, const char *src, size_t src_len,
06437                               const char *filename, val_t func, val_t args,
06438                               val_t this_object, int is_json, int fr,
06439                               uint8_t is_constructor, val_t *res);
06440 
06441 /*
06442  * Try to find the call frame whose `type_mask` intersects with the given
06443  * `type_mask`.
06444  *
06445  * Start from the top call frame, and go deeper until the matching frame is
06446  * found, or there's no more call frames. If the needed frame was not found,
06447  * returns `NULL`.
06448  */
06449 V7_PRIVATE struct v7_call_frame_base *find_call_frame(struct v7 *v7,
06450                                                       uint8_t type_mask);
06451 
06452 #if defined(__cplusplus)
06453 }
06454 #endif /* __cplusplus */
06455 
06456 #endif /* CS_V7_SRC_EVAL_H_ */
06457 #ifdef V7_MODULE_LINES
06458 #line 1 "v7/src/compiler.h"
06459 #endif
06460 /*
06461  * Copyright (c) 2014 Cesanta Software Limited
06462  * All rights reserved
06463  */
06464 
06465 #ifndef CS_V7_SRC_COMPILER_H_
06466 #define CS_V7_SRC_COMPILER_H_
06467 
06468 /* Amalgamated: #include "v7/src/internal.h" */
06469 /* Amalgamated: #include "v7/src/bcode.h" */
06470 /* Amalgamated: #include "v7/src/ast.h" */
06471 
06472 #if !defined(V7_NO_COMPILER)
06473 
06474 #if defined(__cplusplus)
06475 extern "C" {
06476 #endif /* __cplusplus */
06477 
06478 V7_PRIVATE enum v7_err compile_script(struct v7 *v7, struct ast *a,
06479                                       struct bcode *bcode);
06480 
06481 V7_PRIVATE enum v7_err compile_expr(struct v7 *v7, struct ast *a,
06482                                     ast_off_t *ppos, struct bcode *bcode);
06483 
06484 #if defined(__cplusplus)
06485 }
06486 #endif /* __cplusplus */
06487 
06488 #endif /* V7_NO_COMPILER */
06489 
06490 #endif /* CS_V7_SRC_COMPILER_H_ */
06491 #ifdef V7_MODULE_LINES
06492 #line 1 "v7/src/cyg_profile.h"
06493 #endif
06494 /*
06495  * Copyright (c) 2014 Cesanta Software Limited
06496  * All rights reserved
06497  */
06498 
06499 #ifndef CS_V7_SRC_CYG_PROFILE_H_
06500 #define CS_V7_SRC_CYG_PROFILE_H_
06501 
06502 /*
06503  * This file contains GCC/clang instrumentation callbacks, as well as
06504  * accompanying code. The actual code in these callbacks depends on enabled
06505  * features. See cyg_profile.c for some implementation details rationale.
06506  */
06507 
06508 struct v7;
06509 
06510 #if defined(V7_ENABLE_STACK_TRACKING)
06511 
06512 /*
06513  * Stack-tracking functionality:
06514  *
06515  * The idea is that the caller should allocate `struct stack_track_ctx`
06516  * (typically on stack) in the function to track the stack usage of, and call
06517  * `v7_stack_track_start()` in the beginning.
06518  *
06519  * Before quitting current stack frame (for example, before returning from
06520  * function), call `v7_stack_track_end()`, which returns the maximum stack
06521  * consumed size.
06522  *
06523  * These calls can be nested: for example, we may track the stack usage of the
06524  * whole application by using these functions in `main()`, as well as track
06525  * stack usage of any nested functions.
06526  *
06527  * Just to stress: both `v7_stack_track_start()` / `v7_stack_track_end()`
06528  * should be called for the same instance of `struct stack_track_ctx` in the
06529  * same stack frame.
06530  */
06531 
06532 /* stack tracking context */
06533 struct stack_track_ctx {
06534   struct stack_track_ctx *next;
06535   void *start;
06536   void *max;
06537 };
06538 
06539 /* see explanation above */
06540 void v7_stack_track_start(struct v7 *v7, struct stack_track_ctx *ctx);
06541 /* see explanation above */
06542 int v7_stack_track_end(struct v7 *v7, struct stack_track_ctx *ctx);
06543 
06544 void v7_stack_stat_clean(struct v7 *v7);
06545 
06546 #endif /* V7_ENABLE_STACK_TRACKING */
06547 
06548 #endif /* CS_V7_SRC_CYG_PROFILE_H_ */
06549 #ifdef V7_MODULE_LINES
06550 #line 1 "v7/builtin/builtin.h"
06551 #endif
06552 /*
06553  * Copyright (c) 2015 Cesanta Software Limited
06554  * All rights reserved
06555  */
06556 
06557 /*
06558  * === Non-Standard API
06559  *
06560  *   V7 has several non-standard extensions for `String.prototype` in
06561  *   order to give a compact and fast API to access raw data obtained from
06562  *   File, Socket, and hardware input/output such as I2C.
06563  *   V7 IO API functions return
06564  *   string data as a result of read operations, and that string data is a
06565  *   raw byte array. ECMA6 provides `ArrayBuffer` and `DataView` API for dealing
06566  *   with raw bytes, because strings in JavaScript are Unicode. That standard
06567  *   API is too bloated for the embedded use, and does not allow to use handy
06568  *   String API (e.g. `.match()`) against data.
06569  *
06570  *   V7 internally stores strings as byte arrays. All strings created by the
06571  *   String API are UTF8 encoded. Strings that are the result of
06572  *   input/output API calls might not be a valid UTF8 strings, but nevertheless
06573  *   they are represented as strings, and the following API allows to access
06574  *   underlying byte sequence:
06575  *
06576  * ==== String.prototype.at(position) -> number or NaN
06577  *      Return byte at index
06578  *     `position`. Byte value is in 0,255 range. If `position` is out of bounds
06579  *     (either negative or larger then the byte array length), NaN is returned.
06580  *     Example: `"ы".at(0)` returns 0xd1.
06581  *
06582  * ==== String.prototype.blen -> number
06583  *     Return string length in bytes.
06584  *     Example: `"ы".blen` returns 2. Note that `"ы".length` is 1, since that
06585  *     string consists of a single Unicode character (2-byte).
06586  *
06587  * === Builtin API
06588  *
06589  * Builtin API provides additional JavaScript interfaces available for V7
06590  * scripts.
06591  * File API is a wrapper around standard C calls `fopen()`, `fclose()`,
06592  * `fread()`, `fwrite()`, `rename()`, `remove()`.
06593  * Crypto API provides functions for base64, md5, and sha1 encoding/decoding.
06594  * Socket API provides low-level socket API.
06595  *
06596  * ==== File.eval(file_name)
06597  * Parse and run `file_name`.
06598  * Throws an exception if the file doesn't exist, cannot be parsed or if the
06599  * script throws any exception.
06600  *
06601  * ==== File.read(file_name) -> string or undefined
06602  * Read file `file_name` and return a string with a file content.
06603  * On any error, return `undefined` as a result.
06604  *
06605  * ==== File.write(file_name, str) -> true or false
06606  * Write string `str` to a file `file_name`. Return `true` on success,
06607  * `false` on error.
06608  *
06609  * ==== File.open(file_name [, mode]) -> file_object or null
06610  * Open a file `path`. For
06611  * list of valid `mode` values, see `fopen()` documentation. If `mode` is
06612  * not specified, mode `rb` is used, i.e. file is opened in read-only mode.
06613  * Return an opened file object, or null on error. Example:
06614  * `var f = File.open('/etc/passwd'); f.close();`
06615  *
06616  * ==== file_obj.close() -> undefined
06617  * Close opened file object.
06618  * NOTE: it is user's responsibility to close all opened file streams. V7
06619  * does not do that automatically.
06620  *
06621  * ==== file_obj.read() -> string
06622  * Read portion of data from
06623  * an opened file stream. Return string with data, or empty string on EOF
06624  * or error.
06625  *
06626  * ==== file_obj.write(str) -> num_bytes_written
06627  * Write string `str` to the opened file object. Return number of bytes written.
06628  *
06629  * ==== File.rename(old_name, new_name) -> errno
06630  * Rename file `old_name` to
06631  * `new_name`. Return 0 on success, or `errno` value on error.
06632  *
06633  * ==== File.list(dir_name) -> array_of_names
06634  * Return a list of files in a given directory, or `undefined` on error.
06635  *
06636  * ==== File.remove(file_name) -> errno
06637  * Delete file `file_name`.
06638  * Return 0 on success, or `errno` value on error.
06639  *
06640  * ==== Crypto.base64_encode(str)
06641  * Base64-encode input string `str` and return encoded string.
06642  *
06643  * ==== Crypto.base64_decode(str)
06644  * Base64-decode input string `str` and return decoded string.
06645  *
06646  * ==== Crypto.md5(str), Crypto.md5_hex(str)
06647  * Generate MD5 hash from input string `str`. Return 16-byte hash (`md5()`),
06648  * or stringified hexadecimal representation of the hash (`md5_hex`).
06649  *
06650  * ==== Crypto.sha1(str), Crypto.sha1_hex(str)
06651  * Generate SHA1 hash from input string `str`. Return 20-byte hash (`sha1()`),
06652  * or stringified hexadecimal representation of the hash (`sha1_hex`).
06653  *
06654  * ==== Socket.connect(host, port [, is_udp]) -> socket_obj
06655  * Connect to a given host. `host` can be a string IP address, or a host name.
06656  * Optional `is_udp` parameter, if true, indicates that socket should be UDP.
06657  * Return socket object on success, null on error.
06658  *
06659  * ==== Socket.listen(port [, ip_address [,is_udp]]) -> socket_obj
06660  * Create a listening socket on a given port. Optional `ip_address` argument
06661  * specifies and IP address to bind to. Optional `is_udp` parameter, if true,
06662  * indicates that socket should be UDP. Return socket object on success,
06663  * null on error.
06664  *
06665  * ==== socket_obj.accept() -> socket_obj
06666  * Sleep until new incoming connection is arrived. Return accepted socket
06667  * object on success, or `null` on error.
06668  *
06669  * ==== socket_obj.close() -> numeric_errno
06670  * Close socket object. Return 0 on success, or system errno on error.
06671  *
06672  * ==== socket_obj.recv() -> string
06673  * Read data from socket. Return data string, or empty string if peer has
06674  * disconnected, or `null` on error.
06675  *
06676  * ==== socket_obj.recvAll() -> string
06677  * Same as `recv()`, but keeps reading data until socket is closed.
06678  *
06679  * ==== sock.send(string) -> num_bytes_sent
06680  * Send string to the socket. Return number of bytes sent, or 0 on error.
06681  * Simple HTTP client example:
06682  *
06683  *    var s = Socket.connect("google.com", 80);
06684  *    s.send("GET / HTTP/1.0\n\n");
06685  *    var reply = s.recv();
06686  */
06687 
06688 #ifndef CS_V7_BUILTIN_BUILTIN_H_
06689 #define CS_V7_BUILTIN_BUILTIN_H_
06690 
06691 struct v7;
06692 
06693 void init_file(struct v7 *);
06694 void init_socket(struct v7 *);
06695 void init_crypto(struct v7 *);
06696 
06697 #endif /* CS_V7_BUILTIN_BUILTIN_H_ */
06698 #ifdef V7_MODULE_LINES
06699 #line 1 "v7/src/slre.h"
06700 #endif
06701 /*
06702  * Copyright (c) 2014 Cesanta Software Limited
06703  * All rights reserved
06704  *
06705  * This software is dual-licensed: you can redistribute it and/or modify
06706  * it under the terms of the GNU General Public License version 2 as
06707  * published by the Free Software Foundation. For the terms of this
06708  * license, see <http://www.gnu.org/licenses/>.
06709  *
06710  * You are free to use this software under the terms of the GNU General
06711  * Public License, but WITHOUT ANY WARRANTY; without even the implied
06712  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
06713  * See the GNU General Public License for more details.
06714  *
06715  * Alternatively, you can license this software under a commercial
06716  * license, as set out in <https://www.cesanta.com/license>.
06717  */
06718 
06719 #ifndef CS_V7_SRC_SLRE_H_
06720 #define CS_V7_SRC_SLRE_H_
06721 
06722 /* Return codes for slre_compile() */
06723 enum slre_error {
06724   SLRE_OK,
06725   SLRE_INVALID_DEC_DIGIT,
06726   SLRE_INVALID_HEX_DIGIT,
06727   SLRE_INVALID_ESC_CHAR,
06728   SLRE_UNTERM_ESC_SEQ,
06729   SLRE_SYNTAX_ERROR,
06730   SLRE_UNMATCH_LBR,
06731   SLRE_UNMATCH_RBR,
06732   SLRE_NUM_OVERFLOW,
06733   SLRE_INF_LOOP_M_EMP_STR,
06734   SLRE_TOO_MANY_CHARSETS,
06735   SLRE_INV_CHARSET_RANGE,
06736   SLRE_CHARSET_TOO_LARGE,
06737   SLRE_MALFORMED_CHARSET,
06738   SLRE_INVALID_BACK_REFERENCE,
06739   SLRE_TOO_MANY_CAPTURES,
06740   SLRE_INVALID_QUANTIFIER,
06741   SLRE_BAD_CHAR_AFTER_USD
06742 };
06743 
06744 #if V7_ENABLE__RegExp
06745 
06746 #ifdef __cplusplus
06747 extern "C" {
06748 #endif /* __cplusplus */
06749 
06750 /* Regex flags */
06751 #define SLRE_FLAG_G 1  /* Global - match in the whole string */
06752 #define SLRE_FLAG_I 2  /* Ignore case */
06753 #define SLRE_FLAG_M 4  /* Multiline */
06754 #define SLRE_FLAG_RE 8 /* flag RegExp/String */
06755 
06756 /* Describes single capture */
06757 struct slre_cap {
06758   const char *start; /* points to the beginning of the capture group */
06759   const char *end;   /* points to the end of the capture group */
06760 };
06761 
06762 /* Describes all captures */
06763 #define SLRE_MAX_CAPS 32
06764 struct slre_loot {
06765   int num_captures;
06766   struct slre_cap caps[SLRE_MAX_CAPS];
06767 };
06768 
06769 /* Opaque structure that holds compiled regular expression */
06770 struct slre_prog;
06771 
06772 int slre_compile(const char *regexp, size_t regexp_len, const char *flags,
06773                  size_t flags_len, struct slre_prog **, int is_regex);
06774 int slre_exec(struct slre_prog *prog, int flag_g, const char *start,
06775               const char *end, struct slre_loot *loot);
06776 void slre_free(struct slre_prog *prog);
06777 
06778 int slre_match(const char *, size_t, const char *, size_t, const char *, size_t,
06779                struct slre_loot *);
06780 int slre_replace(struct slre_loot *loot, const char *src, size_t src_len,
06781                  const char *replace, size_t rep_len, struct slre_loot *dst);
06782 int slre_get_flags(struct slre_prog *);
06783 
06784 #ifdef __cplusplus
06785 }
06786 #endif /* __cplusplus */
06787 
06788 #endif /* V7_ENABLE__RegExp */
06789 
06790 #endif /* CS_V7_SRC_SLRE_H_ */
06791 #ifdef V7_MODULE_LINES
06792 #line 1 "v7/src/stdlib.h"
06793 #endif
06794 /*
06795  * Copyright (c) 2014 Cesanta Software Limited
06796  * All rights reserved
06797  */
06798 
06799 #ifndef CS_V7_SRC_STDLIB_H_
06800 #define CS_V7_SRC_STDLIB_H_
06801 
06802 /* Amalgamated: #include "v7/src/internal.h" */
06803 /* Amalgamated: #include "v7/src/core.h" */
06804 
06805 #if defined(__cplusplus)
06806 extern "C" {
06807 #endif /* __cplusplus */
06808 
06809 /*V7_PRIVATE*/ void init_stdlib(struct v7 *v7);
06810 
06811 WARN_UNUSED_RESULT
06812 V7_PRIVATE enum v7_err std_eval(struct v7 *v7, v7_val_t arg, v7_val_t this_obj,
06813                                 int is_json, v7_val_t *res);
06814 
06815 #if defined(__cplusplus)
06816 }
06817 #endif /* __cplusplus */
06818 
06819 #endif /* CS_V7_SRC_STDLIB_H_ */
06820 #ifdef V7_MODULE_LINES
06821 #line 1 "v7/src/heapusage.h"
06822 #endif
06823 /*
06824  * Copyright (c) 2014-2016 Cesanta Software Limited
06825  * All rights reserved
06826  */
06827 
06828 #ifndef CS_V7_SRC_HEAPUSAGE_H_
06829 #define CS_V7_SRC_HEAPUSAGE_H_
06830 
06831 #if defined(V7_HEAPUSAGE_ENABLE)
06832 
06833 extern volatile int heap_dont_count;
06834 
06835 /*
06836  * Returns total heap-allocated size in bytes (without any overhead of the
06837  * heap implementation)
06838  */
06839 size_t heapusage_alloc_size(void);
06840 
06841 /*
06842  * Returns number of active allocations
06843  */
06844 size_t heapusage_allocs_cnt(void);
06845 
06846 /*
06847  * Must be called before allocating some memory that should not be indicated as
06848  * memory consumed for some particular operation: for example, when we
06849  * preallocate some GC buffer.
06850  */
06851 #define heapusage_dont_count(a) \
06852   do {                          \
06853     heap_dont_count = a;        \
06854   } while (0)
06855 
06856 #else /* V7_HEAPUSAGE_ENABLE */
06857 
06858 #define heapusage_alloc_size() (0)
06859 #define heapusage_allocs_cnt() (0)
06860 #define heapusage_dont_count(a)
06861 
06862 #endif /* V7_HEAPUSAGE_ENABLE */
06863 
06864 #endif /* CS_V7_SRC_HEAPUSAGE_H_ */
06865 #ifdef V7_MODULE_LINES
06866 #line 1 "v7/src/std_proxy.h"
06867 #endif
06868 /*
06869  * Copyright (c) 2014 Cesanta Software Limited
06870  * All rights reserved
06871  */
06872 
06873 #ifndef CS_V7_SRC_STD_PROXY_H_
06874 #define CS_V7_SRC_STD_PROXY_H_
06875 
06876 /* Amalgamated: #include "v7/src/internal.h" */
06877 /* Amalgamated: #include "v7/src/core.h" */
06878 
06879 #if V7_ENABLE__Proxy
06880 
06881 #define _V7_PROXY_TARGET_NAME "__tgt"
06882 #define _V7_PROXY_HANDLER_NAME "__hnd"
06883 
06884 #if defined(__cplusplus)
06885 extern "C" {
06886 #endif /* __cplusplus */
06887 
06888 #if V7_ENABLE__Proxy
06889 
06890 V7_PRIVATE enum v7_err Proxy_ctor(struct v7 *v7, v7_val_t *res);
06891 
06892 V7_PRIVATE void init_proxy(struct v7 *v7);
06893 
06894 /*
06895  * Returns whether the given name is one of the special Proxy names
06896  * (_V7_PROXY_TARGET_NAME or _V7_PROXY_HANDLER_NAME)
06897  */
06898 V7_PRIVATE int is_special_proxy_name(const char *name, size_t name_len);
06899 
06900 #endif
06901 
06902 #if defined(__cplusplus)
06903 }
06904 #endif /* __cplusplus */
06905 
06906 #endif /* V7_ENABLE__Proxy */
06907 
06908 #endif /* CS_V7_SRC_STD_PROXY_H_ */
06909 #ifdef V7_MODULE_LINES
06910 #line 1 "v7/src/freeze.h"
06911 #endif
06912 /*
06913  * Copyright (c) 2014 Cesanta Software Limited
06914  * All rights reserved
06915  */
06916 
06917 #ifndef CS_V7_SRC_FREEZE_H_
06918 #define CS_V7_SRC_FREEZE_H_
06919 
06920 #ifdef V7_FREEZE
06921 
06922 /* Amalgamated: #include "v7/src/internal.h" */
06923 
06924 struct v7_property;
06925 
06926 #if defined(__cplusplus)
06927 extern "C" {
06928 #endif /* __cplusplus */
06929 
06930 V7_PRIVATE void freeze(struct v7 *v7, char *filename);
06931 V7_PRIVATE void freeze_obj(struct v7 *v7, FILE *f, v7_val_t v);
06932 V7_PRIVATE void freeze_prop(struct v7 *v7, FILE *f, struct v7_property *prop);
06933 
06934 #if defined(__cplusplus)
06935 }
06936 #endif /* __cplusplus */
06937 
06938 #endif /* V7_FREEZE */
06939 
06940 #endif /* CS_V7_SRC_FREEZE_H_ */
06941 #ifdef V7_MODULE_LINES
06942 #line 1 "v7/src/std_array.h"
06943 #endif
06944 /*
06945  * Copyright (c) 2014 Cesanta Software Limited
06946  * All rights reserved
06947  */
06948 
06949 #ifndef CS_V7_SRC_STD_ARRAY_H_
06950 #define CS_V7_SRC_STD_ARRAY_H_
06951 
06952 /* Amalgamated: #include "v7/src/internal.h" */
06953 
06954 #if defined(__cplusplus)
06955 extern "C" {
06956 #endif /* __cplusplus */
06957 
06958 V7_PRIVATE void init_array(struct v7 *v7);
06959 
06960 #if defined(__cplusplus)
06961 }
06962 #endif /* __cplusplus */
06963 
06964 #endif /* CS_V7_SRC_STD_ARRAY_H_ */
06965 #ifdef V7_MODULE_LINES
06966 #line 1 "v7/src/std_boolean.h"
06967 #endif
06968 /*
06969  * Copyright (c) 2014 Cesanta Software Limited
06970  * All rights reserved
06971  */
06972 
06973 #ifndef CS_V7_SRC_STD_BOOLEAN_H_
06974 #define CS_V7_SRC_STD_BOOLEAN_H_
06975 
06976 /* Amalgamated: #include "v7/src/internal.h" */
06977 
06978 #if defined(__cplusplus)
06979 extern "C" {
06980 #endif /* __cplusplus */
06981 
06982 V7_PRIVATE void init_boolean(struct v7 *v7);
06983 
06984 #if defined(__cplusplus)
06985 }
06986 #endif /* __cplusplus */
06987 
06988 #endif /* CS_V7_SRC_STD_BOOLEAN_H_ */
06989 #ifdef V7_MODULE_LINES
06990 #line 1 "v7/src/std_date.h"
06991 #endif
06992 /*
06993  * Copyright (c) 2014 Cesanta Software Limited
06994  * All rights reserved
06995  */
06996 
06997 #ifndef CS_V7_SRC_STD_DATE_H_
06998 #define CS_V7_SRC_STD_DATE_H_
06999 
07000 /* Amalgamated: #include "v7/src/internal.h" */
07001 
07002 #if V7_ENABLE__Date
07003 
07004 #if defined(__cplusplus)
07005 extern "C" {
07006 #endif /* __cplusplus */
07007 
07008 V7_PRIVATE void init_date(struct v7 *v7);
07009 
07010 #if defined(__cplusplus)
07011 }
07012 #endif /* __cplusplus */
07013 
07014 #endif /* V7_ENABLE__Date */
07015 #endif /* CS_V7_SRC_STD_DATE_H_ */
07016 #ifdef V7_MODULE_LINES
07017 #line 1 "v7/src/std_function.h"
07018 #endif
07019 /*
07020  * Copyright (c) 2014 Cesanta Software Limited
07021  * All rights reserved
07022  */
07023 
07024 #ifndef CS_V7_SRC_STD_FUNCTION_H_
07025 #define CS_V7_SRC_STD_FUNCTION_H_
07026 
07027 /* Amalgamated: #include "v7/src/internal.h" */
07028 
07029 #if defined(__cplusplus)
07030 extern "C" {
07031 #endif /* __cplusplus */
07032 
07033 V7_PRIVATE void init_function(struct v7 *v7);
07034 
07035 #if defined(__cplusplus)
07036 }
07037 #endif /* __cplusplus */
07038 
07039 #endif /* CS_V7_SRC_STD_FUNCTION_H_ */
07040 #ifdef V7_MODULE_LINES
07041 #line 1 "v7/src/std_json.h"
07042 #endif
07043 /*
07044  * Copyright (c) 2014 Cesanta Software Limited
07045  * All rights reserved
07046  */
07047 
07048 #ifndef CS_V7_SRC_STD_JSON_H_
07049 #define CS_V7_SRC_STD_JSON_H_
07050 
07051 /* Amalgamated: #include "v7/src/internal.h" */
07052 
07053 #if defined(__cplusplus)
07054 extern "C" {
07055 #endif /* __cplusplus */
07056 
07057 V7_PRIVATE void init_json(struct v7 *v7);
07058 
07059 #if defined(__cplusplus)
07060 }
07061 #endif /* __cplusplus */
07062 
07063 #endif /* CS_V7_SRC_STD_JSON_H_ */
07064 #ifdef V7_MODULE_LINES
07065 #line 1 "v7/src/std_math.h"
07066 #endif
07067 /*
07068  * Copyright (c) 2014 Cesanta Software Limited
07069  * All rights reserved
07070  */
07071 
07072 #ifndef CS_V7_SRC_STD_MATH_H_
07073 #define CS_V7_SRC_STD_MATH_H_
07074 
07075 /* Amalgamated: #include "v7/src/internal.h" */
07076 
07077 #if V7_ENABLE__Math
07078 
07079 #if defined(__cplusplus)
07080 extern "C" {
07081 #endif /* __cplusplus */
07082 
07083 V7_PRIVATE void init_math(struct v7 *v7);
07084 
07085 #if defined(__cplusplus)
07086 }
07087 #endif /* __cplusplus */
07088 
07089 #endif /* V7_ENABLE__Math */
07090 #endif /* CS_V7_SRC_STD_MATH_H_ */
07091 #ifdef V7_MODULE_LINES
07092 #line 1 "v7/src/std_number.h"
07093 #endif
07094 /*
07095  * Copyright (c) 2014 Cesanta Software Limited
07096  * All rights reserved
07097  */
07098 
07099 #ifndef CS_V7_SRC_STD_NUMBER_H_
07100 #define CS_V7_SRC_STD_NUMBER_H_
07101 
07102 /* Amalgamated: #include "v7/src/internal.h" */
07103 
07104 #if defined(__cplusplus)
07105 extern "C" {
07106 #endif /* __cplusplus */
07107 
07108 V7_PRIVATE void init_number(struct v7 *v7);
07109 
07110 #if defined(__cplusplus)
07111 }
07112 #endif /* __cplusplus */
07113 
07114 #endif /* CS_V7_SRC_STD_NUMBER_H_ */
07115 #ifdef V7_MODULE_LINES
07116 #line 1 "v7/src/std_object.h"
07117 #endif
07118 /*
07119  * Copyright (c) 2014 Cesanta Software Limited
07120  * All rights reserved
07121  */
07122 
07123 #ifndef CS_V7_SRC_STD_OBJECT_H_
07124 #define CS_V7_SRC_STD_OBJECT_H_
07125 
07126 /* Amalgamated: #include "v7/src/internal.h" */
07127 /* Amalgamated: #include "v7/src/core.h" */
07128 
07129 struct v7;
07130 
07131 #if defined(__cplusplus)
07132 extern "C" {
07133 #endif /* __cplusplus */
07134 
07135 V7_PRIVATE void init_object(struct v7 *v7);
07136 
07137 WARN_UNUSED_RESULT
07138 V7_PRIVATE enum v7_err Obj_valueOf(struct v7 *v7, v7_val_t *res);
07139 
07140 #if defined(__cplusplus)
07141 }
07142 #endif /* __cplusplus */
07143 
07144 #endif /* CS_V7_SRC_STD_OBJECT_H_ */
07145 #ifdef V7_MODULE_LINES
07146 #line 1 "v7/src/std_regex.h"
07147 #endif
07148 /*
07149  * Copyright (c) 2014 Cesanta Software Limited
07150  * All rights reserved
07151  */
07152 
07153 #ifndef CS_V7_SRC_STD_REGEX_H_
07154 #define CS_V7_SRC_STD_REGEX_H_
07155 
07156 /* Amalgamated: #include "v7/src/internal.h" */
07157 /* Amalgamated: #include "v7/src/core.h" */
07158 
07159 #if V7_ENABLE__RegExp
07160 
07161 #if defined(__cplusplus)
07162 extern "C" {
07163 #endif /* __cplusplus */
07164 
07165 V7_PRIVATE enum v7_err Regex_ctor(struct v7 *v7, v7_val_t *res);
07166 V7_PRIVATE enum v7_err rx_exec(struct v7 *v7, v7_val_t rx, v7_val_t vstr,
07167                                int lind, v7_val_t *res);
07168 
07169 V7_PRIVATE void init_regex(struct v7 *v7);
07170 
07171 #if defined(__cplusplus)
07172 }
07173 #endif /* __cplusplus */
07174 
07175 #endif /* V7_ENABLE__RegExp */
07176 
07177 #endif /* CS_V7_SRC_STD_REGEX_H_ */
07178 #ifdef V7_MODULE_LINES
07179 #line 1 "v7/src/std_string.h"
07180 #endif
07181 /*
07182  * Copyright (c) 2014 Cesanta Software Limited
07183  * All rights reserved
07184  */
07185 
07186 #ifndef CS_V7_SRC_STD_STRING_H_
07187 #define CS_V7_SRC_STD_STRING_H_
07188 
07189 /* Amalgamated: #include "v7/src/internal.h" */
07190 /* Amalgamated: #include "v7/src/core.h" */
07191 
07192 /* Max captures for String.replace() */
07193 #define V7_RE_MAX_REPL_SUB 20
07194 
07195 #if defined(__cplusplus)
07196 extern "C" {
07197 #endif /* __cplusplus */
07198 
07199 V7_PRIVATE void init_string(struct v7 *v7);
07200 
07201 #if defined(__cplusplus)
07202 }
07203 #endif /* __cplusplus */
07204 
07205 #endif /* CS_V7_SRC_STD_STRING_H_ */
07206 #ifdef V7_MODULE_LINES
07207 #line 1 "v7/src/js_stdlib.h"
07208 #endif
07209 /*
07210  * Copyright (c) 2014 Cesanta Software Limited
07211  * All rights reserved
07212  */
07213 
07214 #ifndef CS_V7_SRC_JS_STDLIB_H_
07215 #define CS_V7_SRC_JS_STDLIB_H_
07216 
07217 /* Amalgamated: #include "v7/src/internal.h" */
07218 
07219 #if defined(__cplusplus)
07220 extern "C" {
07221 #endif /* __cplusplus */
07222 
07223 V7_PRIVATE void init_js_stdlib(struct v7 *);
07224 
07225 #if defined(__cplusplus)
07226 }
07227 #endif /* __cplusplus */
07228 
07229 #endif /* CS_V7_SRC_JS_STDLIB_H_ */
07230 #ifdef V7_MODULE_LINES
07231 #line 1 "v7/src/main_public.h"
07232 #endif
07233 /*
07234  * Copyright (c) 2014 Cesanta Software Limited
07235  * All rights reserved
07236  */
07237 
07238 /*
07239  * === v7 main()
07240  */
07241 
07242 #ifndef CS_V7_SRC_MAIN_PUBLIC_H_
07243 #define CS_V7_SRC_MAIN_PUBLIC_H_
07244 
07245 /* Amalgamated: #include "v7/src/core_public.h" */
07246 
07247 #if defined(__cplusplus)
07248 extern "C" {
07249 #endif /* __cplusplus */
07250 
07251 /*
07252  * V7 executable main function.
07253  *
07254  * There are various callbacks available:
07255  *
07256  * `pre_freeze_init()` and `pre_init()` are optional intialization functions,
07257  * aimed to export any extra functionality into vanilla v7 engine. They are
07258  * called after v7 initialization, before executing given files or inline
07259  * expressions. `pre_freeze_init()` is called before "freezing" v7 state;
07260  * whereas `pre_init` called afterwards.
07261  *
07262  * `post_init()`, if provided, is called after executing files and expressions,
07263  * before destroying v7 instance and exiting.
07264  */
07265 int v7_main(int argc, char *argv[], void (*pre_freeze_init)(struct v7 *),
07266             void (*pre_init)(struct v7 *), void (*post_init)(struct v7 *));
07267 
07268 #if defined(__cplusplus)
07269 }
07270 #endif /* __cplusplus */
07271 
07272 #endif /* CS_V7_SRC_MAIN_PUBLIC_H_ */
07273 #ifdef V7_MODULE_LINES
07274 #line 1 "v7/src/main.h"
07275 #endif
07276 /*
07277  * Copyright (c) 2014 Cesanta Software Limited
07278  * All rights reserved
07279  */
07280 
07281 #ifndef CS_V7_SRC_MAIN_H_
07282 #define CS_V7_SRC_MAIN_H_
07283 
07284 /* Amalgamated: #include "v7/src/main_public.h" */
07285 
07286 #endif /* CS_V7_SRC_MAIN_H_ */
07287 #ifndef V7_EXPORT_INTERNAL_HEADERS
07288 #ifdef V7_MODULE_LINES
07289 #line 1 "common/mbuf.c"
07290 #endif
07291 /*
07292  * Copyright (c) 2014 Cesanta Software Limited
07293  * All rights reserved
07294  */
07295 
07296 #ifndef EXCLUDE_COMMON
07297 
07298 #include <assert.h>
07299 #include <string.h>
07300 /* Amalgamated: #include "common/mbuf.h" */
07301 
07302 #ifndef MBUF_REALLOC
07303 #define MBUF_REALLOC realloc
07304 #endif
07305 
07306 #ifndef MBUF_FREE
07307 #define MBUF_FREE free
07308 #endif
07309 
07310 void mbuf_init(struct mbuf *mbuf, size_t initial_size) {
07311   mbuf->len = mbuf->size = 0;
07312   mbuf->buf = NULL;
07313   mbuf_resize(mbuf, initial_size);
07314 }
07315 
07316 void mbuf_free(struct mbuf *mbuf) {
07317   if (mbuf->buf != NULL) {
07318     MBUF_FREE(mbuf->buf);
07319     mbuf_init(mbuf, 0);
07320   }
07321 }
07322 
07323 void mbuf_resize(struct mbuf *a, size_t new_size) {
07324   if (new_size > a->size || (new_size < a->size && new_size >= a->len)) {
07325     char *buf = (char *) MBUF_REALLOC(a->buf, new_size);
07326     /*
07327      * In case realloc fails, there's not much we can do, except keep things as
07328      * they are. Note that NULL is a valid return value from realloc when
07329      * size == 0, but that is covered too.
07330      */
07331     if (buf == NULL && new_size != 0) return;
07332     a->buf = buf;
07333     a->size = new_size;
07334   }
07335 }
07336 
07337 void mbuf_trim(struct mbuf *mbuf) {
07338   mbuf_resize(mbuf, mbuf->len);
07339 }
07340 
07341 size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) {
07342   char *p = NULL;
07343 
07344   assert(a != NULL);
07345   assert(a->len <= a->size);
07346   assert(off <= a->len);
07347 
07348   /* check overflow */
07349   if (~(size_t) 0 - (size_t) a->buf < len) return 0;
07350 
07351   if (a->len + len <= a->size) {
07352     memmove(a->buf + off + len, a->buf + off, a->len - off);
07353     if (buf != NULL) {
07354       memcpy(a->buf + off, buf, len);
07355     }
07356     a->len += len;
07357   } else {
07358     size_t new_size = (size_t)((a->len + len) * MBUF_SIZE_MULTIPLIER);
07359     if ((p = (char *) MBUF_REALLOC(a->buf, new_size)) != NULL) {
07360       a->buf = p;
07361       memmove(a->buf + off + len, a->buf + off, a->len - off);
07362       if (buf != NULL) memcpy(a->buf + off, buf, len);
07363       a->len += len;
07364       a->size = new_size;
07365     } else {
07366       len = 0;
07367     }
07368   }
07369 
07370   return len;
07371 }
07372 
07373 size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) {
07374   return mbuf_insert(a, a->len, buf, len);
07375 }
07376 
07377 void mbuf_remove(struct mbuf *mb, size_t n) {
07378   if (n > 0 && n <= mb->len) {
07379     memmove(mb->buf, mb->buf + n, mb->len - n);
07380     mb->len -= n;
07381   }
07382 }
07383 
07384 #endif /* EXCLUDE_COMMON */
07385 #ifdef V7_MODULE_LINES
07386 #line 1 "common/str_util.c"
07387 #endif
07388 /*
07389  * Copyright (c) 2015 Cesanta Software Limited
07390  * All rights reserved
07391  */
07392 
07393 #ifndef EXCLUDE_COMMON
07394 
07395 /* Amalgamated: #include "common/platform.h" */
07396 /* Amalgamated: #include "common/str_util.h" */
07397 
07398 size_t c_strnlen(const char *s, size_t maxlen) {
07399   size_t l = 0;
07400   for (; l < maxlen && s[l] != '\0'; l++) {
07401   }
07402   return l;
07403 }
07404 
07405 #define C_SNPRINTF_APPEND_CHAR(ch)       \
07406   do {                                   \
07407     if (i < (int) buf_size) buf[i] = ch; \
07408     i++;                                 \
07409   } while (0)
07410 
07411 #define C_SNPRINTF_FLAG_ZERO 1
07412 
07413 #ifdef C_DISABLE_BUILTIN_SNPRINTF
07414 int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
07415   return vsnprintf(buf, buf_size, fmt, ap);
07416 }
07417 #else
07418 static int c_itoa(char *buf, size_t buf_size, int64_t num, int base, int flags,
07419                   int field_width) {
07420   char tmp[40];
07421   int i = 0, k = 0, neg = 0;
07422 
07423   if (num < 0) {
07424     neg++;
07425     num = -num;
07426   }
07427 
07428   /* Print into temporary buffer - in reverse order */
07429   do {
07430     int rem = num % base;
07431     if (rem < 10) {
07432       tmp[k++] = '0' + rem;
07433     } else {
07434       tmp[k++] = 'a' + (rem - 10);
07435     }
07436     num /= base;
07437   } while (num > 0);
07438 
07439   /* Zero padding */
07440   if (flags && C_SNPRINTF_FLAG_ZERO) {
07441     while (k < field_width && k < (int) sizeof(tmp) - 1) {
07442       tmp[k++] = '0';
07443     }
07444   }
07445 
07446   /* And sign */
07447   if (neg) {
07448     tmp[k++] = '-';
07449   }
07450 
07451   /* Now output */
07452   while (--k >= 0) {
07453     C_SNPRINTF_APPEND_CHAR(tmp[k]);
07454   }
07455 
07456   return i;
07457 }
07458 
07459 int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
07460   int ch, i = 0, len_mod, flags, precision, field_width;
07461 
07462   while ((ch = *fmt++) != '\0') {
07463     if (ch != '%') {
07464       C_SNPRINTF_APPEND_CHAR(ch);
07465     } else {
07466       /*
07467        * Conversion specification:
07468        *   zero or more flags (one of: # 0 - <space> + ')
07469        *   an optional minimum  field  width (digits)
07470        *   an  optional precision (. followed by digits, or *)
07471        *   an optional length modifier (one of: hh h l ll L q j z t)
07472        *   conversion specifier (one of: d i o u x X e E f F g G a A c s p n)
07473        */
07474       flags = field_width = precision = len_mod = 0;
07475 
07476       /* Flags. only zero-pad flag is supported. */
07477       if (*fmt == '0') {
07478         flags |= C_SNPRINTF_FLAG_ZERO;
07479       }
07480 
07481       /* Field width */
07482       while (*fmt >= '0' && *fmt <= '9') {
07483         field_width *= 10;
07484         field_width += *fmt++ - '0';
07485       }
07486       /* Dynamic field width */
07487       if (*fmt == '*') {
07488         field_width = va_arg(ap, int);
07489         fmt++;
07490       }
07491 
07492       /* Precision */
07493       if (*fmt == '.') {
07494         fmt++;
07495         if (*fmt == '*') {
07496           precision = va_arg(ap, int);
07497           fmt++;
07498         } else {
07499           while (*fmt >= '0' && *fmt <= '9') {
07500             precision *= 10;
07501             precision += *fmt++ - '0';
07502           }
07503         }
07504       }
07505 
07506       /* Length modifier */
07507       switch (*fmt) {
07508         case 'h':
07509         case 'l':
07510         case 'L':
07511         case 'I':
07512         case 'q':
07513         case 'j':
07514         case 'z':
07515         case 't':
07516           len_mod = *fmt++;
07517           if (*fmt == 'h') {
07518             len_mod = 'H';
07519             fmt++;
07520           }
07521           if (*fmt == 'l') {
07522             len_mod = 'q';
07523             fmt++;
07524           }
07525           break;
07526       }
07527 
07528       ch = *fmt++;
07529       if (ch == 's') {
07530         const char *s = va_arg(ap, const char *); /* Always fetch parameter */
07531         int j;
07532         int pad = field_width - (precision >= 0 ? c_strnlen(s, precision) : 0);
07533         for (j = 0; j < pad; j++) {
07534           C_SNPRINTF_APPEND_CHAR(' ');
07535         }
07536 
07537         /* `s` may be NULL in case of %.*s */
07538         if (s != NULL) {
07539           /* Ignore negative and 0 precisions */
07540           for (j = 0; (precision <= 0 || j < precision) && s[j] != '\0'; j++) {
07541             C_SNPRINTF_APPEND_CHAR(s[j]);
07542           }
07543         }
07544       } else if (ch == 'c') {
07545         ch = va_arg(ap, int); /* Always fetch parameter */
07546         C_SNPRINTF_APPEND_CHAR(ch);
07547       } else if (ch == 'd' && len_mod == 0) {
07548         i += c_itoa(buf + i, buf_size - i, va_arg(ap, int), 10, flags,
07549                     field_width);
07550       } else if (ch == 'd' && len_mod == 'l') {
07551         i += c_itoa(buf + i, buf_size - i, va_arg(ap, long), 10, flags,
07552                     field_width);
07553 #ifdef SSIZE_MAX
07554       } else if (ch == 'd' && len_mod == 'z') {
07555         i += c_itoa(buf + i, buf_size - i, va_arg(ap, ssize_t), 10, flags,
07556                     field_width);
07557 #endif
07558       } else if (ch == 'd' && len_mod == 'q') {
07559         i += c_itoa(buf + i, buf_size - i, va_arg(ap, int64_t), 10, flags,
07560                     field_width);
07561       } else if ((ch == 'x' || ch == 'u') && len_mod == 0) {
07562         i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned),
07563                     ch == 'x' ? 16 : 10, flags, field_width);
07564       } else if ((ch == 'x' || ch == 'u') && len_mod == 'l') {
07565         i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned long),
07566                     ch == 'x' ? 16 : 10, flags, field_width);
07567       } else if ((ch == 'x' || ch == 'u') && len_mod == 'z') {
07568         i += c_itoa(buf + i, buf_size - i, va_arg(ap, size_t),
07569                     ch == 'x' ? 16 : 10, flags, field_width);
07570       } else if (ch == 'p') {
07571         unsigned long num = (unsigned long) (uintptr_t) va_arg(ap, void *);
07572         C_SNPRINTF_APPEND_CHAR('0');
07573         C_SNPRINTF_APPEND_CHAR('x');
07574         i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0);
07575       } else {
07576 #ifndef NO_LIBC
07577         /*
07578          * TODO(lsm): abort is not nice in a library, remove it
07579          * Also, ESP8266 SDK doesn't have it
07580          */
07581         abort();
07582 #endif
07583       }
07584     }
07585   }
07586 
07587   /* Zero-terminate the result */
07588   if (buf_size > 0) {
07589     buf[i < (int) buf_size ? i : (int) buf_size - 1] = '\0';
07590   }
07591 
07592   return i;
07593 }
07594 #endif
07595 
07596 int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) {
07597   int result;
07598   va_list ap;
07599   va_start(ap, fmt);
07600   result = c_vsnprintf(buf, buf_size, fmt, ap);
07601   va_end(ap);
07602   return result;
07603 }
07604 
07605 #ifdef _WIN32
07606 int to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) {
07607   int ret;
07608   char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p;
07609 
07610   strncpy(buf, path, sizeof(buf));
07611   buf[sizeof(buf) - 1] = '\0';
07612 
07613   /* Trim trailing slashes. Leave backslash for paths like "X:\" */
07614   p = buf + strlen(buf) - 1;
07615   while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0';
07616 
07617   memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
07618   ret = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
07619 
07620   /*
07621    * Convert back to Unicode. If doubly-converted string does not match the
07622    * original, something is fishy, reject.
07623    */
07624   WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
07625                       NULL, NULL);
07626   if (strcmp(buf, buf2) != 0) {
07627     wbuf[0] = L'\0';
07628     ret = 0;
07629   }
07630 
07631   return ret;
07632 }
07633 #endif /* _WIN32 */
07634 
07635 /* The simplest O(mn) algorithm. Better implementation are GPLed */
07636 const char *c_strnstr(const char *s, const char *find, size_t slen) {
07637   size_t find_length = strlen(find);
07638   size_t i;
07639 
07640   for (i = 0; i < slen; i++) {
07641     if (i + find_length > slen) {
07642       return NULL;
07643     }
07644 
07645     if (strncmp(&s[i], find, find_length) == 0) {
07646       return &s[i];
07647     }
07648   }
07649 
07650   return NULL;
07651 }
07652 
07653 #endif /* EXCLUDE_COMMON */
07654 #ifdef V7_MODULE_LINES
07655 #line 1 "common/utf.c"
07656 #endif
07657 /*
07658  * The authors of this software are Rob Pike and Ken Thompson.
07659  *              Copyright (c) 2002 by Lucent Technologies.
07660  * Permission to use, copy, modify, and distribute this software for any
07661  * purpose without fee is hereby granted, provided that this entire notice
07662  * is included in all copies of any software which is or includes a copy
07663  * or modification of this software and in all copies of the supporting
07664  * documentation for such software.
07665  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
07666  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
07667  * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
07668  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
07669  */
07670 
07671 #ifndef EXCLUDE_COMMON
07672 
07673 /* clang-format off */
07674 
07675 #include <stdarg.h>
07676 #include <string.h>
07677 /* Amalgamated: #include "common/platform.h" */
07678 /* Amalgamated: #include "common/utf.h" */
07679 
07680 #if CS_ENABLE_UTF8
07681 enum {
07682   Bit1 = 7,
07683   Bitx = 6,
07684   Bit2 = 5,
07685   Bit3 = 4,
07686   Bit4 = 3,
07687   Bit5 = 2,
07688 
07689   T1 = ((1 << (Bit1 + 1)) - 1) ^ 0xFF, /* 0000 0000 */
07690   Tx = ((1 << (Bitx + 1)) - 1) ^ 0xFF, /* 1000 0000 */
07691   T2 = ((1 << (Bit2 + 1)) - 1) ^ 0xFF, /* 1100 0000 */
07692   T3 = ((1 << (Bit3 + 1)) - 1) ^ 0xFF, /* 1110 0000 */
07693   T4 = ((1 << (Bit4 + 1)) - 1) ^ 0xFF, /* 1111 0000 */
07694   T5 = ((1 << (Bit5 + 1)) - 1) ^ 0xFF, /* 1111 1000 */
07695 
07696   Rune1 = (1 << (Bit1 + 0 * Bitx)) - 1, /* 0000 0000 0000 0000 0111 1111 */
07697   Rune2 = (1 << (Bit2 + 1 * Bitx)) - 1, /* 0000 0000 0000 0111 1111 1111 */
07698   Rune3 = (1 << (Bit3 + 2 * Bitx)) - 1, /* 0000 0000 1111 1111 1111 1111 */
07699   Rune4 = (1 << (Bit4 + 3 * Bitx)) - 1, /* 0011 1111 1111 1111 1111 1111 */
07700 
07701   Maskx = (1 << Bitx) - 1, /* 0011 1111 */
07702   Testx = Maskx ^ 0xFF,    /* 1100 0000 */
07703 
07704   Bad = Runeerror
07705 };
07706 
07707 int chartorune(Rune *rune, const char *str) {
07708   int c, c1, c2 /* , c3 */;
07709   unsigned short l;
07710 
07711   /*
07712    * one character sequence
07713    *    00000-0007F => T1
07714    */
07715   c = *(uchar *) str;
07716   if (c < Tx) {
07717     *rune = c;
07718     return 1;
07719   }
07720 
07721   /*
07722    * two character sequence
07723    *    0080-07FF => T2 Tx
07724    */
07725   c1 = *(uchar *) (str + 1) ^ Tx;
07726   if (c1 & Testx) goto bad;
07727   if (c < T3) {
07728     if (c < T2) goto bad;
07729     l = ((c << Bitx) | c1) & Rune2;
07730     if (l <= Rune1) goto bad;
07731     *rune = l;
07732     return 2;
07733   }
07734 
07735   /*
07736    * three character sequence
07737    *    0800-FFFF => T3 Tx Tx
07738    */
07739   c2 = *(uchar *) (str + 2) ^ Tx;
07740   if (c2 & Testx) goto bad;
07741   if (c < T4) {
07742     l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
07743     if (l <= Rune2) goto bad;
07744     *rune = l;
07745     return 3;
07746   }
07747 
07748 /*
07749  * four character sequence
07750  *  10000-10FFFF => T4 Tx Tx Tx
07751  */
07752 /* if(UTFmax >= 4) {
07753         c3 = *(uchar*)(str+3) ^ Tx;
07754         if(c3 & Testx)
07755                 goto bad;
07756         if(c < T5) {
07757                 l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) &
07758 Rune4;
07759                 if(l <= Rune3)
07760                         goto bad;
07761                 if(l > Runemax)
07762                         goto bad;
07763                 *rune = l;
07764                 return 4;
07765         }
07766 } */
07767 
07768 /*
07769  * bad decoding
07770  */
07771 bad:
07772   *rune = Bad;
07773   return 1;
07774 }
07775 
07776 int runetochar(char *str, Rune *rune) {
07777   unsigned short c;
07778 
07779   /*
07780    * one character sequence
07781    *    00000-0007F => 00-7F
07782    */
07783   c = *rune;
07784   if (c <= Rune1) {
07785     str[0] = c;
07786     return 1;
07787   }
07788 
07789   /*
07790    * two character sequence
07791    *    00080-007FF => T2 Tx
07792    */
07793   if (c <= Rune2) {
07794     str[0] = T2 | (c >> 1 * Bitx);
07795     str[1] = Tx | (c & Maskx);
07796     return 2;
07797   }
07798 
07799   /*
07800    * three character sequence
07801    *    00800-0FFFF => T3 Tx Tx
07802    */
07803   /* if(c > Runemax)
07804           c = Runeerror; */
07805   /* if(c <= Rune3) { */
07806   str[0] = T3 | (c >> 2 * Bitx);
07807   str[1] = Tx | ((c >> 1 * Bitx) & Maskx);
07808   str[2] = Tx | (c & Maskx);
07809   return 3;
07810   /* } */
07811 
07812   /*
07813    * four character sequence
07814    *    010000-1FFFFF => T4 Tx Tx Tx
07815    */
07816   /* str[0] = T4 |  (c >> 3*Bitx);
07817   str[1] = Tx | ((c >> 2*Bitx) & Maskx);
07818   str[2] = Tx | ((c >> 1*Bitx) & Maskx);
07819   str[3] = Tx |  (c & Maskx);
07820   return 4; */
07821 }
07822 
07823 int fullrune(const char *str, int n) {
07824   int c;
07825 
07826   if (n <= 0) return 0;
07827   c = *(uchar *) str;
07828   if (c < Tx) return 1;
07829   if (c < T3) return n >= 2;
07830   if (UTFmax == 3 || c < T4) return n >= 3;
07831   return n >= 4;
07832 }
07833 
07834 int utfnlen(const char *s, long m) {
07835   int c;
07836   long n;
07837   Rune rune;
07838   const char *es;
07839 
07840   es = s + m;
07841   for (n = 0; s < es; n++) {
07842     c = *(uchar *) s;
07843     if (c < Runeself) {
07844       s++;
07845       continue;
07846     }
07847     if (!fullrune(s, es - s)) break;
07848     s += chartorune(&rune, s);
07849   }
07850   return n;
07851 }
07852 
07853 const char *utfnshift(const char *s, long m) {
07854   int c;
07855   long n;
07856   Rune rune;
07857 
07858   for (n = 0; n < m; n++) {
07859     c = *(uchar *) s;
07860     if (c < Runeself) {
07861       s++;
07862       continue;
07863     }
07864     s += chartorune(&rune, s);
07865   }
07866   return s;
07867 }
07868 
07869 /*
07870  * The authors of this software are Rob Pike and Ken Thompson.
07871  *              Copyright (c) 2002 by Lucent Technologies.
07872  * Permission to use, copy, modify, and distribute this software for any
07873  * purpose without fee is hereby granted, provided that this entire notice
07874  * is included in all copies of any software which is or includes a copy
07875  * or modification of this software and in all copies of the supporting
07876  * documentation for such software.
07877  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
07878  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
07879  * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
07880  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
07881  */
07882 #include <stdarg.h>
07883 #include <string.h>
07884 /* Amalgamated: #include "common/utf.h" */
07885 
07886 /*
07887  * alpha ranges -
07888  *  only covers ranges not in lower||upper
07889  */
07890 static Rune __alpha2[] = {
07891     0x00d8, 0x00f6, /* Ø - ö */
07892     0x00f8, 0x01f5, /* ø - ǵ */
07893     0x0250, 0x02a8, /* ɐ - ʨ */
07894     0x038e, 0x03a1, /* Ύ - Ρ */
07895     0x03a3, 0x03ce, /* Σ - ώ */
07896     0x03d0, 0x03d6, /* ϐ - ϖ */
07897     0x03e2, 0x03f3, /* Ϣ - ϳ */
07898     0x0490, 0x04c4, /* Ґ - ӄ */
07899     0x0561, 0x0587, /* ա - և */
07900     0x05d0, 0x05ea, /* א - ת */
07901     0x05f0, 0x05f2, /* װ - ײ */
07902     0x0621, 0x063a, /* ء - غ */
07903     0x0640, 0x064a, /* ـ - ي */
07904     0x0671, 0x06b7, /* ٱ - ڷ */
07905     0x06ba, 0x06be, /* ں - ھ */
07906     0x06c0, 0x06ce, /* ۀ - ێ */
07907     0x06d0, 0x06d3, /* ې - ۓ */
07908     0x0905, 0x0939, /* अ - ह */
07909     0x0958, 0x0961, /* क़ - ॡ */
07910     0x0985, 0x098c, /* অ - ঌ */
07911     0x098f, 0x0990, /* এ - ঐ */
07912     0x0993, 0x09a8, /* ও - ন */
07913     0x09aa, 0x09b0, /* প - র */
07914     0x09b6, 0x09b9, /* শ - হ */
07915     0x09dc, 0x09dd, /* ড় - ঢ় */
07916     0x09df, 0x09e1, /* য় - ৡ */
07917     0x09f0, 0x09f1, /* ৰ - ৱ */
07918     0x0a05, 0x0a0a, /* ਅ - ਊ */
07919     0x0a0f, 0x0a10, /* ਏ - ਐ */
07920     0x0a13, 0x0a28, /* ਓ - ਨ */
07921     0x0a2a, 0x0a30, /* ਪ - ਰ */
07922     0x0a32, 0x0a33, /* ਲ - ਲ਼ */
07923     0x0a35, 0x0a36, /* ਵ - ਸ਼ */
07924     0x0a38, 0x0a39, /* ਸ - ਹ */
07925     0x0a59, 0x0a5c, /* ਖ਼ - ੜ */
07926     0x0a85, 0x0a8b, /* અ - ઋ */
07927     0x0a8f, 0x0a91, /* એ - ઑ */
07928     0x0a93, 0x0aa8, /* ઓ - ન */
07929     0x0aaa, 0x0ab0, /* પ - ર */
07930     0x0ab2, 0x0ab3, /* લ - ળ */
07931     0x0ab5, 0x0ab9, /* વ - હ */
07932     0x0b05, 0x0b0c, /* ଅ - ଌ */
07933     0x0b0f, 0x0b10, /* ଏ - ଐ */
07934     0x0b13, 0x0b28, /* ଓ - ନ */
07935     0x0b2a, 0x0b30, /* ପ - ର */
07936     0x0b32, 0x0b33, /* ଲ - ଳ */
07937     0x0b36, 0x0b39, /* ଶ - ହ */
07938     0x0b5c, 0x0b5d, /* ଡ଼ - ଢ଼ */
07939     0x0b5f, 0x0b61, /* ୟ - ୡ */
07940     0x0b85, 0x0b8a, /* அ - ஊ */
07941     0x0b8e, 0x0b90, /* எ - ஐ */
07942     0x0b92, 0x0b95, /* ஒ - க */
07943     0x0b99, 0x0b9a, /* ங - ச */
07944     0x0b9e, 0x0b9f, /* ஞ - ட */
07945     0x0ba3, 0x0ba4, /* ண - த */
07946     0x0ba8, 0x0baa, /* ந - ப */
07947     0x0bae, 0x0bb5, /* ம - வ */
07948     0x0bb7, 0x0bb9, /* ஷ - ஹ */
07949     0x0c05, 0x0c0c, /* అ - ఌ */
07950     0x0c0e, 0x0c10, /* ఎ - ఐ */
07951     0x0c12, 0x0c28, /* ఒ - న */
07952     0x0c2a, 0x0c33, /* ప - ళ */
07953     0x0c35, 0x0c39, /* వ - హ */
07954     0x0c60, 0x0c61, /* ౠ - ౡ */
07955     0x0c85, 0x0c8c, /* ಅ - ಌ */
07956     0x0c8e, 0x0c90, /* ಎ - ಐ */
07957     0x0c92, 0x0ca8, /* ಒ - ನ */
07958     0x0caa, 0x0cb3, /* ಪ - ಳ */
07959     0x0cb5, 0x0cb9, /* ವ - ಹ */
07960     0x0ce0, 0x0ce1, /* ೠ - ೡ */
07961     0x0d05, 0x0d0c, /* അ - ഌ */
07962     0x0d0e, 0x0d10, /* എ - ഐ */
07963     0x0d12, 0x0d28, /* ഒ - ന */
07964     0x0d2a, 0x0d39, /* പ - ഹ */
07965     0x0d60, 0x0d61, /* ൠ - ൡ */
07966     0x0e01, 0x0e30, /* ก - ะ */
07967     0x0e32, 0x0e33, /* า - ำ */
07968     0x0e40, 0x0e46, /* เ - ๆ */
07969     0x0e5a, 0x0e5b, /* ๚ - ๛ */
07970     0x0e81, 0x0e82, /* ກ - ຂ */
07971     0x0e87, 0x0e88, /* ງ - ຈ */
07972     0x0e94, 0x0e97, /* ດ - ທ */
07973     0x0e99, 0x0e9f, /* ນ - ຟ */
07974     0x0ea1, 0x0ea3, /* ມ - ຣ */
07975     0x0eaa, 0x0eab, /* ສ - ຫ */
07976     0x0ead, 0x0eae, /* ອ - ຮ */
07977     0x0eb2, 0x0eb3, /* າ - ຳ */
07978     0x0ec0, 0x0ec4, /* ເ - ໄ */
07979     0x0edc, 0x0edd, /* ໜ - ໝ */
07980     0x0f18, 0x0f19, /* ༘ - ༙ */
07981     0x0f40, 0x0f47, /* ཀ - ཇ */
07982     0x0f49, 0x0f69, /* ཉ - ཀྵ */
07983     0x10d0, 0x10f6, /* ა - ჶ */
07984     0x1100, 0x1159, /* ᄀ - ᅙ */
07985     0x115f, 0x11a2, /* ᅟ - ᆢ */
07986     0x11a8, 0x11f9, /* ᆨ - ᇹ */
07987     0x1e00, 0x1e9b, /* Ḁ - ẛ */
07988     0x1f50, 0x1f57, /* ὐ - ὗ */
07989     0x1f80, 0x1fb4, /* ᾀ - ᾴ */
07990     0x1fb6, 0x1fbc, /* ᾶ - ᾼ */
07991     0x1fc2, 0x1fc4, /* ῂ - ῄ */
07992     0x1fc6, 0x1fcc, /* ῆ - ῌ */
07993     0x1fd0, 0x1fd3, /* ῐ - ΐ */
07994     0x1fd6, 0x1fdb, /* ῖ - Ί */
07995     0x1fe0, 0x1fec, /* ῠ - Ῥ */
07996     0x1ff2, 0x1ff4, /* ῲ - ῴ */
07997     0x1ff6, 0x1ffc, /* ῶ - ῼ */
07998     0x210a, 0x2113, /* ℊ - ℓ */
07999     0x2115, 0x211d, /* ℕ - ℝ */
08000     0x2120, 0x2122, /* ℠ - ™ */
08001     0x212a, 0x2131, /* K - ℱ */
08002     0x2133, 0x2138, /* ℳ - ℸ */
08003     0x3041, 0x3094, /* ぁ - ゔ */
08004     0x30a1, 0x30fa, /* ァ - ヺ */
08005     0x3105, 0x312c, /* ㄅ - ㄬ */
08006     0x3131, 0x318e, /* ㄱ - ㆎ */
08007     0x3192, 0x319f, /* ㆒ - ㆟ */
08008     0x3260, 0x327b, /* ㉠ - ㉻ */
08009     0x328a, 0x32b0, /* ㊊ - ㊰ */
08010     0x32d0, 0x32fe, /* ㋐ - ㋾ */
08011     0x3300, 0x3357, /* ㌀ - ㍗ */
08012     0x3371, 0x3376, /* ㍱ - ㍶ */
08013     0x337b, 0x3394, /* ㍻ - ㎔ */
08014     0x3399, 0x339e, /* ㎙ - ㎞ */
08015     0x33a9, 0x33ad, /* ㎩ - ㎭ */
08016     0x33b0, 0x33c1, /* ㎰ - ㏁ */
08017     0x33c3, 0x33c5, /* ㏃ - ㏅ */
08018     0x33c7, 0x33d7, /* ㏇ - ㏗ */
08019     0x33d9, 0x33dd, /* ㏙ - ㏝ */
08020     0x4e00, 0x9fff, /* 一 - 鿿 */
08021     0xac00, 0xd7a3, /* 가 - 힣 */
08022     0xf900, 0xfb06, /* 豈 - st */
08023     0xfb13, 0xfb17, /* ﬓ - ﬗ */
08024     0xfb1f, 0xfb28, /* ײַ - ﬨ */
08025     0xfb2a, 0xfb36, /* שׁ - זּ */
08026     0xfb38, 0xfb3c, /* טּ - לּ */
08027     0xfb40, 0xfb41, /* נּ - סּ */
08028     0xfb43, 0xfb44, /* ףּ - פּ */
08029     0xfb46, 0xfbb1, /* צּ - ﮱ */
08030     0xfbd3, 0xfd3d, /* ﯓ - ﴽ */
08031     0xfd50, 0xfd8f, /* ﵐ - ﶏ */
08032     0xfd92, 0xfdc7, /* ﶒ - ﷇ */
08033     0xfdf0, 0xfdf9, /* ﷰ - ﷹ */
08034     0xfe70, 0xfe72, /* ﹰ - ﹲ */
08035     0xfe76, 0xfefc, /* ﹶ - ﻼ */
08036     0xff66, 0xff6f, /* ヲ - ッ */
08037     0xff71, 0xff9d, /* ア - ン */
08038     0xffa0, 0xffbe, /* ᅠ - ᄒ */
08039     0xffc2, 0xffc7, /* ᅡ - ᅦ */
08040     0xffca, 0xffcf, /* ᅧ - ᅬ */
08041     0xffd2, 0xffd7, /* ᅭ - ᅲ */
08042     0xffda, 0xffdc, /* ᅳ - ᅵ */
08043 };
08044 
08045 /*
08046  * alpha singlets -
08047  *  only covers ranges not in lower||upper
08048  */
08049 static Rune __alpha1[] = {
08050     0x00aa, /* ª */
08051     0x00b5, /* µ */
08052     0x00ba, /* º */
08053     0x03da, /* Ϛ */
08054     0x03dc, /* Ϝ */
08055     0x03de, /* Ϟ */
08056     0x03e0, /* Ϡ */
08057     0x06d5, /* ە */
08058     0x09b2, /* ল */
08059     0x0a5e, /* ਫ਼ */
08060     0x0a8d, /* ઍ */
08061     0x0ae0, /* ૠ */
08062     0x0b9c, /* ஜ */
08063     0x0cde, /* ೞ */
08064     0x0e4f, /* ๏ */
08065     0x0e84, /* ຄ */
08066     0x0e8a, /* ຊ */
08067     0x0e8d, /* ຍ */
08068     0x0ea5, /* ລ */
08069     0x0ea7, /* ວ */
08070     0x0eb0, /* ະ */
08071     0x0ebd, /* ຽ */
08072     0x1fbe, /* ι */
08073     0x207f, /* ⁿ */
08074     0x20a8, /* ₨ */
08075     0x2102, /* ℂ */
08076     0x2107, /* ℇ */
08077     0x2124, /* ℤ */
08078     0x2126, /* Ω */
08079     0x2128, /* ℨ */
08080     0xfb3e, /* מּ */
08081     0xfe74, /* ﹴ */
08082 };
08083 
08084 /*
08085  * space ranges
08086  */
08087 static Rune __space2[] = {
08088     0x0009, 0x000a, /* tab and newline */
08089     0x0020, 0x0020, /* space */
08090     0x00a0, 0x00a0, /*   */
08091     0x2000, 0x200b, /*   - ​ */
08092     0x2028, 0x2029, /* 
 - 
 */
08093     0x3000, 0x3000, /*   */
08094     0xfeff, 0xfeff, /*  */
08095 };
08096 
08097 /*
08098  * lower case ranges
08099  *  3rd col is conversion excess 500
08100  */
08101 static Rune __toupper2[] = {
08102     0x0061, 0x007a, 468, /* a-z A-Z */
08103     0x00e0, 0x00f6, 468, /* à-ö À-Ö */
08104     0x00f8, 0x00fe, 468, /* ø-þ Ø-Þ */
08105     0x0256, 0x0257, 295, /* ɖ-ɗ Ɖ-Ɗ */
08106     0x0258, 0x0259, 298, /* ɘ-ə Ǝ-Ə */
08107     0x028a, 0x028b, 283, /* ʊ-ʋ Ʊ-Ʋ */
08108     0x03ad, 0x03af, 463, /* έ-ί Έ-Ί */
08109     0x03b1, 0x03c1, 468, /* α-ρ Α-Ρ */
08110     0x03c3, 0x03cb, 468, /* σ-ϋ Σ-Ϋ */
08111     0x03cd, 0x03ce, 437, /* ύ-ώ Ύ-Ώ */
08112     0x0430, 0x044f, 468, /* а-я А-Я */
08113     0x0451, 0x045c, 420, /* ё-ќ Ё-Ќ */
08114     0x045e, 0x045f, 420, /* ў-џ Ў-Џ */
08115     0x0561, 0x0586, 452, /* ա-ֆ Ա-Ֆ */
08116     0x1f00, 0x1f07, 508, /* ἀ-ἇ Ἀ-Ἇ */
08117     0x1f10, 0x1f15, 508, /* ἐ-ἕ Ἐ-Ἕ */
08118     0x1f20, 0x1f27, 508, /* ἠ-ἧ Ἠ-Ἧ */
08119     0x1f30, 0x1f37, 508, /* ἰ-ἷ Ἰ-Ἷ */
08120     0x1f40, 0x1f45, 508, /* ὀ-ὅ Ὀ-Ὅ */
08121     0x1f60, 0x1f67, 508, /* ὠ-ὧ Ὠ-Ὧ */
08122     0x1f70, 0x1f71, 574, /* ὰ-ά Ὰ-Ά */
08123     0x1f72, 0x1f75, 586, /* ὲ-ή Ὲ-Ή */
08124     0x1f76, 0x1f77, 600, /* ὶ-ί Ὶ-Ί */
08125     0x1f78, 0x1f79, 628, /* ὸ-ό Ὸ-Ό */
08126     0x1f7a, 0x1f7b, 612, /* ὺ-ύ Ὺ-Ύ */
08127     0x1f7c, 0x1f7d, 626, /* ὼ-ώ Ὼ-Ώ */
08128     0x1f80, 0x1f87, 508, /* ᾀ-ᾇ ᾈ-ᾏ */
08129     0x1f90, 0x1f97, 508, /* ᾐ-ᾗ ᾘ-ᾟ */
08130     0x1fa0, 0x1fa7, 508, /* ᾠ-ᾧ ᾨ-ᾯ */
08131     0x1fb0, 0x1fb1, 508, /* ᾰ-ᾱ Ᾰ-Ᾱ */
08132     0x1fd0, 0x1fd1, 508, /* ῐ-ῑ Ῐ-Ῑ */
08133     0x1fe0, 0x1fe1, 508, /* ῠ-ῡ Ῠ-Ῡ */
08134     0x2170, 0x217f, 484, /* ⅰ-ⅿ Ⅰ-Ⅿ */
08135     0x24d0, 0x24e9, 474, /* ⓐ-ⓩ Ⓐ-Ⓩ */
08136     0xff41, 0xff5a, 468, /* a-z A-Z */
08137 };
08138 
08139 /*
08140  * lower case singlets
08141  *  2nd col is conversion excess 500
08142  */
08143 static Rune __toupper1[] = {
08144     0x00ff, 621, /* ÿ Ÿ */
08145     0x0101, 499, /* ā Ā */
08146     0x0103, 499, /* ă Ă */
08147     0x0105, 499, /* ą Ą */
08148     0x0107, 499, /* ć Ć */
08149     0x0109, 499, /* ĉ Ĉ */
08150     0x010b, 499, /* ċ Ċ */
08151     0x010d, 499, /* č Č */
08152     0x010f, 499, /* ď Ď */
08153     0x0111, 499, /* đ Đ */
08154     0x0113, 499, /* ē Ē */
08155     0x0115, 499, /* ĕ Ĕ */
08156     0x0117, 499, /* ė Ė */
08157     0x0119, 499, /* ę Ę */
08158     0x011b, 499, /* ě Ě */
08159     0x011d, 499, /* ĝ Ĝ */
08160     0x011f, 499, /* ğ Ğ */
08161     0x0121, 499, /* ġ Ġ */
08162     0x0123, 499, /* ģ Ģ */
08163     0x0125, 499, /* ĥ Ĥ */
08164     0x0127, 499, /* ħ Ħ */
08165     0x0129, 499, /* ĩ Ĩ */
08166     0x012b, 499, /* ī Ī */
08167     0x012d, 499, /* ĭ Ĭ */
08168     0x012f, 499, /* į Į */
08169     0x0131, 268, /* ı I */
08170     0x0133, 499, /* ij IJ */
08171     0x0135, 499, /* ĵ Ĵ */
08172     0x0137, 499, /* ķ Ķ */
08173     0x013a, 499, /* ĺ Ĺ */
08174     0x013c, 499, /* ļ Ļ */
08175     0x013e, 499, /* ľ Ľ */
08176     0x0140, 499, /* ŀ Ŀ */
08177     0x0142, 499, /* ł Ł */
08178     0x0144, 499, /* ń Ń */
08179     0x0146, 499, /* ņ Ņ */
08180     0x0148, 499, /* ň Ň */
08181     0x014b, 499, /* ŋ Ŋ */
08182     0x014d, 499, /* ō Ō */
08183     0x014f, 499, /* ŏ Ŏ */
08184     0x0151, 499, /* ő Ő */
08185     0x0153, 499, /* œ Œ */
08186     0x0155, 499, /* ŕ Ŕ */
08187     0x0157, 499, /* ŗ Ŗ */
08188     0x0159, 499, /* ř Ř */
08189     0x015b, 499, /* ś Ś */
08190     0x015d, 499, /* ŝ Ŝ */
08191     0x015f, 499, /* ş Ş */
08192     0x0161, 499, /* š Š */
08193     0x0163, 499, /* ţ Ţ */
08194     0x0165, 499, /* ť Ť */
08195     0x0167, 499, /* ŧ Ŧ */
08196     0x0169, 499, /* ũ Ũ */
08197     0x016b, 499, /* ū Ū */
08198     0x016d, 499, /* ŭ Ŭ */
08199     0x016f, 499, /* ů Ů */
08200     0x0171, 499, /* ű Ű */
08201     0x0173, 499, /* ų Ų */
08202     0x0175, 499, /* ŵ Ŵ */
08203     0x0177, 499, /* ŷ Ŷ */
08204     0x017a, 499, /* ź Ź */
08205     0x017c, 499, /* ż Ż */
08206     0x017e, 499, /* ž Ž */
08207     0x017f, 200, /* ſ S */
08208     0x0183, 499, /* ƃ Ƃ */
08209     0x0185, 499, /* ƅ Ƅ */
08210     0x0188, 499, /* ƈ Ƈ */
08211     0x018c, 499, /* ƌ Ƌ */
08212     0x0192, 499, /* ƒ Ƒ */
08213     0x0199, 499, /* ƙ Ƙ */
08214     0x01a1, 499, /* ơ Ơ */
08215     0x01a3, 499, /* ƣ Ƣ */
08216     0x01a5, 499, /* ƥ Ƥ */
08217     0x01a8, 499, /* ƨ Ƨ */
08218     0x01ad, 499, /* ƭ Ƭ */
08219     0x01b0, 499, /* ư Ư */
08220     0x01b4, 499, /* ƴ Ƴ */
08221     0x01b6, 499, /* ƶ Ƶ */
08222     0x01b9, 499, /* ƹ Ƹ */
08223     0x01bd, 499, /* ƽ Ƽ */
08224     0x01c5, 499, /* Dž DŽ */
08225     0x01c6, 498, /* dž DŽ */
08226     0x01c8, 499, /* Lj LJ */
08227     0x01c9, 498, /* lj LJ */
08228     0x01cb, 499, /* Nj NJ */
08229     0x01cc, 498, /* nj NJ */
08230     0x01ce, 499, /* ǎ Ǎ */
08231     0x01d0, 499, /* ǐ Ǐ */
08232     0x01d2, 499, /* ǒ Ǒ */
08233     0x01d4, 499, /* ǔ Ǔ */
08234     0x01d6, 499, /* ǖ Ǖ */
08235     0x01d8, 499, /* ǘ Ǘ */
08236     0x01da, 499, /* ǚ Ǚ */
08237     0x01dc, 499, /* ǜ Ǜ */
08238     0x01df, 499, /* ǟ Ǟ */
08239     0x01e1, 499, /* ǡ Ǡ */
08240     0x01e3, 499, /* ǣ Ǣ */
08241     0x01e5, 499, /* ǥ Ǥ */
08242     0x01e7, 499, /* ǧ Ǧ */
08243     0x01e9, 499, /* ǩ Ǩ */
08244     0x01eb, 499, /* ǫ Ǫ */
08245     0x01ed, 499, /* ǭ Ǭ */
08246     0x01ef, 499, /* ǯ Ǯ */
08247     0x01f2, 499, /* Dz DZ */
08248     0x01f3, 498, /* dz DZ */
08249     0x01f5, 499, /* ǵ Ǵ */
08250     0x01fb, 499, /* ǻ Ǻ */
08251     0x01fd, 499, /* ǽ Ǽ */
08252     0x01ff, 499, /* ǿ Ǿ */
08253     0x0201, 499, /* ȁ Ȁ */
08254     0x0203, 499, /* ȃ Ȃ */
08255     0x0205, 499, /* ȅ Ȅ */
08256     0x0207, 499, /* ȇ Ȇ */
08257     0x0209, 499, /* ȉ Ȉ */
08258     0x020b, 499, /* ȋ Ȋ */
08259     0x020d, 499, /* ȍ Ȍ */
08260     0x020f, 499, /* ȏ Ȏ */
08261     0x0211, 499, /* ȑ Ȑ */
08262     0x0213, 499, /* ȓ Ȓ */
08263     0x0215, 499, /* ȕ Ȕ */
08264     0x0217, 499, /* ȗ Ȗ */
08265     0x0253, 290, /* ɓ Ɓ */
08266     0x0254, 294, /* ɔ Ɔ */
08267     0x025b, 297, /* ɛ Ɛ */
08268     0x0260, 295, /* ɠ Ɠ */
08269     0x0263, 293, /* ɣ Ɣ */
08270     0x0268, 291, /* ɨ Ɨ */
08271     0x0269, 289, /* ɩ Ɩ */
08272     0x026f, 289, /* ɯ Ɯ */
08273     0x0272, 287, /* ɲ Ɲ */
08274     0x0283, 282, /* ʃ Ʃ */
08275     0x0288, 282, /* ʈ Ʈ */
08276     0x0292, 281, /* ʒ Ʒ */
08277     0x03ac, 462, /* ά Ά */
08278     0x03cc, 436, /* ό Ό */
08279     0x03d0, 438, /* ϐ Β */
08280     0x03d1, 443, /* ϑ Θ */
08281     0x03d5, 453, /* ϕ Φ */
08282     0x03d6, 446, /* ϖ Π */
08283     0x03e3, 499, /* ϣ Ϣ */
08284     0x03e5, 499, /* ϥ Ϥ */
08285     0x03e7, 499, /* ϧ Ϧ */
08286     0x03e9, 499, /* ϩ Ϩ */
08287     0x03eb, 499, /* ϫ Ϫ */
08288     0x03ed, 499, /* ϭ Ϭ */
08289     0x03ef, 499, /* ϯ Ϯ */
08290     0x03f0, 414, /* ϰ Κ */
08291     0x03f1, 420, /* ϱ Ρ */
08292     0x0461, 499, /* ѡ Ѡ */
08293     0x0463, 499, /* ѣ Ѣ */
08294     0x0465, 499, /* ѥ Ѥ */
08295     0x0467, 499, /* ѧ Ѧ */
08296     0x0469, 499, /* ѩ Ѩ */
08297     0x046b, 499, /* ѫ Ѫ */
08298     0x046d, 499, /* ѭ Ѭ */
08299     0x046f, 499, /* ѯ Ѯ */
08300     0x0471, 499, /* ѱ Ѱ */
08301     0x0473, 499, /* ѳ Ѳ */
08302     0x0475, 499, /* ѵ Ѵ */
08303     0x0477, 499, /* ѷ Ѷ */
08304     0x0479, 499, /* ѹ Ѹ */
08305     0x047b, 499, /* ѻ Ѻ */
08306     0x047d, 499, /* ѽ Ѽ */
08307     0x047f, 499, /* ѿ Ѿ */
08308     0x0481, 499, /* ҁ Ҁ */
08309     0x0491, 499, /* ґ Ґ */
08310     0x0493, 499, /* ғ Ғ */
08311     0x0495, 499, /* ҕ Ҕ */
08312     0x0497, 499, /* җ Җ */
08313     0x0499, 499, /* ҙ Ҙ */
08314     0x049b, 499, /* қ Қ */
08315     0x049d, 499, /* ҝ Ҝ */
08316     0x049f, 499, /* ҟ Ҟ */
08317     0x04a1, 499, /* ҡ Ҡ */
08318     0x04a3, 499, /* ң Ң */
08319     0x04a5, 499, /* ҥ Ҥ */
08320     0x04a7, 499, /* ҧ Ҧ */
08321     0x04a9, 499, /* ҩ Ҩ */
08322     0x04ab, 499, /* ҫ Ҫ */
08323     0x04ad, 499, /* ҭ Ҭ */
08324     0x04af, 499, /* ү Ү */
08325     0x04b1, 499, /* ұ Ұ */
08326     0x04b3, 499, /* ҳ Ҳ */
08327     0x04b5, 499, /* ҵ Ҵ */
08328     0x04b7, 499, /* ҷ Ҷ */
08329     0x04b9, 499, /* ҹ Ҹ */
08330     0x04bb, 499, /* һ Һ */
08331     0x04bd, 499, /* ҽ Ҽ */
08332     0x04bf, 499, /* ҿ Ҿ */
08333     0x04c2, 499, /* ӂ Ӂ */
08334     0x04c4, 499, /* ӄ Ӄ */
08335     0x04c8, 499, /* ӈ Ӈ */
08336     0x04cc, 499, /* ӌ Ӌ */
08337     0x04d1, 499, /* ӑ Ӑ */
08338     0x04d3, 499, /* ӓ Ӓ */
08339     0x04d5, 499, /* ӕ Ӕ */
08340     0x04d7, 499, /* ӗ Ӗ */
08341     0x04d9, 499, /* ә Ә */
08342     0x04db, 499, /* ӛ Ӛ */
08343     0x04dd, 499, /* ӝ Ӝ */
08344     0x04df, 499, /* ӟ Ӟ */
08345     0x04e1, 499, /* ӡ Ӡ */
08346     0x04e3, 499, /* ӣ Ӣ */
08347     0x04e5, 499, /* ӥ Ӥ */
08348     0x04e7, 499, /* ӧ Ӧ */
08349     0x04e9, 499, /* ө Ө */
08350     0x04eb, 499, /* ӫ Ӫ */
08351     0x04ef, 499, /* ӯ Ӯ */
08352     0x04f1, 499, /* ӱ Ӱ */
08353     0x04f3, 499, /* ӳ Ӳ */
08354     0x04f5, 499, /* ӵ Ӵ */
08355     0x04f9, 499, /* ӹ Ӹ */
08356     0x1e01, 499, /* ḁ Ḁ */
08357     0x1e03, 499, /* ḃ Ḃ */
08358     0x1e05, 499, /* ḅ Ḅ */
08359     0x1e07, 499, /* ḇ Ḇ */
08360     0x1e09, 499, /* ḉ Ḉ */
08361     0x1e0b, 499, /* ḋ Ḋ */
08362     0x1e0d, 499, /* ḍ Ḍ */
08363     0x1e0f, 499, /* ḏ Ḏ */
08364     0x1e11, 499, /* ḑ Ḑ */
08365     0x1e13, 499, /* ḓ Ḓ */
08366     0x1e15, 499, /* ḕ Ḕ */
08367     0x1e17, 499, /* ḗ Ḗ */
08368     0x1e19, 499, /* ḙ Ḙ */
08369     0x1e1b, 499, /* ḛ Ḛ */
08370     0x1e1d, 499, /* ḝ Ḝ */
08371     0x1e1f, 499, /* ḟ Ḟ */
08372     0x1e21, 499, /* ḡ Ḡ */
08373     0x1e23, 499, /* ḣ Ḣ */
08374     0x1e25, 499, /* ḥ Ḥ */
08375     0x1e27, 499, /* ḧ Ḧ */
08376     0x1e29, 499, /* ḩ Ḩ */
08377     0x1e2b, 499, /* ḫ Ḫ */
08378     0x1e2d, 499, /* ḭ Ḭ */
08379     0x1e2f, 499, /* ḯ Ḯ */
08380     0x1e31, 499, /* ḱ Ḱ */
08381     0x1e33, 499, /* ḳ Ḳ */
08382     0x1e35, 499, /* ḵ Ḵ */
08383     0x1e37, 499, /* ḷ Ḷ */
08384     0x1e39, 499, /* ḹ Ḹ */
08385     0x1e3b, 499, /* ḻ Ḻ */
08386     0x1e3d, 499, /* ḽ Ḽ */
08387     0x1e3f, 499, /* ḿ Ḿ */
08388     0x1e41, 499, /* ṁ Ṁ */
08389     0x1e43, 499, /* ṃ Ṃ */
08390     0x1e45, 499, /* ṅ Ṅ */
08391     0x1e47, 499, /* ṇ Ṇ */
08392     0x1e49, 499, /* ṉ Ṉ */
08393     0x1e4b, 499, /* ṋ Ṋ */
08394     0x1e4d, 499, /* ṍ Ṍ */
08395     0x1e4f, 499, /* ṏ Ṏ */
08396     0x1e51, 499, /* ṑ Ṑ */
08397     0x1e53, 499, /* ṓ Ṓ */
08398     0x1e55, 499, /* ṕ Ṕ */
08399     0x1e57, 499, /* ṗ Ṗ */
08400     0x1e59, 499, /* ṙ Ṙ */
08401     0x1e5b, 499, /* ṛ Ṛ */
08402     0x1e5d, 499, /* ṝ Ṝ */
08403     0x1e5f, 499, /* ṟ Ṟ */
08404     0x1e61, 499, /* ṡ Ṡ */
08405     0x1e63, 499, /* ṣ Ṣ */
08406     0x1e65, 499, /* ṥ Ṥ */
08407     0x1e67, 499, /* ṧ Ṧ */
08408     0x1e69, 499, /* ṩ Ṩ */
08409     0x1e6b, 499, /* ṫ Ṫ */
08410     0x1e6d, 499, /* ṭ Ṭ */
08411     0x1e6f, 499, /* ṯ Ṯ */
08412     0x1e71, 499, /* ṱ Ṱ */
08413     0x1e73, 499, /* ṳ Ṳ */
08414     0x1e75, 499, /* ṵ Ṵ */
08415     0x1e77, 499, /* ṷ Ṷ */
08416     0x1e79, 499, /* ṹ Ṹ */
08417     0x1e7b, 499, /* ṻ Ṻ */
08418     0x1e7d, 499, /* ṽ Ṽ */
08419     0x1e7f, 499, /* ṿ Ṿ */
08420     0x1e81, 499, /* ẁ Ẁ */
08421     0x1e83, 499, /* ẃ Ẃ */
08422     0x1e85, 499, /* ẅ Ẅ */
08423     0x1e87, 499, /* ẇ Ẇ */
08424     0x1e89, 499, /* ẉ Ẉ */
08425     0x1e8b, 499, /* ẋ Ẋ */
08426     0x1e8d, 499, /* ẍ Ẍ */
08427     0x1e8f, 499, /* ẏ Ẏ */
08428     0x1e91, 499, /* ẑ Ẑ */
08429     0x1e93, 499, /* ẓ Ẓ */
08430     0x1e95, 499, /* ẕ Ẕ */
08431     0x1ea1, 499, /* ạ Ạ */
08432     0x1ea3, 499, /* ả Ả */
08433     0x1ea5, 499, /* ấ Ấ */
08434     0x1ea7, 499, /* ầ Ầ */
08435     0x1ea9, 499, /* ẩ Ẩ */
08436     0x1eab, 499, /* ẫ Ẫ */
08437     0x1ead, 499, /* ậ Ậ */
08438     0x1eaf, 499, /* ắ Ắ */
08439     0x1eb1, 499, /* ằ Ằ */
08440     0x1eb3, 499, /* ẳ Ẳ */
08441     0x1eb5, 499, /* ẵ Ẵ */
08442     0x1eb7, 499, /* ặ Ặ */
08443     0x1eb9, 499, /* ẹ Ẹ */
08444     0x1ebb, 499, /* ẻ Ẻ */
08445     0x1ebd, 499, /* ẽ Ẽ */
08446     0x1ebf, 499, /* ế Ế */
08447     0x1ec1, 499, /* ề Ề */
08448     0x1ec3, 499, /* ể Ể */
08449     0x1ec5, 499, /* ễ Ễ */
08450     0x1ec7, 499, /* ệ Ệ */
08451     0x1ec9, 499, /* ỉ Ỉ */
08452     0x1ecb, 499, /* ị Ị */
08453     0x1ecd, 499, /* ọ Ọ */
08454     0x1ecf, 499, /* ỏ Ỏ */
08455     0x1ed1, 499, /* ố Ố */
08456     0x1ed3, 499, /* ồ Ồ */
08457     0x1ed5, 499, /* ổ Ổ */
08458     0x1ed7, 499, /* ỗ Ỗ */
08459     0x1ed9, 499, /* ộ Ộ */
08460     0x1edb, 499, /* ớ Ớ */
08461     0x1edd, 499, /* ờ Ờ */
08462     0x1edf, 499, /* ở Ở */
08463     0x1ee1, 499, /* ỡ Ỡ */
08464     0x1ee3, 499, /* ợ Ợ */
08465     0x1ee5, 499, /* ụ Ụ */
08466     0x1ee7, 499, /* ủ Ủ */
08467     0x1ee9, 499, /* ứ Ứ */
08468     0x1eeb, 499, /* ừ Ừ */
08469     0x1eed, 499, /* ử Ử */
08470     0x1eef, 499, /* ữ Ữ */
08471     0x1ef1, 499, /* ự Ự */
08472     0x1ef3, 499, /* ỳ Ỳ */
08473     0x1ef5, 499, /* ỵ Ỵ */
08474     0x1ef7, 499, /* ỷ Ỷ */
08475     0x1ef9, 499, /* ỹ Ỹ */
08476     0x1f51, 508, /* ὑ Ὑ */
08477     0x1f53, 508, /* ὓ Ὓ */
08478     0x1f55, 508, /* ὕ Ὕ */
08479     0x1f57, 508, /* ὗ Ὗ */
08480     0x1fb3, 509, /* ᾳ ᾼ */
08481     0x1fc3, 509, /* ῃ ῌ */
08482     0x1fe5, 507, /* ῥ Ῥ */
08483     0x1ff3, 509, /* ῳ ῼ */
08484 };
08485 
08486 /*
08487  * upper case ranges
08488  *  3rd col is conversion excess 500
08489  */
08490 static Rune __tolower2[] = {
08491     0x0041, 0x005a, 532, /* A-Z a-z */
08492     0x00c0, 0x00d6, 532, /* À-Ö à-ö */
08493     0x00d8, 0x00de, 532, /* Ø-Þ ø-þ */
08494     0x0189, 0x018a, 705, /* Ɖ-Ɗ ɖ-ɗ */
08495     0x018e, 0x018f, 702, /* Ǝ-Ə ɘ-ə */
08496     0x01b1, 0x01b2, 717, /* Ʊ-Ʋ ʊ-ʋ */
08497     0x0388, 0x038a, 537, /* Έ-Ί έ-ί */
08498     0x038e, 0x038f, 563, /* Ύ-Ώ ύ-ώ */
08499     0x0391, 0x03a1, 532, /* Α-Ρ α-ρ */
08500     0x03a3, 0x03ab, 532, /* Σ-Ϋ σ-ϋ */
08501     0x0401, 0x040c, 580, /* Ё-Ќ ё-ќ */
08502     0x040e, 0x040f, 580, /* Ў-Џ ў-џ */
08503     0x0410, 0x042f, 532, /* А-Я а-я */
08504     0x0531, 0x0556, 548, /* Ա-Ֆ ա-ֆ */
08505     0x10a0, 0x10c5, 548, /* Ⴀ-Ⴥ ა-ჵ */
08506     0x1f08, 0x1f0f, 492, /* Ἀ-Ἇ ἀ-ἇ */
08507     0x1f18, 0x1f1d, 492, /* Ἐ-Ἕ ἐ-ἕ */
08508     0x1f28, 0x1f2f, 492, /* Ἠ-Ἧ ἠ-ἧ */
08509     0x1f38, 0x1f3f, 492, /* Ἰ-Ἷ ἰ-ἷ */
08510     0x1f48, 0x1f4d, 492, /* Ὀ-Ὅ ὀ-ὅ */
08511     0x1f68, 0x1f6f, 492, /* Ὠ-Ὧ ὠ-ὧ */
08512     0x1f88, 0x1f8f, 492, /* ᾈ-ᾏ ᾀ-ᾇ */
08513     0x1f98, 0x1f9f, 492, /* ᾘ-ᾟ ᾐ-ᾗ */
08514     0x1fa8, 0x1faf, 492, /* ᾨ-ᾯ ᾠ-ᾧ */
08515     0x1fb8, 0x1fb9, 492, /* Ᾰ-Ᾱ ᾰ-ᾱ */
08516     0x1fba, 0x1fbb, 426, /* Ὰ-Ά ὰ-ά */
08517     0x1fc8, 0x1fcb, 414, /* Ὲ-Ή ὲ-ή */
08518     0x1fd8, 0x1fd9, 492, /* Ῐ-Ῑ ῐ-ῑ */
08519     0x1fda, 0x1fdb, 400, /* Ὶ-Ί ὶ-ί */
08520     0x1fe8, 0x1fe9, 492, /* Ῠ-Ῡ ῠ-ῡ */
08521     0x1fea, 0x1feb, 388, /* Ὺ-Ύ ὺ-ύ */
08522     0x1ff8, 0x1ff9, 372, /* Ὸ-Ό ὸ-ό */
08523     0x1ffa, 0x1ffb, 374, /* Ὼ-Ώ ὼ-ώ */
08524     0x2160, 0x216f, 516, /* Ⅰ-Ⅿ ⅰ-ⅿ */
08525     0x24b6, 0x24cf, 526, /* Ⓐ-Ⓩ ⓐ-ⓩ */
08526     0xff21, 0xff3a, 532, /* A-Z a-z */
08527 };
08528 
08529 /*
08530  * upper case singlets
08531  *  2nd col is conversion excess 500
08532  */
08533 static Rune __tolower1[] = {
08534     0x0100, 501, /* Ā ā */
08535     0x0102, 501, /* Ă ă */
08536     0x0104, 501, /* Ą ą */
08537     0x0106, 501, /* Ć ć */
08538     0x0108, 501, /* Ĉ ĉ */
08539     0x010a, 501, /* Ċ ċ */
08540     0x010c, 501, /* Č č */
08541     0x010e, 501, /* Ď ď */
08542     0x0110, 501, /* Đ đ */
08543     0x0112, 501, /* Ē ē */
08544     0x0114, 501, /* Ĕ ĕ */
08545     0x0116, 501, /* Ė ė */
08546     0x0118, 501, /* Ę ę */
08547     0x011a, 501, /* Ě ě */
08548     0x011c, 501, /* Ĝ ĝ */
08549     0x011e, 501, /* Ğ ğ */
08550     0x0120, 501, /* Ġ ġ */
08551     0x0122, 501, /* Ģ ģ */
08552     0x0124, 501, /* Ĥ ĥ */
08553     0x0126, 501, /* Ħ ħ */
08554     0x0128, 501, /* Ĩ ĩ */
08555     0x012a, 501, /* Ī ī */
08556     0x012c, 501, /* Ĭ ĭ */
08557     0x012e, 501, /* Į į */
08558     0x0130, 301, /* İ i */
08559     0x0132, 501, /* IJ ij */
08560     0x0134, 501, /* Ĵ ĵ */
08561     0x0136, 501, /* Ķ ķ */
08562     0x0139, 501, /* Ĺ ĺ */
08563     0x013b, 501, /* Ļ ļ */
08564     0x013d, 501, /* Ľ ľ */
08565     0x013f, 501, /* Ŀ ŀ */
08566     0x0141, 501, /* Ł ł */
08567     0x0143, 501, /* Ń ń */
08568     0x0145, 501, /* Ņ ņ */
08569     0x0147, 501, /* Ň ň */
08570     0x014a, 501, /* Ŋ ŋ */
08571     0x014c, 501, /* Ō ō */
08572     0x014e, 501, /* Ŏ ŏ */
08573     0x0150, 501, /* Ő ő */
08574     0x0152, 501, /* Œ œ */
08575     0x0154, 501, /* Ŕ ŕ */
08576     0x0156, 501, /* Ŗ ŗ */
08577     0x0158, 501, /* Ř ř */
08578     0x015a, 501, /* Ś ś */
08579     0x015c, 501, /* Ŝ ŝ */
08580     0x015e, 501, /* Ş ş */
08581     0x0160, 501, /* Š š */
08582     0x0162, 501, /* Ţ ţ */
08583     0x0164, 501, /* Ť ť */
08584     0x0166, 501, /* Ŧ ŧ */
08585     0x0168, 501, /* Ũ ũ */
08586     0x016a, 501, /* Ū ū */
08587     0x016c, 501, /* Ŭ ŭ */
08588     0x016e, 501, /* Ů ů */
08589     0x0170, 501, /* Ű ű */
08590     0x0172, 501, /* Ų ų */
08591     0x0174, 501, /* Ŵ ŵ */
08592     0x0176, 501, /* Ŷ ŷ */
08593     0x0178, 379, /* Ÿ ÿ */
08594     0x0179, 501, /* Ź ź */
08595     0x017b, 501, /* Ż ż */
08596     0x017d, 501, /* Ž ž */
08597     0x0181, 710, /* Ɓ ɓ */
08598     0x0182, 501, /* Ƃ ƃ */
08599     0x0184, 501, /* Ƅ ƅ */
08600     0x0186, 706, /* Ɔ ɔ */
08601     0x0187, 501, /* Ƈ ƈ */
08602     0x018b, 501, /* Ƌ ƌ */
08603     0x0190, 703, /* Ɛ ɛ */
08604     0x0191, 501, /* Ƒ ƒ */
08605     0x0193, 705, /* Ɠ ɠ */
08606     0x0194, 707, /* Ɣ ɣ */
08607     0x0196, 711, /* Ɩ ɩ */
08608     0x0197, 709, /* Ɨ ɨ */
08609     0x0198, 501, /* Ƙ ƙ */
08610     0x019c, 711, /* Ɯ ɯ */
08611     0x019d, 713, /* Ɲ ɲ */
08612     0x01a0, 501, /* Ơ ơ */
08613     0x01a2, 501, /* Ƣ ƣ */
08614     0x01a4, 501, /* Ƥ ƥ */
08615     0x01a7, 501, /* Ƨ ƨ */
08616     0x01a9, 718, /* Ʃ ʃ */
08617     0x01ac, 501, /* Ƭ ƭ */
08618     0x01ae, 718, /* Ʈ ʈ */
08619     0x01af, 501, /* Ư ư */
08620     0x01b3, 501, /* Ƴ ƴ */
08621     0x01b5, 501, /* Ƶ ƶ */
08622     0x01b7, 719, /* Ʒ ʒ */
08623     0x01b8, 501, /* Ƹ ƹ */
08624     0x01bc, 501, /* Ƽ ƽ */
08625     0x01c4, 502, /* DŽ dž */
08626     0x01c5, 501, /* Dž dž */
08627     0x01c7, 502, /* LJ lj */
08628     0x01c8, 501, /* Lj lj */
08629     0x01ca, 502, /* NJ nj */
08630     0x01cb, 501, /* Nj nj */
08631     0x01cd, 501, /* Ǎ ǎ */
08632     0x01cf, 501, /* Ǐ ǐ */
08633     0x01d1, 501, /* Ǒ ǒ */
08634     0x01d3, 501, /* Ǔ ǔ */
08635     0x01d5, 501, /* Ǖ ǖ */
08636     0x01d7, 501, /* Ǘ ǘ */
08637     0x01d9, 501, /* Ǚ ǚ */
08638     0x01db, 501, /* Ǜ ǜ */
08639     0x01de, 501, /* Ǟ ǟ */
08640     0x01e0, 501, /* Ǡ ǡ */
08641     0x01e2, 501, /* Ǣ ǣ */
08642     0x01e4, 501, /* Ǥ ǥ */
08643     0x01e6, 501, /* Ǧ ǧ */
08644     0x01e8, 501, /* Ǩ ǩ */
08645     0x01ea, 501, /* Ǫ ǫ */
08646     0x01ec, 501, /* Ǭ ǭ */
08647     0x01ee, 501, /* Ǯ ǯ */
08648     0x01f1, 502, /* DZ dz */
08649     0x01f2, 501, /* Dz dz */
08650     0x01f4, 501, /* Ǵ ǵ */
08651     0x01fa, 501, /* Ǻ ǻ */
08652     0x01fc, 501, /* Ǽ ǽ */
08653     0x01fe, 501, /* Ǿ ǿ */
08654     0x0200, 501, /* Ȁ ȁ */
08655     0x0202, 501, /* Ȃ ȃ */
08656     0x0204, 501, /* Ȅ ȅ */
08657     0x0206, 501, /* Ȇ ȇ */
08658     0x0208, 501, /* Ȉ ȉ */
08659     0x020a, 501, /* Ȋ ȋ */
08660     0x020c, 501, /* Ȍ ȍ */
08661     0x020e, 501, /* Ȏ ȏ */
08662     0x0210, 501, /* Ȑ ȑ */
08663     0x0212, 501, /* Ȓ ȓ */
08664     0x0214, 501, /* Ȕ ȕ */
08665     0x0216, 501, /* Ȗ ȗ */
08666     0x0386, 538, /* Ά ά */
08667     0x038c, 564, /* Ό ό */
08668     0x03e2, 501, /* Ϣ ϣ */
08669     0x03e4, 501, /* Ϥ ϥ */
08670     0x03e6, 501, /* Ϧ ϧ */
08671     0x03e8, 501, /* Ϩ ϩ */
08672     0x03ea, 501, /* Ϫ ϫ */
08673     0x03ec, 501, /* Ϭ ϭ */
08674     0x03ee, 501, /* Ϯ ϯ */
08675     0x0460, 501, /* Ѡ ѡ */
08676     0x0462, 501, /* Ѣ ѣ */
08677     0x0464, 501, /* Ѥ ѥ */
08678     0x0466, 501, /* Ѧ ѧ */
08679     0x0468, 501, /* Ѩ ѩ */
08680     0x046a, 501, /* Ѫ ѫ */
08681     0x046c, 501, /* Ѭ ѭ */
08682     0x046e, 501, /* Ѯ ѯ */
08683     0x0470, 501, /* Ѱ ѱ */
08684     0x0472, 501, /* Ѳ ѳ */
08685     0x0474, 501, /* Ѵ ѵ */
08686     0x0476, 501, /* Ѷ ѷ */
08687     0x0478, 501, /* Ѹ ѹ */
08688     0x047a, 501, /* Ѻ ѻ */
08689     0x047c, 501, /* Ѽ ѽ */
08690     0x047e, 501, /* Ѿ ѿ */
08691     0x0480, 501, /* Ҁ ҁ */
08692     0x0490, 501, /* Ґ ґ */
08693     0x0492, 501, /* Ғ ғ */
08694     0x0494, 501, /* Ҕ ҕ */
08695     0x0496, 501, /* Җ җ */
08696     0x0498, 501, /* Ҙ ҙ */
08697     0x049a, 501, /* Қ қ */
08698     0x049c, 501, /* Ҝ ҝ */
08699     0x049e, 501, /* Ҟ ҟ */
08700     0x04a0, 501, /* Ҡ ҡ */
08701     0x04a2, 501, /* Ң ң */
08702     0x04a4, 501, /* Ҥ ҥ */
08703     0x04a6, 501, /* Ҧ ҧ */
08704     0x04a8, 501, /* Ҩ ҩ */
08705     0x04aa, 501, /* Ҫ ҫ */
08706     0x04ac, 501, /* Ҭ ҭ */
08707     0x04ae, 501, /* Ү ү */
08708     0x04b0, 501, /* Ұ ұ */
08709     0x04b2, 501, /* Ҳ ҳ */
08710     0x04b4, 501, /* Ҵ ҵ */
08711     0x04b6, 501, /* Ҷ ҷ */
08712     0x04b8, 501, /* Ҹ ҹ */
08713     0x04ba, 501, /* Һ һ */
08714     0x04bc, 501, /* Ҽ ҽ */
08715     0x04be, 501, /* Ҿ ҿ */
08716     0x04c1, 501, /* Ӂ ӂ */
08717     0x04c3, 501, /* Ӄ ӄ */
08718     0x04c7, 501, /* Ӈ ӈ */
08719     0x04cb, 501, /* Ӌ ӌ */
08720     0x04d0, 501, /* Ӑ ӑ */
08721     0x04d2, 501, /* Ӓ ӓ */
08722     0x04d4, 501, /* Ӕ ӕ */
08723     0x04d6, 501, /* Ӗ ӗ */
08724     0x04d8, 501, /* Ә ә */
08725     0x04da, 501, /* Ӛ ӛ */
08726     0x04dc, 501, /* Ӝ ӝ */
08727     0x04de, 501, /* Ӟ ӟ */
08728     0x04e0, 501, /* Ӡ ӡ */
08729     0x04e2, 501, /* Ӣ ӣ */
08730     0x04e4, 501, /* Ӥ ӥ */
08731     0x04e6, 501, /* Ӧ ӧ */
08732     0x04e8, 501, /* Ө ө */
08733     0x04ea, 501, /* Ӫ ӫ */
08734     0x04ee, 501, /* Ӯ ӯ */
08735     0x04f0, 501, /* Ӱ ӱ */
08736     0x04f2, 501, /* Ӳ ӳ */
08737     0x04f4, 501, /* Ӵ ӵ */
08738     0x04f8, 501, /* Ӹ ӹ */
08739     0x1e00, 501, /* Ḁ ḁ */
08740     0x1e02, 501, /* Ḃ ḃ */
08741     0x1e04, 501, /* Ḅ ḅ */
08742     0x1e06, 501, /* Ḇ ḇ */
08743     0x1e08, 501, /* Ḉ ḉ */
08744     0x1e0a, 501, /* Ḋ ḋ */
08745     0x1e0c, 501, /* Ḍ ḍ */
08746     0x1e0e, 501, /* Ḏ ḏ */
08747     0x1e10, 501, /* Ḑ ḑ */
08748     0x1e12, 501, /* Ḓ ḓ */
08749     0x1e14, 501, /* Ḕ ḕ */
08750     0x1e16, 501, /* Ḗ ḗ */
08751     0x1e18, 501, /* Ḙ ḙ */
08752     0x1e1a, 501, /* Ḛ ḛ */
08753     0x1e1c, 501, /* Ḝ ḝ */
08754     0x1e1e, 501, /* Ḟ ḟ */
08755     0x1e20, 501, /* Ḡ ḡ */
08756     0x1e22, 501, /* Ḣ ḣ */
08757     0x1e24, 501, /* Ḥ ḥ */
08758     0x1e26, 501, /* Ḧ ḧ */
08759     0x1e28, 501, /* Ḩ ḩ */
08760     0x1e2a, 501, /* Ḫ ḫ */
08761     0x1e2c, 501, /* Ḭ ḭ */
08762     0x1e2e, 501, /* Ḯ ḯ */
08763     0x1e30, 501, /* Ḱ ḱ */
08764     0x1e32, 501, /* Ḳ ḳ */
08765     0x1e34, 501, /* Ḵ ḵ */
08766     0x1e36, 501, /* Ḷ ḷ */
08767     0x1e38, 501, /* Ḹ ḹ */
08768     0x1e3a, 501, /* Ḻ ḻ */
08769     0x1e3c, 501, /* Ḽ ḽ */
08770     0x1e3e, 501, /* Ḿ ḿ */
08771     0x1e40, 501, /* Ṁ ṁ */
08772     0x1e42, 501, /* Ṃ ṃ */
08773     0x1e44, 501, /* Ṅ ṅ */
08774     0x1e46, 501, /* Ṇ ṇ */
08775     0x1e48, 501, /* Ṉ ṉ */
08776     0x1e4a, 501, /* Ṋ ṋ */
08777     0x1e4c, 501, /* Ṍ ṍ */
08778     0x1e4e, 501, /* Ṏ ṏ */
08779     0x1e50, 501, /* Ṑ ṑ */
08780     0x1e52, 501, /* Ṓ ṓ */
08781     0x1e54, 501, /* Ṕ ṕ */
08782     0x1e56, 501, /* Ṗ ṗ */
08783     0x1e58, 501, /* Ṙ ṙ */
08784     0x1e5a, 501, /* Ṛ ṛ */
08785     0x1e5c, 501, /* Ṝ ṝ */
08786     0x1e5e, 501, /* Ṟ ṟ */
08787     0x1e60, 501, /* Ṡ ṡ */
08788     0x1e62, 501, /* Ṣ ṣ */
08789     0x1e64, 501, /* Ṥ ṥ */
08790     0x1e66, 501, /* Ṧ ṧ */
08791     0x1e68, 501, /* Ṩ ṩ */
08792     0x1e6a, 501, /* Ṫ ṫ */
08793     0x1e6c, 501, /* Ṭ ṭ */
08794     0x1e6e, 501, /* Ṯ ṯ */
08795     0x1e70, 501, /* Ṱ ṱ */
08796     0x1e72, 501, /* Ṳ ṳ */
08797     0x1e74, 501, /* Ṵ ṵ */
08798     0x1e76, 501, /* Ṷ ṷ */
08799     0x1e78, 501, /* Ṹ ṹ */
08800     0x1e7a, 501, /* Ṻ ṻ */
08801     0x1e7c, 501, /* Ṽ ṽ */
08802     0x1e7e, 501, /* Ṿ ṿ */
08803     0x1e80, 501, /* Ẁ ẁ */
08804     0x1e82, 501, /* Ẃ ẃ */
08805     0x1e84, 501, /* Ẅ ẅ */
08806     0x1e86, 501, /* Ẇ ẇ */
08807     0x1e88, 501, /* Ẉ ẉ */
08808     0x1e8a, 501, /* Ẋ ẋ */
08809     0x1e8c, 501, /* Ẍ ẍ */
08810     0x1e8e, 501, /* Ẏ ẏ */
08811     0x1e90, 501, /* Ẑ ẑ */
08812     0x1e92, 501, /* Ẓ ẓ */
08813     0x1e94, 501, /* Ẕ ẕ */
08814     0x1ea0, 501, /* Ạ ạ */
08815     0x1ea2, 501, /* Ả ả */
08816     0x1ea4, 501, /* Ấ ấ */
08817     0x1ea6, 501, /* Ầ ầ */
08818     0x1ea8, 501, /* Ẩ ẩ */
08819     0x1eaa, 501, /* Ẫ ẫ */
08820     0x1eac, 501, /* Ậ ậ */
08821     0x1eae, 501, /* Ắ ắ */
08822     0x1eb0, 501, /* Ằ ằ */
08823     0x1eb2, 501, /* Ẳ ẳ */
08824     0x1eb4, 501, /* Ẵ ẵ */
08825     0x1eb6, 501, /* Ặ ặ */
08826     0x1eb8, 501, /* Ẹ ẹ */
08827     0x1eba, 501, /* Ẻ ẻ */
08828     0x1ebc, 501, /* Ẽ ẽ */
08829     0x1ebe, 501, /* Ế ế */
08830     0x1ec0, 501, /* Ề ề */
08831     0x1ec2, 501, /* Ể ể */
08832     0x1ec4, 501, /* Ễ ễ */
08833     0x1ec6, 501, /* Ệ ệ */
08834     0x1ec8, 501, /* Ỉ ỉ */
08835     0x1eca, 501, /* Ị ị */
08836     0x1ecc, 501, /* Ọ ọ */
08837     0x1ece, 501, /* Ỏ ỏ */
08838     0x1ed0, 501, /* Ố ố */
08839     0x1ed2, 501, /* Ồ ồ */
08840     0x1ed4, 501, /* Ổ ổ */
08841     0x1ed6, 501, /* Ỗ ỗ */
08842     0x1ed8, 501, /* Ộ ộ */
08843     0x1eda, 501, /* Ớ ớ */
08844     0x1edc, 501, /* Ờ ờ */
08845     0x1ede, 501, /* Ở ở */
08846     0x1ee0, 501, /* Ỡ ỡ */
08847     0x1ee2, 501, /* Ợ ợ */
08848     0x1ee4, 501, /* Ụ ụ */
08849     0x1ee6, 501, /* Ủ ủ */
08850     0x1ee8, 501, /* Ứ ứ */
08851     0x1eea, 501, /* Ừ ừ */
08852     0x1eec, 501, /* Ử ử */
08853     0x1eee, 501, /* Ữ ữ */
08854     0x1ef0, 501, /* Ự ự */
08855     0x1ef2, 501, /* Ỳ ỳ */
08856     0x1ef4, 501, /* Ỵ ỵ */
08857     0x1ef6, 501, /* Ỷ ỷ */
08858     0x1ef8, 501, /* Ỹ ỹ */
08859     0x1f59, 492, /* Ὑ ὑ */
08860     0x1f5b, 492, /* Ὓ ὓ */
08861     0x1f5d, 492, /* Ὕ ὕ */
08862     0x1f5f, 492, /* Ὗ ὗ */
08863     0x1fbc, 491, /* ᾼ ᾳ */
08864     0x1fcc, 491, /* ῌ ῃ */
08865     0x1fec, 493, /* Ῥ ῥ */
08866     0x1ffc, 491, /* ῼ ῳ */
08867 };
08868 
08869 static Rune *rune_bsearch(Rune c, Rune *t, int n, int ne) {
08870   Rune *p;
08871   int m;
08872 
08873   while (n > 1) {
08874     m = n / 2;
08875     p = t + m * ne;
08876     if (c >= p[0]) {
08877       t = p;
08878       n = n - m;
08879     } else
08880       n = m;
08881   }
08882   if (n && c >= t[0]) return t;
08883   return 0;
08884 }
08885 
08886 Rune tolowerrune(Rune c) {
08887   Rune *p;
08888 
08889   p = rune_bsearch(c, __tolower2, nelem(__tolower2) / 3, 3);
08890   if (p && c >= p[0] && c <= p[1]) return c + p[2] - 500;
08891   p = rune_bsearch(c, __tolower1, nelem(__tolower1) / 2, 2);
08892   if (p && c == p[0]) return c + p[1] - 500;
08893   return c;
08894 }
08895 
08896 Rune toupperrune(Rune c) {
08897   Rune *p;
08898 
08899   p = rune_bsearch(c, __toupper2, nelem(__toupper2) / 3, 3);
08900   if (p && c >= p[0] && c <= p[1]) return c + p[2] - 500;
08901   p = rune_bsearch(c, __toupper1, nelem(__toupper1) / 2, 2);
08902   if (p && c == p[0]) return c + p[1] - 500;
08903   return c;
08904 }
08905 
08906 int islowerrune(Rune c) {
08907   Rune *p;
08908 
08909   p = rune_bsearch(c, __toupper2, nelem(__toupper2) / 3, 3);
08910   if (p && c >= p[0] && c <= p[1]) return 1;
08911   p = rune_bsearch(c, __toupper1, nelem(__toupper1) / 2, 2);
08912   if (p && c == p[0]) return 1;
08913   return 0;
08914 }
08915 
08916 int isupperrune(Rune c) {
08917   Rune *p;
08918 
08919   p = rune_bsearch(c, __tolower2, nelem(__tolower2) / 3, 3);
08920   if (p && c >= p[0] && c <= p[1]) return 1;
08921   p = rune_bsearch(c, __tolower1, nelem(__tolower1) / 2, 2);
08922   if (p && c == p[0]) return 1;
08923   return 0;
08924 }
08925 
08926 int isdigitrune(Rune c) {
08927   return c >= '0' && c <= '9';
08928 }
08929 
08930 int isnewline(Rune c) {
08931   return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;
08932 }
08933 
08934 int iswordchar(Rune c) {
08935   return c == '_' || isdigitrune(c) || (c >= 'a' && c <= 'z') ||
08936          (c >= 'A' && c <= 'Z');
08937 }
08938 
08939 int isalpharune(Rune c) {
08940   Rune *p;
08941 
08942   if (isupperrune(c) || islowerrune(c)) return 1;
08943   p = rune_bsearch(c, __alpha2, nelem(__alpha2) / 2, 2);
08944   if (p && c >= p[0] && c <= p[1]) return 1;
08945   p = rune_bsearch(c, __alpha1, nelem(__alpha1), 1);
08946   if (p && c == p[0]) return 1;
08947   return 0;
08948 }
08949 
08950 int isspacerune(Rune c) {
08951   Rune *p;
08952 
08953   p = rune_bsearch(c, __space2, nelem(__space2) / 2, 2);
08954   if (p && c >= p[0] && c <= p[1]) return 1;
08955   return 0;
08956 }
08957 
08958 #else /* CS_ENABLE_UTF8 */
08959 
08960 int chartorune(Rune *rune, const char *str) {
08961   *rune = *(uchar *) str;
08962   return 1;
08963 }
08964 
08965 int fullrune(const char *str, int n) {
08966   (void) str;
08967   return (n <= 0) ? 0 : 1;
08968 }
08969 
08970 int isdigitrune(Rune c) {
08971   return isdigit(c);
08972 }
08973 
08974 int isnewline(Rune c) {
08975   return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;
08976 }
08977 
08978 int iswordchar(Rune c) {
08979   return c == '_' || isdigitrune(c) || (c >= 'a' && c <= 'z') ||
08980          (c >= 'A' && c <= 'Z');
08981 }
08982 
08983 int isalpharune(Rune c) {
08984   return isalpha(c);
08985 }
08986 int islowerrune(Rune c) {
08987   return islower(c);
08988 }
08989 int isspacerune(Rune c) {
08990   return isspace(c);
08991 }
08992 int isupperrune(Rune c) {
08993   return isupper(c);
08994 }
08995 
08996 int runetochar(char *str, Rune *rune) {
08997   str[0] = (char) *rune;
08998   return 1;
08999 }
09000 
09001 Rune tolowerrune(Rune c) {
09002   return tolower(c);
09003 }
09004 Rune toupperrune(Rune c) {
09005   return toupper(c);
09006 }
09007 int utfnlen(const char *s, long m) {
09008   (void) s;
09009   return (int) c_strnlen(s, (size_t) m);
09010 }
09011 
09012 const char *utfnshift(const char *s, long m) {
09013   return s + m;
09014 }
09015 
09016 #endif /* CS_ENABLE_UTF8 */
09017 
09018 #endif /* EXCLUDE_COMMON */
09019 #ifdef V7_MODULE_LINES
09020 #line 1 "common/base64.c"
09021 #endif
09022 /*
09023  * Copyright (c) 2014 Cesanta Software Limited
09024  * All rights reserved
09025  */
09026 
09027 #ifndef EXCLUDE_COMMON
09028 
09029 /* Amalgamated: #include "common/base64.h" */
09030 #include <string.h>
09031 
09032 /* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ */
09033 
09034 #define NUM_UPPERCASES ('Z' - 'A' + 1)
09035 #define NUM_LETTERS (NUM_UPPERCASES * 2)
09036 #define NUM_DIGITS ('9' - '0' + 1)
09037 
09038 /*
09039  * Emit a base64 code char.
09040  *
09041  * Doesn't use memory, thus it's safe to use to safely dump memory in crashdumps
09042  */
09043 static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v) {
09044   if (v < NUM_UPPERCASES) {
09045     ctx->b64_putc(v + 'A', ctx->user_data);
09046   } else if (v < (NUM_LETTERS)) {
09047     ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data);
09048   } else if (v < (NUM_LETTERS + NUM_DIGITS)) {
09049     ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data);
09050   } else {
09051     ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/',
09052                   ctx->user_data);
09053   }
09054 }
09055 
09056 static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) {
09057   int a, b, c;
09058 
09059   a = ctx->chunk[0];
09060   b = ctx->chunk[1];
09061   c = ctx->chunk[2];
09062 
09063   cs_base64_emit_code(ctx, a >> 2);
09064   cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4));
09065   if (ctx->chunk_size > 1) {
09066     cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6));
09067   }
09068   if (ctx->chunk_size > 2) {
09069     cs_base64_emit_code(ctx, c & 63);
09070   }
09071 }
09072 
09073 void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc,
09074                     void *user_data) {
09075   ctx->chunk_size = 0;
09076   ctx->b64_putc = b64_putc;
09077   ctx->user_data = user_data;
09078 }
09079 
09080 void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len) {
09081   const unsigned char *src = (const unsigned char *) str;
09082   size_t i;
09083   for (i = 0; i < len; i++) {
09084     ctx->chunk[ctx->chunk_size++] = src[i];
09085     if (ctx->chunk_size == 3) {
09086       cs_base64_emit_chunk(ctx);
09087       ctx->chunk_size = 0;
09088     }
09089   }
09090 }
09091 
09092 void cs_base64_finish(struct cs_base64_ctx *ctx) {
09093   if (ctx->chunk_size > 0) {
09094     int i;
09095     memset(&ctx->chunk[ctx->chunk_size], 0, 3 - ctx->chunk_size);
09096     cs_base64_emit_chunk(ctx);
09097     for (i = 0; i < (3 - ctx->chunk_size); i++) {
09098       ctx->b64_putc('=', ctx->user_data);
09099     }
09100   }
09101 }
09102 
09103 #define BASE64_ENCODE_BODY                                                \
09104   static const char *b64 =                                                \
09105       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
09106   int i, j, a, b, c;                                                      \
09107                                                                           \
09108   for (i = j = 0; i < src_len; i += 3) {                                  \
09109     a = src[i];                                                           \
09110     b = i + 1 >= src_len ? 0 : src[i + 1];                                \
09111     c = i + 2 >= src_len ? 0 : src[i + 2];                                \
09112                                                                           \
09113     BASE64_OUT(b64[a >> 2]);                                              \
09114     BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]);                           \
09115     if (i + 1 < src_len) {                                                \
09116       BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]);                          \
09117     }                                                                     \
09118     if (i + 2 < src_len) {                                                \
09119       BASE64_OUT(b64[c & 63]);                                            \
09120     }                                                                     \
09121   }                                                                       \
09122                                                                           \
09123   while (j % 4 != 0) {                                                    \
09124     BASE64_OUT('=');                                                      \
09125   }                                                                       \
09126   BASE64_FLUSH()
09127 
09128 #define BASE64_OUT(ch) \
09129   do {                 \
09130     dst[j++] = (ch);   \
09131   } while (0)
09132 
09133 #define BASE64_FLUSH() \
09134   do {                 \
09135     dst[j++] = '\0';   \
09136   } while (0)
09137 
09138 void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
09139   BASE64_ENCODE_BODY;
09140 }
09141 
09142 #undef BASE64_OUT
09143 #undef BASE64_FLUSH
09144 
09145 #ifndef CS_DISABLE_STDIO
09146 #define BASE64_OUT(ch)      \
09147   do {                      \
09148     fprintf(f, "%c", (ch)); \
09149     j++;                    \
09150   } while (0)
09151 
09152 #define BASE64_FLUSH()
09153 
09154 void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len) {
09155   BASE64_ENCODE_BODY;
09156 }
09157 
09158 #undef BASE64_OUT
09159 #undef BASE64_FLUSH
09160 #endif /* !CS_DISABLE_STDIO */
09161 
09162 /* Convert one byte of encoded base64 input stream to 6-bit chunk */
09163 static unsigned char from_b64(unsigned char ch) {
09164   /* Inverse lookup map */
09165   static const unsigned char tab[128] = {
09166       255, 255, 255, 255,
09167       255, 255, 255, 255, /*  0 */
09168       255, 255, 255, 255,
09169       255, 255, 255, 255, /*  8 */
09170       255, 255, 255, 255,
09171       255, 255, 255, 255, /*  16 */
09172       255, 255, 255, 255,
09173       255, 255, 255, 255, /*  24 */
09174       255, 255, 255, 255,
09175       255, 255, 255, 255, /*  32 */
09176       255, 255, 255, 62,
09177       255, 255, 255, 63, /*  40 */
09178       52,  53,  54,  55,
09179       56,  57,  58,  59, /*  48 */
09180       60,  61,  255, 255,
09181       255, 200, 255, 255, /*  56   '=' is 200, on index 61 */
09182       255, 0,   1,   2,
09183       3,   4,   5,   6, /*  64 */
09184       7,   8,   9,   10,
09185       11,  12,  13,  14, /*  72 */
09186       15,  16,  17,  18,
09187       19,  20,  21,  22, /*  80 */
09188       23,  24,  25,  255,
09189       255, 255, 255, 255, /*  88 */
09190       255, 26,  27,  28,
09191       29,  30,  31,  32, /*  96 */
09192       33,  34,  35,  36,
09193       37,  38,  39,  40, /*  104 */
09194       41,  42,  43,  44,
09195       45,  46,  47,  48, /*  112 */
09196       49,  50,  51,  255,
09197       255, 255, 255, 255, /*  120 */
09198   };
09199   return tab[ch & 127];
09200 }
09201 
09202 int cs_base64_decode(const unsigned char *s, int len, char *dst) {
09203   unsigned char a, b, c, d;
09204   int orig_len = len;
09205   while (len >= 4 && (a = from_b64(s[0])) != 255 &&
09206          (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
09207          (d = from_b64(s[3])) != 255) {
09208     s += 4;
09209     len -= 4;
09210     if (a == 200 || b == 200) break; /* '=' can't be there */
09211     *dst++ = a << 2 | b >> 4;
09212     if (c == 200) break;
09213     *dst++ = b << 4 | c >> 2;
09214     if (d == 200) break;
09215     *dst++ = c << 6 | d;
09216   }
09217   *dst = 0;
09218   return orig_len - len;
09219 }
09220 
09221 #endif /* EXCLUDE_COMMON */
09222 #ifdef V7_MODULE_LINES
09223 #line 1 "common/md5.c"
09224 #endif
09225 /*
09226  * This code implements the MD5 message-digest algorithm.
09227  * The algorithm is due to Ron Rivest.  This code was
09228  * written by Colin Plumb in 1993, no copyright is claimed.
09229  * This code is in the public domain; do with it what you wish.
09230  *
09231  * Equivalent code is available from RSA Data Security, Inc.
09232  * This code has been tested against that, and is equivalent,
09233  * except that you don't need to include two pages of legalese
09234  * with every copy.
09235  *
09236  * To compute the message digest of a chunk of bytes, declare an
09237  * MD5Context structure, pass it to MD5Init, call MD5Update as
09238  * needed on buffers full of bytes, and then call MD5Final, which
09239  * will fill a supplied 16-byte array with the digest.
09240  */
09241 
09242 #if !defined(DISABLE_MD5) && !defined(EXCLUDE_COMMON)
09243 
09244 /* Amalgamated: #include "common/md5.h" */
09245 
09246 #ifndef CS_ENABLE_NATIVE_MD5
09247 static void byteReverse(unsigned char *buf, unsigned longs) {
09248 /* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */
09249 #if BYTE_ORDER == BIG_ENDIAN
09250   do {
09251     uint32_t t = (uint32_t)((unsigned) buf[3] << 8 | buf[2]) << 16 |
09252                  ((unsigned) buf[1] << 8 | buf[0]);
09253     *(uint32_t *) buf = t;
09254     buf += 4;
09255   } while (--longs);
09256 #else
09257   (void) buf;
09258   (void) longs;
09259 #endif
09260 }
09261 
09262 #define F1(x, y, z) (z ^ (x & (y ^ z)))
09263 #define F2(x, y, z) F1(z, x, y)
09264 #define F3(x, y, z) (x ^ y ^ z)
09265 #define F4(x, y, z) (y ^ (x | ~z))
09266 
09267 #define MD5STEP(f, w, x, y, z, data, s) \
09268   (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
09269 
09270 /*
09271  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
09272  * initialization constants.
09273  */
09274 void MD5_Init(MD5_CTX *ctx) {
09275   ctx->buf[0] = 0x67452301;
09276   ctx->buf[1] = 0xefcdab89;
09277   ctx->buf[2] = 0x98badcfe;
09278   ctx->buf[3] = 0x10325476;
09279 
09280   ctx->bits[0] = 0;
09281   ctx->bits[1] = 0;
09282 }
09283 
09284 static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
09285   register uint32_t a, b, c, d;
09286 
09287   a = buf[0];
09288   b = buf[1];
09289   c = buf[2];
09290   d = buf[3];
09291 
09292   MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
09293   MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
09294   MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
09295   MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
09296   MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
09297   MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
09298   MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
09299   MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
09300   MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
09301   MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
09302   MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
09303   MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
09304   MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
09305   MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
09306   MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
09307   MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
09308 
09309   MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
09310   MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
09311   MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
09312   MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
09313   MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
09314   MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
09315   MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
09316   MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
09317   MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
09318   MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
09319   MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
09320   MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
09321   MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
09322   MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
09323   MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
09324   MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
09325 
09326   MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
09327   MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
09328   MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
09329   MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
09330   MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
09331   MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
09332   MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
09333   MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
09334   MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
09335   MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
09336   MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
09337   MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
09338   MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
09339   MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
09340   MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
09341   MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
09342 
09343   MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
09344   MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
09345   MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
09346   MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
09347   MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
09348   MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
09349   MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
09350   MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
09351   MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
09352   MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
09353   MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
09354   MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
09355   MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
09356   MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
09357   MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
09358   MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
09359 
09360   buf[0] += a;
09361   buf[1] += b;
09362   buf[2] += c;
09363   buf[3] += d;
09364 }
09365 
09366 void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, size_t len) {
09367   uint32_t t;
09368 
09369   t = ctx->bits[0];
09370   if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
09371   ctx->bits[1] += (uint32_t) len >> 29;
09372 
09373   t = (t >> 3) & 0x3f;
09374 
09375   if (t) {
09376     unsigned char *p = (unsigned char *) ctx->in + t;
09377 
09378     t = 64 - t;
09379     if (len < t) {
09380       memcpy(p, buf, len);
09381       return;
09382     }
09383     memcpy(p, buf, t);
09384     byteReverse(ctx->in, 16);
09385     MD5Transform(ctx->buf, (uint32_t *) ctx->in);
09386     buf += t;
09387     len -= t;
09388   }
09389 
09390   while (len >= 64) {
09391     memcpy(ctx->in, buf, 64);
09392     byteReverse(ctx->in, 16);
09393     MD5Transform(ctx->buf, (uint32_t *) ctx->in);
09394     buf += 64;
09395     len -= 64;
09396   }
09397 
09398   memcpy(ctx->in, buf, len);
09399 }
09400 
09401 void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) {
09402   unsigned count;
09403   unsigned char *p;
09404   uint32_t *a;
09405 
09406   count = (ctx->bits[0] >> 3) & 0x3F;
09407 
09408   p = ctx->in + count;
09409   *p++ = 0x80;
09410   count = 64 - 1 - count;
09411   if (count < 8) {
09412     memset(p, 0, count);
09413     byteReverse(ctx->in, 16);
09414     MD5Transform(ctx->buf, (uint32_t *) ctx->in);
09415     memset(ctx->in, 0, 56);
09416   } else {
09417     memset(p, 0, count - 8);
09418   }
09419   byteReverse(ctx->in, 14);
09420 
09421   a = (uint32_t *) ctx->in;
09422   a[14] = ctx->bits[0];
09423   a[15] = ctx->bits[1];
09424 
09425   MD5Transform(ctx->buf, (uint32_t *) ctx->in);
09426   byteReverse((unsigned char *) ctx->buf, 4);
09427   memcpy(digest, ctx->buf, 16);
09428   memset((char *) ctx, 0, sizeof(*ctx));
09429 }
09430 #endif /* CS_ENABLE_NATIVE_MD5 */
09431 
09432 /*
09433  * Stringify binary data. Output buffer size must be 2 * size_of_input + 1
09434  * because each byte of input takes 2 bytes in string representation
09435  * plus 1 byte for the terminating \0 character.
09436  */
09437 void cs_to_hex(char *to, const unsigned char *p, size_t len) {
09438   static const char *hex = "0123456789abcdef";
09439 
09440   for (; len--; p++) {
09441     *to++ = hex[p[0] >> 4];
09442     *to++ = hex[p[0] & 0x0f];
09443   }
09444   *to = '\0';
09445 }
09446 
09447 char *cs_md5(char buf[33], ...) {
09448   unsigned char hash[16];
09449   const unsigned char *p;
09450   va_list ap;
09451   MD5_CTX ctx;
09452 
09453   MD5_Init(&ctx);
09454 
09455   va_start(ap, buf);
09456   while ((p = va_arg(ap, const unsigned char *) ) != NULL) {
09457     size_t len = va_arg(ap, size_t);
09458     MD5_Update(&ctx, p, len);
09459   }
09460   va_end(ap);
09461 
09462   MD5_Final(hash, &ctx);
09463   cs_to_hex(buf, hash, sizeof(hash));
09464 
09465   return buf;
09466 }
09467 
09468 #endif /* EXCLUDE_COMMON */
09469 #ifdef V7_MODULE_LINES
09470 #line 1 "common/sha1.c"
09471 #endif
09472 /* Copyright(c) By Steve Reid <steve@edmweb.com> */
09473 /* 100% Public Domain */
09474 
09475 #if !defined(DISABLE_SHA1) && !defined(EXCLUDE_COMMON)
09476 
09477 /* Amalgamated: #include "common/sha1.h" */
09478 
09479 #define SHA1HANDSOFF
09480 #if defined(__sun)
09481 /* Amalgamated: #include "common/solarisfixes.h" */
09482 #endif
09483 
09484 union char64long16 {
09485   unsigned char c[64];
09486   uint32_t l[16];
09487 };
09488 
09489 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
09490 
09491 static uint32_t blk0(union char64long16 *block, int i) {
09492 /* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
09493 #if BYTE_ORDER == LITTLE_ENDIAN
09494   block->l[i] =
09495       (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF);
09496 #endif
09497   return block->l[i];
09498 }
09499 
09500 /* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
09501 #undef blk
09502 #undef R0
09503 #undef R1
09504 #undef R2
09505 #undef R3
09506 #undef R4
09507 
09508 #define blk(i)                                                               \
09509   (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
09510                               block->l[(i + 2) & 15] ^ block->l[i & 15],     \
09511                           1))
09512 #define R0(v, w, x, y, z, i)                                          \
09513   z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
09514   w = rol(w, 30);
09515 #define R1(v, w, x, y, z, i)                                  \
09516   z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
09517   w = rol(w, 30);
09518 #define R2(v, w, x, y, z, i)                          \
09519   z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
09520   w = rol(w, 30);
09521 #define R3(v, w, x, y, z, i)                                        \
09522   z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
09523   w = rol(w, 30);
09524 #define R4(v, w, x, y, z, i)                          \
09525   z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
09526   w = rol(w, 30);
09527 
09528 void cs_sha1_transform(uint32_t state[5], const unsigned char buffer[64]) {
09529   uint32_t a, b, c, d, e;
09530   union char64long16 block[1];
09531 
09532   memcpy(block, buffer, 64);
09533   a = state[0];
09534   b = state[1];
09535   c = state[2];
09536   d = state[3];
09537   e = state[4];
09538   R0(a, b, c, d, e, 0);
09539   R0(e, a, b, c, d, 1);
09540   R0(d, e, a, b, c, 2);
09541   R0(c, d, e, a, b, 3);
09542   R0(b, c, d, e, a, 4);
09543   R0(a, b, c, d, e, 5);
09544   R0(e, a, b, c, d, 6);
09545   R0(d, e, a, b, c, 7);
09546   R0(c, d, e, a, b, 8);
09547   R0(b, c, d, e, a, 9);
09548   R0(a, b, c, d, e, 10);
09549   R0(e, a, b, c, d, 11);
09550   R0(d, e, a, b, c, 12);
09551   R0(c, d, e, a, b, 13);
09552   R0(b, c, d, e, a, 14);
09553   R0(a, b, c, d, e, 15);
09554   R1(e, a, b, c, d, 16);
09555   R1(d, e, a, b, c, 17);
09556   R1(c, d, e, a, b, 18);
09557   R1(b, c, d, e, a, 19);
09558   R2(a, b, c, d, e, 20);
09559   R2(e, a, b, c, d, 21);
09560   R2(d, e, a, b, c, 22);
09561   R2(c, d, e, a, b, 23);
09562   R2(b, c, d, e, a, 24);
09563   R2(a, b, c, d, e, 25);
09564   R2(e, a, b, c, d, 26);
09565   R2(d, e, a, b, c, 27);
09566   R2(c, d, e, a, b, 28);
09567   R2(b, c, d, e, a, 29);
09568   R2(a, b, c, d, e, 30);
09569   R2(e, a, b, c, d, 31);
09570   R2(d, e, a, b, c, 32);
09571   R2(c, d, e, a, b, 33);
09572   R2(b, c, d, e, a, 34);
09573   R2(a, b, c, d, e, 35);
09574   R2(e, a, b, c, d, 36);
09575   R2(d, e, a, b, c, 37);
09576   R2(c, d, e, a, b, 38);
09577   R2(b, c, d, e, a, 39);
09578   R3(a, b, c, d, e, 40);
09579   R3(e, a, b, c, d, 41);
09580   R3(d, e, a, b, c, 42);
09581   R3(c, d, e, a, b, 43);
09582   R3(b, c, d, e, a, 44);
09583   R3(a, b, c, d, e, 45);
09584   R3(e, a, b, c, d, 46);
09585   R3(d, e, a, b, c, 47);
09586   R3(c, d, e, a, b, 48);
09587   R3(b, c, d, e, a, 49);
09588   R3(a, b, c, d, e, 50);
09589   R3(e, a, b, c, d, 51);
09590   R3(d, e, a, b, c, 52);
09591   R3(c, d, e, a, b, 53);
09592   R3(b, c, d, e, a, 54);
09593   R3(a, b, c, d, e, 55);
09594   R3(e, a, b, c, d, 56);
09595   R3(d, e, a, b, c, 57);
09596   R3(c, d, e, a, b, 58);
09597   R3(b, c, d, e, a, 59);
09598   R4(a, b, c, d, e, 60);
09599   R4(e, a, b, c, d, 61);
09600   R4(d, e, a, b, c, 62);
09601   R4(c, d, e, a, b, 63);
09602   R4(b, c, d, e, a, 64);
09603   R4(a, b, c, d, e, 65);
09604   R4(e, a, b, c, d, 66);
09605   R4(d, e, a, b, c, 67);
09606   R4(c, d, e, a, b, 68);
09607   R4(b, c, d, e, a, 69);
09608   R4(a, b, c, d, e, 70);
09609   R4(e, a, b, c, d, 71);
09610   R4(d, e, a, b, c, 72);
09611   R4(c, d, e, a, b, 73);
09612   R4(b, c, d, e, a, 74);
09613   R4(a, b, c, d, e, 75);
09614   R4(e, a, b, c, d, 76);
09615   R4(d, e, a, b, c, 77);
09616   R4(c, d, e, a, b, 78);
09617   R4(b, c, d, e, a, 79);
09618   state[0] += a;
09619   state[1] += b;
09620   state[2] += c;
09621   state[3] += d;
09622   state[4] += e;
09623   /* Erase working structures. The order of operations is important,
09624    * used to ensure that compiler doesn't optimize those out. */
09625   memset(block, 0, sizeof(block));
09626   a = b = c = d = e = 0;
09627   (void) a;
09628   (void) b;
09629   (void) c;
09630   (void) d;
09631   (void) e;
09632 }
09633 
09634 void cs_sha1_init(cs_sha1_ctx *context) {
09635   context->state[0] = 0x67452301;
09636   context->state[1] = 0xEFCDAB89;
09637   context->state[2] = 0x98BADCFE;
09638   context->state[3] = 0x10325476;
09639   context->state[4] = 0xC3D2E1F0;
09640   context->count[0] = context->count[1] = 0;
09641 }
09642 
09643 void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data,
09644                     uint32_t len) {
09645   uint32_t i, j;
09646 
09647   j = context->count[0];
09648   if ((context->count[0] += len << 3) < j) context->count[1]++;
09649   context->count[1] += (len >> 29);
09650   j = (j >> 3) & 63;
09651   if ((j + len) > 63) {
09652     memcpy(&context->buffer[j], data, (i = 64 - j));
09653     cs_sha1_transform(context->state, context->buffer);
09654     for (; i + 63 < len; i += 64) {
09655       cs_sha1_transform(context->state, &data[i]);
09656     }
09657     j = 0;
09658   } else
09659     i = 0;
09660   memcpy(&context->buffer[j], &data[i], len - i);
09661 }
09662 
09663 void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context) {
09664   unsigned i;
09665   unsigned char finalcount[8], c;
09666 
09667   for (i = 0; i < 8; i++) {
09668     finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >>
09669                                       ((3 - (i & 3)) * 8)) &
09670                                      255);
09671   }
09672   c = 0200;
09673   cs_sha1_update(context, &c, 1);
09674   while ((context->count[0] & 504) != 448) {
09675     c = 0000;
09676     cs_sha1_update(context, &c, 1);
09677   }
09678   cs_sha1_update(context, finalcount, 8);
09679   for (i = 0; i < 20; i++) {
09680     digest[i] =
09681         (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
09682   }
09683   memset(context, '\0', sizeof(*context));
09684   memset(&finalcount, '\0', sizeof(finalcount));
09685 }
09686 
09687 void cs_hmac_sha1(const unsigned char *key, size_t keylen,
09688                   const unsigned char *data, size_t datalen,
09689                   unsigned char out[20]) {
09690   cs_sha1_ctx ctx;
09691   unsigned char buf1[64], buf2[64], tmp_key[20], i;
09692 
09693   if (keylen > sizeof(buf1)) {
09694     cs_sha1_init(&ctx);
09695     cs_sha1_update(&ctx, key, keylen);
09696     cs_sha1_final(tmp_key, &ctx);
09697     key = tmp_key;
09698     keylen = sizeof(tmp_key);
09699   }
09700 
09701   memset(buf1, 0, sizeof(buf1));
09702   memset(buf2, 0, sizeof(buf2));
09703   memcpy(buf1, key, keylen);
09704   memcpy(buf2, key, keylen);
09705 
09706   for (i = 0; i < sizeof(buf1); i++) {
09707     buf1[i] ^= 0x36;
09708     buf2[i] ^= 0x5c;
09709   }
09710 
09711   cs_sha1_init(&ctx);
09712   cs_sha1_update(&ctx, buf1, sizeof(buf1));
09713   cs_sha1_update(&ctx, data, datalen);
09714   cs_sha1_final(out, &ctx);
09715 
09716   cs_sha1_init(&ctx);
09717   cs_sha1_update(&ctx, buf2, sizeof(buf2));
09718   cs_sha1_update(&ctx, out, 20);
09719   cs_sha1_final(out, &ctx);
09720 }
09721 
09722 #endif /* EXCLUDE_COMMON */
09723 #ifdef V7_MODULE_LINES
09724 #line 1 "common/cs_dirent.c"
09725 #endif
09726 /*
09727  * Copyright (c) 2015 Cesanta Software Limited
09728  * All rights reserved
09729  */
09730 
09731 #ifndef EXCLUDE_COMMON
09732 
09733 /* Amalgamated: #include "common/cs_dirent.h" */
09734 
09735 /*
09736  * This file contains POSIX opendir/closedir/readdir API implementation
09737  * for systems which do not natively support it (e.g. Windows).
09738  */
09739 
09740 #ifndef MG_FREE
09741 #define MG_FREE free
09742 #endif
09743 
09744 #ifndef MG_MALLOC
09745 #define MG_MALLOC malloc
09746 #endif
09747 
09748 #ifdef _WIN32
09749 DIR *opendir(const char *name) {
09750   DIR *dir = NULL;
09751   wchar_t wpath[MAX_PATH];
09752   DWORD attrs;
09753 
09754   if (name == NULL) {
09755     SetLastError(ERROR_BAD_ARGUMENTS);
09756   } else if ((dir = (DIR *) MG_MALLOC(sizeof(*dir))) == NULL) {
09757     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
09758   } else {
09759     to_wchar(name, wpath, ARRAY_SIZE(wpath));
09760     attrs = GetFileAttributesW(wpath);
09761     if (attrs != 0xFFFFFFFF && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
09762       (void) wcscat(wpath, L"\\*");
09763       dir->handle = FindFirstFileW(wpath, &dir->info);
09764       dir->result.d_name[0] = '\0';
09765     } else {
09766       MG_FREE(dir);
09767       dir = NULL;
09768     }
09769   }
09770 
09771   return dir;
09772 }
09773 
09774 int closedir(DIR *dir) {
09775   int result = 0;
09776 
09777   if (dir != NULL) {
09778     if (dir->handle != INVALID_HANDLE_VALUE)
09779       result = FindClose(dir->handle) ? 0 : -1;
09780     MG_FREE(dir);
09781   } else {
09782     result = -1;
09783     SetLastError(ERROR_BAD_ARGUMENTS);
09784   }
09785 
09786   return result;
09787 }
09788 
09789 struct dirent *readdir(DIR *dir) {
09790   struct dirent *result = NULL;
09791 
09792   if (dir) {
09793     if (dir->handle != INVALID_HANDLE_VALUE) {
09794       result = &dir->result;
09795       (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1,
09796                                  result->d_name, sizeof(result->d_name), NULL,
09797                                  NULL);
09798 
09799       if (!FindNextFileW(dir->handle, &dir->info)) {
09800         (void) FindClose(dir->handle);
09801         dir->handle = INVALID_HANDLE_VALUE;
09802       }
09803 
09804     } else {
09805       SetLastError(ERROR_FILE_NOT_FOUND);
09806     }
09807   } else {
09808     SetLastError(ERROR_BAD_ARGUMENTS);
09809   }
09810 
09811   return result;
09812 }
09813 #endif
09814 
09815 #ifdef CS_ENABLE_SPIFFS
09816 
09817 DIR *opendir(const char *dir_name) {
09818   DIR *dir = NULL;
09819   extern spiffs fs;
09820 
09821   if (dir_name != NULL && (dir = (DIR *) malloc(sizeof(*dir))) != NULL &&
09822       SPIFFS_opendir(&fs, (char *) dir_name, &dir->dh) == NULL) {
09823     free(dir);
09824     dir = NULL;
09825   }
09826 
09827   return dir;
09828 }
09829 
09830 int closedir(DIR *dir) {
09831   if (dir != NULL) {
09832     SPIFFS_closedir(&dir->dh);
09833     free(dir);
09834   }
09835   return 0;
09836 }
09837 
09838 struct dirent *readdir(DIR *dir) {
09839   return SPIFFS_readdir(&dir->dh, &dir->de);
09840 }
09841 
09842 /* SPIFFs doesn't support directory operations */
09843 int rmdir(const char *path) {
09844   (void) path;
09845   return ENOTDIR;
09846 }
09847 
09848 int mkdir(const char *path, mode_t mode) {
09849   (void) path;
09850   (void) mode;
09851   /* for spiffs supports only root dir, which comes from mongoose as '.' */
09852   return (strlen(path) == 1 && *path == '.') ? 0 : ENOTDIR;
09853 }
09854 
09855 #endif /* CS_ENABLE_SPIFFS */
09856 
09857 #endif /* EXCLUDE_COMMON */
09858 
09859 /* ISO C requires a translation unit to contain at least one declaration */
09860 typedef int cs_dirent_dummy;
09861 #ifdef V7_MODULE_LINES
09862 #line 1 "common/cs_file.c"
09863 #endif
09864 /*
09865  * Copyright (c) 2015 Cesanta Software Limited
09866  * All rights reserved
09867  */
09868 
09869 /* Amalgamated: #include "common/cs_file.h" */
09870 
09871 #include <stdio.h>
09872 #include <stdlib.h>
09873 
09874 #ifdef CS_MMAP
09875 #include <fcntl.h>
09876 #include <sys/mman.h>
09877 #include <sys/stat.h>
09878 #endif
09879 
09880 #ifndef EXCLUDE_COMMON
09881 char *cs_read_file(const char *path, size_t *size) {
09882   FILE *fp;
09883   char *data = NULL;
09884   if ((fp = fopen(path, "rb")) == NULL) {
09885   } else if (fseek(fp, 0, SEEK_END) != 0) {
09886     fclose(fp);
09887   } else {
09888     *size = ftell(fp);
09889     data = (char *) malloc(*size + 1);
09890     if (data != NULL) {
09891       fseek(fp, 0, SEEK_SET); /* Some platforms might not have rewind(), Oo */
09892       if (fread(data, 1, *size, fp) != *size) {
09893         free(data);
09894         return NULL;
09895       }
09896       data[*size] = '\0';
09897     }
09898     fclose(fp);
09899   }
09900   return data;
09901 }
09902 #endif /* EXCLUDE_COMMON */
09903 
09904 #ifdef CS_MMAP
09905 char *cs_mmap_file(const char *path, size_t *size) {
09906   char *r;
09907   int fd = open(path, O_RDONLY);
09908   struct stat st;
09909   if (fd == -1) return NULL;
09910   fstat(fd, &st);
09911   *size = (size_t) st.st_size;
09912   r = (char *) mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
09913   if (r == MAP_FAILED) return NULL;
09914   return r;
09915 }
09916 #endif
09917 #ifdef V7_MODULE_LINES
09918 #line 1 "common/cs_strtod.c"
09919 #endif
09920 #include <ctype.h>
09921 #include <math.h>
09922 
09923 #include <stdlib.h>
09924 
09925 int cs_strncasecmp(const char *s1, const char *s2, size_t n) {
09926   if (n == 0) {
09927     return 0;
09928   }
09929 
09930   while (n-- != 0 && tolower((int) *s1) == tolower((int) *s2)) {
09931     if (n == 0 || *s1 == '\0' || *s2 == '\0') {
09932       break;
09933     }
09934     s1++;
09935     s2++;
09936   }
09937 
09938   return tolower(*(unsigned char *) s1) - tolower(*(unsigned char *) s2);
09939 }
09940 
09941 /*
09942  * based on Source:
09943  * https://github.com/anakod/Sming/blob/master/Sming/system/stringconversion.cpp#L93
09944  */
09945 
09946 double cs_strtod(const char *str, char **endptr) {
09947   double result = 0.0;
09948   char c;
09949   const char *str_start;
09950   struct {
09951     unsigned neg : 1;        /* result is negative */
09952     unsigned decimals : 1;   /* parsing decimal part */
09953     unsigned is_exp : 1;     /* parsing exponent like e+5 */
09954     unsigned is_exp_neg : 1; /* exponent is negative */
09955   } flags = {0, 0, 0, 0};
09956 
09957   while (isspace((int) *str)) {
09958     str++;
09959   }
09960 
09961   if (*str == 0) {
09962     /* only space in str? */
09963     if (endptr != 0) *endptr = (char *) str;
09964     return result;
09965   }
09966 
09967   /* Handle leading plus/minus signs */
09968   while (*str == '-' || *str == '+') {
09969     if (*str == '-') {
09970       flags.neg = !flags.neg;
09971     }
09972     str++;
09973   }
09974 
09975   if (cs_strncasecmp(str, "NaN", 3) == 0) {
09976     if (endptr != 0) *endptr = (char *) str + 3;
09977     return NAN;
09978   }
09979 
09980   if (cs_strncasecmp(str, "INF", 3) == 0) {
09981     str += 3;
09982     if (cs_strncasecmp(str, "INITY", 5) == 0) str += 5;
09983     if (endptr != 0) *endptr = (char *) str;
09984     return flags.neg ? -INFINITY : INFINITY;
09985   }
09986 
09987   str_start = str;
09988 
09989   if (*str == '0' && (*(str + 1) == 'x' || *(str + 1) == 'X')) {
09990     /* base 16 */
09991     str += 2;
09992     while ((c = tolower((int) *str))) {
09993       int d;
09994       if (c >= '0' && c <= '9') {
09995         d = c - '0';
09996       } else if (c >= 'a' && c <= 'f') {
09997         d = 10 + (c - 'a');
09998       } else {
09999         break;
10000       }
10001       result = 16 * result + d;
10002       str++;
10003     }
10004   } else if (*str == '0' && (*(str + 1) == 'b' || *(str + 1) == 'B')) {
10005     /* base 2 */
10006     str += 2;
10007     while ((c = *str)) {
10008       int d = c - '0';
10009       if (c != '0' && c != '1') break;
10010       result = 2 * result + d;
10011       str++;
10012     }
10013   } else if (*str == '0' && *(str + 1) >= '0' && *(str + 1) <= '7') {
10014     /* base 8 */
10015     while ((c = *str)) {
10016       int d = c - '0';
10017       if (c < '0' || c > '7') {
10018         /* fallback to base 10 */
10019         str = str_start;
10020         break;
10021       }
10022       result = 8 * result + d;
10023       str++;
10024     }
10025   }
10026 
10027   if (str == str_start) {
10028     /* base 10 */
10029 
10030     /* exponent specified explicitly, like in 3e-5, exponent is -5 */
10031     int exp = 0;
10032     /* exponent calculated from dot, like in 1.23, exponent is -2 */
10033     int exp_dot = 0;
10034 
10035     result = 0;
10036 
10037     while ((c = *str)) {
10038       int d;
10039 
10040       if (c == '.') {
10041         if (!flags.decimals) {
10042           /* going to parse decimal part */
10043           flags.decimals = 1;
10044           str++;
10045           continue;
10046         } else {
10047           /* non-expected dot: assume number data is over */
10048           break;
10049         }
10050       } else if (c == 'e' || c == 'E') {
10051         /* going to parse exponent part */
10052         flags.is_exp = 1;
10053         str++;
10054         c = *str;
10055 
10056         /* check sign of the exponent */
10057         if (c == '-' || c == '+') {
10058           if (c == '-') {
10059             flags.is_exp_neg = 1;
10060           }
10061           str++;
10062         }
10063 
10064         continue;
10065       }
10066 
10067       d = c - '0';
10068       if (d < 0 || d > 9) {
10069         break;
10070       }
10071 
10072       if (!flags.is_exp) {
10073         /* apply current digit to the result */
10074         result = 10 * result + d;
10075         if (flags.decimals) {
10076           exp_dot--;
10077         }
10078       } else {
10079         /* apply current digit to the exponent */
10080         if (flags.is_exp_neg) {
10081           if (exp > -1022) {
10082             exp = 10 * exp - d;
10083           }
10084         } else {
10085           if (exp < 1023) {
10086             exp = 10 * exp + d;
10087           }
10088         }
10089       }
10090 
10091       str++;
10092     }
10093 
10094     exp += exp_dot;
10095 
10096     /*
10097      * TODO(dfrank): it probably makes sense not to adjust intermediate `double
10098      * result`, but build double number accordingly to IEEE 754 from taken
10099      * (integer) mantissa, exponent and sign. That would work faster, and we
10100      * can avoid any possible round errors.
10101      */
10102 
10103     /* if exponent is non-zero, apply it */
10104     if (exp != 0) {
10105       if (exp < 0) {
10106         while (exp++ != 0) {
10107           result /= 10;
10108         }
10109       } else {
10110         while (exp-- != 0) {
10111           result *= 10;
10112         }
10113       }
10114     }
10115   }
10116 
10117   if (flags.neg) {
10118     result = -result;
10119   }
10120 
10121   if (endptr != 0) {
10122     *endptr = (char *) str;
10123   }
10124 
10125   return result;
10126 }
10127 #ifdef V7_MODULE_LINES
10128 #line 1 "common/coroutine.c"
10129 #endif
10130 /*
10131  * Copyright (c) 2015 Cesanta Software Limited
10132  * All rights reserved
10133  */
10134 
10135 /*
10136  * Module that provides generic macros and functions to implement "coroutines",
10137  * i.e. C code that uses `mbuf` as a stack for function calls.
10138  *
10139  * More info: see the design doc: https://goo.gl/kfcG61
10140  */
10141 
10142 #include <string.h>
10143 #include <stdlib.h>
10144 
10145 /* Amalgamated: #include "common/coroutine.h" */
10146 
10147 /*
10148  * Unwinds stack by 1 function. Used when we're returning from function and
10149  * when an exception is thrown.
10150  */
10151 static void _level_up(struct cr_ctx *p_ctx) {
10152   /* get size of current function's stack data */
10153   size_t locals_size = _CR_CURR_FUNC_LOCALS_SIZE(p_ctx);
10154 
10155   /* check stacks underflow */
10156   if (_CR_STACK_FID_UND_CHECK(p_ctx, 1 /*fid*/)) {
10157     p_ctx->status = CR_RES__ERR_STACK_CALL_UNDERFLOW;
10158     return;
10159   } else if (_CR_STACK_DATA_UND_CHECK(p_ctx, locals_size)) {
10160     p_ctx->status = CR_RES__ERR_STACK_DATA_UNDERFLOW;
10161     return;
10162   }
10163 
10164   /* decrement stacks */
10165   _CR_STACK_DATA_FREE(p_ctx, locals_size);
10166   _CR_STACK_FID_FREE(p_ctx, 1 /*fid*/);
10167   p_ctx->stack_ret.len = p_ctx->cur_fid_idx;
10168 
10169   /* if we have exception marker here, adjust cur_fid_idx */
10170   while (CR_CURR_FUNC_C(p_ctx) == CR_FID__TRY_MARKER) {
10171     /* check for stack underflow */
10172     if (_CR_STACK_FID_UND_CHECK(p_ctx, _CR_TRY_SIZE)) {
10173       p_ctx->status = CR_RES__ERR_STACK_CALL_UNDERFLOW;
10174       return;
10175     }
10176     _CR_STACK_FID_FREE(p_ctx, _CR_TRY_SIZE);
10177   }
10178 }
10179 
10180 enum cr_status cr_on_iter_begin(struct cr_ctx *p_ctx) {
10181   if (p_ctx->status != CR_RES__OK) {
10182     goto out;
10183   } else if (p_ctx->called_fid != CR_FID__NONE) {
10184     /* need to call new function */
10185 
10186     size_t locals_size = p_ctx->p_func_descrs[p_ctx->called_fid].locals_size;
10187     /*
10188      * increment stack pointers
10189      */
10190     /* make sure this function has correct `struct cr_func_desc` entry */
10191     assert(locals_size == p_ctx->call_locals_size);
10192     /*
10193      * make sure we haven't mistakenly included "zero-sized" `.._arg_t`
10194      * structure in `.._locals_t` struct
10195      *
10196      * By "zero-sized" I mean `cr_zero_size_type_t`.
10197      */
10198     assert(locals_size < sizeof(cr_zero_size_type_t));
10199 
10200     _CR_STACK_DATA_ALLOC(p_ctx, locals_size);
10201     _CR_STACK_RET_ALLOC(p_ctx, 1 /*fid*/);
10202     p_ctx->cur_fid_idx = p_ctx->stack_ret.len;
10203 
10204     /* copy arguments to our "stack" (and advance locals stack pointer) */
10205     memcpy(p_ctx->stack_data.buf + p_ctx->stack_data.len - locals_size,
10206            p_ctx->p_arg_retval, p_ctx->call_arg_size);
10207 
10208     /* set function id */
10209     CR_CURR_FUNC_C(p_ctx) = p_ctx->called_fid;
10210 
10211     /* clear called_fid */
10212     p_ctx->called_fid = CR_FID__NONE;
10213 
10214   } else if (p_ctx->need_return) {
10215     /* need to return from the currently running function */
10216 
10217     _level_up(p_ctx);
10218     if (p_ctx->status != CR_RES__OK) {
10219       goto out;
10220     }
10221 
10222     p_ctx->need_return = 0;
10223 
10224   } else if (p_ctx->need_yield) {
10225     /* need to yield */
10226 
10227     p_ctx->need_yield = 0;
10228     p_ctx->status = CR_RES__OK_YIELDED;
10229     goto out;
10230 
10231   } else if (p_ctx->thrown_exc != CR_EXC_ID__NONE) {
10232     /* exception was thrown */
10233 
10234     /* unwind stack until we reach the bottom, or find some try-catch blocks */
10235     do {
10236       _level_up(p_ctx);
10237       if (p_ctx->status != CR_RES__OK) {
10238         goto out;
10239       }
10240 
10241       if (_CR_TRY_MARKER(p_ctx) == CR_FID__TRY_MARKER) {
10242         /* we have some try-catch here, go to the first catch */
10243         CR_CURR_FUNC_C(p_ctx) = _CR_TRY_CATCH_FID(p_ctx);
10244         break;
10245       } else if (CR_CURR_FUNC_C(p_ctx) == CR_FID__NONE) {
10246         /* we've reached the bottom of the stack */
10247         p_ctx->status = CR_RES__ERR_UNCAUGHT_EXCEPTION;
10248         break;
10249       }
10250 
10251     } while (1);
10252   }
10253 
10254   /* remember pointer to current function's locals */
10255   _CR_CUR_FUNC_LOCALS_UPD(p_ctx);
10256 
10257 out:
10258   return p_ctx->status;
10259 }
10260 
10261 void cr_context_init(struct cr_ctx *p_ctx, union user_arg_ret *p_arg_retval,
10262                      size_t arg_retval_size,
10263                      const struct cr_func_desc *p_func_descrs) {
10264   /*
10265    * make sure we haven't mistakenly included "zero-sized" `.._arg_t`
10266    * structure in `union user_arg_ret`.
10267    *
10268    * By "zero-sized" I mean `cr_zero_size_type_t`.
10269    */
10270   assert(arg_retval_size < sizeof(cr_zero_size_type_t));
10271 #ifdef NDEBUG
10272   (void) arg_retval_size;
10273 #endif
10274 
10275   memset(p_ctx, 0x00, sizeof(*p_ctx));
10276 
10277   p_ctx->p_func_descrs = p_func_descrs;
10278   p_ctx->p_arg_retval = p_arg_retval;
10279 
10280   mbuf_init(&p_ctx->stack_data, 0);
10281   mbuf_init(&p_ctx->stack_ret, 0);
10282 
10283   mbuf_append(&p_ctx->stack_ret, NULL, 1 /*starting byte for CR_FID__NONE*/);
10284   p_ctx->cur_fid_idx = p_ctx->stack_ret.len;
10285 
10286   _CR_CALL_PREPARE(p_ctx, CR_FID__NONE, 0, 0, CR_FID__NONE);
10287 }
10288 
10289 void cr_context_free(struct cr_ctx *p_ctx) {
10290   mbuf_free(&p_ctx->stack_data);
10291   mbuf_free(&p_ctx->stack_ret);
10292 }
10293 #ifdef V7_MODULE_LINES
10294 #line 1 "common/platforms/mbed/mbed_libc.c"
10295 #endif
10296 /*
10297  * Copyright (c) 2014-2016 Cesanta Software Limited
10298  * All rights reserved
10299  */
10300 
10301 #if CS_PLATFORM == CS_P_MBED
10302 
10303 long timezone;
10304 
10305 #endif /* CS_PLATFORM == CS_P_MBED */
10306 #ifdef V7_MODULE_LINES
10307 #line 1 "v7/builtin/file.c"
10308 #endif
10309 /*
10310  * Copyright (c) 2014 Cesanta Software Limited
10311  * All rights reserved
10312  */
10313 
10314 /* Amalgamated: #include "v7/src/internal.h" */
10315 /* Amalgamated: #include "v7/src/core.h" */
10316 /* Amalgamated: #include "v7/src/primitive.h" */
10317 /* Amalgamated: #include "v7/src/string.h" */
10318 /* Amalgamated: #include "v7/src/exceptions.h" */
10319 /* Amalgamated: #include "v7/src/object.h" */
10320 /* Amalgamated: #include "v7/src/exec.h" */
10321 /* Amalgamated: #include "v7/src/array.h" */
10322 /* Amalgamated: #include "common/mbuf.h" */
10323 /* Amalgamated: #include "common/cs_file.h" */
10324 /* Amalgamated: #include "v7/src/v7_features.h" */
10325 /* Amalgamated: #include "common/cs_dirent.h" */
10326 
10327 #if defined(V7_ENABLE_FILE) && !defined(V7_NO_FS)
10328 
10329 static const char s_fd_prop[] = "__fd";
10330 
10331 #ifndef NO_LIBC
10332 static FILE *v7_val_to_file(struct v7 *v7, v7_val_t val) {
10333   (void) v7;
10334   return (FILE *) v7_get_ptr(v7, val);
10335 }
10336 
10337 static v7_val_t v7_file_to_val(struct v7 *v7, FILE *file) {
10338   (void) v7;
10339   return v7_mk_foreign(v7, file);
10340 }
10341 
10342 static int v7_is_file_type(v7_val_t val) {
10343   return v7_is_foreign(val);
10344 }
10345 #else
10346 FILE *v7_val_to_file(struct v7 *v7, v7_val_t val);
10347 v7_val_t v7_file_to_val(struct v7 *v7, FILE *file);
10348 int v7_is_file_type(v7_val_t val);
10349 #endif
10350 
10351 WARN_UNUSED_RESULT
10352 V7_PRIVATE enum v7_err File_eval(struct v7 *v7, v7_val_t *res) {
10353   enum v7_err rcode = V7_OK;
10354   v7_val_t arg0 = v7_arg(v7, 0);
10355 
10356   *res = V7_UNDEFINED;
10357 
10358   if (v7_is_string(arg0)) {
10359     const char *s = v7_get_cstring(v7, &arg0);
10360     if (s == NULL) {
10361       rcode = v7_throwf(v7, "TypeError", "Invalid string");
10362       goto clean;
10363     }
10364 
10365     v7_set_gc_enabled(v7, 1);
10366     rcode = v7_exec_file(v7, s, res);
10367     if (rcode != V7_OK) {
10368       goto clean;
10369     }
10370   }
10371 
10372 clean:
10373   return rcode;
10374 }
10375 
10376 WARN_UNUSED_RESULT
10377 V7_PRIVATE enum v7_err File_exists(struct v7 *v7, v7_val_t *res) {
10378   enum v7_err rcode = V7_OK;
10379   v7_val_t arg0 = v7_arg(v7, 0);
10380 
10381   *res = v7_mk_boolean(v7, 0);
10382 
10383   if (v7_is_string(arg0)) {
10384     const char *fname = v7_get_cstring(v7, &arg0);
10385     if (fname != NULL) {
10386       struct stat st;
10387       if (stat(fname, &st) == 0) *res = v7_mk_boolean(v7, 1);
10388     }
10389   }
10390 
10391   return rcode;
10392 }
10393 
10394 WARN_UNUSED_RESULT
10395 static enum v7_err f_read(struct v7 *v7, int all, v7_val_t *res) {
10396   enum v7_err rcode = V7_OK;
10397   v7_val_t this_obj = v7_get_this(v7);
10398   v7_val_t arg0 = v7_get(v7, this_obj, s_fd_prop, sizeof(s_fd_prop) - 1);
10399 
10400   if (v7_is_file_type(arg0)) {
10401     struct mbuf m;
10402     char buf[BUFSIZ];
10403     int n;
10404     FILE *fp = v7_val_to_file(v7, arg0);
10405 
10406     /* Read file contents into mbuf */
10407     mbuf_init(&m, 0);
10408     while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
10409       mbuf_append(&m, buf, n);
10410       if (!all) {
10411         break;
10412       }
10413     }
10414 
10415     if (m.len > 0) {
10416       *res = v7_mk_string(v7, m.buf, m.len, 1);
10417       mbuf_free(&m);
10418       goto clean;
10419     }
10420   }
10421   *res = v7_mk_string(v7, "", 0, 1);
10422 
10423 clean:
10424   return rcode;
10425 }
10426 
10427 WARN_UNUSED_RESULT
10428 V7_PRIVATE enum v7_err File_obj_read(struct v7 *v7, v7_val_t *res) {
10429   return f_read(v7, 0, res);
10430 }
10431 
10432 WARN_UNUSED_RESULT
10433 V7_PRIVATE enum v7_err File_obj_write(struct v7 *v7, v7_val_t *res) {
10434   enum v7_err rcode = V7_OK;
10435   v7_val_t this_obj = v7_get_this(v7);
10436   v7_val_t arg0 = v7_get(v7, this_obj, s_fd_prop, sizeof(s_fd_prop) - 1);
10437   v7_val_t arg1 = v7_arg(v7, 0);
10438   size_t n, sent = 0, len = 0;
10439 
10440   if (v7_is_file_type(arg0) && v7_is_string(arg1)) {
10441     const char *s = v7_get_string(v7, &arg1, &len);
10442     FILE *fp = v7_val_to_file(v7, arg0);
10443     while (sent < len && (n = fwrite(s + sent, 1, len - sent, fp)) > 0) {
10444       sent += n;
10445     }
10446   }
10447 
10448   *res = v7_mk_number(v7, sent);
10449 
10450   return rcode;
10451 }
10452 
10453 WARN_UNUSED_RESULT
10454 V7_PRIVATE enum v7_err File_obj_close(struct v7 *v7, v7_val_t *res) {
10455   enum v7_err rcode = V7_OK;
10456   v7_val_t this_obj = v7_get_this(v7);
10457   v7_val_t prop = v7_get(v7, this_obj, s_fd_prop, sizeof(s_fd_prop) - 1);
10458   int ires = -1;
10459 
10460   if (v7_is_file_type(prop)) {
10461     ires = fclose(v7_val_to_file(v7, prop));
10462   }
10463 
10464   *res = v7_mk_number(v7, ires);
10465 
10466   return rcode;
10467 }
10468 
10469 WARN_UNUSED_RESULT
10470 V7_PRIVATE enum v7_err File_open(struct v7 *v7, v7_val_t *res) {
10471   enum v7_err rcode = V7_OK;
10472   v7_val_t arg0 = v7_arg(v7, 0);
10473   v7_val_t arg1 = v7_arg(v7, 1);
10474   FILE *fp = NULL;
10475 
10476   if (v7_is_string(arg0)) {
10477     const char *s1 = v7_get_cstring(v7, &arg0);
10478     const char *s2 = "rb"; /* Open files in read mode by default */
10479 
10480     if (v7_is_string(arg1)) {
10481       s2 = v7_get_cstring(v7, &arg1);
10482     }
10483 
10484     if (s1 == NULL || s2 == NULL) {
10485       *res = V7_NULL;
10486       goto clean;
10487     }
10488 
10489     fp = fopen(s1, s2);
10490     if (fp != NULL) {
10491       v7_val_t obj = v7_mk_object(v7);
10492       v7_val_t file_proto = v7_get(
10493           v7, v7_get(v7, v7_get_global(v7), "File", ~0), "prototype", ~0);
10494       v7_set_proto(v7, obj, file_proto);
10495       v7_def(v7, obj, s_fd_prop, sizeof(s_fd_prop) - 1, V7_DESC_ENUMERABLE(0),
10496              v7_file_to_val(v7, fp));
10497       *res = obj;
10498       goto clean;
10499     }
10500   }
10501 
10502   *res = V7_NULL;
10503 
10504 clean:
10505   return rcode;
10506 }
10507 
10508 WARN_UNUSED_RESULT
10509 V7_PRIVATE enum v7_err File_read(struct v7 *v7, v7_val_t *res) {
10510   v7_val_t arg0 = v7_arg(v7, 0);
10511 
10512   if (v7_is_string(arg0)) {
10513     const char *path = v7_get_cstring(v7, &arg0);
10514     size_t size = 0;
10515     char *data = cs_read_file(path, &size);
10516     if (data != NULL) {
10517       *res = v7_mk_string(v7, data, size, 1);
10518       free(data);
10519     }
10520   }
10521 
10522   return V7_OK;
10523 }
10524 
10525 WARN_UNUSED_RESULT
10526 V7_PRIVATE enum v7_err File_write(struct v7 *v7, v7_val_t *res) {
10527   v7_val_t arg0 = v7_arg(v7, 0);
10528   v7_val_t arg1 = v7_arg(v7, 1);
10529   *res = v7_mk_boolean(v7, 0);
10530 
10531   if (v7_is_string(arg0) && v7_is_string(arg1)) {
10532     const char *path = v7_get_cstring(v7, &arg0);
10533     size_t len;
10534     const char *buf = v7_get_string(v7, &arg1, &len);
10535     FILE *fp = fopen(path, "wb+");
10536     if (fp != NULL) {
10537       if (fwrite(buf, 1, len, fp) == len) {
10538         *res = v7_mk_boolean(v7, 1);
10539       }
10540       fclose(fp);
10541     }
10542   }
10543 
10544   return V7_OK;
10545 }
10546 
10547 WARN_UNUSED_RESULT
10548 V7_PRIVATE enum v7_err File_rename(struct v7 *v7, v7_val_t *res) {
10549   enum v7_err rcode = V7_OK;
10550   v7_val_t arg0 = v7_arg(v7, 0);
10551   v7_val_t arg1 = v7_arg(v7, 1);
10552   int ires = -1;
10553 
10554   if (v7_is_string(arg0) && v7_is_string(arg1)) {
10555     const char *from = v7_get_cstring(v7, &arg0);
10556     const char *to = v7_get_cstring(v7, &arg1);
10557     if (from == NULL || to == NULL) {
10558       *res = v7_mk_number(v7, ENOENT);
10559       goto clean;
10560     }
10561 
10562     ires = rename(from, to);
10563   }
10564 
10565   *res = v7_mk_number(v7, ires == 0 ? 0 : errno);
10566 
10567 clean:
10568   return rcode;
10569 }
10570 
10571 WARN_UNUSED_RESULT
10572 V7_PRIVATE enum v7_err File_loadJSON(struct v7 *v7, v7_val_t *res) {
10573   enum v7_err rcode = V7_OK;
10574   v7_val_t arg0 = v7_arg(v7, 0);
10575 
10576   *res = V7_UNDEFINED;
10577 
10578   if (v7_is_string(arg0)) {
10579     const char *file_name = v7_get_cstring(v7, &arg0);
10580     if (file_name == NULL) {
10581       goto clean;
10582     }
10583 
10584     rcode = v7_parse_json_file(v7, file_name, res);
10585     if (rcode != V7_OK) {
10586       /* swallow exception and return undefined */
10587       v7_clear_thrown_value(v7);
10588       rcode = V7_OK;
10589       *res = V7_UNDEFINED;
10590     }
10591   }
10592 
10593 clean:
10594   return rcode;
10595 }
10596 
10597 WARN_UNUSED_RESULT
10598 V7_PRIVATE enum v7_err File_remove(struct v7 *v7, v7_val_t *res) {
10599   enum v7_err rcode = V7_OK;
10600   v7_val_t arg0 = v7_arg(v7, 0);
10601   int ires = -1;
10602 
10603   if (v7_is_string(arg0)) {
10604     const char *path = v7_get_cstring(v7, &arg0);
10605     if (path == NULL) {
10606       *res = v7_mk_number(v7, ENOENT);
10607       goto clean;
10608     }
10609     ires = remove(path);
10610   }
10611   *res = v7_mk_number(v7, ires == 0 ? 0 : errno);
10612 
10613 clean:
10614   return rcode;
10615 }
10616 
10617 #if V7_ENABLE__File__list
10618 WARN_UNUSED_RESULT
10619 V7_PRIVATE enum v7_err File_list(struct v7 *v7, v7_val_t *res) {
10620   enum v7_err rcode = V7_OK;
10621   v7_val_t arg0 = v7_arg(v7, 0);
10622 
10623   *res = V7_UNDEFINED;
10624 
10625   if (v7_is_string(arg0)) {
10626     const char *path = v7_get_cstring(v7, &arg0);
10627     struct dirent *dp;
10628     DIR *dirp;
10629 
10630     if (path == NULL) {
10631       goto clean;
10632     }
10633 
10634     if ((dirp = (opendir(path))) != NULL) {
10635       *res = v7_mk_array(v7);
10636       while ((dp = readdir(dirp)) != NULL) {
10637         /* Do not show current and parent dirs */
10638         if (strcmp((const char *) dp->d_name, ".") == 0 ||
10639             strcmp((const char *) dp->d_name, "..") == 0) {
10640           continue;
10641         }
10642         /* Add file name to the list */
10643         v7_array_push(v7, *res,
10644                       v7_mk_string(v7, (const char *) dp->d_name,
10645                                    strlen((const char *) dp->d_name), 1));
10646       }
10647       closedir(dirp);
10648     }
10649   }
10650 
10651 clean:
10652   return rcode;
10653 }
10654 #endif /* V7_ENABLE__File__list */
10655 
10656 void init_file(struct v7 *v7) {
10657   v7_val_t file_obj = v7_mk_object(v7), file_proto = v7_mk_object(v7);
10658   v7_set(v7, v7_get_global(v7), "File", 4, file_obj);
10659   v7_set(v7, file_obj, "prototype", 9, file_proto);
10660 
10661   v7_set_method(v7, file_obj, "eval", File_eval);
10662   v7_set_method(v7, file_obj, "exists", File_exists);
10663   v7_set_method(v7, file_obj, "remove", File_remove);
10664   v7_set_method(v7, file_obj, "rename", File_rename);
10665   v7_set_method(v7, file_obj, "open", File_open);
10666   v7_set_method(v7, file_obj, "read", File_read);
10667   v7_set_method(v7, file_obj, "write", File_write);
10668   v7_set_method(v7, file_obj, "loadJSON", File_loadJSON);
10669 #if V7_ENABLE__File__list
10670   v7_set_method(v7, file_obj, "list", File_list);
10671 #endif
10672 
10673   v7_set_method(v7, file_proto, "close", File_obj_close);
10674   v7_set_method(v7, file_proto, "read", File_obj_read);
10675   v7_set_method(v7, file_proto, "write", File_obj_write);
10676 
10677 #if V7_ENABLE__File__require
10678   v7_def(v7, v7_get_global(v7), "_modcache", ~0, 0, v7_mk_object(v7));
10679   if (v7_exec(v7,
10680               "function require(m) { "
10681               "  if (m in _modcache) { return _modcache[m]; }"
10682               "  var module = {exports:{}};"
10683               "  File.eval(m);"
10684               "  return (_modcache[m] = module.exports)"
10685               " }",
10686               NULL) != V7_OK) {
10687     /* TODO(mkm): percolate failure */
10688   }
10689 #endif
10690 }
10691 #else
10692 void init_file(struct v7 *v7) {
10693   (void) v7;
10694 }
10695 #endif /* NO_LIBC */
10696 #ifdef V7_MODULE_LINES
10697 #line 1 "v7/builtin/socket.c"
10698 #endif
10699 /*
10700  * Copyright (c) 2015 Cesanta Software Limited
10701  * All rights reserved
10702  */
10703 
10704 /* Amalgamated: #include "v7/src/internal.h" */
10705 /* Amalgamated: #include "v7/src/core.h" */
10706 /* Amalgamated: #include "v7/src/string.h" */
10707 /* Amalgamated: #include "v7/src/object.h" */
10708 /* Amalgamated: #include "v7/src/primitive.h" */
10709 /* Amalgamated: #include "v7/src/conversion.h" */
10710 /* Amalgamated: #include "common/mbuf.h" */
10711 /* Amalgamated: #include "common/platform.h" */
10712 
10713 #ifdef V7_ENABLE_SOCKET
10714 
10715 #ifdef __WATCOM__
10716 #define SOMAXCONN 128
10717 #endif
10718 
10719 #ifndef RECV_BUF_SIZE
10720 #define RECV_BUF_SIZE 1024
10721 #endif
10722 
10723 static const char s_sock_prop[] = "__sock";
10724 
10725 static uint32_t s_resolve(struct v7 *v7, v7_val_t ip_address) {
10726   size_t n;
10727   const char *s = v7_get_string(v7, &ip_address, &n);
10728   struct hostent *he = gethostbyname(s);
10729   return he == NULL ? 0 : *(uint32_t *) he->h_addr_list[0];
10730 }
10731 
10732 WARN_UNUSED_RESULT
10733 static enum v7_err s_fd_to_sock_obj(struct v7 *v7, sock_t fd, v7_val_t *res) {
10734   enum v7_err rcode = V7_OK;
10735   v7_val_t sock_proto =
10736       v7_get(v7, v7_get(v7, v7_get_global(v7), "Socket", ~0), "prototype", ~0);
10737 
10738   *res = v7_mk_object(v7);
10739   v7_set_proto(v7, *res, sock_proto);
10740   v7_def(v7, *res, s_sock_prop, sizeof(s_sock_prop) - 1, V7_DESC_ENUMERABLE(0),
10741          v7_mk_number(v7, fd));
10742 
10743   return rcode;
10744 }
10745 
10746 /* Socket.connect(host, port [, is_udp]) -> socket_object */
10747 WARN_UNUSED_RESULT
10748 V7_PRIVATE enum v7_err Socket_connect(struct v7 *v7, v7_val_t *res) {
10749   enum v7_err rcode = V7_OK;
10750   v7_val_t arg0 = v7_arg(v7, 0);
10751   v7_val_t arg1 = v7_arg(v7, 1);
10752   v7_val_t arg2 = v7_arg(v7, 2);
10753 
10754   if (v7_is_number(arg1) && v7_is_string(arg0)) {
10755     struct sockaddr_in sin;
10756     sock_t sock =
10757         socket(AF_INET, v7_is_truthy(v7, arg2) ? SOCK_DGRAM : SOCK_STREAM, 0);
10758     memset(&sin, 0, sizeof(sin));
10759     sin.sin_family = AF_INET;
10760     sin.sin_addr.s_addr = s_resolve(v7, arg0);
10761     sin.sin_port = htons((uint16_t) v7_get_double(v7, arg1));
10762     if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
10763       closesocket(sock);
10764     } else {
10765       rcode = s_fd_to_sock_obj(v7, sock, res);
10766       goto clean;
10767     }
10768   }
10769 
10770   *res = V7_NULL;
10771 
10772 clean:
10773   return rcode;
10774 }
10775 
10776 /* Socket.listen(port [, ip_address [,is_udp]]) -> sock */
10777 WARN_UNUSED_RESULT
10778 V7_PRIVATE enum v7_err Socket_listen(struct v7 *v7, v7_val_t *res) {
10779   enum v7_err rcode = V7_OK;
10780   v7_val_t arg0 = v7_arg(v7, 0);
10781   v7_val_t arg1 = v7_arg(v7, 1);
10782   v7_val_t arg2 = v7_arg(v7, 2);
10783 
10784   if (v7_is_number(arg0)) {
10785     struct sockaddr_in sin;
10786     int on = 1;
10787     sock_t sock =
10788         socket(AF_INET, v7_is_truthy(v7, arg2) ? SOCK_DGRAM : SOCK_STREAM, 0);
10789     memset(&sin, 0, sizeof(sin));
10790     sin.sin_family = AF_INET;
10791     sin.sin_port = htons((uint16_t) v7_get_double(v7, arg0));
10792     if (v7_is_string(arg1)) {
10793       sin.sin_addr.s_addr = s_resolve(v7, arg1);
10794     }
10795 
10796 #if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE)
10797     /* "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" http://goo.gl/RmrFTm */
10798     setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *) &on, sizeof(on));
10799 #endif
10800 
10801 #if !defined(_WIN32) || defined(SO_EXCLUSIVEADDRUSE)
10802     /*
10803      * SO_RESUSEADDR is not enabled on Windows because the semantics of
10804      * SO_REUSEADDR on UNIX and Windows is different. On Windows,
10805      * SO_REUSEADDR allows to bind a socket to a port without error even if
10806      * the port is already open by another program. This is not the behavior
10807      * SO_REUSEADDR was designed for, and leads to hard-to-track failure
10808      * scenarios. Therefore, SO_REUSEADDR was disabled on Windows unless
10809      * SO_EXCLUSIVEADDRUSE is supported and set on a socket.
10810      */
10811     setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on));
10812 #endif
10813 
10814     if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) == 0) {
10815       listen(sock, SOMAXCONN);
10816       rcode = s_fd_to_sock_obj(v7, sock, res);
10817       goto clean;
10818     } else {
10819       closesocket(sock);
10820     }
10821   }
10822 
10823   *res = V7_NULL;
10824 
10825 clean:
10826   return rcode;
10827 }
10828 
10829 WARN_UNUSED_RESULT
10830 V7_PRIVATE enum v7_err Socket_accept(struct v7 *v7, v7_val_t *res) {
10831   enum v7_err rcode = V7_OK;
10832   v7_val_t this_obj = v7_get_this(v7);
10833   v7_val_t prop = v7_get(v7, this_obj, s_sock_prop, sizeof(s_sock_prop) - 1);
10834 
10835   if (v7_is_number(prop)) {
10836     struct sockaddr_in sin;
10837     socklen_t len = sizeof(sin);
10838     sock_t sock = (sock_t) v7_get_double(v7, prop);
10839     sock_t fd = accept(sock, (struct sockaddr *) &sin, &len);
10840     if (fd != INVALID_SOCKET) {
10841       rcode = s_fd_to_sock_obj(v7, fd, res);
10842       if (rcode == V7_OK) {
10843         char *remote_host = inet_ntoa(sin.sin_addr);
10844         v7_set(v7, *res, "remoteHost", ~0,
10845                v7_mk_string(v7, remote_host, ~0, 1));
10846       }
10847       goto clean;
10848     }
10849   }
10850   *res = V7_NULL;
10851 
10852 clean:
10853   return rcode;
10854 }
10855 
10856 /* sock.close() -> errno */
10857 WARN_UNUSED_RESULT
10858 V7_PRIVATE enum v7_err Socket_close(struct v7 *v7, v7_val_t *res) {
10859   enum v7_err rcode = V7_OK;
10860   v7_val_t this_obj = v7_get_this(v7);
10861   v7_val_t prop = v7_get(v7, this_obj, s_sock_prop, sizeof(s_sock_prop) - 1);
10862   *res = v7_mk_number(v7, closesocket((sock_t) v7_get_double(v7, prop)));
10863 
10864   return rcode;
10865 }
10866 
10867 /* sock.recv() -> string */
10868 WARN_UNUSED_RESULT
10869 static enum v7_err s_recv(struct v7 *v7, int all, v7_val_t *res) {
10870   enum v7_err rcode = V7_OK;
10871   v7_val_t this_obj = v7_get_this(v7);
10872   v7_val_t prop = v7_get(v7, this_obj, s_sock_prop, sizeof(s_sock_prop) - 1);
10873 
10874   if (v7_is_number(prop)) {
10875     char buf[RECV_BUF_SIZE];
10876     sock_t sock = (sock_t) v7_get_double(v7, prop);
10877     struct mbuf m;
10878     int n;
10879 
10880     mbuf_init(&m, 0);
10881     while ((n = recv(sock, buf, sizeof(buf), 0)) > 0) {
10882       mbuf_append(&m, buf, n);
10883       if (!all) {
10884         break;
10885       }
10886     }
10887 
10888     if (n <= 0) {
10889       closesocket(sock);
10890       v7_def(v7, this_obj, s_sock_prop, sizeof(s_sock_prop) - 1,
10891              V7_DESC_ENUMERABLE(0), v7_mk_number(v7, INVALID_SOCKET));
10892     }
10893 
10894     if (m.len > 0) {
10895       *res = v7_mk_string(v7, m.buf, m.len, 1);
10896       mbuf_free(&m);
10897       goto clean;
10898     }
10899   }
10900 
10901   *res = V7_NULL;
10902 
10903 clean:
10904   return rcode;
10905 }
10906 
10907 WARN_UNUSED_RESULT
10908 V7_PRIVATE enum v7_err Socket_recvAll(struct v7 *v7, v7_val_t *res) {
10909   return s_recv(v7, 1, res);
10910 }
10911 
10912 WARN_UNUSED_RESULT
10913 V7_PRIVATE enum v7_err Socket_recv(struct v7 *v7, v7_val_t *res) {
10914   return s_recv(v7, 0, res);
10915 }
10916 
10917 WARN_UNUSED_RESULT
10918 V7_PRIVATE enum v7_err Socket_send(struct v7 *v7, v7_val_t *res) {
10919   enum v7_err rcode = V7_OK;
10920   v7_val_t this_obj = v7_get_this(v7);
10921   v7_val_t arg0 = v7_arg(v7, 0);
10922   v7_val_t prop = v7_get(v7, this_obj, s_sock_prop, sizeof(s_sock_prop) - 1);
10923   size_t len, sent = 0;
10924 
10925   if (v7_is_number(prop) && v7_is_string(arg0)) {
10926     const char *s = v7_get_string(v7, &arg0, &len);
10927     sock_t sock = (sock_t) v7_get_double(v7, prop);
10928     int n;
10929 
10930     while (sent < len && (n = send(sock, s + sent, len - sent, 0)) > 0) {
10931       sent += n;
10932     }
10933   }
10934 
10935   *res = v7_mk_number(v7, sent);
10936 
10937   return rcode;
10938 }
10939 
10940 void init_socket(struct v7 *v7) {
10941   v7_val_t socket_obj = v7_mk_object(v7), sock_proto = v7_mk_object(v7);
10942 
10943   v7_set(v7, v7_get_global(v7), "Socket", 6, socket_obj);
10944   sock_proto = v7_mk_object(v7);
10945   v7_set(v7, socket_obj, "prototype", 9, sock_proto);
10946 
10947   v7_set_method(v7, socket_obj, "connect", Socket_connect);
10948   v7_set_method(v7, socket_obj, "listen", Socket_listen);
10949 
10950   v7_set_method(v7, sock_proto, "accept", Socket_accept);
10951   v7_set_method(v7, sock_proto, "send", Socket_send);
10952   v7_set_method(v7, sock_proto, "recv", Socket_recv);
10953   v7_set_method(v7, sock_proto, "recvAll", Socket_recvAll);
10954   v7_set_method(v7, sock_proto, "close", Socket_close);
10955 
10956 #ifdef _WIN32
10957   {
10958     WSADATA data;
10959     WSAStartup(MAKEWORD(2, 2), &data);
10960     /* TODO(alashkin): add WSACleanup call */
10961   }
10962 #else
10963   signal(SIGPIPE, SIG_IGN);
10964 #endif
10965 }
10966 #else
10967 void init_socket(struct v7 *v7) {
10968   (void) v7;
10969 }
10970 #endif
10971 #ifdef V7_MODULE_LINES
10972 #line 1 "v7/builtin/crypto.c"
10973 #endif
10974 /*
10975  * Copyright (c) 2015 Cesanta Software Limited
10976  * All rights reserved
10977  */
10978 
10979 #include <stdlib.h>
10980 #include <string.h>
10981 
10982 /* Amalgamated: #include "v7/src/internal.h" */
10983 /* Amalgamated: #include "v7/src/core.h" */
10984 /* Amalgamated: #include "v7/src/primitive.h" */
10985 /* Amalgamated: #include "v7/src/string.h" */
10986 /* Amalgamated: #include "v7/src/object.h" */
10987 /* Amalgamated: #include "common/md5.h" */
10988 /* Amalgamated: #include "common/sha1.h" */
10989 /* Amalgamated: #include "common/base64.h" */
10990 
10991 #ifdef V7_ENABLE_CRYPTO
10992 
10993 typedef void (*b64_func_t)(const unsigned char *, int, char *);
10994 
10995 WARN_UNUSED_RESULT
10996 static enum v7_err b64_transform(struct v7 *v7, b64_func_t func, double mult,
10997                                  v7_val_t *res) {
10998   enum v7_err rcode = V7_OK;
10999   v7_val_t arg0 = v7_arg(v7, 0);
11000   *res = V7_UNDEFINED;
11001 
11002   if (v7_is_string(arg0)) {
11003     size_t n;
11004     const char *s = v7_get_string(v7, &arg0, &n);
11005     char *buf = (char *) malloc(n * mult + 4);
11006     if (buf != NULL) {
11007       func((const unsigned char *) s, (int) n, buf);
11008       *res = v7_mk_string(v7, buf, strlen(buf), 1);
11009       free(buf);
11010     }
11011   }
11012 
11013   return rcode;
11014 }
11015 
11016 WARN_UNUSED_RESULT
11017 V7_PRIVATE enum v7_err Crypto_base64_decode(struct v7 *v7, v7_val_t *res) {
11018   return b64_transform(v7, (b64_func_t) cs_base64_decode, 0.75, res);
11019 }
11020 
11021 WARN_UNUSED_RESULT
11022 V7_PRIVATE enum v7_err Crypto_base64_encode(struct v7 *v7, v7_val_t *res) {
11023   return b64_transform(v7, cs_base64_encode, 1.5, res);
11024 }
11025 
11026 static void v7_md5(const char *data, size_t len, char buf[16]) {
11027   MD5_CTX ctx;
11028   MD5_Init(&ctx);
11029   MD5_Update(&ctx, (unsigned char *) data, len);
11030   MD5_Final((unsigned char *) buf, &ctx);
11031 }
11032 
11033 static void v7_sha1(const char *data, size_t len, char buf[20]) {
11034   cs_sha1_ctx ctx;
11035   cs_sha1_init(&ctx);
11036   cs_sha1_update(&ctx, (unsigned char *) data, len);
11037   cs_sha1_final((unsigned char *) buf, &ctx);
11038 }
11039 
11040 WARN_UNUSED_RESULT
11041 V7_PRIVATE enum v7_err Crypto_md5(struct v7 *v7, v7_val_t *res) {
11042   enum v7_err rcode = V7_OK;
11043   v7_val_t arg0 = v7_arg(v7, 0);
11044 
11045   if (v7_is_string(arg0)) {
11046     size_t len;
11047     const char *data = v7_get_string(v7, &arg0, &len);
11048     char buf[16];
11049     v7_md5(data, len, buf);
11050     *res = v7_mk_string(v7, buf, sizeof(buf), 1);
11051     goto clean;
11052   }
11053 
11054   *res = V7_NULL;
11055 
11056 clean:
11057   return rcode;
11058 }
11059 
11060 WARN_UNUSED_RESULT
11061 V7_PRIVATE enum v7_err Crypto_md5_hex(struct v7 *v7, v7_val_t *res) {
11062   enum v7_err rcode = V7_OK;
11063   v7_val_t arg0 = v7_arg(v7, 0);
11064 
11065   if (v7_is_string(arg0)) {
11066     size_t len;
11067     const char *data = v7_get_string(v7, &arg0, &len);
11068     char hash[16], buf[sizeof(hash) * 2 + 1];
11069     v7_md5(data, len, hash);
11070     cs_to_hex(buf, (unsigned char *) hash, sizeof(hash));
11071     *res = v7_mk_string(v7, buf, sizeof(buf) - 1, 1);
11072     goto clean;
11073   }
11074   *res = V7_NULL;
11075 
11076 clean:
11077   return rcode;
11078 }
11079 
11080 WARN_UNUSED_RESULT
11081 V7_PRIVATE enum v7_err Crypto_sha1(struct v7 *v7, v7_val_t *res) {
11082   enum v7_err rcode = V7_OK;
11083   v7_val_t arg0 = v7_arg(v7, 0);
11084 
11085   if (v7_is_string(arg0)) {
11086     size_t len;
11087     const char *data = v7_get_string(v7, &arg0, &len);
11088     char buf[20];
11089     v7_sha1(data, len, buf);
11090     *res = v7_mk_string(v7, buf, sizeof(buf), 1);
11091     goto clean;
11092   }
11093   *res = V7_NULL;
11094 
11095 clean:
11096   return rcode;
11097 }
11098 
11099 WARN_UNUSED_RESULT
11100 V7_PRIVATE enum v7_err Crypto_sha1_hex(struct v7 *v7, v7_val_t *res) {
11101   enum v7_err rcode = V7_OK;
11102   v7_val_t arg0 = v7_arg(v7, 0);
11103 
11104   if (v7_is_string(arg0)) {
11105     size_t len;
11106     const char *data = v7_get_string(v7, &arg0, &len);
11107     char hash[20], buf[sizeof(hash) * 2 + 1];
11108     v7_sha1(data, len, hash);
11109     cs_to_hex(buf, (unsigned char *) hash, sizeof(hash));
11110     *res = v7_mk_string(v7, buf, sizeof(buf) - 1, 1);
11111     goto clean;
11112   }
11113   *res = V7_NULL;
11114 
11115 clean:
11116   return rcode;
11117 }
11118 #endif
11119 
11120 void init_crypto(struct v7 *v7) {
11121 #ifdef V7_ENABLE_CRYPTO
11122   v7_val_t obj = v7_mk_object(v7);
11123   v7_set(v7, v7_get_global(v7), "Crypto", 6, obj);
11124   v7_set_method(v7, obj, "md5", Crypto_md5);
11125   v7_set_method(v7, obj, "md5_hex", Crypto_md5_hex);
11126   v7_set_method(v7, obj, "sha1", Crypto_sha1);
11127   v7_set_method(v7, obj, "sha1_hex", Crypto_sha1_hex);
11128   v7_set_method(v7, obj, "base64_encode", Crypto_base64_encode);
11129   v7_set_method(v7, obj, "base64_decode", Crypto_base64_decode);
11130 #else
11131   (void) v7;
11132 #endif
11133 }
11134 #ifdef V7_MODULE_LINES
11135 #line 1 "v7/src/varint.c"
11136 #endif
11137 /*
11138  * Copyright (c) 2014 Cesanta Software Limited
11139  * All rights reserved
11140  */
11141 
11142 /* Amalgamated: #include "v7/src/internal.h" */
11143 /* Amalgamated: #include "v7/src/varint.h" */
11144 
11145 #if defined(__cplusplus)
11146 extern "C" {
11147 #endif /* __cplusplus */
11148 
11149 /*
11150  * Strings in AST are encoded as tuples (length, string).
11151  * Length is variable-length: if high bit is set in a byte, next byte is used.
11152  * Maximum string length with such encoding is 2 ^ (7 * 4) == 256 MiB,
11153  * assuming that sizeof(size_t) == 4.
11154  * Small string length (less then 128 bytes) is encoded in 1 byte.
11155  */
11156 V7_PRIVATE size_t decode_varint(const unsigned char *p, int *llen) {
11157   size_t i = 0, string_len = 0;
11158 
11159   do {
11160     /*
11161      * Each byte of varint contains 7 bits, in little endian order.
11162      * MSB is a continuation bit: it tells whether next byte is used.
11163      */
11164     string_len |= (p[i] & 0x7f) << (7 * i);
11165     /*
11166      * First we increment i, then check whether it is within boundary and
11167      * whether decoded byte had continuation bit set.
11168      */
11169   } while (++i < sizeof(size_t) && (p[i - 1] & 0x80));
11170   *llen = i;
11171 
11172   return string_len;
11173 }
11174 
11175 /* Return number of bytes to store length */
11176 V7_PRIVATE int calc_llen(size_t len) {
11177   int n = 0;
11178 
11179   do {
11180     n++;
11181   } while (len >>= 7);
11182 
11183   return n;
11184 }
11185 
11186 V7_PRIVATE int encode_varint(size_t len, unsigned char *p) {
11187   int i, llen = calc_llen(len);
11188 
11189   for (i = 0; i < llen; i++) {
11190     p[i] = (len & 0x7f) | (i < llen - 1 ? 0x80 : 0);
11191     len >>= 7;
11192   }
11193 
11194   return llen;
11195 }
11196 
11197 #if defined(__cplusplus)
11198 }
11199 #endif /* __cplusplus */
11200 #ifdef V7_MODULE_LINES
11201 #line 1 "v7/src/tokenizer.c"
11202 #endif
11203 /*
11204  * Copyright (c) 2014 Cesanta Software Limited
11205  * All rights reserved
11206  */
11207 
11208 /* Amalgamated: #include "common/cs_strtod.h" */
11209 /* Amalgamated: #include "common/utf.h" */
11210 
11211 /* Amalgamated: #include "v7/src/internal.h" */
11212 /* Amalgamated: #include "v7/src/core.h" */
11213 
11214 #if !defined(V7_NO_COMPILER)
11215 
11216 /*
11217  * NOTE(lsm): Must be in the same order as enum for keywords. See comment
11218  * for function get_tok() for rationale for that.
11219  */
11220 static const struct v7_vec_const s_keywords[] = {
11221     V7_VEC("break"),      V7_VEC("case"),     V7_VEC("catch"),
11222     V7_VEC("continue"),   V7_VEC("debugger"), V7_VEC("default"),
11223     V7_VEC("delete"),     V7_VEC("do"),       V7_VEC("else"),
11224     V7_VEC("false"),      V7_VEC("finally"),  V7_VEC("for"),
11225     V7_VEC("function"),   V7_VEC("if"),       V7_VEC("in"),
11226     V7_VEC("instanceof"), V7_VEC("new"),      V7_VEC("null"),
11227     V7_VEC("return"),     V7_VEC("switch"),   V7_VEC("this"),
11228     V7_VEC("throw"),      V7_VEC("true"),     V7_VEC("try"),
11229     V7_VEC("typeof"),     V7_VEC("var"),      V7_VEC("void"),
11230     V7_VEC("while"),      V7_VEC("with")};
11231 
11232 V7_PRIVATE int is_reserved_word_token(enum v7_tok tok) {
11233   return tok >= TOK_BREAK && tok <= TOK_WITH;
11234 }
11235 
11236 /*
11237  * Move ptr to the next token, skipping comments and whitespaces.
11238  * Return number of new line characters detected.
11239  */
11240 V7_PRIVATE int skip_to_next_tok(const char **ptr, const char *src_end) {
11241   const char *s = *ptr, *p = NULL;
11242   int num_lines = 0;
11243 
11244   while (s != p && s < src_end && *s != '\0' &&
11245          (isspace((unsigned char) *s) || *s == '/')) {
11246     p = s;
11247     while (s < src_end && *s != '\0' && isspace((unsigned char) *s)) {
11248       if (*s == '\n') num_lines++;
11249       s++;
11250     }
11251     if ((s + 1) < src_end && s[0] == '/' && s[1] == '/') {
11252       s += 2;
11253       while (s < src_end && s[0] != '\0' && s[0] != '\n') s++;
11254     }
11255     if ((s + 1) < src_end && s[0] == '/' && s[1] == '*') {
11256       s += 2;
11257       while (s < src_end && s[0] != '\0' && !(s[-1] == '/' && s[-2] == '*')) {
11258         if (s[0] == '\n') num_lines++;
11259         s++;
11260       }
11261     }
11262   }
11263   *ptr = s;
11264 
11265   return num_lines;
11266 }
11267 
11268 /* Advance `s` pointer to the end of identifier  */
11269 static void ident(const char **s, const char *src_end) {
11270   const unsigned char *p = (unsigned char *) *s;
11271   int n;
11272   Rune r;
11273 
11274   while ((const char *) p < src_end && p[0] != '\0') {
11275     if (p[0] == '$' || p[0] == '_' || isalnum(p[0])) {
11276       /* $, _, or any alphanumeric are valid identifier characters */
11277       p++;
11278     } else if ((const char *) (p + 5) < src_end && p[0] == '\\' &&
11279                p[1] == 'u' && isxdigit(p[2]) && isxdigit(p[3]) &&
11280                isxdigit(p[4]) && isxdigit(p[5])) {
11281       /* Unicode escape, \uXXXX . Could be used like "var \u0078 = 1;" */
11282       p += 6;
11283     } else if ((n = chartorune(&r, (char *) p)) > 1 && isalpharune(r)) {
11284       /*
11285        * TODO(dfrank): the chartorune() call above can read `p` past the
11286        * src_end, so it might crash on incorrect code. The solution would be
11287        * to modify `chartorune()` to accept src_end argument as well.
11288        */
11289       /* Unicode alphanumeric character */
11290       p += n;
11291     } else {
11292       break;
11293     }
11294   }
11295 
11296   *s = (char *) p;
11297 }
11298 
11299 static enum v7_tok kw(const char *s, size_t len, int ntoks, enum v7_tok tok) {
11300   int i;
11301 
11302   for (i = 0; i < ntoks; i++) {
11303     if (s_keywords[(tok - TOK_BREAK) + i].len == len &&
11304         memcmp(s_keywords[(tok - TOK_BREAK) + i].p + 1, s + 1, len - 1) == 0)
11305       break;
11306   }
11307 
11308   return i == ntoks ? TOK_IDENTIFIER : (enum v7_tok)(tok + i);
11309 }
11310 
11311 static enum v7_tok punct1(const char **s, const char *src_end, int ch1,
11312                           enum v7_tok tok1, enum v7_tok tok2) {
11313   (*s)++;
11314   if (*s < src_end && **s == ch1) {
11315     (*s)++;
11316     return tok1;
11317   } else {
11318     return tok2;
11319   }
11320 }
11321 
11322 static enum v7_tok punct2(const char **s, const char *src_end, int ch1,
11323                           enum v7_tok tok1, int ch2, enum v7_tok tok2,
11324                           enum v7_tok tok3) {
11325   if ((*s + 2) < src_end && s[0][1] == ch1 && s[0][2] == ch2) {
11326     (*s) += 3;
11327     return tok2;
11328   }
11329 
11330   return punct1(s, src_end, ch1, tok1, tok3);
11331 }
11332 
11333 static enum v7_tok punct3(const char **s, const char *src_end, int ch1,
11334                           enum v7_tok tok1, int ch2, enum v7_tok tok2,
11335                           enum v7_tok tok3) {
11336   (*s)++;
11337   if (*s < src_end) {
11338     if (**s == ch1) {
11339       (*s)++;
11340       return tok1;
11341     } else if (**s == ch2) {
11342       (*s)++;
11343       return tok2;
11344     }
11345   }
11346   return tok3;
11347 }
11348 
11349 static void parse_number(const char *s, const char **end, double *num) {
11350   *num = cs_strtod(s, (char **) end);
11351 }
11352 
11353 static enum v7_tok parse_str_literal(const char **p, const char *src_end) {
11354   const char *s = *p;
11355   int quote = '\0';
11356 
11357   if (s < src_end) {
11358     quote = *s++;
11359   }
11360 
11361   /* Scan string literal, handle escape sequences */
11362   for (; s < src_end && *s != '\0' && *s != quote; s++) {
11363     if (*s == '\\') {
11364       switch (s[1]) {
11365         case 'b':
11366         case 'f':
11367         case 'n':
11368         case 'r':
11369         case 't':
11370         case 'v':
11371         case '\\':
11372           s++;
11373           break;
11374         default:
11375           if (s[1] == quote) s++;
11376           break;
11377       }
11378     }
11379   }
11380 
11381   if (s < src_end && *s == quote) {
11382     s++;
11383     *p = s;
11384     return TOK_STRING_LITERAL;
11385   } else {
11386     return TOK_END_OF_INPUT;
11387   }
11388 }
11389 
11390 /*
11391  * This function is the heart of the tokenizer.
11392  * Organized as a giant switch statement.
11393  *
11394  * Switch statement is by the first character of the input stream. If first
11395  * character begins with a letter, it could be either keyword or identifier.
11396  * get_tok() calls ident() which shifts `s` pointer to the end of the word.
11397  * Now, tokenizer knows that the word begins at `p` and ends at `s`.
11398  * It calls function kw() to scan over the keywords that start with `p[0]`
11399  * letter. Therefore, keyword tokens and keyword strings must be in the
11400  * same order, to let kw() function work properly.
11401  * If kw() finds a keyword match, it returns keyword token.
11402  * Otherwise, it returns TOK_IDENTIFIER.
11403  * NOTE(lsm): `prev_tok` is a previously parsed token. It is needed for
11404  * correctly parsing regex literals.
11405  */
11406 V7_PRIVATE enum v7_tok get_tok(const char **s, const char *src_end, double *n,
11407                                enum v7_tok prev_tok) {
11408   const char *p = *s;
11409 
11410   if (p >= src_end) {
11411     return TOK_END_OF_INPUT;
11412   }
11413 
11414   switch (*p) {
11415     /* Letters */
11416     case 'a':
11417       ident(s, src_end);
11418       return TOK_IDENTIFIER;
11419     case 'b':
11420       ident(s, src_end);
11421       return kw(p, *s - p, 1, TOK_BREAK);
11422     case 'c':
11423       ident(s, src_end);
11424       return kw(p, *s - p, 3, TOK_CASE);
11425     case 'd':
11426       ident(s, src_end);
11427       return kw(p, *s - p, 4, TOK_DEBUGGER);
11428     case 'e':
11429       ident(s, src_end);
11430       return kw(p, *s - p, 1, TOK_ELSE);
11431     case 'f':
11432       ident(s, src_end);
11433       return kw(p, *s - p, 4, TOK_FALSE);
11434     case 'g':
11435     case 'h':
11436       ident(s, src_end);
11437       return TOK_IDENTIFIER;
11438     case 'i':
11439       ident(s, src_end);
11440       return kw(p, *s - p, 3, TOK_IF);
11441     case 'j':
11442     case 'k':
11443     case 'l':
11444     case 'm':
11445       ident(s, src_end);
11446       return TOK_IDENTIFIER;
11447     case 'n':
11448       ident(s, src_end);
11449       return kw(p, *s - p, 2, TOK_NEW);
11450     case 'o':
11451     case 'p':
11452     case 'q':
11453       ident(s, src_end);
11454       return TOK_IDENTIFIER;
11455     case 'r':
11456       ident(s, src_end);
11457       return kw(p, *s - p, 1, TOK_RETURN);
11458     case 's':
11459       ident(s, src_end);
11460       return kw(p, *s - p, 1, TOK_SWITCH);
11461     case 't':
11462       ident(s, src_end);
11463       return kw(p, *s - p, 5, TOK_THIS);
11464     case 'u':
11465       ident(s, src_end);
11466       return TOK_IDENTIFIER;
11467     case 'v':
11468       ident(s, src_end);
11469       return kw(p, *s - p, 2, TOK_VAR);
11470     case 'w':
11471       ident(s, src_end);
11472       return kw(p, *s - p, 2, TOK_WHILE);
11473     case 'x':
11474     case 'y':
11475     case 'z':
11476       ident(s, src_end);
11477       return TOK_IDENTIFIER;
11478 
11479     case '_':
11480     case '$':
11481     case 'A':
11482     case 'B':
11483     case 'C':
11484     case 'D':
11485     case 'E':
11486     case 'F':
11487     case 'G':
11488     case 'H':
11489     case 'I':
11490     case 'J':
11491     case 'K':
11492     case 'L':
11493     case 'M':
11494     case 'N':
11495     case 'O':
11496     case 'P':
11497     case 'Q':
11498     case 'R':
11499     case 'S':
11500     case 'T':
11501     case 'U':
11502     case 'V':
11503     case 'W':
11504     case 'X':
11505     case 'Y':
11506     case 'Z':
11507     case '\\': /* Identifier may start with unicode escape sequence */
11508       ident(s, src_end);
11509       return TOK_IDENTIFIER;
11510 
11511     /* Numbers */
11512     case '0':
11513     case '1':
11514     case '2':
11515     case '3':
11516     case '4':
11517     case '5':
11518     case '6':
11519     case '7':
11520     case '8':
11521     case '9':
11522       parse_number(p, s, n);
11523       return TOK_NUMBER;
11524 
11525     /* String literals */
11526     case '\'':
11527     case '"':
11528       return parse_str_literal(s, src_end);
11529 
11530     /* Punctuators */
11531     case '=':
11532       return punct2(s, src_end, '=', TOK_EQ, '=', TOK_EQ_EQ, TOK_ASSIGN);
11533     case '!':
11534       return punct2(s, src_end, '=', TOK_NE, '=', TOK_NE_NE, TOK_NOT);
11535 
11536     case '%':
11537       return punct1(s, src_end, '=', TOK_REM_ASSIGN, TOK_REM);
11538     case '*':
11539       return punct1(s, src_end, '=', TOK_MUL_ASSIGN, TOK_MUL);
11540     case '/':
11541       /*
11542        * TOK_DIV, TOK_DIV_ASSIGN, and TOK_REGEX_LITERAL start with `/` char.
11543        * Division can happen after an expression.
11544        * In expressions like this:
11545        *            a /= b; c /= d;
11546        * things between slashes is NOT a regex literal.
11547        * The switch below catches all cases where division happens.
11548        */
11549       switch (prev_tok) {
11550         case TOK_CLOSE_CURLY:
11551         case TOK_CLOSE_PAREN:
11552         case TOK_CLOSE_BRACKET:
11553         case TOK_IDENTIFIER:
11554         case TOK_NUMBER:
11555           return punct1(s, src_end, '=', TOK_DIV_ASSIGN, TOK_DIV);
11556         default:
11557           /* Not a division - this is a regex. Scan until closing slash */
11558           for (p++; p < src_end && *p != '\0' && *p != '\n'; p++) {
11559             if (*p == '\\') {
11560               /* Skip escape sequence */
11561               p++;
11562             } else if (*p == '/') {
11563               /* This is a closing slash */
11564               p++;
11565               /* Skip regex flags */
11566               while (*p == 'g' || *p == 'i' || *p == 'm') {
11567                 p++;
11568               }
11569               *s = p;
11570               return TOK_REGEX_LITERAL;
11571             }
11572           }
11573           break;
11574       }
11575       return punct1(s, src_end, '=', TOK_DIV_ASSIGN, TOK_DIV);
11576     case '^':
11577       return punct1(s, src_end, '=', TOK_XOR_ASSIGN, TOK_XOR);
11578 
11579     case '+':
11580       return punct3(s, src_end, '+', TOK_PLUS_PLUS, '=', TOK_PLUS_ASSIGN,
11581                     TOK_PLUS);
11582     case '-':
11583       return punct3(s, src_end, '-', TOK_MINUS_MINUS, '=', TOK_MINUS_ASSIGN,
11584                     TOK_MINUS);
11585     case '&':
11586       return punct3(s, src_end, '&', TOK_LOGICAL_AND, '=', TOK_AND_ASSIGN,
11587                     TOK_AND);
11588     case '|':
11589       return punct3(s, src_end, '|', TOK_LOGICAL_OR, '=', TOK_OR_ASSIGN,
11590                     TOK_OR);
11591 
11592     case '<':
11593       if (*s + 1 < src_end && s[0][1] == '=') {
11594         (*s) += 2;
11595         return TOK_LE;
11596       }
11597       return punct2(s, src_end, '<', TOK_LSHIFT, '=', TOK_LSHIFT_ASSIGN,
11598                     TOK_LT);
11599     case '>':
11600       if (*s + 1 < src_end && s[0][1] == '=') {
11601         (*s) += 2;
11602         return TOK_GE;
11603       }
11604       if (*s + 3 < src_end && s[0][1] == '>' && s[0][2] == '>' &&
11605           s[0][3] == '=') {
11606         (*s) += 4;
11607         return TOK_URSHIFT_ASSIGN;
11608       }
11609       if (*s + 2 < src_end && s[0][1] == '>' && s[0][2] == '>') {
11610         (*s) += 3;
11611         return TOK_URSHIFT;
11612       }
11613       return punct2(s, src_end, '>', TOK_RSHIFT, '=', TOK_RSHIFT_ASSIGN,
11614                     TOK_GT);
11615 
11616     case '{':
11617       (*s)++;
11618       return TOK_OPEN_CURLY;
11619     case '}':
11620       (*s)++;
11621       return TOK_CLOSE_CURLY;
11622     case '(':
11623       (*s)++;
11624       return TOK_OPEN_PAREN;
11625     case ')':
11626       (*s)++;
11627       return TOK_CLOSE_PAREN;
11628     case '[':
11629       (*s)++;
11630       return TOK_OPEN_BRACKET;
11631     case ']':
11632       (*s)++;
11633       return TOK_CLOSE_BRACKET;
11634     case '.':
11635       switch (*(*s + 1)) {
11636         /* Numbers */
11637         case '0':
11638         case '1':
11639         case '2':
11640         case '3':
11641         case '4':
11642         case '5':
11643         case '6':
11644         case '7':
11645         case '8':
11646         case '9':
11647           parse_number(p, s, n);
11648           return TOK_NUMBER;
11649       }
11650       (*s)++;
11651       return TOK_DOT;
11652     case ';':
11653       (*s)++;
11654       return TOK_SEMICOLON;
11655     case ':':
11656       (*s)++;
11657       return TOK_COLON;
11658     case '?':
11659       (*s)++;
11660       return TOK_QUESTION;
11661     case '~':
11662       (*s)++;
11663       return TOK_TILDA;
11664     case ',':
11665       (*s)++;
11666       return TOK_COMMA;
11667 
11668     default: {
11669       /* Handle unicode variables */
11670       Rune r;
11671       if (chartorune(&r, *s) > 1 && isalpharune(r)) {
11672         ident(s, src_end);
11673         return TOK_IDENTIFIER;
11674       }
11675       return TOK_END_OF_INPUT;
11676     }
11677   }
11678 }
11679 
11680 #ifdef TEST_RUN
11681 int main(void) {
11682   const char *src =
11683       "for (var fo++ = -1; /= <= 1.17; x<<) { == <<=, 'x')} "
11684       "Infinity %=x<<=2";
11685   const char *src_end = src + strlen(src);
11686   enum v7_tok tok;
11687   double num;
11688   const char *p = src;
11689 
11690   skip_to_next_tok(&src, src_end);
11691   while ((tok = get_tok(&src, src_end, &num)) != TOK_END_OF_INPUT) {
11692     printf("%d [%.*s]\n", tok, (int) (src - p), p);
11693     skip_to_next_tok(&src, src_end);
11694     p = src;
11695   }
11696   printf("%d [%.*s]\n", tok, (int) (src - p), p);
11697 
11698   return 0;
11699 }
11700 #endif
11701 
11702 #endif /* V7_NO_COMPILER */
11703 #ifdef V7_MODULE_LINES
11704 #line 1 "v7/src/ast.c"
11705 #endif
11706 /*
11707  * Copyright (c) 2014 Cesanta Software Limited
11708  * All rights reserved
11709  */
11710 
11711 /* Amalgamated: #include "common/cs_strtod.h" */
11712 /* Amalgamated: #include "common/mbuf.h" */
11713 
11714 /* Amalgamated: #include "v7/src/internal.h" */
11715 /* Amalgamated: #include "v7/src/varint.h" */
11716 /* Amalgamated: #include "v7/src/ast.h" */
11717 /* Amalgamated: #include "v7/src/core.h" */
11718 /* Amalgamated: #include "v7/src/string.h" */
11719 /* Amalgamated: #include "common/str_util.h" */
11720 
11721 #if !defined(V7_NO_COMPILER)
11722 
11723 #ifdef V7_LARGE_AST
11724 typedef uint32_t ast_skip_t;
11725 #else
11726 typedef uint16_t ast_skip_t;
11727 #define AST_SKIP_MAX UINT16_MAX
11728 #endif
11729 
11730 #ifndef V7_DISABLE_AST_TAG_NAMES
11731 #define AST_ENTRY(name, has_varint, has_inlined, num_skips, num_subtrees) \
11732   { (name), (has_varint), (has_inlined), (num_skips), (num_subtrees) }
11733 #else
11734 #define AST_ENTRY(name, has_varint, has_inlined, num_skips, num_subtrees) \
11735   { (has_varint), (has_inlined), (num_skips), (num_subtrees) }
11736 #endif
11737 
11738 /*
11739  * The structure of AST nodes cannot be described in portable ANSI C,
11740  * since they are variable length and packed (unaligned).
11741  *
11742  * Here each node's body is described with a pseudo-C structure notation.
11743  * The pseudo type `child` represents a variable length byte sequence
11744  * representing a fully serialized child node.
11745  *
11746  * `child body[]` represents a sequence of such subtrees.
11747  *
11748  * Pseudo-labels, such as `end:` represent the targets of skip fields
11749  * with the same name (e.g. `ast_skip_t end`).
11750  *
11751  * Skips allow skipping a subtree or sequence of subtrees.
11752  *
11753  * Sequences of subtrees (i.e. `child []`) have to be terminated by a skip:
11754  * they don't have a termination tag; all nodes whose position is before the
11755  * skip are part of the sequence.
11756  *
11757  * Skips are encoded as network-byte-order 16-bit offsets counted from the
11758  * first byte of the node body (i.e. not counting the tag itself).
11759  * This currently limits the the maximum size of a function body to 64k.
11760  *
11761  * Notes:
11762  *
11763  * - Some nodes contain skips just for performance or because it simplifies
11764  * the implementation of the interpreter. For example, technically, the FOR
11765  * node doesn't need the `body` skip in order to be correctly traversed.
11766  * However, being able to quickly skip the `iter` expression is useful
11767  * also because it allows the interpreter to avoid traversing the expression
11768  * subtree without evaluating it, just in order to find the next subtree.
11769  *
11770  * - The name `skip` was chosen because `offset` was too overloaded in general
11771  * and label` is part of our domain model (i.e. JS has a label AST node type).
11772  *
11773  *
11774  * So, each node has a mandatory field: *tag* (see `enum ast_tag`), and a
11775  * number of optional fields. Whether the node has one or another optional
11776  * field is determined by the *node descriptor*: `struct ast_node_def`. For
11777  * each node type (i.e. for each element of `enum ast_tag`) there is a
11778  * corresponding descriptor: see `ast_node_defs`.
11779  *
11780  * Optional fields are:
11781  *
11782  * - *varint*: a varint-encoded number. At the moment, this field is only used
11783  *   together with the next field: inlined data, and a varint number determines
11784  *   the inlined data length.
11785  * - *inlined data*: a node-specific data. Size of it is determined by the
11786  *   previous field: varint.
11787  * - *skips*: as explained above, these are integer offsets, encoded in
11788  *   big-endian. The number of skips is determined by the node descriptor
11789  *   (`struct ast_node_def`). The size of each skip is either 16 or 32 bits,
11790  *   depending on whether the macro `V7_LARGE_AST` is set. The order of skips
11791  *   is determined by the `enum ast_which_skip`. See examples below for
11792  *   clarity.
11793  * - *subtrees*: child nodes. Some nodes have fixed number of child nodes; in
11794  *   this case, the descriptor has non-zero field `num_subtrees`.  Otherwise,
11795  *   `num_subtrees` is zero, and consumer handles child nodes one by one, until
11796  *   the end of the node is reached (end of the node is determined by the `end`
11797  *   skip)
11798  *
11799  *
11800  * Examples:
11801  *
11802  * Let's start from the very easy example script: "300;"
11803  *
11804  * Tree looks as follows:
11805  *
11806  *    $ ./v7 -e "300;" -t
11807  *      SCRIPT
11808  *        /- [...] -/
11809  *        NUM 300
11810  *
11811  * Binary data is:
11812  *
11813  *    $ ./v7 -e "300;" -b | od -A n -t x1
11814  *    56 07 41 53 54 56 31 30 00 01 00 09 00 00 13 03
11815  *    33 30 30
11816  *
11817  * Let's break it down and examine:
11818  *
11819  *    - 56 07 41 53 54 56 31 30 00
11820  *        Just a format prefix:
11821  *        Null-terminated string: `"V\007ASTV10"` (see `BIN_AST_SIGNATURE`)
11822  *    - 01
11823  *        AST tag: `AST_SCRIPT`. As you see in `ast_node_defs` below, node of
11824  *        this type has neither *varint* nor *inlined data* fields, but it has
11825  *        2 skips: `end` and `next`. `end` is a skip to the end of the current
11826  *        node (`SCRIPT`), and `next` will be explained below.
11827  *
11828  *        The size of each skip depends on whether `V7_LARGE_AST` is defined.
11829  *        If it is, then size is 32 bit, otherwise it's 16 bit. In this
11830  *        example, we have 16-bit skips.
11831  *
11832  *        The order of skips is determined by the `enum ast_which_skip`. If you
11833  *        check, you'll see that `AST_END_SKIP` is 0, and `AST_VAR_NEXT_SKIP`
11834  *        is 1. So, `end` skip fill be the first, and `next` will be the second:
11835  *    - 00 09
11836  *        `end` skip: 9 bytes. It's the size of the whole `SCRIPT` data. So, if
11837  *        we have an index of the `ASC_SCRIPT` tag, we can just add this skip
11838  *        (9) to this index, and therefore skip over the whole node.
11839  *    - 00 00
11840  *        `next` skip. `next` actually means "next variable node": since
11841  *        variables are hoisted in JavaScript, when the interpreter starts
11842  *        executing a top-level code or any function, it needs to get a list of
11843  *        all defined variables. The `SCRIPT` node has a "skip" to the first
11844  *        `var` or `function` declaration, which, in turn, has a "skip" to the
11845  *        next one, etc. If there is no next `var` declaration, then 0 is
11846  *        stored.
11847  *
11848  *        In our super-simple script, we have no `var` neither `function`
11849  *        declarations, so, this skip is 0.
11850  *
11851  *        Now, the body of our SCRIPT node goes, which contains child nodes:
11852  *
11853  *    - 13
11854  *        AST tag: `AST_NUM`. Look at the `ast_node_defs`, and we'll see that
11855  *        nodes of this type don't have any skips, but they do have the varint
11856  *        field and the inlined data. Here we go:
11857  *    - 03
11858  *        Varint value: 3
11859  *    - 33 30 30
11860  *        UTF-8 string "300"
11861  *
11862  * ---------------
11863  *
11864  * The next example is a bit more interesting:
11865  *
11866  *    var foo,
11867  *        bar = 1;
11868  *    foo = 3;
11869  *    var baz = 4;
11870  *
11871  * Tree:
11872  *
11873  *    $ ./v7 -e 'var foo, bar=1; foo=3; var baz = 4;' -t
11874  *    SCRIPT
11875  *      /- [...] -/
11876  *      VAR
11877  *        /- [...] -/
11878  *        VAR_DECL foo
11879  *          NOP
11880  *        VAR_DECL bar
11881  *          NUM 1
11882  *      ASSIGN
11883  *        IDENT foo
11884  *        NUM 3
11885  *      VAR
11886  *        /- [...] -/
11887  *        VAR_DECL baz
11888  *          NUM 4
11889  *
11890  * Binary:
11891  *
11892  *    $ ./v7 -e 'var foo, bar=1; foo=3; var baz = 4;' -b | od -A n -t x1
11893  *    56 07 41 53 54 56 31 30 00 01 00 2d 00 05 02 00
11894  *    12 00 1c 03 03 66 6f 6f 00 03 03 62 61 72 13 01
11895  *    31 07 14 03 66 6f 6f 13 01 33 02 00 0c 00 00 03
11896  *    03 62 61 7a 13 01 34
11897  *
11898  * Break it down:
11899  *
11900  *    - 56 07 41 53 54 56 31 30 00
11901  *        `"V\007ASTV10"`
11902  *    - 01:       AST tag: `AST_SCRIPT`
11903  *    - 00 2d:    `end` skip: 0x2d = 45 bytes
11904  *    - 00 05:    `next` skip: an offset from `AST_SCRIPT` byte to the first
11905  *                `var` declaration.
11906  *
11907  *        Now, body of the SCRIPT node begins, which contains child nodes,
11908  *        and the first node is the var declaration `var foo, bar=1;`:
11909  *
11910  *        SCRIPT node body: {{{
11911  *    - 02:       AST tag: `AST_VAR`
11912  *    - 00 12:    `end` skip: 18 bytes from tag byte to the end of current node
11913  *    - 00 1c:    `next` skip: 28 bytes from tag byte to the next `var` node
11914  *
11915  *        The VAR node contains arbitrary number of child nodes, so, consumer
11916  *        takes advantage of the `end` skip.
11917  *
11918  *        VAR node body: {{{
11919  *    - 03:       AST tag: `AST_VAR_DECL`
11920  *    - 03:       Varint value: 3 (the length of the inlined data: a variable
11921  *name)
11922  *    - 66 6f 6f: UTF-8 string: "foo"
11923  *    - 00:       AST tag: `AST_NOP`
11924  *                Since we haven't provided any value to store into `foo`, NOP
11925  *                without any additional data is stored in AST.
11926  *
11927  *    - 03:       AST tag: `AST_VAR_DECL`
11928  *    - 03:       Varint value: 3 (the length of the inlined data: a variable
11929  *name)
11930  *    - 62 61 72: UTF-8 string: "bar"
11931  *    - 13:       AST tag: `AST_NUM`
11932  *    - 01:       Varint value: 1
11933  *    - 31:       UTF-8 string "1"
11934  *        VAR body end }}}
11935  *
11936  *    - 07:       AST tag: `AST_ASSIGN`
11937  *
11938  *        The ASSIGN node has fixed number of subrees: 2 (lvalue and rvalue),
11939  *        so there's no `end` skip.
11940  *
11941  *        ASSIGN node body: {{{
11942  *    - 14:       AST tag: `AST_IDENT`
11943  *    - 03:       Varint value: 3
11944  *    - 66 6f 6f: UTF-8 string: "foo"
11945  *
11946  *    - 13:       AST tag: `AST_NUM`
11947  *    - 01:       Varint value: 1
11948  *    - 33:       UTF-8 string: "3"
11949  *        ASSIGN body end }}}
11950  *
11951  *    - 02:       AST tag: `AST_VAR`
11952  *    - 00 0c:    `end` skip: 12 bytes from tag byte to the end of current node
11953  *    - 00 00:    `next` skip: no more `var` nodes
11954  *
11955  *        VAR node body: {{{
11956  *    - 03:       AST tag: `AST_VAR_DECL`
11957  *    - 03:       Varint value: 3 (the length of the inlined data: a variable
11958  *name)
11959  *    - 62 61 7a: UTF-8 string: "baz"
11960  *    - 13:       AST tag: `AST_NUM`
11961  *    - 01:       Varint value: 1
11962  *    - 34:       UTF-8 string "4"
11963  *        VAR body end }}}
11964  *        SCRIPT body end }}}
11965  *
11966  * --------------------------
11967  */
11968 
11969 const struct ast_node_def ast_node_defs[] = {
11970     AST_ENTRY("NOP", 0, 0, 0, 0), /* struct {} */
11971 
11972     /*
11973      * struct {
11974      *   ast_skip_t end;
11975      *   ast_skip_t first_var;
11976      *   child body[];
11977      * end:
11978      * }
11979      */
11980     AST_ENTRY("SCRIPT", 0, 0, 2, 0),
11981     /*
11982      * struct {
11983      *   ast_skip_t end;
11984      *   ast_skip_t next;
11985      *   child decls[];
11986      * end:
11987      * }
11988      */
11989     AST_ENTRY("VAR", 0, 0, 2, 0),
11990     /*
11991      * struct {
11992      *   varint len;
11993      *   char name[len];
11994      *   child expr;
11995      * }
11996      */
11997     AST_ENTRY("VAR_DECL", 1, 1, 0, 1),
11998     /*
11999      * struct {
12000      *   varint len;
12001      *   char name[len];
12002      *   child expr;
12003      * }
12004      */
12005     AST_ENTRY("FUNC_DECL", 1, 1, 0, 1),
12006     /*
12007      * struct {
12008      *   ast_skip_t end;
12009      *   ast_skip_t end_true;
12010      *   child cond;
12011      *   child iftrue[];
12012      * end_true:
12013      *   child iffalse[];
12014      * end:
12015      * }
12016      */
12017     AST_ENTRY("IF", 0, 0, 2, 1),
12018     /*
12019      * TODO(mkm) distinguish function expressions
12020      * from function statements.
12021      * Function statements behave like vars and need a
12022      * next field for hoisting.
12023      * We can also ignore the name for function expressions
12024      * if it's only needed for debugging.
12025      *
12026      * struct {
12027      *   ast_skip_t end;
12028      *   ast_skip_t first_var;
12029      *   ast_skip_t body;
12030      *   child name;
12031      *   child params[];
12032      * body:
12033      *   child body[];
12034      * end:
12035      * }
12036      */
12037     AST_ENTRY("FUNC", 0, 0, 3, 1),
12038     AST_ENTRY("ASSIGN", 0, 0, 0, 2),         /* struct { child left, right; } */
12039     AST_ENTRY("REM_ASSIGN", 0, 0, 0, 2),     /* struct { child left, right; } */
12040     AST_ENTRY("MUL_ASSIGN", 0, 0, 0, 2),     /* struct { child left, right; } */
12041     AST_ENTRY("DIV_ASSIGN", 0, 0, 0, 2),     /* struct { child left, right; } */
12042     AST_ENTRY("XOR_ASSIGN", 0, 0, 0, 2),     /* struct { child left, right; } */
12043     AST_ENTRY("PLUS_ASSIGN", 0, 0, 0, 2),    /* struct { child left, right; } */
12044     AST_ENTRY("MINUS_ASSIGN", 0, 0, 0, 2),   /* struct { child left, right; } */
12045     AST_ENTRY("OR_ASSIGN", 0, 0, 0, 2),      /* struct { child left, right; } */
12046     AST_ENTRY("AND_ASSIGN", 0, 0, 0, 2),     /* struct { child left, right; } */
12047     AST_ENTRY("LSHIFT_ASSIGN", 0, 0, 0, 2),  /* struct { child left, right; } */
12048     AST_ENTRY("RSHIFT_ASSIGN", 0, 0, 0, 2),  /* struct { child left, right; } */
12049     AST_ENTRY("URSHIFT_ASSIGN", 0, 0, 0, 2), /* struct { child left, right; } */
12050     AST_ENTRY("NUM", 1, 1, 0, 0),    /* struct { varint len, char s[len]; } */
12051     AST_ENTRY("IDENT", 1, 1, 0, 0),  /* struct { varint len, char s[len]; } */
12052     AST_ENTRY("STRING", 1, 1, 0, 0), /* struct { varint len, char s[len]; } */
12053     AST_ENTRY("REGEX", 1, 1, 0, 0),  /* struct { varint len, char s[len]; } */
12054     AST_ENTRY("LABEL", 1, 1, 0, 0),  /* struct { varint len, char s[len]; } */
12055 
12056     /*
12057      * struct {
12058      *   ast_skip_t end;
12059      *   child body[];
12060      * end:
12061      * }
12062      */
12063     AST_ENTRY("SEQ", 0, 0, 1, 0),
12064     /*
12065      * struct {
12066      *   ast_skip_t end;
12067      *   child cond;
12068      *   child body[];
12069      * end:
12070      * }
12071      */
12072     AST_ENTRY("WHILE", 0, 0, 1, 1),
12073     /*
12074      * struct {
12075      *   ast_skip_t end;
12076      *   ast_skip_t cond;
12077      *   child body[];
12078      * cond:
12079      *   child cond;
12080      * end:
12081      * }
12082      */
12083     AST_ENTRY("DOWHILE", 0, 0, 2, 0),
12084     /*
12085      * struct {
12086      *   ast_skip_t end;
12087      *   ast_skip_t body;
12088      *   child init;
12089      *   child cond;
12090      *   child iter;
12091      * body:
12092      *   child body[];
12093      * end:
12094      * }
12095      */
12096     AST_ENTRY("FOR", 0, 0, 2, 3),
12097     /*
12098      * struct {
12099      *   ast_skip_t end;
12100      *   ast_skip_t dummy; // allows to quickly promote a for to a for in
12101      *   child var;
12102      *   child expr;
12103      *   child dummy;
12104      *   child body[];
12105      * end:
12106      * }
12107      */
12108     AST_ENTRY("FOR_IN", 0, 0, 2, 3),
12109     AST_ENTRY("COND", 0, 0, 0, 3), /* struct { child cond, iftrue, iffalse; } */
12110     AST_ENTRY("DEBUGGER", 0, 0, 0, 0), /* struct {} */
12111     AST_ENTRY("BREAK", 0, 0, 0, 0),    /* struct {} */
12112 
12113     /*
12114      * struct {
12115      *   child label; // TODO(mkm): inline
12116      * }
12117      */
12118     AST_ENTRY("LAB_BREAK", 0, 0, 0, 1),
12119     AST_ENTRY("CONTINUE", 0, 0, 0, 0), /* struct {} */
12120 
12121     /*
12122      * struct {
12123      *   child label; // TODO(mkm): inline
12124      * }
12125      */
12126     AST_ENTRY("LAB_CONTINUE", 0, 0, 0, 1),
12127     AST_ENTRY("RETURN", 0, 0, 0, 0),     /* struct {} */
12128     AST_ENTRY("VAL_RETURN", 0, 0, 0, 1), /* struct { child expr; } */
12129     AST_ENTRY("THROW", 0, 0, 0, 1),      /* struct { child expr; } */
12130 
12131     /*
12132      * struct {
12133      *   ast_skip_t end;
12134      *   ast_skip_t catch;
12135      *   ast_skip_t finally;
12136      *   child try[];
12137      * catch:
12138      *   child var; // TODO(mkm): inline
12139      *   child catch[];
12140      * finally:
12141      *   child finally[];
12142      * end:
12143      * }
12144      */
12145     AST_ENTRY("TRY", 0, 0, 3, 1),
12146     /*
12147      * struct {
12148      *   ast_skip_t end;
12149      *   ast_skip_t def;
12150      *   child expr;
12151      *   child cases[];
12152      * def:
12153      *   child default?; // optional
12154      * end:
12155      * }
12156      */
12157     AST_ENTRY("SWITCH", 0, 0, 2, 1),
12158     /*
12159      * struct {
12160      *   ast_skip_t end;
12161      *   child val;
12162      *   child stmts[];
12163      * end:
12164      * }
12165      */
12166     AST_ENTRY("CASE", 0, 0, 1, 1),
12167     /*
12168      * struct {
12169      *   ast_skip_t end;
12170      *   child stmts[];
12171      * end:
12172      * }
12173      */
12174     AST_ENTRY("DEFAULT", 0, 0, 1, 0),
12175     /*
12176      * struct {
12177      *   ast_skip_t end;
12178      *   child expr;
12179      *   child body[];
12180      * end:
12181      * }
12182      */
12183     AST_ENTRY("WITH", 0, 0, 1, 1),
12184     AST_ENTRY("LOG_OR", 0, 0, 0, 2),      /* struct { child left, right; } */
12185     AST_ENTRY("LOG_AND", 0, 0, 0, 2),     /* struct { child left, right; } */
12186     AST_ENTRY("OR", 0, 0, 0, 2),          /* struct { child left, right; } */
12187     AST_ENTRY("XOR", 0, 0, 0, 2),         /* struct { child left, right; } */
12188     AST_ENTRY("AND", 0, 0, 0, 2),         /* struct { child left, right; } */
12189     AST_ENTRY("EQ", 0, 0, 0, 2),          /* struct { child left, right; } */
12190     AST_ENTRY("EQ_EQ", 0, 0, 0, 2),       /* struct { child left, right; } */
12191     AST_ENTRY("NE", 0, 0, 0, 2),          /* struct { child left, right; } */
12192     AST_ENTRY("NE_NE", 0, 0, 0, 2),       /* struct { child left, right; } */
12193     AST_ENTRY("LE", 0, 0, 0, 2),          /* struct { child left, right; } */
12194     AST_ENTRY("LT", 0, 0, 0, 2),          /* struct { child left, right; } */
12195     AST_ENTRY("GE", 0, 0, 0, 2),          /* struct { child left, right; } */
12196     AST_ENTRY("GT", 0, 0, 0, 2),          /* struct { child left, right; } */
12197     AST_ENTRY("IN", 0, 0, 0, 2),          /* struct { child left, right; } */
12198     AST_ENTRY("INSTANCEOF", 0, 0, 0, 2),  /* struct { child left, right; } */
12199     AST_ENTRY("LSHIFT", 0, 0, 0, 2),      /* struct { child left, right; } */
12200     AST_ENTRY("RSHIFT", 0, 0, 0, 2),      /* struct { child left, right; } */
12201     AST_ENTRY("URSHIFT", 0, 0, 0, 2),     /* struct { child left, right; } */
12202     AST_ENTRY("ADD", 0, 0, 0, 2),         /* struct { child left, right; } */
12203     AST_ENTRY("SUB", 0, 0, 0, 2),         /* struct { child left, right; } */
12204     AST_ENTRY("REM", 0, 0, 0, 2),         /* struct { child left, right; } */
12205     AST_ENTRY("MUL", 0, 0, 0, 2),         /* struct { child left, right; } */
12206     AST_ENTRY("DIV", 0, 0, 0, 2),         /* struct { child left, right; } */
12207     AST_ENTRY("POS", 0, 0, 0, 1),         /* struct { child expr; } */
12208     AST_ENTRY("NEG", 0, 0, 0, 1),         /* struct { child expr; } */
12209     AST_ENTRY("NOT", 0, 0, 0, 1),         /* struct { child expr; } */
12210     AST_ENTRY("LOGICAL_NOT", 0, 0, 0, 1), /* struct { child expr; } */
12211     AST_ENTRY("VOID", 0, 0, 0, 1),        /* struct { child expr; } */
12212     AST_ENTRY("DELETE", 0, 0, 0, 1),      /* struct { child expr; } */
12213     AST_ENTRY("TYPEOF", 0, 0, 0, 1),      /* struct { child expr; } */
12214     AST_ENTRY("PREINC", 0, 0, 0, 1),      /* struct { child expr; } */
12215     AST_ENTRY("PREDEC", 0, 0, 0, 1),      /* struct { child expr; } */
12216     AST_ENTRY("POSTINC", 0, 0, 0, 1),     /* struct { child expr; } */
12217     AST_ENTRY("POSTDEC", 0, 0, 0, 1),     /* struct { child expr; } */
12218 
12219     /*
12220      * struct {
12221      *   varint len;
12222      *   char ident[len];
12223      *   child expr;
12224      * }
12225      */
12226     AST_ENTRY("MEMBER", 1, 1, 0, 1),
12227     /*
12228      * struct {
12229      *   child expr;
12230      *   child index;
12231      * }
12232      */
12233     AST_ENTRY("INDEX", 0, 0, 0, 2),
12234     /*
12235      * struct {
12236      *   ast_skip_t end;
12237      *   child expr;
12238      *   child args[];
12239      * end:
12240      * }
12241      */
12242     AST_ENTRY("CALL", 0, 0, 1, 1),
12243     /*
12244      * struct {
12245      *   ast_skip_t end;
12246      *   child expr;
12247      *   child args[];
12248      * end:
12249      * }
12250      */
12251     AST_ENTRY("NEW", 0, 0, 1, 1),
12252     /*
12253      * struct {
12254      *   ast_skip_t end;
12255      *   child elements[];
12256      * end:
12257      * }
12258      */
12259     AST_ENTRY("ARRAY", 0, 0, 1, 0),
12260     /*
12261      * struct {
12262      *   ast_skip_t end;
12263      *   child props[];
12264      * end:
12265      * }
12266      */
12267     AST_ENTRY("OBJECT", 0, 0, 1, 0),
12268     /*
12269      * struct {
12270      *   varint len;
12271      *   char name[len];
12272      *   child expr;
12273      * }
12274      */
12275     AST_ENTRY("PROP", 1, 1, 0, 1),
12276     /*
12277      * struct {
12278      *   child func;
12279      * }
12280      */
12281     AST_ENTRY("GETTER", 0, 0, 0, 1),
12282     /*
12283      * struct {
12284      *   child func;
12285      * end:
12286      * }
12287      */
12288     AST_ENTRY("SETTER", 0, 0, 0, 1),
12289     AST_ENTRY("THIS", 0, 0, 0, 0),       /* struct {} */
12290     AST_ENTRY("TRUE", 0, 0, 0, 0),       /* struct {} */
12291     AST_ENTRY("FALSE", 0, 0, 0, 0),      /* struct {} */
12292     AST_ENTRY("NULL", 0, 0, 0, 0),       /* struct {} */
12293     AST_ENTRY("UNDEF", 0, 0, 0, 0),      /* struct {} */
12294     AST_ENTRY("USE_STRICT", 0, 0, 0, 0), /* struct {} */
12295 };
12296 
12297 /*
12298  * A flag which is used to mark node's tag byte if the node has line number
12299  * data encoded (varint after skips). See `ast_get_line_no()`.
12300  */
12301 #define AST_TAG_LINENO_PRESENT 0x80
12302 
12303 V7_STATIC_ASSERT(AST_MAX_TAG < 256, ast_tag_should_fit_in_char);
12304 V7_STATIC_ASSERT(AST_MAX_TAG == ARRAY_SIZE(ast_node_defs), bad_node_defs);
12305 V7_STATIC_ASSERT(AST_MAX_TAG <= AST_TAG_LINENO_PRESENT, bad_AST_LINE_NO);
12306 
12307 #if V7_ENABLE_FOOTPRINT_REPORT
12308 const size_t ast_node_defs_size = sizeof(ast_node_defs);
12309 const size_t ast_node_defs_count = ARRAY_SIZE(ast_node_defs);
12310 #endif
12311 
12312 /*
12313  * Converts a given byte `t` (which should be read from the AST data buffer)
12314  * into `enum ast_tag`. This function is needed because tag might be marked
12315  * with the `AST_TAG_LINENO_PRESENT` flag; the returned tag is always unmarked,
12316  * and if the flag was indeed set, `lineno_present` is set to 1; otherwise
12317  * it is set to 0.
12318  *
12319  * `lineno_present` is allowed to be NULL, if the caller doesn't care of the
12320  * line number presence.
12321  */
12322 static enum ast_tag uint8_to_tag(uint8_t t, uint8_t *lineno_present) {
12323   if (t & AST_TAG_LINENO_PRESENT) {
12324     t &= ~AST_TAG_LINENO_PRESENT;
12325     if (lineno_present != NULL) {
12326       *lineno_present = 1;
12327     }
12328   } else if (lineno_present != NULL) {
12329     *lineno_present = 0;
12330   }
12331   return (enum ast_tag) t;
12332 }
12333 
12334 V7_PRIVATE ast_off_t
12335 ast_insert_node(struct ast *a, ast_off_t pos, enum ast_tag tag) {
12336   uint8_t t = (uint8_t) tag;
12337   const struct ast_node_def *d = &ast_node_defs[tag];
12338   ast_off_t cur = pos;
12339 
12340   assert(tag < AST_MAX_TAG);
12341 
12342   mbuf_insert(&a->mbuf, cur, (char *) &t, sizeof(t));
12343   cur += sizeof(t);
12344 
12345   mbuf_insert(&a->mbuf, cur, NULL, sizeof(ast_skip_t) * d->num_skips);
12346   cur += sizeof(ast_skip_t) * d->num_skips;
12347 
12348   if (d->num_skips) {
12349     ast_set_skip(a, pos + 1, AST_END_SKIP);
12350   }
12351 
12352   return pos + 1;
12353 }
12354 
12355 V7_PRIVATE void ast_modify_tag(struct ast *a, ast_off_t tag_off,
12356                                enum ast_tag tag) {
12357   a->mbuf.buf[tag_off] = tag | (a->mbuf.buf[tag_off] & 0x80);
12358 }
12359 
12360 #ifndef V7_DISABLE_LINE_NUMBERS
12361 V7_PRIVATE void ast_add_line_no(struct ast *a, ast_off_t tag_off, int line_no) {
12362   ast_off_t ln_off = tag_off + 1 /* tag byte */;
12363   int llen = calc_llen(line_no);
12364 
12365   ast_move_to_inlined_data(a, &ln_off);
12366   mbuf_insert(&a->mbuf, ln_off, NULL, llen);
12367   encode_varint(line_no, (unsigned char *) (a->mbuf.buf + ln_off));
12368 
12369   assert(a->mbuf.buf[tag_off] < AST_MAX_TAG);
12370   a->mbuf.buf[tag_off] |= AST_TAG_LINENO_PRESENT;
12371 }
12372 #endif
12373 
12374 V7_PRIVATE ast_off_t
12375 ast_set_skip(struct ast *a, ast_off_t pos, enum ast_which_skip skip) {
12376   return ast_modify_skip(a, pos, a->mbuf.len, skip);
12377 }
12378 
12379 V7_PRIVATE ast_off_t ast_modify_skip(struct ast *a, ast_off_t pos,
12380                                      ast_off_t where,
12381                                      enum ast_which_skip skip) {
12382   uint8_t *p = (uint8_t *) a->mbuf.buf + pos + skip * sizeof(ast_skip_t);
12383   ast_skip_t delta = where - pos;
12384 #ifndef NDEBUG
12385   enum ast_tag tag = uint8_to_tag(*(a->mbuf.buf + pos - 1), NULL);
12386   const struct ast_node_def *def = &ast_node_defs[tag];
12387 #endif
12388   assert(pos <= where);
12389 
12390 #ifndef V7_LARGE_AST
12391   /* the value of delta overflowed, therefore the ast is not useable */
12392   if (where - pos > AST_SKIP_MAX) {
12393     a->has_overflow = 1;
12394   }
12395 #endif
12396 
12397   /* assertion, to be optimizable out */
12398   assert((int) skip < def->num_skips);
12399 
12400 #ifdef V7_LARGE_AST
12401   p[0] = delta >> 24;
12402   p[1] = delta >> 16 & 0xff;
12403   p[2] = delta >> 8 & 0xff;
12404   p[3] = delta & 0xff;
12405 #else
12406   p[0] = delta >> 8;
12407   p[1] = delta & 0xff;
12408 #endif
12409   return where;
12410 }
12411 
12412 V7_PRIVATE ast_off_t
12413 ast_get_skip(struct ast *a, ast_off_t pos, enum ast_which_skip skip) {
12414   uint8_t *p;
12415   assert(pos + skip * sizeof(ast_skip_t) < a->mbuf.len);
12416 
12417   p = (uint8_t *) a->mbuf.buf + pos + skip * sizeof(ast_skip_t);
12418 #ifdef V7_LARGE_AST
12419   return pos + (p[3] | p[2] << 8 | p[1] << 16 | p[0] << 24);
12420 #else
12421   return pos + (p[1] | p[0] << 8);
12422 #endif
12423 }
12424 
12425 V7_PRIVATE enum ast_tag ast_fetch_tag(struct ast *a, ast_off_t *ppos) {
12426   enum ast_tag ret;
12427   assert(*ppos < a->mbuf.len);
12428 
12429   ret = uint8_to_tag(*(a->mbuf.buf + (*ppos)++), NULL);
12430 
12431   return ret;
12432 }
12433 
12434 V7_PRIVATE void ast_move_to_children(struct ast *a, ast_off_t *ppos) {
12435   enum ast_tag tag = uint8_to_tag(*(a->mbuf.buf + *ppos - 1), NULL);
12436   const struct ast_node_def *def = &ast_node_defs[tag];
12437   assert(*ppos - 1 < a->mbuf.len);
12438 
12439   ast_move_to_inlined_data(a, ppos);
12440 
12441   /* skip varint + inline data, if present */
12442   if (def->has_varint) {
12443     int llen;
12444     size_t slen = decode_varint((unsigned char *) a->mbuf.buf + *ppos, &llen);
12445     *ppos += llen;
12446     if (def->has_inlined) {
12447       *ppos += slen;
12448     }
12449   }
12450 }
12451 
12452 V7_PRIVATE ast_off_t ast_insert_inlined_node(struct ast *a, ast_off_t pos,
12453                                              enum ast_tag tag, const char *name,
12454                                              size_t len) {
12455   const struct ast_node_def *d = &ast_node_defs[tag];
12456 
12457   ast_off_t offset = ast_insert_node(a, pos, tag);
12458 
12459   assert(d->has_inlined);
12460 
12461   embed_string(&a->mbuf, offset + sizeof(ast_skip_t) * d->num_skips, name, len,
12462                EMBSTR_UNESCAPE);
12463 
12464   return offset;
12465 }
12466 
12467 V7_PRIVATE int ast_get_line_no(struct ast *a, ast_off_t pos) {
12468   /*
12469    * by default we'll return 0, meaning that the AST node does not contain line
12470    * number data
12471    */
12472   int ret = 0;
12473 
12474 #ifndef V7_DISABLE_LINE_NUMBERS
12475   uint8_t lineno_present;
12476   enum ast_tag tag = uint8_to_tag(*(a->mbuf.buf + pos - 1), &lineno_present);
12477 
12478   if (lineno_present) {
12479     /* line number is present, so, let's decode it */
12480     int llen;
12481 
12482     /* skip skips */
12483     pos += ast_node_defs[tag].num_skips * sizeof(ast_skip_t);
12484 
12485     /* get line number */
12486     ret = decode_varint((unsigned char *) a->mbuf.buf + pos, &llen);
12487   }
12488 #else
12489   (void) a;
12490   (void) pos;
12491 #endif
12492 
12493   return ret;
12494 }
12495 
12496 V7_PRIVATE void ast_move_to_inlined_data(struct ast *a, ast_off_t *ppos) {
12497   uint8_t lineno_present = 0;
12498   enum ast_tag tag = uint8_to_tag(*(a->mbuf.buf + *ppos - 1), &lineno_present);
12499   const struct ast_node_def *def = &ast_node_defs[tag];
12500   assert(*ppos - 1 < a->mbuf.len);
12501 
12502   /* skip skips */
12503   *ppos += def->num_skips * sizeof(ast_skip_t);
12504 
12505   /* skip line_no, if present */
12506   if (lineno_present) {
12507     int llen;
12508     int line_no = decode_varint((unsigned char *) a->mbuf.buf + *ppos, &llen);
12509     *ppos += llen;
12510 
12511     (void) line_no;
12512   }
12513 }
12514 
12515 V7_PRIVATE char *ast_get_inlined_data(struct ast *a, ast_off_t pos, size_t *n) {
12516   int llen;
12517   assert(pos < a->mbuf.len);
12518 
12519   ast_move_to_inlined_data(a, &pos);
12520 
12521   *n = decode_varint((unsigned char *) a->mbuf.buf + pos, &llen);
12522   return a->mbuf.buf + pos + llen;
12523 }
12524 
12525 V7_PRIVATE double ast_get_num(struct ast *a, ast_off_t pos) {
12526   double ret;
12527   char *str;
12528   size_t str_len;
12529   char buf[12];
12530   char *p = buf;
12531   str = ast_get_inlined_data(a, pos, &str_len);
12532   assert(str + str_len <= a->mbuf.buf + a->mbuf.len);
12533 
12534   if (str_len > sizeof(buf) - 1) {
12535     p = (char *) malloc(str_len + 1);
12536   }
12537   strncpy(p, str, str_len);
12538   p[str_len] = '\0';
12539   ret = cs_strtod(p, NULL);
12540   if (p != buf) free(p);
12541   return ret;
12542 }
12543 
12544 #ifndef NO_LIBC
12545 static void comment_at_depth(FILE *fp, const char *fmt, int depth, ...) {
12546   int i;
12547   STATIC char buf[256];
12548   va_list ap;
12549   va_start(ap, depth);
12550 
12551   c_vsnprintf(buf, sizeof(buf), fmt, ap);
12552 
12553   for (i = 0; i < depth; i++) {
12554     fprintf(fp, "  ");
12555   }
12556   fprintf(fp, "/* [%s] */\n", buf);
12557 }
12558 #endif
12559 
12560 V7_PRIVATE void ast_skip_tree(struct ast *a, ast_off_t *ppos) {
12561   enum ast_tag tag = ast_fetch_tag(a, ppos);
12562   const struct ast_node_def *def = &ast_node_defs[tag];
12563   ast_off_t skips = *ppos;
12564   int i;
12565   ast_move_to_children(a, ppos);
12566 
12567   for (i = 0; i < def->num_subtrees; i++) {
12568     ast_skip_tree(a, ppos);
12569   }
12570 
12571   if (def->num_skips > AST_END_SKIP) {
12572     ast_off_t end = ast_get_skip(a, skips, AST_END_SKIP);
12573 
12574     while (*ppos < end) {
12575       ast_skip_tree(a, ppos);
12576     }
12577   }
12578 }
12579 
12580 #ifndef NO_LIBC
12581 V7_PRIVATE void ast_dump_tree(FILE *fp, struct ast *a, ast_off_t *ppos,
12582                               int depth) {
12583   enum ast_tag tag = ast_fetch_tag(a, ppos);
12584   const struct ast_node_def *def = &ast_node_defs[tag];
12585   ast_off_t skips = *ppos;
12586   size_t slen;
12587   int i, llen;
12588 
12589   for (i = 0; i < depth; i++) {
12590     fprintf(fp, "  ");
12591   }
12592 
12593 #ifndef V7_DISABLE_AST_TAG_NAMES
12594   fprintf(fp, "%s", def->name);
12595 #else
12596   fprintf(fp, "TAG_%d", tag);
12597 #endif
12598 
12599   if (def->has_inlined) {
12600     ast_off_t pos_tmp = *ppos;
12601     ast_move_to_inlined_data(a, &pos_tmp);
12602 
12603     slen = decode_varint((unsigned char *) a->mbuf.buf + pos_tmp, &llen);
12604     fprintf(fp, " %.*s\n", (int) slen, a->mbuf.buf + pos_tmp + llen);
12605   } else {
12606     fprintf(fp, "\n");
12607   }
12608 
12609   ast_move_to_children(a, ppos);
12610 
12611   for (i = 0; i < def->num_subtrees; i++) {
12612     ast_dump_tree(fp, a, ppos, depth + 1);
12613   }
12614 
12615   if (ast_node_defs[tag].num_skips) {
12616     /*
12617      * first skip always encodes end of the last children sequence.
12618      * so unless we care how the subtree sequences are grouped together
12619      * (and we currently don't) we can just read until the end of that skip.
12620      */
12621     ast_off_t end = ast_get_skip(a, skips, AST_END_SKIP);
12622 
12623     comment_at_depth(fp, "...", depth + 1);
12624     while (*ppos < end) {
12625       int s;
12626       for (s = ast_node_defs[tag].num_skips - 1; s > 0; s--) {
12627         if (*ppos == ast_get_skip(a, skips, (enum ast_which_skip) s)) {
12628           comment_at_depth(fp, "%d ->", depth + 1, s);
12629           break;
12630         }
12631       }
12632       ast_dump_tree(fp, a, ppos, depth + 1);
12633     }
12634   }
12635 }
12636 #endif
12637 
12638 V7_PRIVATE void ast_init(struct ast *ast, size_t len) {
12639   mbuf_init(&ast->mbuf, len);
12640   ast->refcnt = 0;
12641   ast->has_overflow = 0;
12642 }
12643 
12644 V7_PRIVATE void ast_optimize(struct ast *ast) {
12645   /*
12646    * leave one trailing byte so that literals can be
12647    * null terminated on the fly.
12648    */
12649   mbuf_resize(&ast->mbuf, ast->mbuf.len + 1);
12650 }
12651 
12652 V7_PRIVATE void ast_free(struct ast *ast) {
12653   mbuf_free(&ast->mbuf);
12654   ast->refcnt = 0;
12655   ast->has_overflow = 0;
12656 }
12657 
12658 V7_PRIVATE void release_ast(struct v7 *v7, struct ast *a) {
12659   (void) v7;
12660 
12661   if (a->refcnt != 0) a->refcnt--;
12662 
12663   if (a->refcnt == 0) {
12664 #if V7_ENABLE__Memory__stats
12665     v7->function_arena_ast_size -= a->mbuf.size;
12666 #endif
12667     ast_free(a);
12668     free(a);
12669   }
12670 }
12671 
12672 #endif /* V7_NO_COMPILER */
12673 #ifdef V7_MODULE_LINES
12674 #line 1 "v7/src/bcode.c"
12675 #endif
12676 /*
12677  * Copyright (c) 2014 Cesanta Software Limited
12678  * All rights reserved
12679  */
12680 
12681 /* Amalgamated: #include "v7/src/internal.h" */
12682 /* Amalgamated: #include "v7/src/bcode.h" */
12683 /* Amalgamated: #include "v7/src/varint.h" */
12684 /* Amalgamated: #include "v7/src/exceptions.h" */
12685 /* Amalgamated: #include "v7/src/gc.h" */
12686 /* Amalgamated: #include "v7/src/core.h" */
12687 /* Amalgamated: #include "v7/src/regexp.h" */
12688 /* Amalgamated: #include "v7/src/function.h" */
12689 /* Amalgamated: #include "v7/src/util.h" */
12690 /* Amalgamated: #include "v7/src/shdata.h" */
12691 
12692 /*
12693  * TODO(dfrank): implement `bcode_serialize_*` more generically, so that they
12694  * can write to buffer instead of a `FILE`. Then, remove a need for mmap here.
12695  */
12696 #if CS_PLATFORM == CS_P_UNIX
12697 #include <sys/mman.h>
12698 #endif
12699 
12700 #if defined(V7_BCODE_DUMP) || defined(V7_BCODE_TRACE)
12701 /* clang-format off */
12702 static const char *op_names[] = {
12703   "DROP",
12704   "DUP",
12705   "2DUP",
12706   "SWAP",
12707   "STASH",
12708   "UNSTASH",
12709   "SWAP_DROP",
12710   "PUSH_UNDEFINED",
12711   "PUSH_NULL",
12712   "PUSH_THIS",
12713   "PUSH_TRUE",
12714   "PUSH_FALSE",
12715   "PUSH_ZERO",
12716   "PUSH_ONE",
12717   "PUSH_LIT",
12718   "NOT",
12719   "LOGICAL_NOT",
12720   "NEG",
12721   "POS",
12722   "ADD",
12723   "SUB",
12724   "REM",
12725   "MUL",
12726   "DIV",
12727   "LSHIFT",
12728   "RSHIFT",
12729   "URSHIFT",
12730   "OR",
12731   "XOR",
12732   "AND",
12733   "EQ_EQ",
12734   "EQ",
12735   "NE",
12736   "NE_NE",
12737   "LT",
12738   "LE",
12739   "GT",
12740   "GE",
12741   "INSTANCEOF",
12742   "TYPEOF",
12743   "IN",
12744   "GET",
12745   "SET",
12746   "SET_VAR",
12747   "GET_VAR",
12748   "SAFE_GET_VAR",
12749   "JMP",
12750   "JMP_TRUE",
12751   "JMP_FALSE",
12752   "JMP_TRUE_DROP",
12753   "JMP_IF_CONTINUE",
12754   "CREATE_OBJ",
12755   "CREATE_ARR",
12756   "PUSH_PROP_ITER_CTX",
12757   "NEXT_PROP",
12758   "FUNC_LIT",
12759   "CALL",
12760   "NEW",
12761   "CHECK_CALL",
12762   "RET",
12763   "DELETE",
12764   "DELETE_VAR",
12765   "TRY_PUSH_CATCH",
12766   "TRY_PUSH_FINALLY",
12767   "TRY_PUSH_LOOP",
12768   "TRY_PUSH_SWITCH",
12769   "TRY_POP",
12770   "AFTER_FINALLY",
12771   "THROW",
12772   "BREAK",
12773   "CONTINUE",
12774   "ENTER_CATCH",
12775   "EXIT_CATCH",
12776 };
12777 /* clang-format on */
12778 
12779 V7_STATIC_ASSERT(OP_MAX == ARRAY_SIZE(op_names), bad_op_names);
12780 V7_STATIC_ASSERT(OP_MAX <= _OP_LINE_NO, bad_OP_LINE_NO);
12781 #endif
12782 
12783 static void bcode_serialize_func(struct v7 *v7, struct bcode *bcode, FILE *out);
12784 
12785 static size_t bcode_ops_append(struct bcode_builder *bbuilder, const void *buf,
12786                                size_t len) {
12787   size_t ret;
12788 #if V7_ENABLE__Memory__stats
12789   bbuilder->v7->bcode_ops_size -= bbuilder->ops.len;
12790 #endif
12791   ret = mbuf_append(&bbuilder->ops, buf, len);
12792 #if V7_ENABLE__Memory__stats
12793   bbuilder->v7->bcode_ops_size += bbuilder->ops.len;
12794 #endif
12795   return ret;
12796 }
12797 
12798 /*
12799  * Initialize bcode builder. The `bcode` should be already initialized by the
12800  * caller, and should be empty (i.e. should not own any ops, literals, etc)
12801  *
12802  * TODO(dfrank) : probably make `bcode_builder_init()` to initialize `bcode`
12803  * as well
12804  */
12805 V7_PRIVATE void bcode_builder_init(struct v7 *v7,
12806                                    struct bcode_builder *bbuilder,
12807                                    struct bcode *bcode) {
12808   memset(bbuilder, 0x00, sizeof(*bbuilder));
12809   bbuilder->v7 = v7;
12810   bbuilder->bcode = bcode;
12811 
12812   mbuf_init(&bbuilder->ops, 0);
12813   mbuf_init(&bbuilder->lit, 0);
12814 }
12815 
12816 /*
12817  * Finalize bcode builder: propagate data to the bcode and transfer the
12818  * ownership from builder to bcode
12819  */
12820 V7_PRIVATE void bcode_builder_finalize(struct bcode_builder *bbuilder) {
12821   mbuf_trim(&bbuilder->ops);
12822   bbuilder->bcode->ops.p = bbuilder->ops.buf;
12823   bbuilder->bcode->ops.len = bbuilder->ops.len;
12824   mbuf_init(&bbuilder->ops, 0);
12825 
12826   mbuf_trim(&bbuilder->lit);
12827   bbuilder->bcode->lit.p = bbuilder->lit.buf;
12828   bbuilder->bcode->lit.len = bbuilder->lit.len;
12829   mbuf_init(&bbuilder->lit, 0);
12830 
12831   memset(bbuilder, 0x00, sizeof(*bbuilder));
12832 }
12833 
12834 #if defined(V7_BCODE_DUMP) || defined(V7_BCODE_TRACE)
12835 V7_PRIVATE void dump_op(struct v7 *v7, FILE *f, struct bcode *bcode,
12836                         char **ops) {
12837   char *p = *ops;
12838 
12839   assert(*p < OP_MAX);
12840   fprintf(f, "%zu: %s", (size_t)(p - bcode->ops.p), op_names[(uint8_t) *p]);
12841   switch (*p) {
12842     case OP_PUSH_LIT:
12843     case OP_SAFE_GET_VAR:
12844     case OP_GET_VAR:
12845     case OP_SET_VAR: {
12846       size_t idx = bcode_get_varint(&p);
12847       fprintf(f, "(%lu): ", (unsigned long) idx);
12848       v7_fprint(f, v7, ((val_t *) bcode->lit.p)[idx]);
12849       break;
12850     }
12851     case OP_CALL:
12852     case OP_NEW:
12853       p++;
12854       fprintf(f, "(%d)", *p);
12855       break;
12856     case OP_JMP:
12857     case OP_JMP_FALSE:
12858     case OP_JMP_TRUE:
12859     case OP_JMP_TRUE_DROP:
12860     case OP_JMP_IF_CONTINUE:
12861     case OP_TRY_PUSH_CATCH:
12862     case OP_TRY_PUSH_FINALLY:
12863     case OP_TRY_PUSH_LOOP:
12864     case OP_TRY_PUSH_SWITCH: {
12865       bcode_off_t target;
12866       p++;
12867       memcpy(&target, p, sizeof(target));
12868       fprintf(f, "(%lu)", (unsigned long) target);
12869       p += sizeof(target) - 1;
12870       break;
12871     }
12872     default:
12873       break;
12874   }
12875   fprintf(f, "\n");
12876   *ops = p;
12877 }
12878 #endif
12879 
12880 #ifdef V7_BCODE_DUMP
12881 V7_PRIVATE void dump_bcode(struct v7 *v7, FILE *f, struct bcode *bcode) {
12882   char *p = bcode_end_names(bcode->ops.p, bcode->names_cnt);
12883   char *end = bcode->ops.p + bcode->ops.len;
12884   for (; p < end; p++) {
12885     dump_op(v7, f, bcode, &p);
12886   }
12887 }
12888 #endif
12889 
12890 V7_PRIVATE void bcode_init(struct bcode *bcode, uint8_t strict_mode,
12891                            void *filename, uint8_t filename_in_rom) {
12892   memset(bcode, 0x00, sizeof(*bcode));
12893   bcode->refcnt = 0;
12894   bcode->args_cnt = 0;
12895   bcode->strict_mode = strict_mode;
12896 #ifndef V7_DISABLE_FILENAMES
12897   bcode->filename = filename;
12898   bcode->filename_in_rom = filename_in_rom;
12899 #else
12900   (void) filename;
12901   (void) filename_in_rom;
12902 #endif
12903 }
12904 
12905 V7_PRIVATE void bcode_free(struct v7 *v7, struct bcode *bcode) {
12906   (void) v7;
12907 #if V7_ENABLE__Memory__stats
12908   if (!bcode->ops_in_rom) {
12909     v7->bcode_ops_size -= bcode->ops.len;
12910   }
12911 
12912   v7->bcode_lit_total_size -= bcode->lit.len;
12913   if (bcode->deserialized) {
12914     v7->bcode_lit_deser_size -= bcode->lit.len;
12915   }
12916 #endif
12917 
12918   if (!bcode->ops_in_rom) {
12919     free(bcode->ops.p);
12920   }
12921   memset(&bcode->ops, 0x00, sizeof(bcode->ops));
12922 
12923   free(bcode->lit.p);
12924   memset(&bcode->lit, 0x00, sizeof(bcode->lit));
12925 
12926 #ifndef V7_DISABLE_FILENAMES
12927   if (!bcode->filename_in_rom && bcode->filename != NULL) {
12928     shdata_release((struct shdata *) bcode->filename);
12929     bcode->filename = NULL;
12930   }
12931 #endif
12932 
12933   bcode->refcnt = 0;
12934 }
12935 
12936 V7_PRIVATE void retain_bcode(struct v7 *v7, struct bcode *b) {
12937   (void) v7;
12938   if (!b->frozen) {
12939     b->refcnt++;
12940   }
12941 }
12942 
12943 V7_PRIVATE void release_bcode(struct v7 *v7, struct bcode *b) {
12944   (void) v7;
12945   if (b->frozen) return;
12946 
12947   assert(b->refcnt > 0);
12948   if (b->refcnt != 0) b->refcnt--;
12949 
12950   if (b->refcnt == 0) {
12951     bcode_free(v7, b);
12952     free(b);
12953   }
12954 }
12955 
12956 #ifndef V7_DISABLE_FILENAMES
12957 V7_PRIVATE const char *bcode_get_filename(struct bcode *bcode) {
12958   const char *ret = NULL;
12959   if (bcode->filename_in_rom) {
12960     ret = (const char *) bcode->filename;
12961   } else if (bcode->filename != NULL) {
12962     ret = (const char *) shdata_get_payload((struct shdata *) bcode->filename);
12963   }
12964   return ret;
12965 }
12966 #endif
12967 
12968 V7_PRIVATE void bcode_copy_filename_from(struct bcode *dst, struct bcode *src) {
12969 #ifndef V7_DISABLE_FILENAMES
12970   dst->filename_in_rom = src->filename_in_rom;
12971   dst->filename = src->filename;
12972 
12973   if (src->filename != NULL && !src->filename_in_rom) {
12974     shdata_retain((struct shdata *) dst->filename);
12975   }
12976 #else
12977   (void) dst;
12978   (void) src;
12979 #endif
12980 }
12981 
12982 V7_PRIVATE void bcode_op(struct bcode_builder *bbuilder, uint8_t op) {
12983   bcode_ops_append(bbuilder, &op, 1);
12984 }
12985 
12986 #ifndef V7_DISABLE_LINE_NUMBERS
12987 V7_PRIVATE void bcode_append_lineno(struct bcode_builder *bbuilder,
12988                                     int line_no) {
12989   int offset = bbuilder->ops.len;
12990   bcode_add_varint(bbuilder, (line_no << 1) | 1);
12991   bbuilder->ops.buf[offset] = msb_lsb_swap(bbuilder->ops.buf[offset]);
12992   assert(bbuilder->ops.buf[offset] & _OP_LINE_NO);
12993 }
12994 #endif
12995 
12996 /*
12997  * Appends varint-encoded integer to the `ops` mbuf
12998  */
12999 V7_PRIVATE void bcode_add_varint(struct bcode_builder *bbuilder, size_t value) {
13000   int k = calc_llen(value); /* Calculate how many bytes length takes */
13001   int offset = bbuilder->ops.len;
13002 
13003   /* Allocate buffer */
13004   bcode_ops_append(bbuilder, NULL, k);
13005 
13006   /* Write value */
13007   encode_varint(value, (unsigned char *) bbuilder->ops.buf + offset);
13008 }
13009 
13010 V7_PRIVATE size_t bcode_get_varint(char **ops) {
13011   size_t ret = 0;
13012   int len = 0;
13013   (*ops)++;
13014   ret = decode_varint((unsigned char *) *ops, &len);
13015   *ops += len - 1;
13016   return ret;
13017 }
13018 
13019 static int bcode_is_inline_string(struct v7 *v7, val_t val) {
13020   uint64_t tag = val & V7_TAG_MASK;
13021   if (v7->is_precompiling && v7_is_string(val)) {
13022     return 1;
13023   }
13024   return tag == V7_TAG_STRING_I || tag == V7_TAG_STRING_5;
13025 }
13026 
13027 static int bcode_is_inline_func(struct v7 *v7, val_t val) {
13028   return (v7->is_precompiling && is_js_function(val));
13029 }
13030 
13031 static int bcode_is_inline_regexp(struct v7 *v7, val_t val) {
13032   return (v7->is_precompiling && v7_is_regexp(v7, val));
13033 }
13034 
13035 V7_PRIVATE lit_t bcode_add_lit(struct bcode_builder *bbuilder, val_t val) {
13036   lit_t lit;
13037   memset(&lit, 0, sizeof(lit));
13038 
13039   if (bcode_is_inline_string(bbuilder->v7, val) ||
13040       bcode_is_inline_func(bbuilder->v7, val) || v7_is_number(val) ||
13041       bcode_is_inline_regexp(bbuilder->v7, val)) {
13042     /* literal should be inlined (it's `bcode_op_lit()` who does this) */
13043     lit.mode = LIT_MODE__INLINED;
13044     lit.v.inline_val = val;
13045   } else {
13046     /* literal will now be added to the literal table */
13047     lit.mode = LIT_MODE__TABLE;
13048     lit.v.lit_idx = bbuilder->lit.len / sizeof(val);
13049 
13050 #if V7_ENABLE__Memory__stats
13051     bbuilder->v7->bcode_lit_total_size -= bbuilder->lit.len;
13052     if (bbuilder->bcode->deserialized) {
13053       bbuilder->v7->bcode_lit_deser_size -= bbuilder->lit.len;
13054     }
13055 #endif
13056 
13057     mbuf_append(&bbuilder->lit, &val, sizeof(val));
13058 
13059     /*
13060      * immediately propagate current lit buffer to the bcode, so that GC will
13061      * be aware of it
13062      */
13063     bbuilder->bcode->lit.p = bbuilder->lit.buf;
13064     bbuilder->bcode->lit.len = bbuilder->lit.len;
13065 
13066 #if V7_ENABLE__Memory__stats
13067     bbuilder->v7->bcode_lit_total_size += bbuilder->lit.len;
13068     if (bbuilder->bcode->deserialized) {
13069       bbuilder->v7->bcode_lit_deser_size += bbuilder->lit.len;
13070     }
13071 #endif
13072   }
13073   return lit;
13074 }
13075 
13076 #if 0
13077 V7_PRIVATE v7_val_t bcode_get_lit(struct bcode *bcode, size_t idx) {
13078   val_t ret;
13079   memcpy(&ret, bcode->lit.p + (size_t) idx * sizeof(ret), sizeof(ret));
13080   return ret;
13081 }
13082 #endif
13083 
13084 static const char *bcode_deserialize_func(struct v7 *v7, struct bcode *bcode,
13085                                           const char *data);
13086 
13087 V7_PRIVATE v7_val_t
13088 bcode_decode_lit(struct v7 *v7, struct bcode *bcode, char **ops) {
13089   struct v7_vec *vec = &bcode->lit;
13090   size_t idx = bcode_get_varint(ops);
13091   switch (idx) {
13092     case BCODE_INLINE_STRING_TYPE_TAG: {
13093       val_t res;
13094       size_t len = bcode_get_varint(ops);
13095       res = v7_mk_string(
13096           v7, (const char *) *ops + 1 /*skip BCODE_INLINE_STRING_TYPE_TAG*/,
13097           len, !bcode->ops_in_rom);
13098       *ops += len + 1;
13099       return res;
13100     }
13101     case BCODE_INLINE_NUMBER_TYPE_TAG: {
13102       val_t res;
13103       memcpy(&res, *ops + 1 /*skip BCODE_INLINE_NUMBER_TYPE_TAG*/, sizeof(res));
13104       *ops += sizeof(res);
13105       return res;
13106     }
13107     case BCODE_INLINE_FUNC_TYPE_TAG: {
13108       /*
13109        * Create half-done function: without scope but _with_ prototype. Scope
13110        * will be set by `bcode_instantiate_function()`.
13111        *
13112        * The fact that the prototype is already set will make
13113        * `bcode_instantiate_function()` just set scope on this function,
13114        * instead of creating a new one.
13115        */
13116       val_t res = mk_js_function(v7, NULL, v7_mk_object(v7));
13117 
13118       /* Create bcode in this half-done function */
13119       struct v7_js_function *func = get_js_function_struct(res);
13120 
13121       func->bcode = (struct bcode *) calloc(1, sizeof(*func->bcode));
13122       bcode_init(func->bcode, bcode->strict_mode, NULL /* will be set below */,
13123                  0);
13124       bcode_copy_filename_from(func->bcode, bcode);
13125       retain_bcode(v7, func->bcode);
13126 
13127       /* deserialize the function's bcode from `ops` */
13128       *ops = (char *) bcode_deserialize_func(
13129           v7, func->bcode, *ops + 1 /*skip BCODE_INLINE_FUNC_TYPE_TAG*/);
13130 
13131       /* decrement *ops, because it will be incremented by `eval_bcode` soon */
13132       *ops -= 1;
13133 
13134       return res;
13135     }
13136     case BCODE_INLINE_REGEXP_TYPE_TAG: {
13137 #if V7_ENABLE__RegExp
13138       enum v7_err rcode = V7_OK;
13139       val_t res;
13140       size_t len_src, len_flags;
13141       char *buf_src, *buf_flags;
13142 
13143       len_src = bcode_get_varint(ops);
13144       buf_src = *ops + 1;
13145       *ops += len_src + 1 /* nul term */;
13146 
13147       len_flags = bcode_get_varint(ops);
13148       buf_flags = *ops + 1;
13149       *ops += len_flags + 1 /* nul term */;
13150 
13151       rcode = v7_mk_regexp(v7, buf_src, len_src, buf_flags, len_flags, &res);
13152       assert(rcode == V7_OK);
13153       (void) rcode;
13154 
13155       return res;
13156 #else
13157       fprintf(stderr, "Firmware is built without -DV7_ENABLE__RegExp\n");
13158       abort();
13159 #endif
13160     }
13161     default:
13162       return ((val_t *) vec->p)[idx - BCODE_MAX_INLINE_TYPE_TAG];
13163   }
13164 }
13165 
13166 V7_PRIVATE void bcode_op_lit(struct bcode_builder *bbuilder, enum opcode op,
13167                              lit_t lit) {
13168   bcode_op(bbuilder, op);
13169 
13170   switch (lit.mode) {
13171     case LIT_MODE__TABLE:
13172       bcode_add_varint(bbuilder, lit.v.lit_idx + BCODE_MAX_INLINE_TYPE_TAG);
13173       break;
13174 
13175     case LIT_MODE__INLINED:
13176       if (v7_is_string(lit.v.inline_val)) {
13177         size_t len;
13178         const char *s = v7_get_string(bbuilder->v7, &lit.v.inline_val, &len);
13179         bcode_add_varint(bbuilder, BCODE_INLINE_STRING_TYPE_TAG);
13180         bcode_add_varint(bbuilder, len);
13181         bcode_ops_append(bbuilder, s, len + 1 /* nul term */);
13182       } else if (v7_is_number(lit.v.inline_val)) {
13183         bcode_add_varint(bbuilder, BCODE_INLINE_NUMBER_TYPE_TAG);
13184         /*
13185          * TODO(dfrank): we can save some memory by storing string
13186          * representation of a number here, instead of wasting 8 bytes for each
13187          * number.
13188          *
13189          * Alternatively, we can add more tags for integers, like
13190          * `BCODE_INLINE_S08_TYPE_TAG`, `BCODE_INLINE_S16_TYPE_TAG`, etc, since
13191          * integers are the most common numbers for sure.
13192          */
13193         bcode_ops_append(bbuilder, &lit.v.inline_val, sizeof(lit.v.inline_val));
13194       } else if (is_js_function(lit.v.inline_val)) {
13195 /*
13196  * TODO(dfrank): implement `bcode_serialize_*` more generically, so
13197  * that they can write to buffer instead of a `FILE`. Then, remove this
13198  * workaround with `CS_PLATFORM == CS_P_UNIX`, `tmpfile()`, etc.
13199  */
13200 #if CS_PLATFORM == CS_P_UNIX
13201         struct v7_js_function *func;
13202         FILE *fp = tmpfile();
13203         long len = 0;
13204         char *p;
13205 
13206         func = get_js_function_struct(lit.v.inline_val);
13207 
13208         /* we inline functions if only we're precompiling */
13209         assert(bbuilder->v7->is_precompiling);
13210 
13211         bcode_add_varint(bbuilder, BCODE_INLINE_FUNC_TYPE_TAG);
13212         bcode_serialize_func(bbuilder->v7, func->bcode, fp);
13213 
13214         fflush(fp);
13215 
13216         len = ftell(fp);
13217 
13218         p = (char *) mmap(NULL, len, PROT_WRITE, MAP_PRIVATE, fileno(fp), 0);
13219 
13220         bcode_ops_append(bbuilder, p, len);
13221 
13222         fclose(fp);
13223 #endif
13224       } else if (v7_is_regexp(bbuilder->v7, lit.v.inline_val)) {
13225 #if V7_ENABLE__RegExp
13226         struct v7_regexp *rp =
13227             v7_get_regexp_struct(bbuilder->v7, lit.v.inline_val);
13228         bcode_add_varint(bbuilder, BCODE_INLINE_REGEXP_TYPE_TAG);
13229 
13230         /* append regexp source */
13231         {
13232           size_t len;
13233           const char *buf =
13234               v7_get_string(bbuilder->v7, &rp->regexp_string, &len);
13235           bcode_add_varint(bbuilder, len);
13236           bcode_ops_append(bbuilder, buf, len + 1 /* nul term */);
13237         }
13238 
13239         /* append regexp flags */
13240         {
13241           char buf[_V7_REGEXP_MAX_FLAGS_LEN + 1 /* nul term */];
13242           size_t len = get_regexp_flags_str(bbuilder->v7, rp, buf);
13243           bcode_add_varint(bbuilder, len);
13244           bcode_ops_append(bbuilder, buf, len + 1 /* nul term */);
13245         }
13246 #else
13247         fprintf(stderr, "Firmware is built without -DV7_ENABLE__RegExp\n");
13248         abort();
13249 #endif
13250       } else {
13251         /* invalid type of inlined value */
13252         abort();
13253       }
13254       break;
13255 
13256     default:
13257       /* invalid literal mode */
13258       abort();
13259       break;
13260   }
13261 }
13262 
13263 V7_PRIVATE void bcode_push_lit(struct bcode_builder *bbuilder, lit_t lit) {
13264   bcode_op_lit(bbuilder, OP_PUSH_LIT, lit);
13265 }
13266 
13267 WARN_UNUSED_RESULT
13268     /*V7_PRIVATE*/ enum v7_err
13269     bcode_add_name(struct bcode_builder *bbuilder, const char *p, size_t len,
13270                    size_t *idx) {
13271   enum v7_err rcode = V7_OK;
13272   int llen;
13273   size_t ops_index;
13274 
13275   /*
13276    * if name length is not provided, assume it's null-terminated and calculate
13277    * it
13278    */
13279   if (len == ~((size_t) 0)) {
13280     len = strlen(p);
13281   }
13282 
13283   /* index at which to put name. If not provided, we'll append at the end */
13284   if (idx != NULL) {
13285     ops_index = *idx;
13286   } else {
13287     ops_index = bbuilder->ops.len;
13288   }
13289 
13290   /* calculate how much varint len will take */
13291   llen = calc_llen(len);
13292 
13293   /* reserve space in `ops` buffer */
13294   mbuf_insert(&bbuilder->ops, ops_index, NULL, llen + len + 1 /*null-term*/);
13295 
13296   {
13297     char *ops = bbuilder->ops.buf + ops_index;
13298 
13299     /* put varint len */
13300     ops += encode_varint(len, (unsigned char *) ops);
13301 
13302     /* put string */
13303     memcpy(ops, p, len);
13304     ops += len;
13305 
13306     /* null-terminate */
13307     *ops++ = 0x00;
13308 
13309     if (idx != NULL) {
13310       *idx = ops - bbuilder->ops.buf;
13311     }
13312   }
13313 
13314   /* maintain total number of names */
13315   if (bbuilder->bcode->names_cnt < V7_NAMES_CNT_MAX) {
13316     bbuilder->bcode->names_cnt++;
13317   } else {
13318     rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "Too many local variables");
13319   }
13320 
13321   return rcode;
13322 }
13323 
13324 /*V7_PRIVATE*/ char *bcode_end_names(char *ops, size_t names_cnt) {
13325   while (names_cnt--) {
13326     ops = bcode_next_name(ops, NULL, NULL);
13327   }
13328   return ops;
13329 }
13330 
13331 V7_PRIVATE char *bcode_next_name(char *ops, char **pname, size_t *plen) {
13332   size_t len;
13333   int llen;
13334 
13335   len = decode_varint((unsigned char *) ops, &llen);
13336 
13337   ops += llen;
13338 
13339   if (pname != NULL) {
13340     *pname = ops;
13341   }
13342 
13343   if (plen != NULL) {
13344     *plen = len;
13345   }
13346 
13347   ops += len + 1 /*null-terminator*/;
13348   return ops;
13349 }
13350 
13351 V7_PRIVATE char *bcode_next_name_v(struct v7 *v7, struct bcode *bcode,
13352                                    char *ops, val_t *res) {
13353   char *name;
13354   size_t len;
13355 
13356   ops = bcode_next_name(ops, &name, &len);
13357 
13358   /*
13359    * If `ops` is in RAM, we create owned string, since the string may outlive
13360    * bcode. Otherwise (`ops` is in ROM), we create foreign string.
13361    */
13362   *res = v7_mk_string(v7, name, len, !bcode->ops_in_rom);
13363 
13364   return ops;
13365 }
13366 
13367 V7_PRIVATE bcode_off_t bcode_pos(struct bcode_builder *bbuilder) {
13368   return bbuilder->ops.len;
13369 }
13370 
13371 /*
13372  * Appends a branch target and returns its location.
13373  * This location can be updated with bcode_patch_target.
13374  * To be issued following a JMP_* bytecode
13375  */
13376 V7_PRIVATE bcode_off_t bcode_add_target(struct bcode_builder *bbuilder) {
13377   bcode_off_t pos = bcode_pos(bbuilder);
13378   bcode_off_t zero = 0;
13379   bcode_ops_append(bbuilder, &zero, sizeof(bcode_off_t));
13380   return pos;
13381 }
13382 
13383 /*
13384  * Appends an op requiring a branch target. See bcode_add_target.
13385  *
13386  * This function is used only internally, but used in a complicated mix of
13387  * configurations, hence the commented V7_PRIVATE
13388  */
13389 /*V7_PRIVATE*/ bcode_off_t bcode_op_target(struct bcode_builder *bbuilder,
13390                                            uint8_t op) {
13391   bcode_op(bbuilder, op);
13392   return bcode_add_target(bbuilder);
13393 }
13394 
13395 /*V7_PRIVATE*/ void bcode_patch_target(struct bcode_builder *bbuilder,
13396                                        bcode_off_t label, bcode_off_t target) {
13397   memcpy(bbuilder->ops.buf + label, &target, sizeof(target));
13398 }
13399 
13400 /*V7_PRIVATE*/ void bcode_serialize(struct v7 *v7, struct bcode *bcode,
13401                                     FILE *out) {
13402   (void) v7;
13403   (void) bcode;
13404 
13405   fwrite(BIN_BCODE_SIGNATURE, sizeof(BIN_BCODE_SIGNATURE), 1, out);
13406   bcode_serialize_func(v7, bcode, out);
13407 }
13408 
13409 static void bcode_serialize_varint(int n, FILE *out) {
13410   unsigned char buf[8];
13411   int k = calc_llen(n);
13412   encode_varint(n, buf);
13413   fwrite(buf, k, 1, out);
13414 }
13415 
13416 static void bcode_serialize_func(struct v7 *v7, struct bcode *bcode,
13417                                  FILE *out) {
13418   struct v7_vec *vec;
13419   (void) v7;
13420 
13421   /*
13422    * All literals should be inlined into `ops`, so we expect literals table
13423    * to be empty here
13424    */
13425   assert(bcode->lit.len == 0);
13426 
13427   /* args_cnt */
13428   bcode_serialize_varint(bcode->args_cnt, out);
13429 
13430   /* names_cnt */
13431   bcode_serialize_varint(bcode->names_cnt, out);
13432 
13433   /* func_name_present */
13434   bcode_serialize_varint(bcode->func_name_present, out);
13435 
13436   /*
13437    * bcode:
13438    * <varint> // opcodes length
13439    * <opcode>*
13440    */
13441   vec = &bcode->ops;
13442   bcode_serialize_varint(vec->len, out);
13443   fwrite(vec->p, vec->len, 1, out);
13444 }
13445 
13446 static size_t bcode_deserialize_varint(const char **data) {
13447   size_t ret = 0;
13448   int len = 0;
13449   ret = decode_varint((const unsigned char *) (*data), &len);
13450   *data += len;
13451   return ret;
13452 }
13453 
13454 static const char *bcode_deserialize_func(struct v7 *v7, struct bcode *bcode,
13455                                           const char *data) {
13456   size_t size;
13457   struct bcode_builder bbuilder;
13458 
13459   bcode_builder_init(v7, &bbuilder, bcode);
13460 
13461   /*
13462    * before deserializing, set the corresponding flag, so that metrics will be
13463    * updated accordingly
13464    */
13465   bcode->deserialized = 1;
13466 
13467   /*
13468    * In serialized functions, all literals are inlined into `ops`, so we don't
13469    * deserialize them here in any way
13470    */
13471 
13472   /* get number of args */
13473   bcode->args_cnt = bcode_deserialize_varint(&data);
13474 
13475   /* get number of names */
13476   bcode->names_cnt = bcode_deserialize_varint(&data);
13477 
13478   /* get whether the function name is present in `names` */
13479   bcode->func_name_present = bcode_deserialize_varint(&data);
13480 
13481   /* get opcode size */
13482   size = bcode_deserialize_varint(&data);
13483 
13484   bbuilder.ops.buf = (char *) data;
13485   bbuilder.ops.size = size;
13486   bbuilder.ops.len = size;
13487 
13488   bcode->ops_in_rom = 1;
13489 
13490   data += size;
13491 
13492   bcode_builder_finalize(&bbuilder);
13493   return data;
13494 }
13495 
13496 V7_PRIVATE void bcode_deserialize(struct v7 *v7, struct bcode *bcode,
13497                                   const char *data) {
13498   data = bcode_deserialize_func(v7, bcode, data);
13499 }
13500 #ifdef V7_MODULE_LINES
13501 #line 1 "v7/src/eval.c"
13502 #endif
13503 /*
13504  * Copyright (c) 2014 Cesanta Software Limited
13505  * All rights reserved
13506  */
13507 
13508 /* Amalgamated: #include "common/str_util.h" */
13509 /* Amalgamated: #include "v7/src/internal.h" */
13510 /* Amalgamated: #include "v7/src/eval.h" */
13511 /* Amalgamated: #include "v7/src/string.h" */
13512 /* Amalgamated: #include "v7/src/array.h" */
13513 /* Amalgamated: #include "v7/src/object.h" */
13514 /* Amalgamated: #include "v7/src/gc.h" */
13515 /* Amalgamated: #include "v7/src/compiler.h" */
13516 /* Amalgamated: #include "v7/src/cyg_profile.h" */
13517 /* Amalgamated: #include "v7/src/core.h" */
13518 /* Amalgamated: #include "v7/src/function.h" */
13519 /* Amalgamated: #include "v7/src/util.h" */
13520 /* Amalgamated: #include "v7/src/shdata.h" */
13521 /* Amalgamated: #include "v7/src/exceptions.h" */
13522 /* Amalgamated: #include "v7/src/conversion.h" */
13523 /* Amalgamated: #include "v7/src/varint.h" */
13524 
13525 /*
13526  * Bcode offsets in "try stack" are stored in JS numbers, i.e.  in `double`s.
13527  * Apart from the offset itself, we also need some additional data:
13528  *
13529  * - type of the block that offset represents (`catch`, `finally`, `switch`,
13530  *   or some loop)
13531  * - size of the stack when the block is created (needed when throwing, since
13532  *   if exception is thrown from the middle of the expression, the stack may
13533  *   have any arbitrary length)
13534  *
13535  * We bake all this data into integer part of the double (53 bits) :
13536  *
13537  * - 32 bits: bcode offset
13538  * - 3 bits: "tag": the type of the block
13539  * - 16 bits: stack size
13540  */
13541 
13542 /*
13543  * Widths of data parts
13544  */
13545 #define LBLOCK_OFFSET_WIDTH 32
13546 #define LBLOCK_TAG_WIDTH 3
13547 #define LBLOCK_STACK_SIZE_WIDTH 16
13548 
13549 /*
13550  * Shifts of data parts
13551  */
13552 #define LBLOCK_OFFSET_SHIFT (0)
13553 #define LBLOCK_TAG_SHIFT (LBLOCK_OFFSET_SHIFT + LBLOCK_OFFSET_WIDTH)
13554 #define LBLOCK_STACK_SIZE_SHIFT (LBLOCK_TAG_SHIFT + LBLOCK_TAG_WIDTH)
13555 #define LBLOCK_TOTAL_WIDTH (LBLOCK_STACK_SIZE_SHIFT + LBLOCK_STACK_SIZE_WIDTH)
13556 
13557 /*
13558  * Masks of data parts
13559  */
13560 #define LBLOCK_OFFSET_MASK \
13561   ((int64_t)(((int64_t) 1 << LBLOCK_OFFSET_WIDTH) - 1) << LBLOCK_OFFSET_SHIFT)
13562 #define LBLOCK_TAG_MASK \
13563   ((int64_t)(((int64_t) 1 << LBLOCK_TAG_WIDTH) - 1) << LBLOCK_TAG_SHIFT)
13564 #define LBLOCK_STACK_SIZE_MASK                             \
13565   ((int64_t)(((int64_t) 1 << LBLOCK_STACK_SIZE_WIDTH) - 1) \
13566    << LBLOCK_STACK_SIZE_SHIFT)
13567 
13568 /*
13569  * Self-check: make sure all the data can fit into double's mantissa
13570  */
13571 #if (LBLOCK_TOTAL_WIDTH > 53)
13572 #error lblock width is too large, it can't fit into double's mantissa
13573 #endif
13574 
13575 /*
13576  * Tags that are used for bcode offsets in "try stack"
13577  */
13578 #define LBLOCK_TAG_CATCH ((int64_t) 0x01 << LBLOCK_TAG_SHIFT)
13579 #define LBLOCK_TAG_FINALLY ((int64_t) 0x02 << LBLOCK_TAG_SHIFT)
13580 #define LBLOCK_TAG_LOOP ((int64_t) 0x03 << LBLOCK_TAG_SHIFT)
13581 #define LBLOCK_TAG_SWITCH ((int64_t) 0x04 << LBLOCK_TAG_SHIFT)
13582 
13583 /*
13584  * Yields 32-bit bcode offset value
13585  */
13586 #define LBLOCK_OFFSET(v) \
13587   ((bcode_off_t)(((v) &LBLOCK_OFFSET_MASK) >> LBLOCK_OFFSET_SHIFT))
13588 
13589 /*
13590  * Yields tag value (unshifted, to be compared with macros like
13591  * `LBLOCK_TAG_CATCH`, etc)
13592  */
13593 #define LBLOCK_TAG(v) ((v) &LBLOCK_TAG_MASK)
13594 
13595 /*
13596  * Yields stack size
13597  */
13598 #define LBLOCK_STACK_SIZE(v) \
13599   (((v) &LBLOCK_STACK_SIZE_MASK) >> LBLOCK_STACK_SIZE_SHIFT)
13600 
13601 /*
13602  * Yields `int64_t` value to be stored as a JavaScript number
13603  */
13604 #define LBLOCK_ITEM_CREATE(offset, tag, stack_size) \
13605   ((int64_t)(offset) | (tag) |                      \
13606    (((int64_t)(stack_size)) << LBLOCK_STACK_SIZE_SHIFT))
13607 
13608 /*
13609  * make sure `bcode_off_t` is just 32-bit, so that it can fit in double
13610  * with 3-bit tag
13611  */
13612 V7_STATIC_ASSERT((sizeof(bcode_off_t) * 8) == LBLOCK_OFFSET_WIDTH,
13613                  wrong_size_of_bcode_off_t);
13614 
13615 #define PUSH(v) stack_push(&v7->stack, v)
13616 #define POP() stack_pop(&v7->stack)
13617 #define TOS() stack_tos(&v7->stack)
13618 #define SP() stack_sp(&v7->stack)
13619 
13620 /*
13621  * Local-to-function block types that we might want to consider when unwinding
13622  * stack for whatever reason. see `unwind_local_blocks_stack()`.
13623  */
13624 enum local_block {
13625   LOCAL_BLOCK_NONE = (0),
13626   LOCAL_BLOCK_CATCH = (1 << 0),
13627   LOCAL_BLOCK_FINALLY = (1 << 1),
13628   LOCAL_BLOCK_LOOP = (1 << 2),
13629   LOCAL_BLOCK_SWITCH = (1 << 3),
13630 };
13631 
13632 /*
13633  * Like `V7_TRY()`, but to be used inside `eval_bcode()` only: you should
13634  * wrap all calls to cfunctions into `BTRY()` instead of `V7_TRY()`.
13635  *
13636  * If the provided function returns something other than `V7_OK`, this macro
13637  * calls `bcode_perform_throw`, which performs bcode stack unwinding.
13638  */
13639 #define BTRY(call)                                                            \
13640   do {                                                                        \
13641     enum v7_err _e = call;                                                    \
13642     (void) _you_should_use_BTRY_in_eval_bcode_only;                           \
13643     if (_e != V7_OK) {                                                        \
13644       V7_TRY(bcode_perform_throw(v7, &r, 0 /*don't take value from stack*/)); \
13645       goto op_done;                                                           \
13646     }                                                                         \
13647   } while (0)
13648 
13649 V7_PRIVATE void stack_push(struct mbuf *s, val_t v) {
13650   mbuf_append(s, &v, sizeof(v));
13651 }
13652 
13653 V7_PRIVATE val_t stack_pop(struct mbuf *s) {
13654   assert(s->len >= sizeof(val_t));
13655   s->len -= sizeof(val_t);
13656   return *(val_t *) (s->buf + s->len);
13657 }
13658 
13659 V7_PRIVATE val_t stack_tos(struct mbuf *s) {
13660   assert(s->len >= sizeof(val_t));
13661   return *(val_t *) (s->buf + s->len - sizeof(val_t));
13662 }
13663 
13664 #ifdef V7_BCODE_TRACE_STACK
13665 V7_PRIVATE val_t stack_at(struct mbuf *s, size_t idx) {
13666   assert(s->len >= sizeof(val_t) * idx);
13667   return *(val_t *) (s->buf + s->len - sizeof(val_t) - idx * sizeof(val_t));
13668 }
13669 #endif
13670 
13671 V7_PRIVATE int stack_sp(struct mbuf *s) {
13672   return s->len / sizeof(val_t);
13673 }
13674 
13675 /*
13676  * Delete a property with name `name`, `len` from an object `obj`. If the
13677  * object does not contain own property with the given `name`, moves to `obj`'s
13678  * prototype, and so on.
13679  *
13680  * If the property is eventually found, it is deleted, and `0` is returned.
13681  * Otherwise, `-1` is returned.
13682  *
13683  * If `len` is -1/MAXUINT/~0, then `name` must be 0-terminated.
13684  *
13685  * See `v7_del()` as well.
13686  */
13687 static int del_property_deep(struct v7 *v7, val_t obj, const char *name,
13688                              size_t len) {
13689   if (!v7_is_object(obj)) {
13690     return -1;
13691   }
13692   for (; obj != V7_NULL; obj = v7_get_proto(v7, obj)) {
13693     int del_res;
13694     if ((del_res = v7_del(v7, obj, name, len)) != -1) {
13695       return del_res;
13696     }
13697   }
13698   return -1;
13699 }
13700 
13701 /* Visual studio 2012+ has signbit() */
13702 #if defined(_MSC_VER) && _MSC_VER < 1700
13703 static int signbit(double x) {
13704   double s = _copysign(1, x);
13705   return s < 0;
13706 }
13707 #endif
13708 
13709 static double b_int_bin_op(enum opcode op, double a, double b) {
13710   int32_t ia = isnan(a) || isinf(a) ? 0 : (int32_t)(int64_t) a;
13711   int32_t ib = isnan(b) || isinf(b) ? 0 : (int32_t)(int64_t) b;
13712 
13713   switch (op) {
13714     case OP_LSHIFT:
13715       return (int32_t)((uint32_t) ia << ((uint32_t) ib & 31));
13716     case OP_RSHIFT:
13717       return ia >> ((uint32_t) ib & 31);
13718     case OP_URSHIFT:
13719       return (uint32_t) ia >> ((uint32_t) ib & 31);
13720     case OP_OR:
13721       return ia | ib;
13722     case OP_XOR:
13723       return ia ^ ib;
13724     case OP_AND:
13725       return ia & ib;
13726     default:
13727       assert(0);
13728   }
13729   return 0;
13730 }
13731 
13732 static double b_num_bin_op(enum opcode op, double a, double b) {
13733   /*
13734    * For certain operations, the result is always NaN if either of arguments
13735    * is NaN
13736    */
13737   switch (op) {
13738     case OP_ADD:
13739     case OP_SUB:
13740     case OP_MUL:
13741     case OP_DIV:
13742     case OP_REM:
13743       if (isnan(a) || isnan(b)) {
13744         return NAN;
13745       }
13746       break;
13747     default:
13748       break;
13749   }
13750 
13751   switch (op) {
13752     case OP_ADD: /* simple fixed width nodes with no payload */
13753       return a + b;
13754     case OP_SUB:
13755       return a - b;
13756     case OP_REM:
13757       if (b == 0 || isnan(b) || isnan(a) || isinf(b) || isinf(a)) {
13758         return NAN;
13759       }
13760       return (int) a % (int) b;
13761     case OP_MUL:
13762       return a * b;
13763     case OP_DIV:
13764       if (b == 0) {
13765         if (a == 0) return NAN;
13766         return (!signbit(a) == !signbit(b)) ? INFINITY : -INFINITY;
13767       }
13768       return a / b;
13769     case OP_LSHIFT:
13770     case OP_RSHIFT:
13771     case OP_URSHIFT:
13772     case OP_OR:
13773     case OP_XOR:
13774     case OP_AND:
13775       return b_int_bin_op(op, a, b);
13776     default:
13777       assert(0);
13778   }
13779   return 0;
13780 }
13781 
13782 static int b_bool_bin_op(enum opcode op, double a, double b) {
13783 #ifdef V7_BROKEN_NAN
13784   if (isnan(a) || isnan(b)) return op == OP_NE || op == OP_NE_NE;
13785 #endif
13786 
13787   switch (op) {
13788     case OP_EQ:
13789     case OP_EQ_EQ:
13790       return a == b;
13791     case OP_NE:
13792     case OP_NE_NE:
13793       return a != b;
13794     case OP_LT:
13795       return a < b;
13796     case OP_LE:
13797       return a <= b;
13798     case OP_GT:
13799       return a > b;
13800     case OP_GE:
13801       return a >= b;
13802     default:
13803       assert(0);
13804   }
13805   return 0;
13806 }
13807 
13808 static bcode_off_t bcode_get_target(char **ops) {
13809   bcode_off_t target;
13810   (*ops)++;
13811   memcpy(&target, *ops, sizeof(target));
13812   *ops += sizeof(target) - 1;
13813   return target;
13814 }
13815 
13816 struct bcode_registers {
13817   /*
13818    * TODO(dfrank): make it contain `struct v7_call_frame_bcode *`
13819    * and use `bcode_ops` in-place, or probably drop the `bcode_registers`
13820    * whatsoever
13821    */
13822   struct bcode *bcode;
13823   char *ops;
13824   char *end;
13825   unsigned int need_inc_ops : 1;
13826 };
13827 
13828 /*
13829  * If returning from function implicitly, then set return value to `undefined`.
13830  *
13831  * And if function was called as a constructor, then make sure returned
13832  * value is an object.
13833  */
13834 static void bcode_adjust_retval(struct v7 *v7, uint8_t is_explicit_return) {
13835   if (!is_explicit_return) {
13836     /* returning implicitly: set return value to `undefined` */
13837     POP();
13838     PUSH(V7_UNDEFINED);
13839   }
13840 
13841   if (v7->call_stack->is_constructor && !v7_is_object(TOS())) {
13842     /* constructor is going to return non-object: replace it with `this` */
13843     POP();
13844     PUSH(v7_get_this(v7));
13845   }
13846 }
13847 
13848 static void bcode_restore_registers(struct v7 *v7, struct bcode *bcode,
13849                                     struct bcode_registers *r) {
13850   r->bcode = bcode;
13851   r->ops = bcode->ops.p;
13852   r->end = r->ops + bcode->ops.len;
13853 
13854   (void) v7;
13855 }
13856 
13857 V7_PRIVATE struct v7_call_frame_base *find_call_frame(struct v7 *v7,
13858                                                       uint8_t type_mask) {
13859   struct v7_call_frame_base *ret = v7->call_stack;
13860 
13861   while (ret != NULL && !(ret->type_mask & type_mask)) {
13862     ret = ret->prev;
13863   }
13864 
13865   return ret;
13866 }
13867 
13868 static struct v7_call_frame_private *find_call_frame_private(struct v7 *v7) {
13869   return (struct v7_call_frame_private *) find_call_frame(
13870       v7, V7_CALL_FRAME_MASK_PRIVATE);
13871 }
13872 
13873 static struct v7_call_frame_bcode *find_call_frame_bcode(struct v7 *v7) {
13874   return (struct v7_call_frame_bcode *) find_call_frame(
13875       v7, V7_CALL_FRAME_MASK_BCODE);
13876 }
13877 
13878 #if 0
13879 static struct v7_call_frame_cfunc *find_call_frame_cfunc(struct v7 *v7) {
13880   return (struct v7_call_frame_cfunc *) find_call_frame(
13881       v7, V7_CALL_FRAME_MASK_CFUNC);
13882 }
13883 #endif
13884 
13885 static struct v7_call_frame_base *create_call_frame(struct v7 *v7,
13886                                                     size_t size) {
13887   struct v7_call_frame_base *call_frame_base = NULL;
13888 
13889   call_frame_base = (struct v7_call_frame_base *) calloc(1, size);
13890 
13891   /* save previous call frame */
13892   call_frame_base->prev = v7->call_stack;
13893 
13894   /* by default, inherit line_no from the previous frame */
13895   if (v7->call_stack != NULL) {
13896     call_frame_base->line_no = v7->call_stack->line_no;
13897   }
13898 
13899   return call_frame_base;
13900 }
13901 
13902 static void init_call_frame_private(struct v7 *v7,
13903                                     struct v7_call_frame_private *call_frame,
13904                                     val_t scope) {
13905   /* make a snapshot of the current state */
13906   {
13907     struct v7_call_frame_private *cf = find_call_frame_private(v7);
13908     if (cf != NULL) {
13909       cf->stack_size = v7->stack.len;
13910     }
13911   }
13912 
13913   /* set a type flag */
13914   call_frame->base.type_mask |= V7_CALL_FRAME_MASK_PRIVATE;
13915 
13916   /* fill the new frame with data */
13917   call_frame->vals.scope = scope;
13918   /* `try_stack` will be lazily created in `eval_try_push()`*/
13919   call_frame->vals.try_stack = V7_UNDEFINED;
13920 }
13921 
13922 static void init_call_frame_bcode(struct v7 *v7,
13923                                   struct v7_call_frame_bcode *call_frame,
13924                                   char *prev_bcode_ops, struct bcode *bcode,
13925                                   val_t this_obj, val_t scope,
13926                                   uint8_t is_constructor) {
13927   init_call_frame_private(v7, &call_frame->base, scope);
13928 
13929   /* make a snapshot of the current state */
13930   {
13931     struct v7_call_frame_bcode *cf = find_call_frame_bcode(v7);
13932     if (cf != NULL) {
13933       cf->bcode_ops = prev_bcode_ops;
13934 
13935       /* remember thrown value */
13936       cf->vals.thrown_error = v7->vals.thrown_error;
13937       cf->base.base.is_thrown = v7->is_thrown;
13938     }
13939   }
13940 
13941   /* set a type flag */
13942   call_frame->base.base.type_mask |= V7_CALL_FRAME_MASK_BCODE;
13943 
13944   /* fill the new frame with data */
13945   call_frame->bcode = bcode;
13946   call_frame->vals.this_obj = this_obj;
13947   call_frame->base.base.is_constructor = is_constructor;
13948 }
13949 
13950 /*
13951  * Create new bcode call frame object and fill it with data
13952  */
13953 static void append_call_frame_bcode(struct v7 *v7, char *prev_bcode_ops,
13954                                     struct bcode *bcode, val_t this_obj,
13955                                     val_t scope, uint8_t is_constructor) {
13956   struct v7_call_frame_bcode *call_frame =
13957       (struct v7_call_frame_bcode *) create_call_frame(v7, sizeof(*call_frame));
13958 
13959   init_call_frame_bcode(v7, call_frame, prev_bcode_ops, bcode, this_obj, scope,
13960                         is_constructor);
13961 
13962   v7->call_stack = &call_frame->base.base;
13963 }
13964 
13965 static void append_call_frame_private(struct v7 *v7, val_t scope) {
13966   struct v7_call_frame_private *call_frame =
13967       (struct v7_call_frame_private *) create_call_frame(v7,
13968                                                          sizeof(*call_frame));
13969   init_call_frame_private(v7, call_frame, scope);
13970 
13971   v7->call_stack = &call_frame->base;
13972 }
13973 
13974 static void append_call_frame_cfunc(struct v7 *v7, val_t this_obj,
13975                                     v7_cfunction_t *cfunc) {
13976   struct v7_call_frame_cfunc *call_frame =
13977       (struct v7_call_frame_cfunc *) create_call_frame(v7, sizeof(*call_frame));
13978 
13979   /* set a type flag */
13980   call_frame->base.type_mask |= V7_CALL_FRAME_MASK_CFUNC;
13981 
13982   /* fill the new frame with data */
13983   call_frame->cfunc = cfunc;
13984   call_frame->vals.this_obj = this_obj;
13985 
13986   v7->call_stack = &call_frame->base;
13987 }
13988 
13989 /*
13990  * The caller's bcode object is needed because we have to restore literals
13991  * and `end` registers.
13992  *
13993  * TODO(mkm): put this state on a return stack
13994  *
13995  * Caller of bcode_perform_call is responsible for owning `call_frame`
13996  */
13997 static enum v7_err bcode_perform_call(struct v7 *v7, v7_val_t scope_frame,
13998                                       struct v7_js_function *func,
13999                                       struct bcode_registers *r,
14000                                       val_t this_object, char *ops,
14001                                       uint8_t is_constructor) {
14002   /* new scope_frame will inherit from the function's scope */
14003   obj_prototype_set(v7, get_object_struct(scope_frame), &func->scope->base);
14004 
14005   /* create new `call_frame` which will replace `v7->call_stack` */
14006   append_call_frame_bcode(v7, r->ops + 1, func->bcode, this_object, scope_frame,
14007                           is_constructor);
14008 
14009   bcode_restore_registers(v7, func->bcode, r);
14010 
14011   /* adjust `ops` since names were already read from it */
14012   r->ops = ops;
14013 
14014   /* `ops` already points to the needed instruction, no need to increment it */
14015   r->need_inc_ops = 0;
14016 
14017   return V7_OK;
14018 }
14019 
14020 /*
14021  * Apply data from the "private" call frame, typically after some other frame
14022  * was just unwound.
14023  *
14024  * The `call_frame` may actually be `NULL`, if the top frame was unwound.
14025  */
14026 static void apply_frame_private(struct v7 *v7,
14027                                 struct v7_call_frame_private *call_frame) {
14028   /*
14029    * Adjust data stack length (restore saved).
14030    *
14031    * If `call_frame` is NULL, it means that the last call frame was just
14032    * unwound, and hence the data stack size should be 0.
14033    */
14034   size_t stack_size = (call_frame != NULL ? call_frame->stack_size : 0);
14035   assert(stack_size <= v7->stack.len);
14036   v7->stack.len = stack_size;
14037 }
14038 
14039 /*
14040  * Apply data from the "bcode" call frame, typically after some other frame
14041  * was just unwound.
14042  *
14043  * The `call_frame` may actually be `NULL`, if the top frame was unwound; but
14044  * in this case, `r` must be `NULL` too, by design. See inline comment below.
14045  */
14046 static void apply_frame_bcode(struct v7 *v7,
14047                               struct v7_call_frame_bcode *call_frame,
14048                               struct bcode_registers *r) {
14049   if (r != NULL) {
14050     /*
14051      * Note: if `r` is non-NULL, then `call_frame` should be non-NULL as well,
14052      * by design. If this invariant is violated, it means that
14053      * `unwind_stack_1level()` is misused.
14054      */
14055     assert(call_frame != NULL);
14056 
14057     bcode_restore_registers(v7, call_frame->bcode, r);
14058     r->ops = call_frame->bcode_ops;
14059 
14060     /*
14061      * restore thrown value if only there's no new thrown value
14062      * (otherwise, the new one overrides the previous one)
14063      */
14064     if (!v7->is_thrown) {
14065       v7->vals.thrown_error = call_frame->vals.thrown_error;
14066       v7->is_thrown = call_frame->base.base.is_thrown;
14067     }
14068   }
14069 }
14070 
14071 /*
14072  * Unwinds `call_stack` by 1 frame.
14073  *
14074  * Returns the type of the unwound frame
14075  */
14076 static v7_call_frame_mask_t unwind_stack_1level(struct v7 *v7,
14077                                                 struct bcode_registers *r) {
14078   v7_call_frame_mask_t type_mask;
14079 #ifdef V7_BCODE_TRACE
14080   fprintf(stderr, "unwinding stack by 1 level\n");
14081 #endif
14082 
14083   type_mask = v7->call_stack->type_mask;
14084 
14085   /* drop the top frame */
14086   {
14087     struct v7_call_frame_base *tmp = v7->call_stack;
14088     v7->call_stack = v7->call_stack->prev;
14089     free(tmp);
14090   }
14091 
14092   /*
14093    * depending on the unwound frame type, apply data from the top call frame(s)
14094    * which are still alive (if any)
14095    */
14096 
14097   if (type_mask & V7_CALL_FRAME_MASK_PRIVATE) {
14098     apply_frame_private(v7, find_call_frame_private(v7));
14099   }
14100 
14101   if (type_mask & V7_CALL_FRAME_MASK_BCODE) {
14102     apply_frame_bcode(v7, find_call_frame_bcode(v7), r);
14103   }
14104 
14105   if (type_mask & V7_CALL_FRAME_MASK_CFUNC) {
14106     /* Nothing to do here at the moment */
14107   }
14108 
14109   return type_mask;
14110 }
14111 
14112 /*
14113  * Unwinds local "try stack" (i.e. local-to-current-function stack of nested
14114  * `try` blocks), looking for local-to-function blocks.
14115  *
14116  * Block types of interest are specified with `wanted_blocks_mask`: it's a
14117  * bitmask of `enum local_block` values.
14118  *
14119  * Only blocks of specified types will be considered, others will be dropped.
14120  *
14121  * If `restore_stack_size` is non-zero, the `v7->stack.len` will be restored
14122  * to the value saved when the block was created. This is useful when throwing,
14123  * since if we throw from the middle of the expression, the stack could have
14124  * any size. But you probably shouldn't set this flag when breaking and
14125  * returning, since it may hide real bugs in the opcode.
14126  *
14127  * Returns id of the block type that control was transferred into, or
14128  * `LOCAL_BLOCK_NONE` if no appropriate block was found. Note: returned value
14129  * contains at most 1 block bit; it can't contain multiple bits.
14130  */
14131 static enum local_block unwind_local_blocks_stack(
14132     struct v7 *v7, struct bcode_registers *r, unsigned int wanted_blocks_mask,
14133     uint8_t restore_stack_size) {
14134   val_t arr = V7_UNDEFINED;
14135   struct gc_tmp_frame tf = new_tmp_frame(v7);
14136   enum local_block found_block = LOCAL_BLOCK_NONE;
14137   unsigned long length;
14138 
14139   tmp_stack_push(&tf, &arr);
14140 
14141   arr = find_call_frame_private(v7)->vals.try_stack;
14142   if (v7_is_array(v7, arr)) {
14143     /*
14144      * pop latest element from "try stack", loop until we need to transfer
14145      * control there
14146      */
14147     while ((length = v7_array_length(v7, arr)) > 0) {
14148       /* get latest offset from the "try stack" */
14149       int64_t offset = v7_get_double(v7, v7_array_get(v7, arr, length - 1));
14150       enum local_block cur_block = LOCAL_BLOCK_NONE;
14151 
14152       /* get id of the current block type */
14153       switch (LBLOCK_TAG(offset)) {
14154         case LBLOCK_TAG_CATCH:
14155           cur_block = LOCAL_BLOCK_CATCH;
14156           break;
14157         case LBLOCK_TAG_FINALLY:
14158           cur_block = LOCAL_BLOCK_FINALLY;
14159           break;
14160         case LBLOCK_TAG_LOOP:
14161           cur_block = LOCAL_BLOCK_LOOP;
14162           break;
14163         case LBLOCK_TAG_SWITCH:
14164           cur_block = LOCAL_BLOCK_SWITCH;
14165           break;
14166         default:
14167           assert(0);
14168           break;
14169       }
14170 
14171       if (cur_block & wanted_blocks_mask) {
14172         /* need to transfer control to this offset */
14173         r->ops = r->bcode->ops.p + LBLOCK_OFFSET(offset);
14174 #ifdef V7_BCODE_TRACE
14175         fprintf(stderr, "transferring to block #%d: %u\n", (int) cur_block,
14176                 (unsigned int) LBLOCK_OFFSET(offset));
14177 #endif
14178         found_block = cur_block;
14179         /* if needed, restore stack size to the saved value */
14180         if (restore_stack_size) {
14181           v7->stack.len = LBLOCK_STACK_SIZE(offset);
14182         }
14183         break;
14184       } else {
14185 #ifdef V7_BCODE_TRACE
14186         fprintf(stderr, "skipped block #%d: %u\n", (int) cur_block,
14187                 (unsigned int) LBLOCK_OFFSET(offset));
14188 #endif
14189         /*
14190          * since we don't need to control transfer there, just pop
14191          * it from the "try stack"
14192          */
14193         v7_array_del(v7, arr, length - 1);
14194       }
14195     }
14196   }
14197 
14198   tmp_frame_cleanup(&tf);
14199   return found_block;
14200 }
14201 
14202 /*
14203  * Perform break, if there is a `finally` block in effect, transfer
14204  * control there.
14205  */
14206 static void bcode_perform_break(struct v7 *v7, struct bcode_registers *r) {
14207   enum local_block found;
14208   unsigned int mask;
14209   v7->is_breaking = 0;
14210   if (v7->is_continuing) {
14211     mask = LOCAL_BLOCK_LOOP;
14212   } else {
14213     mask = LOCAL_BLOCK_LOOP | LOCAL_BLOCK_SWITCH;
14214   }
14215 
14216   /*
14217    * Keep unwinding until we find local block of interest. We should not
14218    * encounter any "function" frames; only "private" frames are allowed.
14219    */
14220   for (;;) {
14221     /*
14222      * Try to unwind local "try stack", considering only `finally` and `break`.
14223      */
14224     found = unwind_local_blocks_stack(v7, r, mask | LOCAL_BLOCK_FINALLY, 0);
14225     if (found == LOCAL_BLOCK_NONE) {
14226       /*
14227        * no blocks found: this may happen if only the `break` or `continue` has
14228        * occurred inside "private" frame. So, unwind this frame, make sure it
14229        * is indeed a "private" frame, and keep unwinding local blocks.
14230        */
14231       v7_call_frame_mask_t frame_type_mask = unwind_stack_1level(v7, r);
14232       assert(frame_type_mask == V7_CALL_FRAME_MASK_PRIVATE);
14233       (void) frame_type_mask;
14234     } else {
14235       /* found some block to transfer control into, stop unwinding */
14236       break;
14237     }
14238   }
14239 
14240   /*
14241    * upon exit of a finally block we'll reenter here if is_breaking is true.
14242    * See OP_AFTER_FINALLY.
14243    */
14244   if (found == LOCAL_BLOCK_FINALLY) {
14245     v7->is_breaking = 1;
14246   }
14247 
14248   /* `ops` already points to the needed instruction, no need to increment it */
14249   r->need_inc_ops = 0;
14250 }
14251 
14252 /*
14253  * Perform return, but if there is a `finally` block in effect, transfer
14254  * control there.
14255  *
14256  * If `take_retval` is non-zero, value to return will be popped from stack
14257  * (and saved into `v7->vals.returned_value`), otherwise, it won't ae affected.
14258  */
14259 static enum v7_err bcode_perform_return(struct v7 *v7,
14260                                         struct bcode_registers *r,
14261                                         int take_retval) {
14262   /*
14263    * We should either take retval from the stack, or some value should already
14264    * de pending to return
14265    */
14266   assert(take_retval || v7->is_returned);
14267 
14268   if (take_retval) {
14269     /* taking return value from stack */
14270     v7->vals.returned_value = POP();
14271     v7->is_returned = 1;
14272 
14273     /*
14274      * returning (say, from `finally`) dismisses any errors that are eeing
14275      * thrown at the moment as well
14276      */
14277     v7->is_thrown = 0;
14278     v7->vals.thrown_error = V7_UNDEFINED;
14279   }
14280 
14281   /*
14282    * Keep unwinding until we unwound "function" frame, or found some `finally`
14283    * block.
14284    */
14285   for (;;) {
14286     /* Try to unwind local "try stack", considering only `finally` blocks */
14287     if (unwind_local_blocks_stack(v7, r, (LOCAL_BLOCK_FINALLY), 0) ==
14288         LOCAL_BLOCK_NONE) {
14289       /*
14290        * no `finally` blocks were found, so, unwind stack by 1 level, and see
14291        * if it's a "function" frame. If not, will keep unwinding.
14292        */
14293       if (unwind_stack_1level(v7, r) & V7_CALL_FRAME_MASK_BCODE) {
14294         /*
14295          * unwound frame is a "function" frame, so, push returned value to
14296          * stack, and stop unwinding
14297          */
14298         PUSH(v7->vals.returned_value);
14299         v7->is_returned = 0;
14300         v7->vals.returned_value = V7_UNDEFINED;
14301 
14302         break;
14303       }
14304     } else {
14305       /* found `finally` block, so, stop unwinding */
14306       break;
14307     }
14308   }
14309 
14310   /* `ops` already points to the needed instruction, no need to increment it */
14311   r->need_inc_ops = 0;
14312 
14313   return V7_OK;
14314 }
14315 
14316 /*
14317  * Perform throw inside `eval_bcode()`.
14318  *
14319  * If `take_thrown_value` is non-zero, value to return will be popped from
14320  * stack (and saved into `v7->vals.thrown_error`), otherwise, it won't be
14321  * affected.
14322  *
14323  * Returns `V7_OK` if thrown exception was caught, `V7_EXEC_EXCEPTION`
14324  * otherwise (in this case, evaluation of current script must be stopped)
14325  *
14326  * When calling this function from `eval_rcode()`, you should wrap this call
14327  * into the `V7_TRY()` macro.
14328  */
14329 static enum v7_err bcode_perform_throw(struct v7 *v7, struct bcode_registers *r,
14330                                        int take_thrown_value) {
14331   enum v7_err rcode = V7_OK;
14332   enum local_block found;
14333 
14334   assert(take_thrown_value || v7->is_thrown);
14335 
14336   if (take_thrown_value) {
14337     v7->vals.thrown_error = POP();
14338     v7->is_thrown = 1;
14339 
14340     /* Throwing dismisses any pending return values */
14341     v7->is_returned = 0;
14342     v7->vals.returned_value = V7_UNDEFINED;
14343   }
14344 
14345   while ((found = unwind_local_blocks_stack(
14346               v7, r, (LOCAL_BLOCK_CATCH | LOCAL_BLOCK_FINALLY), 1)) ==
14347          LOCAL_BLOCK_NONE) {
14348     if (v7->call_stack != v7->bottom_call_frame) {
14349 #ifdef V7_BCODE_TRACE
14350       fprintf(stderr, "not at the bottom of the stack, going to unwind..\n");
14351 #endif
14352       /* not reached bottom of the stack yet, keep unwinding */
14353       unwind_stack_1level(v7, r);
14354     } else {
14355 /* reached stack bottom: uncaught exception */
14356 #ifdef V7_BCODE_TRACE
14357       fprintf(stderr, "reached stack bottom: uncaught exception\n");
14358 #endif
14359       rcode = V7_EXEC_EXCEPTION;
14360       break;
14361     }
14362   }
14363 
14364   if (found == LOCAL_BLOCK_CATCH) {
14365     /*
14366      * we're going to enter `catch` block, so, populate TOS with the thrown
14367      * value, and clear it in v7 context.
14368      */
14369     PUSH(v7->vals.thrown_error);
14370     v7->is_thrown = 0;
14371     v7->vals.thrown_error = V7_UNDEFINED;
14372   }
14373 
14374   /* `ops` already points to the needed instruction, no need to increment it */
14375   r->need_inc_ops = 0;
14376 
14377   return rcode;
14378 }
14379 
14380 /*
14381  * Throws reference error from `eval_bcode()`. Always wrap a call to this
14382  * function into `V7_TRY()`.
14383  */
14384 static enum v7_err bcode_throw_reference_error(struct v7 *v7,
14385                                                struct bcode_registers *r,
14386                                                val_t var_name) {
14387   enum v7_err rcode = V7_OK;
14388   const char *s;
14389   size_t name_len;
14390 
14391   assert(v7_is_string(var_name));
14392   s = v7_get_string(v7, &var_name, &name_len);
14393 
14394   rcode = v7_throwf(v7, REFERENCE_ERROR, "[%.*s] is not defined",
14395                     (int) name_len, s);
14396   (void) rcode;
14397   return bcode_perform_throw(v7, r, 0);
14398 }
14399 
14400 /*
14401  * Takes a half-done function (either from literal table or deserialized from
14402  * `ops` inlined data), and returns a ready-to-use function.
14403  *
14404  * The actual behaviour depends on whether the half-done function has
14405  * `prototype` defined. If there's no prototype (i.e. it's `undefined`), then
14406  * the new function is created, with bcode from a given one. If, however,
14407  * the prototype is defined, it means that the function was just deserialized
14408  * from `ops`, so we only need to set `scope` on it.
14409  *
14410  * Assumes `func` is owned by the caller.
14411  */
14412 static val_t bcode_instantiate_function(struct v7 *v7, val_t func) {
14413   val_t res;
14414   struct v7_generic_object *scope;
14415   struct v7_js_function *f;
14416   assert(is_js_function(func));
14417   f = get_js_function_struct(func);
14418 
14419   scope = get_generic_object_struct(get_scope(v7));
14420 
14421   if (v7_is_undefined(v7_get(v7, func, "prototype", 9))) {
14422     /*
14423      * Function's `prototype` is `undefined`: it means that the function is
14424      * created by the compiler and is stored in the literal table. We have to
14425      * create completely new function
14426      */
14427     struct v7_js_function *rf;
14428 
14429     res = mk_js_function(v7, scope, v7_mk_object(v7));
14430 
14431     /* Copy and retain bcode */
14432     rf = get_js_function_struct(res);
14433     rf->bcode = f->bcode;
14434     retain_bcode(v7, rf->bcode);
14435   } else {
14436     /*
14437      * Function's `prototype` is NOT `undefined`: it means that the function is
14438      * deserialized from inline `ops` data, and we just need to set scope on
14439      * it.
14440      */
14441     res = func;
14442     f->scope = scope;
14443   }
14444 
14445   return res;
14446 }
14447 
14448 /**
14449  * Call C function `func` with given `this_object` and array of arguments
14450  * `args`. `func` should be a C function pointer, not C function object.
14451  */
14452 static enum v7_err call_cfunction(struct v7 *v7, val_t func, val_t this_object,
14453                                   val_t args, uint8_t is_constructor,
14454                                   val_t *res) {
14455   enum v7_err rcode = V7_OK;
14456   uint8_t saved_inhibit_gc = v7->inhibit_gc;
14457   val_t saved_arguments = v7->vals.arguments;
14458   struct gc_tmp_frame tf = new_tmp_frame(v7);
14459   v7_cfunction_t *cfunc = get_cfunction_ptr(v7, func);
14460 
14461   *res = V7_UNDEFINED;
14462 
14463   tmp_stack_push(&tf, &saved_arguments);
14464 
14465   append_call_frame_cfunc(v7, this_object, cfunc);
14466 
14467   /*
14468    * prepare cfunction environment
14469    */
14470   v7->inhibit_gc = 1;
14471   v7->vals.arguments = args;
14472 
14473   /* call C function */
14474   rcode = cfunc(v7, res);
14475   if (rcode != V7_OK) {
14476     goto clean;
14477   }
14478 
14479   if (is_constructor && !v7_is_object(*res)) {
14480     /* constructor returned non-object: replace it with `this` */
14481     *res = v7_get_this(v7);
14482   }
14483 
14484 clean:
14485   v7->vals.arguments = saved_arguments;
14486   v7->inhibit_gc = saved_inhibit_gc;
14487 
14488   unwind_stack_1level(v7, NULL);
14489 
14490   tmp_frame_cleanup(&tf);
14491   return rcode;
14492 }
14493 
14494 /*
14495  * Evaluate `OP_TRY_PUSH_CATCH` or `OP_TRY_PUSH_FINALLY`: Take an offset (from
14496  * the parameter of opcode) and push it onto "try stack"
14497  */
14498 static void eval_try_push(struct v7 *v7, enum opcode op,
14499                           struct bcode_registers *r) {
14500   val_t arr = V7_UNDEFINED;
14501   struct gc_tmp_frame tf = new_tmp_frame(v7);
14502   bcode_off_t target;
14503   int64_t offset_tag = 0;
14504 
14505   tmp_stack_push(&tf, &arr);
14506 
14507   /* make sure "try stack" array exists */
14508   arr = find_call_frame_private(v7)->vals.try_stack;
14509   if (!v7_is_array(v7, arr)) {
14510     arr = v7_mk_dense_array(v7);
14511     find_call_frame_private(v7)->vals.try_stack = arr;
14512   }
14513 
14514   /*
14515    * push the target address at the end of the "try stack" array
14516    */
14517   switch (op) {
14518     case OP_TRY_PUSH_CATCH:
14519       offset_tag = LBLOCK_TAG_CATCH;
14520       break;
14521     case OP_TRY_PUSH_FINALLY:
14522       offset_tag = LBLOCK_TAG_FINALLY;
14523       break;
14524     case OP_TRY_PUSH_LOOP:
14525       offset_tag = LBLOCK_TAG_LOOP;
14526       break;
14527     case OP_TRY_PUSH_SWITCH:
14528       offset_tag = LBLOCK_TAG_SWITCH;
14529       break;
14530     default:
14531       assert(0);
14532       break;
14533   }
14534   target = bcode_get_target(&r->ops);
14535   v7_array_push(v7, arr, v7_mk_number(v7, LBLOCK_ITEM_CREATE(target, offset_tag,
14536                                                              v7->stack.len)));
14537 
14538   tmp_frame_cleanup(&tf);
14539 }
14540 
14541 /*
14542  * Evaluate `OP_TRY_POP`: just pop latest item from "try stack", ignoring it
14543  */
14544 static enum v7_err eval_try_pop(struct v7 *v7) {
14545   enum v7_err rcode = V7_OK;
14546   val_t arr = V7_UNDEFINED;
14547   unsigned long length;
14548   struct gc_tmp_frame tf = new_tmp_frame(v7);
14549 
14550   tmp_stack_push(&tf, &arr);
14551 
14552   /* get "try stack" array, which must be defined and must not be emtpy */
14553   arr = find_call_frame_private(v7)->vals.try_stack;
14554   if (!v7_is_array(v7, arr)) {
14555     rcode = v7_throwf(v7, "Error", "TRY_POP when try_stack is not an array");
14556     V7_TRY(V7_INTERNAL_ERROR);
14557   }
14558 
14559   length = v7_array_length(v7, arr);
14560   if (length == 0) {
14561     rcode = v7_throwf(v7, "Error", "TRY_POP when try_stack is empty");
14562     V7_TRY(V7_INTERNAL_ERROR);
14563   }
14564 
14565   /* delete the latest element of this array */
14566   v7_array_del(v7, arr, length - 1);
14567 
14568 clean:
14569   tmp_frame_cleanup(&tf);
14570   return rcode;
14571 }
14572 
14573 static void own_bcode(struct v7 *v7, struct bcode *p) {
14574   mbuf_append(&v7->act_bcodes, &p, sizeof(p));
14575 }
14576 
14577 static void disown_bcode(struct v7 *v7, struct bcode *p) {
14578 #ifndef NDEBUG
14579   struct bcode **vp =
14580       (struct bcode **) (v7->act_bcodes.buf + v7->act_bcodes.len - sizeof(p));
14581 
14582   /* given `p` should be the last item */
14583   assert(*vp == p);
14584 #endif
14585   v7->act_bcodes.len -= sizeof(p);
14586 }
14587 
14588 /* Keeps track of last evaluated bcodes in order to improve error reporting */
14589 static void push_bcode_history(struct v7 *v7, enum opcode op) {
14590   size_t i;
14591 
14592   if (op == OP_CHECK_CALL || op == OP_CALL || op == OP_NEW) return;
14593 
14594   for (i = ARRAY_SIZE(v7->last_ops) - 1; i > 0; i--) {
14595     v7->last_ops[i] = v7->last_ops[i - 1];
14596   }
14597   v7->last_ops[0] = op;
14598 }
14599 
14600 #ifndef V7_DISABLE_CALL_ERROR_CONTEXT
14601 static void reset_last_name(struct v7 *v7) {
14602   v7->vals.last_name[0] = V7_UNDEFINED;
14603   v7->vals.last_name[1] = V7_UNDEFINED;
14604 }
14605 #else
14606 static void reset_last_name(struct v7 *v7) {
14607   /* should be inlined out */
14608   (void) v7;
14609 }
14610 #endif
14611 
14612 static void prop_iter_ctx_dtor(struct v7 *v7, void *ud) {
14613   struct prop_iter_ctx *ctx = (struct prop_iter_ctx *) ud;
14614   v7_destruct_prop_iter_ctx(v7, ctx);
14615   free(ctx);
14616 }
14617 
14618 /*
14619  * Evaluates given `bcode`. If `reset_line_no` is non-zero, the line number
14620  * is initially reset to 1; otherwise, it is inherited from the previous call
14621  * frame.
14622  */
14623 WARN_UNUSED_RESULT
14624 V7_PRIVATE enum v7_err eval_bcode(struct v7 *v7, struct bcode *bcode,
14625                                   val_t this_object, uint8_t reset_line_no,
14626                                   val_t *_res) {
14627   struct bcode_registers r;
14628   enum v7_err rcode = V7_OK;
14629   struct v7_call_frame_base *saved_bottom_call_frame = v7->bottom_call_frame;
14630 
14631   /*
14632    * Dummy variable just to enforce that `BTRY()` macro is used only inside the
14633    * `eval_bcode()` function
14634    */
14635   uint8_t _you_should_use_BTRY_in_eval_bcode_only = 0;
14636 
14637   char buf[512];
14638 
14639   val_t res = V7_UNDEFINED, v1 = V7_UNDEFINED, v2 = V7_UNDEFINED,
14640         v3 = V7_UNDEFINED, v4 = V7_UNDEFINED, scope_frame = V7_UNDEFINED;
14641   struct gc_tmp_frame tf = new_tmp_frame(v7);
14642 
14643   append_call_frame_bcode(v7, NULL, bcode, this_object, get_scope(v7), 0);
14644 
14645   if (reset_line_no) {
14646     v7->call_stack->line_no = 1;
14647   }
14648 
14649   /*
14650    * Set current call stack as the "bottom" call stack, so that bcode evaluator
14651    * will exit when it reaches this "bottom"
14652    */
14653   v7->bottom_call_frame = v7->call_stack;
14654 
14655   bcode_restore_registers(v7, bcode, &r);
14656 
14657   tmp_stack_push(&tf, &res);
14658   tmp_stack_push(&tf, &v1);
14659   tmp_stack_push(&tf, &v2);
14660   tmp_stack_push(&tf, &v3);
14661   tmp_stack_push(&tf, &v4);
14662   tmp_stack_push(&tf, &scope_frame);
14663 
14664   /*
14665    * populate local variables on current scope, making them undeletable
14666    * (since they're defined with `var`)
14667    */
14668   {
14669     size_t i;
14670     for (i = 0; i < bcode->names_cnt; ++i) {
14671       r.ops = bcode_next_name_v(v7, bcode, r.ops, &v1);
14672 
14673       /* set undeletable property on current scope */
14674       V7_TRY(def_property_v(v7, get_scope(v7), v1, V7_DESC_CONFIGURABLE(0),
14675                             V7_UNDEFINED, 1 /*as_assign*/, NULL));
14676     }
14677   }
14678 
14679 restart:
14680   while (r.ops < r.end && rcode == V7_OK) {
14681     enum opcode op = (enum opcode) * r.ops;
14682 
14683 #ifndef V7_DISABLE_LINE_NUMBERS
14684     if ((uint8_t) op >= _OP_LINE_NO) {
14685       unsigned char buf[sizeof(size_t)];
14686       int len;
14687       size_t max_llen = sizeof(buf);
14688 
14689       /* ASAN doesn't like out of bound reads */
14690       if (r.ops + max_llen > r.end) {
14691         max_llen = r.end - r.ops;
14692       }
14693 
14694       /*
14695        * before we decode varint, we'll have to swap MSB and LSB, but we can't
14696        * do it in place since we're decoding from constant memory, so, we also
14697        * have to copy the data to the temp buffer first. 4 bytes should be
14698        * enough for everyone's line number.
14699        */
14700       memcpy(buf, r.ops, max_llen);
14701       buf[0] = msb_lsb_swap(buf[0]);
14702 
14703       v7->call_stack->line_no = decode_varint(buf, &len) >> 1;
14704       assert((size_t) len <= sizeof(buf));
14705       r.ops += len;
14706 
14707       continue;
14708     }
14709 #endif
14710 
14711     push_bcode_history(v7, op);
14712 
14713     if (v7->need_gc) {
14714       if (maybe_gc(v7)) {
14715         v7->need_gc = 0;
14716       }
14717     }
14718 
14719     r.need_inc_ops = 1;
14720 #ifdef V7_BCODE_TRACE
14721     {
14722       char *dops = r.ops;
14723       fprintf(stderr, "eval ");
14724       dump_op(v7, stderr, r.bcode, &dops);
14725     }
14726 #endif
14727 
14728     switch (op) {
14729       case OP_DROP:
14730         POP();
14731         break;
14732       case OP_DUP:
14733         v1 = POP();
14734         PUSH(v1);
14735         PUSH(v1);
14736         break;
14737       case OP_2DUP:
14738         v2 = POP();
14739         v1 = POP();
14740         PUSH(v1);
14741         PUSH(v2);
14742         PUSH(v1);
14743         PUSH(v2);
14744         break;
14745       case OP_SWAP:
14746         v1 = POP();
14747         v2 = POP();
14748         PUSH(v1);
14749         PUSH(v2);
14750         break;
14751       case OP_STASH:
14752         assert(!v7->is_stashed);
14753         v7->vals.stash = TOS();
14754         v7->is_stashed = 1;
14755         break;
14756       case OP_UNSTASH:
14757         assert(v7->is_stashed);
14758         POP();
14759         PUSH(v7->vals.stash);
14760         v7->vals.stash = V7_UNDEFINED;
14761         v7->is_stashed = 0;
14762         break;
14763 
14764       case OP_SWAP_DROP:
14765         v1 = POP();
14766         POP();
14767         PUSH(v1);
14768         break;
14769 
14770       case OP_PUSH_UNDEFINED:
14771         PUSH(V7_UNDEFINED);
14772         break;
14773       case OP_PUSH_NULL:
14774         PUSH(V7_NULL);
14775         break;
14776       case OP_PUSH_THIS:
14777         PUSH(v7_get_this(v7));
14778         reset_last_name(v7);
14779         break;
14780       case OP_PUSH_TRUE:
14781         PUSH(v7_mk_boolean(v7, 1));
14782         reset_last_name(v7);
14783         break;
14784       case OP_PUSH_FALSE:
14785         PUSH(v7_mk_boolean(v7, 0));
14786         reset_last_name(v7);
14787         break;
14788       case OP_PUSH_ZERO:
14789         PUSH(v7_mk_number(v7, 0));
14790         reset_last_name(v7);
14791         break;
14792       case OP_PUSH_ONE:
14793         PUSH(v7_mk_number(v7, 1));
14794         reset_last_name(v7);
14795         break;
14796       case OP_PUSH_LIT: {
14797         PUSH(bcode_decode_lit(v7, r.bcode, &r.ops));
14798 #ifndef V7_DISABLE_CALL_ERROR_CONTEXT
14799         /* name tracking */
14800         if (!v7_is_string(TOS())) {
14801           reset_last_name(v7);
14802         }
14803 #endif
14804         break;
14805       }
14806       case OP_LOGICAL_NOT:
14807         v1 = POP();
14808         PUSH(v7_mk_boolean(v7, !v7_is_truthy(v7, v1)));
14809         break;
14810       case OP_NOT: {
14811         v1 = POP();
14812         BTRY(to_number_v(v7, v1, &v1));
14813         PUSH(v7_mk_number(v7, ~(int32_t) v7_get_double(v7, v1)));
14814         break;
14815       }
14816       case OP_NEG: {
14817         v1 = POP();
14818         BTRY(to_number_v(v7, v1, &v1));
14819         PUSH(v7_mk_number(v7, -v7_get_double(v7, v1)));
14820         break;
14821       }
14822       case OP_POS: {
14823         v1 = POP();
14824         BTRY(to_number_v(v7, v1, &v1));
14825         PUSH(v1);
14826         break;
14827       }
14828       case OP_ADD: {
14829         v2 = POP();
14830         v1 = POP();
14831 
14832         /*
14833          * If either operand is an object, convert both of them to primitives
14834          */
14835         if (v7_is_object(v1) || v7_is_object(v2)) {
14836           BTRY(to_primitive(v7, v1, V7_TO_PRIMITIVE_HINT_AUTO, &v1));
14837           BTRY(to_primitive(v7, v2, V7_TO_PRIMITIVE_HINT_AUTO, &v2));
14838         }
14839 
14840         if (v7_is_string(v1) || v7_is_string(v2)) {
14841           /* Convert both operands to strings, and concatenate */
14842 
14843           BTRY(primitive_to_str(v7, v1, &v1, NULL, 0, NULL));
14844           BTRY(primitive_to_str(v7, v2, &v2, NULL, 0, NULL));
14845 
14846           PUSH(s_concat(v7, v1, v2));
14847         } else {
14848           /* Convert both operands to numbers, and sum */
14849 
14850           BTRY(primitive_to_number(v7, v1, &v1));
14851           BTRY(primitive_to_number(v7, v2, &v2));
14852 
14853           PUSH(v7_mk_number(v7, b_num_bin_op(op, v7_get_double(v7, v1),
14854                                              v7_get_double(v7, v2))));
14855         }
14856         break;
14857       }
14858       case OP_SUB:
14859       case OP_REM:
14860       case OP_MUL:
14861       case OP_DIV:
14862       case OP_LSHIFT:
14863       case OP_RSHIFT:
14864       case OP_URSHIFT:
14865       case OP_OR:
14866       case OP_XOR:
14867       case OP_AND: {
14868         v2 = POP();
14869         v1 = POP();
14870 
14871         BTRY(to_number_v(v7, v1, &v1));
14872         BTRY(to_number_v(v7, v2, &v2));
14873 
14874         PUSH(v7_mk_number(v7, b_num_bin_op(op, v7_get_double(v7, v1),
14875                                            v7_get_double(v7, v2))));
14876         break;
14877       }
14878       case OP_EQ_EQ: {
14879         v2 = POP();
14880         v1 = POP();
14881         if (v7_is_string(v1) && v7_is_string(v2)) {
14882           res = v7_mk_boolean(v7, s_cmp(v7, v1, v2) == 0);
14883         } else if (v1 == v2 && v1 == V7_TAG_NAN) {
14884           res = v7_mk_boolean(v7, 0);
14885         } else {
14886           res = v7_mk_boolean(v7, v1 == v2);
14887         }
14888         PUSH(res);
14889         break;
14890       }
14891       case OP_NE_NE: {
14892         v2 = POP();
14893         v1 = POP();
14894         if (v7_is_string(v1) && v7_is_string(v2)) {
14895           res = v7_mk_boolean(v7, s_cmp(v7, v1, v2) != 0);
14896         } else if (v1 == v2 && v1 == V7_TAG_NAN) {
14897           res = v7_mk_boolean(v7, 1);
14898         } else {
14899           res = v7_mk_boolean(v7, v1 != v2);
14900         }
14901         PUSH(res);
14902         break;
14903       }
14904       case OP_EQ:
14905       case OP_NE: {
14906         v2 = POP();
14907         v1 = POP();
14908         /*
14909          * TODO(dfrank) : it's not really correct. Fix it accordingly to
14910          * the p. 4.9 of The Definitive Guide (page 71)
14911          */
14912         if (((v7_is_object(v1) || v7_is_object(v2)) && v1 == v2)) {
14913           res = v7_mk_boolean(v7, op == OP_EQ);
14914           PUSH(res);
14915           break;
14916         } else if (v7_is_undefined(v1) || v7_is_null(v1)) {
14917           res = v7_mk_boolean(
14918               v7, (op != OP_EQ) ^ (v7_is_undefined(v2) || v7_is_null(v2)));
14919           PUSH(res);
14920           break;
14921         } else if (v7_is_undefined(v2) || v7_is_null(v2)) {
14922           res = v7_mk_boolean(
14923               v7, (op != OP_EQ) ^ (v7_is_undefined(v1) || v7_is_null(v1)));
14924           PUSH(res);
14925           break;
14926         }
14927 
14928         if (v7_is_string(v1) && v7_is_string(v2)) {
14929           int cmp = s_cmp(v7, v1, v2);
14930           switch (op) {
14931             case OP_EQ:
14932               res = v7_mk_boolean(v7, cmp == 0);
14933               break;
14934             case OP_NE:
14935               res = v7_mk_boolean(v7, cmp != 0);
14936               break;
14937             default:
14938               /* should never be here */
14939               assert(0);
14940           }
14941         } else {
14942           /* Convert both operands to numbers */
14943 
14944           BTRY(to_number_v(v7, v1, &v1));
14945           BTRY(to_number_v(v7, v2, &v2));
14946 
14947           res = v7_mk_boolean(v7, b_bool_bin_op(op, v7_get_double(v7, v1),
14948                                                 v7_get_double(v7, v2)));
14949         }
14950         PUSH(res);
14951         break;
14952       }
14953       case OP_LT:
14954       case OP_LE:
14955       case OP_GT:
14956       case OP_GE: {
14957         v2 = POP();
14958         v1 = POP();
14959         BTRY(to_primitive(v7, v1, V7_TO_PRIMITIVE_HINT_NUMBER, &v1));
14960         BTRY(to_primitive(v7, v2, V7_TO_PRIMITIVE_HINT_NUMBER, &v2));
14961 
14962         if (v7_is_string(v1) && v7_is_string(v2)) {
14963           int cmp = s_cmp(v7, v1, v2);
14964           switch (op) {
14965             case OP_LT:
14966               res = v7_mk_boolean(v7, cmp < 0);
14967               break;
14968             case OP_LE:
14969               res = v7_mk_boolean(v7, cmp <= 0);
14970               break;
14971             case OP_GT:
14972               res = v7_mk_boolean(v7, cmp > 0);
14973               break;
14974             case OP_GE:
14975               res = v7_mk_boolean(v7, cmp >= 0);
14976               break;
14977             default:
14978               /* should never be here */
14979               assert(0);
14980           }
14981         } else {
14982           /* Convert both operands to numbers */
14983 
14984           BTRY(to_number_v(v7, v1, &v1));
14985           BTRY(to_number_v(v7, v2, &v2));
14986 
14987           res = v7_mk_boolean(v7, b_bool_bin_op(op, v7_get_double(v7, v1),
14988                                                 v7_get_double(v7, v2)));
14989         }
14990         PUSH(res);
14991         break;
14992       }
14993       case OP_INSTANCEOF: {
14994         v2 = POP();
14995         v1 = POP();
14996         if (!v7_is_callable(v7, v2)) {
14997           BTRY(v7_throwf(v7, TYPE_ERROR,
14998                          "Expecting a function in instanceof check"));
14999           goto op_done;
15000         } else {
15001           PUSH(v7_mk_boolean(
15002               v7, is_prototype_of(v7, v1, v7_get(v7, v2, "prototype", 9))));
15003         }
15004         break;
15005       }
15006       case OP_TYPEOF:
15007         v1 = POP();
15008         switch (val_type(v7, v1)) {
15009           case V7_TYPE_NUMBER:
15010             res = v7_mk_string(v7, "number", 6, 1);
15011             break;
15012           case V7_TYPE_STRING:
15013             res = v7_mk_string(v7, "string", 6, 1);
15014             break;
15015           case V7_TYPE_BOOLEAN:
15016             res = v7_mk_string(v7, "boolean", 7, 1);
15017             break;
15018           case V7_TYPE_FUNCTION_OBJECT:
15019           case V7_TYPE_CFUNCTION_OBJECT:
15020           case V7_TYPE_CFUNCTION:
15021             res = v7_mk_string(v7, "function", 8, 1);
15022             break;
15023           case V7_TYPE_UNDEFINED:
15024             res = v7_mk_string(v7, "undefined", 9, 1);
15025             break;
15026           default:
15027             res = v7_mk_string(v7, "object", 6, 1);
15028             break;
15029         }
15030         PUSH(res);
15031         break;
15032       case OP_IN: {
15033         struct v7_property *prop = NULL;
15034         v2 = POP();
15035         v1 = POP();
15036         BTRY(to_string(v7, v1, NULL, buf, sizeof(buf), NULL));
15037         prop = v7_get_property(v7, v2, buf, ~0);
15038         PUSH(v7_mk_boolean(v7, prop != NULL));
15039       } break;
15040       case OP_GET:
15041         v2 = POP();
15042         v1 = POP();
15043         BTRY(v7_get_throwing_v(v7, v1, v2, &v3));
15044         PUSH(v3);
15045 #ifndef V7_DISABLE_CALL_ERROR_CONTEXT
15046         v7->vals.last_name[1] = v7->vals.last_name[0];
15047         v7->vals.last_name[0] = v2;
15048 #endif
15049         break;
15050       case OP_SET: {
15051         v3 = POP();
15052         v2 = POP();
15053         v1 = POP();
15054 
15055         /* convert name to string, if it's not already */
15056         BTRY(to_string(v7, v2, &v2, NULL, 0, NULL));
15057 
15058         /* set value */
15059         BTRY(set_property_v(v7, v1, v2, v3, NULL));
15060 
15061         PUSH(v3);
15062         break;
15063       }
15064       case OP_GET_VAR:
15065       case OP_SAFE_GET_VAR: {
15066         struct v7_property *p = NULL;
15067         assert(r.ops < r.end - 1);
15068         v1 = bcode_decode_lit(v7, r.bcode, &r.ops);
15069         BTRY(v7_get_property_v(v7, get_scope(v7), v1, &p));
15070         if (p == NULL) {
15071           if (op == OP_SAFE_GET_VAR) {
15072             PUSH(V7_UNDEFINED);
15073           } else {
15074             /* variable does not exist: Reference Error */
15075             V7_TRY(bcode_throw_reference_error(v7, &r, v1));
15076             goto op_done;
15077           }
15078           break;
15079         } else {
15080           BTRY(v7_property_value(v7, get_scope(v7), p, &v2));
15081           PUSH(v2);
15082         }
15083 #ifndef V7_DISABLE_CALL_ERROR_CONTEXT
15084         v7->vals.last_name[0] = v1;
15085         v7->vals.last_name[1] = V7_UNDEFINED;
15086 #endif
15087         break;
15088       }
15089       case OP_SET_VAR: {
15090         struct v7_property *prop;
15091         v3 = POP();
15092         v2 = bcode_decode_lit(v7, r.bcode, &r.ops);
15093         v1 = get_scope(v7);
15094 
15095         BTRY(to_string(v7, v2, NULL, buf, sizeof(buf), NULL));
15096         prop = v7_get_property(v7, v1, buf, strlen(buf));
15097         if (prop != NULL) {
15098           /* Property already exists: update its value */
15099           /*
15100            * TODO(dfrank): currently we can't use `def_property_v()` here,
15101            * because if the property was already found somewhere in the
15102            * prototype chain, then it should be updated, instead of creating a
15103            * new one on the top of the scope.
15104            *
15105            * Probably we need to make `def_property_v()` more generic and
15106            * use it here; or split `def_property_v()` into smaller pieces and
15107            * use one of them here.
15108            */
15109           if (!(prop->attributes & V7_PROPERTY_NON_WRITABLE)) {
15110             prop->value = v3;
15111           }
15112         } else if (!r.bcode->strict_mode) {
15113           /*
15114            * Property does not exist: since we're not in strict mode, let's
15115            * create new property at Global Object
15116            */
15117           BTRY(set_property_v(v7, v7_get_global(v7), v2, v3, NULL));
15118         } else {
15119           /*
15120            * In strict mode, throw reference error instead of polluting Global
15121            * Object
15122            */
15123           V7_TRY(bcode_throw_reference_error(v7, &r, v2));
15124           goto op_done;
15125         }
15126         PUSH(v3);
15127         break;
15128       }
15129       case OP_JMP: {
15130         bcode_off_t target = bcode_get_target(&r.ops);
15131         r.ops = r.bcode->ops.p + target - 1;
15132         break;
15133       }
15134       case OP_JMP_FALSE: {
15135         bcode_off_t target = bcode_get_target(&r.ops);
15136         v1 = POP();
15137         if (!v7_is_truthy(v7, v1)) {
15138           r.ops = r.bcode->ops.p + target - 1;
15139         }
15140         break;
15141       }
15142       case OP_JMP_TRUE: {
15143         bcode_off_t target = bcode_get_target(&r.ops);
15144         v1 = POP();
15145         if (v7_is_truthy(v7, v1)) {
15146           r.ops = r.bcode->ops.p + target - 1;
15147         }
15148         break;
15149       }
15150       case OP_JMP_TRUE_DROP: {
15151         bcode_off_t target = bcode_get_target(&r.ops);
15152         v1 = POP();
15153         if (v7_is_truthy(v7, v1)) {
15154           r.ops = r.bcode->ops.p + target - 1;
15155           v1 = POP();
15156           POP();
15157           PUSH(v1);
15158         }
15159         break;
15160       }
15161       case OP_JMP_IF_CONTINUE: {
15162         bcode_off_t target = bcode_get_target(&r.ops);
15163         if (v7->is_continuing) {
15164           r.ops = r.bcode->ops.p + target - 1;
15165         }
15166         v7->is_continuing = 0;
15167         break;
15168       }
15169       case OP_CREATE_OBJ:
15170         PUSH(v7_mk_object(v7));
15171         break;
15172       case OP_CREATE_ARR:
15173         PUSH(v7_mk_array(v7));
15174         break;
15175       case OP_PUSH_PROP_ITER_CTX: {
15176         struct prop_iter_ctx *ctx =
15177             (struct prop_iter_ctx *) calloc(1, sizeof(*ctx));
15178         BTRY(init_prop_iter_ctx(v7, TOS(), 1, ctx));
15179         v1 = v7_mk_object(v7);
15180         v7_set_user_data(v7, v1, ctx);
15181         v7_set_destructor_cb(v7, v1, prop_iter_ctx_dtor);
15182         PUSH(v1);
15183         break;
15184       }
15185       case OP_NEXT_PROP: {
15186         struct prop_iter_ctx *ctx = NULL;
15187         int ok = 0;
15188         v1 = POP(); /* ctx */
15189         v2 = POP(); /* object */
15190 
15191         ctx = (struct prop_iter_ctx *) v7_get_user_data(v7, v1);
15192 
15193         if (v7_is_object(v2)) {
15194           v7_prop_attr_t attrs;
15195 
15196           do {
15197             /* iterate properties until we find a non-hidden enumerable one */
15198             do {
15199               BTRY(next_prop(v7, ctx, &res, NULL, &attrs, &ok));
15200             } while (ok && (attrs & (_V7_PROPERTY_HIDDEN |
15201                                      V7_PROPERTY_NON_ENUMERABLE)));
15202 
15203             if (!ok) {
15204               /* no more properties in this object: proceed to the prototype */
15205               v2 = v7_get_proto(v7, v2);
15206               if (get_generic_object_struct(v2) != NULL) {
15207                 /*
15208                  * the prototype is a generic object, so, init the context for
15209                  * props iteration
15210                  */
15211                 v7_destruct_prop_iter_ctx(v7, ctx);
15212                 BTRY(init_prop_iter_ctx(v7, v2, 1, ctx));
15213               } else {
15214                 /*
15215                  * we can't iterate the prototype's props, so, just stop
15216                  * iteration.
15217                  */
15218                 ctx = NULL;
15219               }
15220             }
15221           } while (!ok && ctx != NULL);
15222         } else {
15223           /*
15224            * Not an object: reset the context.
15225            */
15226           ctx = NULL;
15227         }
15228 
15229         if (ctx == NULL) {
15230           PUSH(v7_mk_boolean(v7, 0));
15231 
15232           /*
15233            * We could leave the context unfreed, and let the
15234            * `prop_iter_ctx_dtor()` free it when the v1 will be GC-d, but
15235            * let's do that earlier.
15236            */
15237           ctx = (struct prop_iter_ctx *) v7_get_user_data(v7, v1);
15238           v7_destruct_prop_iter_ctx(v7, ctx);
15239           free(ctx);
15240           v7_set_user_data(v7, v1, NULL);
15241           v7_set_destructor_cb(v7, v1, NULL);
15242         } else {
15243           PUSH(v2);
15244           PUSH(v1);
15245           PUSH(res);
15246           PUSH(v7_mk_boolean(v7, 1));
15247         }
15248         break;
15249       }
15250       case OP_FUNC_LIT: {
15251         v1 = POP();
15252         v2 = bcode_instantiate_function(v7, v1);
15253         PUSH(v2);
15254         break;
15255       }
15256       case OP_CHECK_CALL:
15257         v1 = TOS();
15258         if (!v7_is_callable(v7, v1)) {
15259           int arity = 0;
15260           enum v7_err ignore;
15261 /* tried to call non-function object: throw a TypeError */
15262 
15263 #ifndef V7_DISABLE_CALL_ERROR_CONTEXT
15264           /*
15265            * try to provide some useful context for the error message
15266            * using a good-enough heuristics
15267            * but defer actual throw when process the incriminated call
15268            * in order to evaluate the arguments as required by the spec.
15269            */
15270           if (v7->last_ops[0] == OP_GET_VAR) {
15271             arity = 1;
15272           } else if (v7->last_ops[0] == OP_GET &&
15273                      v7->last_ops[1] == OP_PUSH_LIT) {
15274             /*
15275              * OP_PUSH_LIT is used to both push property names for OP_GET
15276              * and for pushing actual literals. During PUSH_LIT push lit
15277              * evaluation we reset the last name variable in case the literal
15278              * is not a string, such as in `[].foo()`.
15279              * Unfortunately it doesn't handle `"foo".bar()`; could be
15280              * solved by adding another bytecode for property literals but
15281              * probably it doesn't matter much.
15282              */
15283             if (v7_is_undefined(v7->vals.last_name[1])) {
15284               arity = 1;
15285             } else {
15286               arity = 2;
15287             }
15288           }
15289 #endif
15290 
15291           switch (arity) {
15292             case 0:
15293               ignore = v7_throwf(v7, TYPE_ERROR, "value is not a function");
15294               break;
15295 #ifndef V7_DISABLE_CALL_ERROR_CONTEXT
15296 
15297             case 1:
15298               ignore = v7_throwf(v7, TYPE_ERROR, "%s is not a function",
15299                                  v7_get_cstring(v7, &v7->vals.last_name[0]));
15300               break;
15301             case 2:
15302               ignore = v7_throwf(v7, TYPE_ERROR, "%s.%s is not a function",
15303                                  v7_get_cstring(v7, &v7->vals.last_name[1]),
15304                                  v7_get_cstring(v7, &v7->vals.last_name[0]));
15305               break;
15306 #endif
15307           };
15308 
15309           v7->vals.call_check_ex = v7->vals.thrown_error;
15310           v7_clear_thrown_value(v7);
15311           (void) ignore;
15312         }
15313         break;
15314       case OP_CALL:
15315       case OP_NEW: {
15316         /* Naive implementation pending stack frame redesign */
15317         int args = (int) *(++r.ops);
15318         uint8_t is_constructor = (op == OP_NEW);
15319 
15320         if (SP() < (args + 1 /*func*/ + 1 /*this*/)) {
15321           BTRY(v7_throwf(v7, INTERNAL_ERROR, "stack underflow"));
15322           goto op_done;
15323         } else {
15324           v2 = v7_mk_dense_array(v7);
15325           while (args > 0) {
15326             BTRY(v7_array_set_throwing(v7, v2, --args, POP(), NULL));
15327           }
15328           /* pop function to call */
15329           v1 = POP();
15330 
15331           /* pop `this` */
15332           v3 = POP();
15333 
15334           /*
15335            * adjust `this` if the function is called with the constructor
15336            * invocation pattern
15337            */
15338           if (is_constructor) {
15339             /*
15340              * The function is invoked as a constructor: we ignore `this`
15341              * value popped from stack, create new object and set prototype.
15342              */
15343 
15344             /*
15345              * get "prototype" property from the constructor function,
15346              * and make sure it's an object
15347              */
15348             v4 = v7_get(v7, v1 /*func*/, "prototype", 9);
15349             if (!v7_is_object(v4)) {
15350               /* TODO(dfrank): box primitive value */
15351               BTRY(v7_throwf(
15352                   v7, TYPE_ERROR,
15353                   "Cannot set a primitive value as object prototype"));
15354               goto op_done;
15355             } else if (is_cfunction_lite(v4)) {
15356               /*
15357                * TODO(dfrank): maybe add support for a cfunction pointer to be
15358                * a prototype
15359                */
15360               BTRY(v7_throwf(v7, TYPE_ERROR,
15361                              "Not implemented: cfunction as a prototype"));
15362               goto op_done;
15363             }
15364 
15365             /* create an object with given prototype */
15366             v3 = mk_object(v7, v4 /*prototype*/);
15367             v4 = V7_UNDEFINED;
15368           }
15369 
15370           if (!v7_is_callable(v7, v1)) {
15371             /* tried to call non-function object: throw a TypeError */
15372             BTRY(v7_throw(v7, v7->vals.call_check_ex));
15373             goto op_done;
15374           } else if (is_cfunction_lite(v1) || is_cfunction_obj(v7, v1)) {
15375             /* call cfunction */
15376 
15377             /*
15378              * In "function invocation pattern", the `this` value popped from
15379              * stack is an `undefined`. And in non-strict mode, we should change
15380              * it to global object.
15381              */
15382             if (!is_constructor && !r.bcode->strict_mode &&
15383                 v7_is_undefined(v3)) {
15384               v3 = v7->vals.global_object;
15385             }
15386 
15387             BTRY(call_cfunction(v7, v1 /*func*/, v3 /*this*/, v2 /*args*/,
15388                                 is_constructor, &v4));
15389 
15390             /* push value returned from C function to bcode stack */
15391             PUSH(v4);
15392 
15393           } else {
15394             char *ops;
15395             struct v7_js_function *func = get_js_function_struct(v1);
15396 
15397             /*
15398              * In "function invocation pattern", the `this` value popped from
15399              * stack is an `undefined`. And in non-strict mode, we should change
15400              * it to global object.
15401              */
15402             if (!is_constructor && !func->bcode->strict_mode &&
15403                 v7_is_undefined(v3)) {
15404               v3 = v7->vals.global_object;
15405             }
15406 
15407             scope_frame = v7_mk_object(v7);
15408 
15409             /*
15410              * Before actual opcodes, `ops` contains one or more
15411              * null-terminated strings: first of all, the function name (if the
15412              * function is anonymous, it's an empty string).
15413              *
15414              * Then, argument names follow. We know number of arguments, so, we
15415              * know how many names to take.
15416              *
15417              * And then, local variable names follow. We know total number of
15418              * strings (`names_cnt`), so, again, we know how many names to
15419              * take.
15420              */
15421 
15422             ops = func->bcode->ops.p;
15423 
15424             /* populate function itself */
15425             ops = bcode_next_name_v(v7, func->bcode, ops, &v4);
15426             BTRY(def_property_v(v7, scope_frame, v4, V7_DESC_CONFIGURABLE(0),
15427                                 v1, 0 /*not assign*/, NULL));
15428 
15429             /* populate arguments */
15430             {
15431               int arg_num;
15432               for (arg_num = 0; arg_num < func->bcode->args_cnt; ++arg_num) {
15433                 ops = bcode_next_name_v(v7, func->bcode, ops, &v4);
15434                 BTRY(def_property_v(
15435                     v7, scope_frame, v4, V7_DESC_CONFIGURABLE(0),
15436                     v7_array_get(v7, v2, arg_num), 0 /*not assign*/, NULL));
15437               }
15438             }
15439 
15440             /* populate `arguments` object */
15441 
15442             /*
15443              * TODO(dfrank): it's actually much more complicated than that:
15444              * it's not an array, it's an array-like object. More, in
15445              * non-strict mode, elements of `arguments` object are just aliases
15446              * for actual arguments, so this one:
15447              *
15448              *   `(function(a){arguments[0]=2; return a;})(1);`
15449              *
15450              * should yield 2. Currently, it yields 1.
15451              */
15452             v7_def(v7, scope_frame, "arguments", 9, V7_DESC_CONFIGURABLE(0),
15453                    v2);
15454 
15455             /* populate local variables */
15456             {
15457               uint8_t loc_num;
15458               uint8_t loc_cnt = func->bcode->names_cnt - func->bcode->args_cnt -
15459                                 1 /*func name*/;
15460               for (loc_num = 0; loc_num < loc_cnt; ++loc_num) {
15461                 ops = bcode_next_name_v(v7, func->bcode, ops, &v4);
15462                 BTRY(def_property_v(v7, scope_frame, v4,
15463                                     V7_DESC_CONFIGURABLE(0), V7_UNDEFINED,
15464                                     0 /*not assign*/, NULL));
15465               }
15466             }
15467 
15468             /* transfer control to the function */
15469             V7_TRY(bcode_perform_call(v7, scope_frame, func, &r, v3 /*this*/,
15470                                       ops, is_constructor));
15471 
15472             scope_frame = V7_UNDEFINED;
15473           }
15474         }
15475         break;
15476       }
15477       case OP_RET:
15478         bcode_adjust_retval(v7, 1 /*explicit return*/);
15479         V7_TRY(bcode_perform_return(v7, &r, 1 /*take value from stack*/));
15480         break;
15481       case OP_DELETE:
15482       case OP_DELETE_VAR: {
15483         size_t name_len;
15484         struct v7_property *prop;
15485 
15486         res = v7_mk_boolean(v7, 1);
15487 
15488         /* pop property name to delete */
15489         v2 = POP();
15490 
15491         if (op == OP_DELETE) {
15492           /* pop object to delete the property from */
15493           v1 = POP();
15494         } else {
15495           /* use scope as an object to delete the property from */
15496           v1 = get_scope(v7);
15497         }
15498 
15499         if (!v7_is_object(v1)) {
15500           /*
15501            * the "object" to delete a property from is not actually an object
15502            * (at least this can happen with cfunction pointers), will just
15503            * return `true`
15504            */
15505           goto delete_clean;
15506         }
15507 
15508         BTRY(to_string(v7, v2, NULL, buf, sizeof(buf), &name_len));
15509 
15510         prop = v7_get_property(v7, v1, buf, name_len);
15511         if (prop == NULL) {
15512           /* not found a property; will just return `true` */
15513           goto delete_clean;
15514         }
15515 
15516         /* found needed property */
15517 
15518         if (prop->attributes & V7_PROPERTY_NON_CONFIGURABLE) {
15519           /*
15520            * this property is undeletable. In non-strict mode, we just
15521            * return `false`; otherwise, we throw.
15522            */
15523           if (!r.bcode->strict_mode) {
15524             res = v7_mk_boolean(v7, 0);
15525           } else {
15526             BTRY(v7_throwf(v7, TYPE_ERROR, "Cannot delete property '%s'", buf));
15527             goto op_done;
15528           }
15529         } else {
15530           /*
15531            * delete property: when we operate on the current scope, we should
15532            * walk the prototype chain when deleting property.
15533            *
15534            * But when we operate on a "real" object, we should delete own
15535            * properties only.
15536            */
15537           if (op == OP_DELETE) {
15538             v7_del(v7, v1, buf, name_len);
15539           } else {
15540             del_property_deep(v7, v1, buf, name_len);
15541           }
15542         }
15543 
15544       delete_clean:
15545         PUSH(res);
15546         break;
15547       }
15548       case OP_TRY_PUSH_CATCH:
15549       case OP_TRY_PUSH_FINALLY:
15550       case OP_TRY_PUSH_LOOP:
15551       case OP_TRY_PUSH_SWITCH:
15552         eval_try_push(v7, op, &r);
15553         break;
15554       case OP_TRY_POP:
15555         V7_TRY(eval_try_pop(v7));
15556         break;
15557       case OP_AFTER_FINALLY:
15558         /*
15559          * exited from `finally` block: if some value is currently being
15560          * returned, continue returning it.
15561          *
15562          * Likewise, if some value is currently being thrown, continue
15563          * unwinding stack.
15564          */
15565         if (v7->is_thrown) {
15566           V7_TRY(
15567               bcode_perform_throw(v7, &r, 0 /*don't take value from stack*/));
15568           goto op_done;
15569         } else if (v7->is_returned) {
15570           V7_TRY(
15571               bcode_perform_return(v7, &r, 0 /*don't take value from stack*/));
15572           break;
15573         } else if (v7->is_breaking) {
15574           bcode_perform_break(v7, &r);
15575         }
15576         break;
15577       case OP_THROW:
15578         V7_TRY(bcode_perform_throw(v7, &r, 1 /*take thrown value*/));
15579         goto op_done;
15580       case OP_BREAK:
15581         bcode_perform_break(v7, &r);
15582         break;
15583       case OP_CONTINUE:
15584         v7->is_continuing = 1;
15585         bcode_perform_break(v7, &r);
15586         break;
15587       case OP_ENTER_CATCH: {
15588         /* pop thrown value from stack */
15589         v1 = POP();
15590         /* get the name of the thrown value */
15591         v2 = bcode_decode_lit(v7, r.bcode, &r.ops);
15592 
15593         /*
15594          * create a new stack frame (a "private" one), and set exception
15595          * property on it
15596          */
15597         scope_frame = v7_mk_object(v7);
15598         BTRY(set_property_v(v7, scope_frame, v2, v1, NULL));
15599 
15600         /* Push this "private" frame on the call stack */
15601 
15602         /* new scope_frame will inherit from the current scope */
15603 
15604         obj_prototype_set(v7, get_object_struct(scope_frame),
15605                           get_object_struct(get_scope(v7)));
15606 
15607         /*
15608          * Create new `call_frame` which will replace `v7->call_stack`.
15609          */
15610         append_call_frame_private(v7, scope_frame);
15611 
15612         break;
15613       }
15614       case OP_EXIT_CATCH: {
15615         v7_call_frame_mask_t frame_type_mask;
15616         /* unwind 1 frame */
15617         frame_type_mask = unwind_stack_1level(v7, &r);
15618         /* make sure the unwound frame is a "private" frame */
15619         assert(frame_type_mask == V7_CALL_FRAME_MASK_PRIVATE);
15620 #if defined(NDEBUG)
15621         (void) frame_type_mask;
15622 #endif
15623         break;
15624       }
15625       default:
15626         BTRY(v7_throwf(v7, INTERNAL_ERROR, "Unknown opcode: %d", (int) op));
15627         goto op_done;
15628     }
15629 
15630   op_done:
15631 #ifdef V7_BCODE_TRACE
15632     /* print current stack state */
15633     {
15634       char buf[40];
15635       char *str = v7_stringify(v7, TOS(), buf, sizeof(buf), V7_STRINGIFY_DEBUG);
15636       fprintf(stderr, "        stack size: %u, TOS: '%s'\n",
15637               (unsigned int) (v7->stack.len / sizeof(val_t)), str);
15638       if (str != buf) {
15639         free(str);
15640       }
15641 
15642 #ifdef V7_BCODE_TRACE_STACK
15643       {
15644         size_t i;
15645         for (i = 0; i < (v7->stack.len / sizeof(val_t)); i++) {
15646           char *str = v7_stringify(v7, stack_at(&v7->stack, i), buf,
15647                                    sizeof(buf), V7_STRINGIFY_DEBUG);
15648 
15649           fprintf(stderr, "        #: '%s'\n", str);
15650 
15651           if (str != buf) {
15652             free(str);
15653           }
15654         }
15655       }
15656 #endif
15657     }
15658 #endif
15659     if (r.need_inc_ops) {
15660       r.ops++;
15661     }
15662   }
15663 
15664   /* implicit return */
15665   if (v7->call_stack != v7->bottom_call_frame) {
15666 #ifdef V7_BCODE_TRACE
15667     fprintf(stderr, "return implicitly\n");
15668 #endif
15669     bcode_adjust_retval(v7, 0 /*implicit return*/);
15670     V7_TRY(bcode_perform_return(v7, &r, 1));
15671     goto restart;
15672   } else {
15673 #ifdef V7_BCODE_TRACE
15674     const char *s = (get_scope(v7) != v7->vals.global_object)
15675                         ? "not global object"
15676                         : "global object";
15677     fprintf(stderr, "reached bottom_call_frame (%s)\n", s);
15678 #endif
15679   }
15680 
15681 clean:
15682 
15683   if (rcode == V7_OK) {
15684 /*
15685  * bcode evaluated successfully. Make sure try stack is empty.
15686  * (data stack will be checked below, in `clean`)
15687  */
15688 #ifndef NDEBUG
15689     {
15690       unsigned long try_stack_len =
15691           v7_array_length(v7, find_call_frame_private(v7)->vals.try_stack);
15692       if (try_stack_len != 0) {
15693         fprintf(stderr, "try_stack_len=%lu, should be 0\n", try_stack_len);
15694       }
15695       assert(try_stack_len == 0);
15696     }
15697 #endif
15698 
15699     /* get the value returned from the evaluated script */
15700     *_res = POP();
15701   }
15702 
15703   assert(v7->bottom_call_frame == v7->call_stack);
15704   unwind_stack_1level(v7, NULL);
15705 
15706   v7->bottom_call_frame = saved_bottom_call_frame;
15707 
15708   tmp_frame_cleanup(&tf);
15709   return rcode;
15710 }
15711 
15712 /*
15713  * TODO(dfrank) this function is probably too overloaded: it handles both
15714  * `v7_exec` and `v7_apply`. Read below why it's written this way, but it's
15715  * probably a good idea to factor out common functionality in some other
15716  * function.
15717  *
15718  * If `src` is not `NULL`, then we behave in favour of `v7_exec`: parse,
15719  * compile, and evaluate the script. The `func` and `args` are ignored.
15720  *
15721  * If, however, `src` is `NULL`, then we behave in favour of `v7_apply`: we
15722  * call the provided `func` with `args`. But unlike interpreter, we can't just
15723  * call the provided function: we need to setup environment for this call.
15724  *
15725  * Currently, we just quickly generate the "wrapper" bcode for the function.
15726  * This wrapper bcode looks like this:
15727  *
15728  *    OP_PUSH_UNDEFINED
15729  *    OP_PUSH_LIT       # push this
15730  *    OP_PUSH_LIT       # push function
15731  *    OP_PUSH_LIT       # push arg1
15732  *    OP_PUSH_LIT       # push arg2
15733  *    ...
15734  *    OP_PUSH_LIT       # push argN
15735  *    OP_CALL(N)        # call function with N arguments
15736  *    OP_SWAP_DROP
15737  *
15738  * and then, bcode evaluator proceeds with this code.
15739  *
15740  * In fact, both cases (eval or apply) are quite similar: we should prepare
15741  * environment for the bcode evaluation in exactly the same way, and the only
15742  * different part is where we get the bcode from. This is why that
15743  * functionality is baked in the single function, but it would be good to make
15744  * it suck less.
15745  */
15746 V7_PRIVATE enum v7_err b_exec(struct v7 *v7, const char *src, size_t src_len,
15747                               const char *filename, val_t func, val_t args,
15748                               val_t this_object, int is_json, int fr,
15749                               uint8_t is_constructor, val_t *res) {
15750 #if defined(V7_BCODE_TRACE_SRC)
15751   fprintf(stderr, "src:'%s'\n", src);
15752 #endif
15753 
15754 /* TODO(mkm): use GC pool */
15755 #if !defined(V7_NO_COMPILER)
15756   struct ast *a = (struct ast *) malloc(sizeof(struct ast));
15757 #endif
15758   size_t saved_stack_len = v7->stack.len;
15759   enum v7_err rcode = V7_OK;
15760   val_t _res = V7_UNDEFINED;
15761   struct gc_tmp_frame tf = new_tmp_frame(v7);
15762   struct bcode *bcode = NULL;
15763 #if defined(V7_ENABLE_STACK_TRACKING)
15764   struct stack_track_ctx stack_track_ctx;
15765 #endif
15766   struct {
15767     unsigned noopt : 1;
15768     unsigned line_no_reset : 1;
15769   } flags = {0, 0};
15770 
15771   (void) filename;
15772 
15773 #if defined(V7_ENABLE_STACK_TRACKING)
15774   v7_stack_track_start(v7, &stack_track_ctx);
15775 #endif
15776 
15777   tmp_stack_push(&tf, &func);
15778   tmp_stack_push(&tf, &args);
15779   tmp_stack_push(&tf, &this_object);
15780   tmp_stack_push(&tf, &_res);
15781 
15782   /* init new bcode */
15783   bcode = (struct bcode *) calloc(1, sizeof(*bcode));
15784 
15785   bcode_init(bcode,
15786 #ifndef V7_FORCE_STRICT_MODE
15787              0,
15788 #else
15789              1,
15790 #endif
15791 #ifndef V7_DISABLE_FILENAMES
15792              filename ? shdata_create_from_string(filename) : NULL,
15793 #else
15794              NULL,
15795 #endif
15796              0 /*filename not in ROM*/
15797              );
15798 
15799   retain_bcode(v7, bcode);
15800   own_bcode(v7, bcode);
15801 
15802 #if !defined(V7_NO_COMPILER)
15803   ast_init(a, 0);
15804   a->refcnt = 1;
15805 #endif
15806 
15807   if (src != NULL) {
15808     /* Caller provided some source code, so, handle it somehow */
15809 
15810     flags.line_no_reset = 1;
15811 
15812     if (src_len >= sizeof(BIN_BCODE_SIGNATURE) &&
15813         strncmp(BIN_BCODE_SIGNATURE, src, sizeof(BIN_BCODE_SIGNATURE)) == 0) {
15814       /* we have a serialized bcode */
15815 
15816       bcode_deserialize(v7, bcode, src + sizeof(BIN_BCODE_SIGNATURE));
15817 
15818 /*
15819  * Currently, we only support serialized bcode that is stored in some
15820  * mmapped memory. Otherwise, we don't yet have any mechanism to free
15821  * this memory at the appropriate time.
15822  */
15823 
15824 /*
15825  * TODO(dfrank): currently, we remove this assert, and introduce memory
15826  * leak. We need to support that properly.
15827  */
15828 #if 0
15829       assert(fr == 0);
15830 #else
15831       if (fr) {
15832         fr = 0;
15833       }
15834 #endif
15835     } else {
15836 /* Maybe regular JavaScript source or binary AST data */
15837 #if !defined(V7_NO_COMPILER)
15838 
15839       if (src_len >= sizeof(BIN_AST_SIGNATURE) &&
15840           strncmp(BIN_AST_SIGNATURE, src, sizeof(BIN_AST_SIGNATURE)) == 0) {
15841         /* we have binary AST data */
15842 
15843         if (fr == 0) {
15844           /* Unmanaged memory, usually rom or mmapped flash */
15845           mbuf_free(&a->mbuf);
15846           a->mbuf.buf = (char *) (src + sizeof(BIN_AST_SIGNATURE));
15847           a->mbuf.size = a->mbuf.len = src_len - sizeof(BIN_AST_SIGNATURE);
15848           a->refcnt++; /* prevent freeing */
15849           flags.noopt = 1;
15850         } else {
15851           mbuf_append(&a->mbuf, src + sizeof(BIN_AST_SIGNATURE),
15852                       src_len - sizeof(BIN_AST_SIGNATURE));
15853         }
15854       } else {
15855         /* we have regular JavaScript source, so, parse it */
15856         V7_TRY(parse(v7, a, src, src_len, is_json));
15857       }
15858 
15859       /* we now have binary AST, let's compile it */
15860 
15861       if (!flags.noopt) {
15862         ast_optimize(a);
15863       }
15864 #if V7_ENABLE__Memory__stats
15865       v7->function_arena_ast_size += a->mbuf.size;
15866 #endif
15867 
15868       if (v7_is_undefined(this_object)) {
15869         this_object = v7->vals.global_object;
15870       }
15871 
15872       if (!is_json) {
15873         V7_TRY(compile_script(v7, a, bcode));
15874       } else {
15875         ast_off_t pos = 0;
15876         V7_TRY(compile_expr(v7, a, &pos, bcode));
15877       }
15878 #else  /* V7_NO_COMPILER */
15879       (void) is_json;
15880       /* Parsing JavaScript code is disabled */
15881       rcode = v7_throwf(v7, SYNTAX_ERROR,
15882                         "Parsing JS code is disabled by V7_NO_COMPILER");
15883       V7_THROW(V7_SYNTAX_ERROR);
15884 #endif /* V7_NO_COMPILER */
15885     }
15886 
15887   } else if (is_js_function(func)) {
15888     /*
15889      * Caller did not provide source code, so, assume we should call
15890      * provided function. Here, we prepare "wrapper" bcode.
15891      */
15892 
15893     struct bcode_builder bbuilder;
15894     lit_t lit;
15895     int args_cnt = v7_array_length(v7, args);
15896 
15897     bcode_builder_init(v7, &bbuilder, bcode);
15898 
15899     bcode_op(&bbuilder, OP_PUSH_UNDEFINED);
15900 
15901     /* push `this` */
15902     lit = bcode_add_lit(&bbuilder, this_object);
15903     bcode_push_lit(&bbuilder, lit);
15904 
15905     /* push func literal */
15906     lit = bcode_add_lit(&bbuilder, func);
15907     bcode_push_lit(&bbuilder, lit);
15908 
15909     /* push args */
15910     {
15911       int i;
15912       for (i = 0; i < args_cnt; i++) {
15913         lit = bcode_add_lit(&bbuilder, v7_array_get(v7, args, i));
15914         bcode_push_lit(&bbuilder, lit);
15915       }
15916     }
15917 
15918     bcode_op(&bbuilder, OP_CALL);
15919     /* TODO(dfrank): check if args <= 0x7f */
15920     bcode_op(&bbuilder, (uint8_t) args_cnt);
15921 
15922     bcode_op(&bbuilder, OP_SWAP_DROP);
15923 
15924     bcode_builder_finalize(&bbuilder);
15925   } else if (is_cfunction_lite(func) || is_cfunction_obj(v7, func)) {
15926     /* call cfunction */
15927 
15928     V7_TRY(call_cfunction(v7, func, this_object, args, is_constructor, &_res));
15929 
15930     goto clean;
15931   } else {
15932     /* value is not a function */
15933     V7_TRY(v7_throwf(v7, TYPE_ERROR, "value is not a function"));
15934   }
15935 
15936 /* We now have bcode to evaluate; proceed to it */
15937 
15938 #if !defined(V7_NO_COMPILER)
15939   /*
15940    * Before we evaluate bcode, we can safely release AST since it's not needed
15941    * anymore. Note that there's no leak here: if we `goto clean` from somewhere
15942    * above, we'll anyway release the AST under `clean` as well.
15943    */
15944   release_ast(v7, a);
15945   a = NULL;
15946 #endif /* V7_NO_COMPILER */
15947 
15948   /* Evaluate bcode */
15949   V7_TRY(eval_bcode(v7, bcode, this_object, flags.line_no_reset, &_res));
15950 
15951 clean:
15952 
15953   /* free `src` if needed */
15954   /*
15955    * TODO(dfrank) : free it above, just after parsing, and make sure you use
15956    * V7_TRY2() with custom label instead of V7_TRY()
15957    */
15958   if (src != NULL && fr) {
15959     free((void *) src);
15960   }
15961 
15962   /* disown and release current bcode */
15963   disown_bcode(v7, bcode);
15964   release_bcode(v7, bcode);
15965   bcode = NULL;
15966 
15967   if (rcode != V7_OK) {
15968     /* some exception happened. */
15969     _res = v7->vals.thrown_error;
15970 
15971     /*
15972      * if this is a top-level bcode, clear thrown error from the v7 context
15973      *
15974      * TODO(dfrank): do we really need to do this?
15975      *
15976      * If we don't clear the error, then we should clear it manually after each
15977      * call to v7_exec() or friends; otherwise, all the following calls will
15978      * see this error.
15979      *
15980      * On the other hand, user would still need to clear the error if he calls
15981      * v7_exec() from some cfunction. So, currently, sometimes we don't need
15982      * to clear the error, and sometimes we do, which is confusing.
15983      */
15984     if (v7->act_bcodes.len == 0) {
15985       v7->vals.thrown_error = V7_UNDEFINED;
15986       v7->is_thrown = 0;
15987     }
15988   }
15989 
15990   /*
15991    * Data stack should have the same length as it was before evaluating script.
15992    */
15993   if (v7->stack.len != saved_stack_len) {
15994     fprintf(stderr, "len=%d, saved=%d\n", (int) v7->stack.len,
15995             (int) saved_stack_len);
15996   }
15997   assert(v7->stack.len == saved_stack_len);
15998 
15999 #if !defined(V7_NO_COMPILER)
16000   /*
16001    * release AST if needed (normally, it's already released above, before
16002    * bcode evaluation)
16003    */
16004   if (a != NULL) {
16005     release_ast(v7, a);
16006     a = NULL;
16007   }
16008 #endif /* V7_NO_COMPILER */
16009 
16010   if (is_constructor && !v7_is_object(_res)) {
16011     /* constructor returned non-object: replace it with `this` */
16012     _res = v7_get_this(v7);
16013   }
16014 
16015   /* Provide the caller with the result, if asked to do so */
16016   if (res != NULL) {
16017     *res = _res;
16018   }
16019 
16020 #if defined(V7_ENABLE_STACK_TRACKING)
16021   {
16022     int diff = v7_stack_track_end(v7, &stack_track_ctx);
16023     if (diff > v7->stack_stat[V7_STACK_STAT_EXEC]) {
16024       v7->stack_stat[V7_STACK_STAT_EXEC] = diff;
16025     }
16026   }
16027 #endif
16028 
16029   tmp_frame_cleanup(&tf);
16030   return rcode;
16031 }
16032 
16033 WARN_UNUSED_RESULT
16034 V7_PRIVATE enum v7_err b_apply(struct v7 *v7, v7_val_t func, v7_val_t this_obj,
16035                                v7_val_t args, uint8_t is_constructor,
16036                                v7_val_t *res) {
16037   return b_exec(v7, NULL, 0, NULL, func, args, this_obj, 0, 0, is_constructor,
16038                 res);
16039 }
16040 #ifdef V7_MODULE_LINES
16041 #line 1 "v7/src/core.c"
16042 #endif
16043 /*
16044  * Copyright (c) 2014 Cesanta Software Limited
16045  * All rights reserved
16046  */
16047 
16048 /* Amalgamated: #include "v7/builtin/builtin.h" */
16049 /* Amalgamated: #include "v7/src/internal.h" */
16050 /* Amalgamated: #include "v7/src/object.h" */
16051 /* Amalgamated: #include "v7/src/core.h" */
16052 /* Amalgamated: #include "v7/src/primitive.h" */
16053 /* Amalgamated: #include "v7/src/array.h" */
16054 /* Amalgamated: #include "v7/src/slre.h" */
16055 /* Amalgamated: #include "v7/src/bcode.h" */
16056 /* Amalgamated: #include "v7/src/stdlib.h" */
16057 /* Amalgamated: #include "v7/src/gc.h" */
16058 /* Amalgamated: #include "v7/src/heapusage.h" */
16059 /* Amalgamated: #include "v7/src/eval.h" */
16060 
16061 #ifdef V7_THAW
16062 extern struct v7_vals *fr_vals;
16063 #endif
16064 
16065 #ifdef HAS_V7_INFINITY
16066 double _v7_infinity;
16067 #endif
16068 
16069 #ifdef HAS_V7_NAN
16070 double _v7_nan;
16071 #endif
16072 
16073 #if defined(V7_CYG_PROFILE_ON)
16074 struct v7 *v7_head = NULL;
16075 #endif
16076 
16077 static void generic_object_destructor(struct v7 *v7, void *ptr) {
16078   struct v7_generic_object *o = (struct v7_generic_object *) ptr;
16079   struct v7_property *p;
16080   struct mbuf *abuf;
16081 
16082   /* TODO(mkm): make regexp use user data API */
16083   p = v7_get_own_property2(v7, v7_object_to_value(&o->base), "", 0,
16084                            _V7_PROPERTY_HIDDEN);
16085 
16086 #if V7_ENABLE__RegExp
16087   if (p != NULL && (p->value & V7_TAG_MASK) == V7_TAG_REGEXP) {
16088     struct v7_regexp *rp = (struct v7_regexp *) get_ptr(p->value);
16089     v7_disown(v7, &rp->regexp_string);
16090     slre_free(rp->compiled_regexp);
16091     free(rp);
16092   }
16093 #endif
16094 
16095   if (o->base.attributes & V7_OBJ_DENSE_ARRAY) {
16096     if (p != NULL &&
16097         ((abuf = (struct mbuf *) v7_get_ptr(v7, p->value)) != NULL)) {
16098       mbuf_free(abuf);
16099       free(abuf);
16100     }
16101   }
16102 
16103   if (o->base.attributes & V7_OBJ_HAS_DESTRUCTOR) {
16104     struct v7_property *p;
16105     for (p = o->base.properties; p != NULL; p = p->next) {
16106       if (p->attributes & _V7_PROPERTY_USER_DATA_AND_DESTRUCTOR) {
16107         if (v7_is_foreign(p->name)) {
16108           v7_destructor_cb_t *cb =
16109               (v7_destructor_cb_t *) v7_get_ptr(v7, p->name);
16110           cb(v7, v7_get_ptr(v7, p->value));
16111         }
16112         break;
16113       }
16114     }
16115   }
16116 
16117 #if defined(V7_ENABLE_ENTITY_IDS)
16118   o->base.entity_id_base = V7_ENTITY_ID_PART_NONE;
16119   o->base.entity_id_spec = V7_ENTITY_ID_PART_NONE;
16120 #endif
16121 }
16122 
16123 static void function_destructor(struct v7 *v7, void *ptr) {
16124   struct v7_js_function *f = (struct v7_js_function *) ptr;
16125   (void) v7;
16126   if (f == NULL) return;
16127 
16128   if (f->bcode != NULL) {
16129     release_bcode(v7, f->bcode);
16130   }
16131 
16132 #if defined(V7_ENABLE_ENTITY_IDS)
16133   f->base.entity_id_base = V7_ENTITY_ID_PART_NONE;
16134   f->base.entity_id_spec = V7_ENTITY_ID_PART_NONE;
16135 #endif
16136 }
16137 
16138 #if defined(V7_ENABLE_ENTITY_IDS)
16139 static void property_destructor(struct v7 *v7, void *ptr) {
16140   struct v7_property *p = (struct v7_property *) ptr;
16141   (void) v7;
16142   if (p == NULL) return;
16143 
16144   p->entity_id = V7_ENTITY_ID_NONE;
16145 }
16146 #endif
16147 
16148 struct v7 *v7_create(void) {
16149   struct v7_create_opts opts;
16150   memset(&opts, 0, sizeof(opts));
16151   return v7_create_opt(opts);
16152 }
16153 
16154 struct v7 *v7_create_opt(struct v7_create_opts opts) {
16155   struct v7 *v7 = NULL;
16156   char z = 0;
16157 
16158 #if defined(HAS_V7_INFINITY) || defined(HAS_V7_NAN)
16159   double zero = 0.0;
16160 #endif
16161 
16162 #ifdef HAS_V7_INFINITY
16163   _v7_infinity = 1.0 / zero;
16164 #endif
16165 #ifdef HAS_V7_NAN
16166   _v7_nan = zero / zero;
16167 #endif
16168 
16169   if (opts.object_arena_size == 0) opts.object_arena_size = 200;
16170   if (opts.function_arena_size == 0) opts.function_arena_size = 100;
16171   if (opts.property_arena_size == 0) opts.property_arena_size = 400;
16172 
16173   if ((v7 = (struct v7 *) calloc(1, sizeof(*v7))) != NULL) {
16174 #ifdef V7_STACK_SIZE
16175     v7->sp_limit = (void *) ((uintptr_t) opts.c_stack_base - (V7_STACK_SIZE));
16176     v7->sp_lwm = opts.c_stack_base;
16177 #ifdef V7_STACK_GUARD_MIN_SIZE
16178     v7_sp_limit = v7->sp_limit;
16179 #endif
16180 #endif
16181 
16182 #if defined(V7_CYG_PROFILE_ON)
16183     v7->next_v7 = v7_head;
16184     v7_head = v7;
16185 #endif
16186 
16187 #ifndef V7_DISABLE_STR_ALLOC_SEQ
16188     v7->gc_next_asn = 0;
16189     v7->gc_min_asn = 0;
16190 #endif
16191 
16192     v7->cur_dense_prop =
16193         (struct v7_property *) calloc(1, sizeof(struct v7_property));
16194     gc_arena_init(&v7->generic_object_arena, sizeof(struct v7_generic_object),
16195                   opts.object_arena_size, 10, "object");
16196     v7->generic_object_arena.destructor = generic_object_destructor;
16197     gc_arena_init(&v7->function_arena, sizeof(struct v7_js_function),
16198                   opts.function_arena_size, 10, "function");
16199     v7->function_arena.destructor = function_destructor;
16200     gc_arena_init(&v7->property_arena, sizeof(struct v7_property),
16201                   opts.property_arena_size, 10, "property");
16202 #if defined(V7_ENABLE_ENTITY_IDS)
16203     v7->property_arena.destructor = property_destructor;
16204 #endif
16205 
16206     /*
16207      * The compacting GC exploits the null terminator of the previous
16208      * string as marker.
16209      */
16210     mbuf_append(&v7->owned_strings, &z, 1);
16211 
16212     v7->inhibit_gc = 1;
16213     v7->vals.thrown_error = V7_UNDEFINED;
16214 
16215     v7->call_stack = NULL;
16216     v7->bottom_call_frame = NULL;
16217 
16218 #if defined(V7_THAW) && !defined(V7_FREEZE_NOT_READONLY)
16219     {
16220       struct v7_generic_object *obj;
16221       v7->vals = *fr_vals;
16222       v7->vals.global_object = v7_mk_object(v7);
16223 
16224       /*
16225        * The global object has to be mutable.
16226        */
16227       obj = get_generic_object_struct(v7->vals.global_object);
16228       *obj = *get_generic_object_struct(fr_vals->global_object);
16229       obj->base.attributes &= ~(V7_OBJ_NOT_EXTENSIBLE | V7_OBJ_OFF_HEAP);
16230       v7_set(v7, v7->vals.global_object, "global", 6, v7->vals.global_object);
16231     }
16232 #else
16233     init_stdlib(v7);
16234     init_file(v7);
16235     init_crypto(v7);
16236     init_socket(v7);
16237 #endif
16238 
16239     v7->inhibit_gc = 0;
16240   }
16241 
16242   return v7;
16243 }
16244 
16245 val_t v7_get_global(struct v7 *v7) {
16246   return v7->vals.global_object;
16247 }
16248 
16249 void v7_destroy(struct v7 *v7) {
16250   if (v7 == NULL) return;
16251   gc_arena_destroy(v7, &v7->generic_object_arena);
16252   gc_arena_destroy(v7, &v7->function_arena);
16253   gc_arena_destroy(v7, &v7->property_arena);
16254 
16255   mbuf_free(&v7->owned_strings);
16256   mbuf_free(&v7->owned_values);
16257   mbuf_free(&v7->foreign_strings);
16258   mbuf_free(&v7->json_visited_stack);
16259   mbuf_free(&v7->tmp_stack);
16260   mbuf_free(&v7->act_bcodes);
16261   mbuf_free(&v7->stack);
16262 
16263 #if defined(V7_CYG_PROFILE_ON)
16264   /* delete this v7 */
16265   {
16266     struct v7 *v, **prevp = &v7_head;
16267     for (v = v7_head; v != NULL; prevp = &v->next_v7, v = v->next_v7) {
16268       if (v == v7) {
16269         *prevp = v->next_v7;
16270         break;
16271       }
16272     }
16273   }
16274 #endif
16275 
16276   free(v7->cur_dense_prop);
16277   free(v7);
16278 }
16279 
16280 v7_val_t v7_get_this(struct v7 *v7) {
16281   /*
16282    * By default, when there's no active call frame, will return Global Object
16283    */
16284   v7_val_t ret = v7->vals.global_object;
16285 
16286   struct v7_call_frame_base *call_frame =
16287       find_call_frame(v7, V7_CALL_FRAME_MASK_BCODE | V7_CALL_FRAME_MASK_CFUNC);
16288 
16289   if (call_frame != NULL) {
16290     if (call_frame->type_mask & V7_CALL_FRAME_MASK_BCODE) {
16291       ret = ((struct v7_call_frame_bcode *) call_frame)->vals.this_obj;
16292     } else if (call_frame->type_mask & V7_CALL_FRAME_MASK_CFUNC) {
16293       ret = ((struct v7_call_frame_cfunc *) call_frame)->vals.this_obj;
16294     } else {
16295       assert(0);
16296     }
16297   }
16298 
16299   return ret;
16300 }
16301 
16302 V7_PRIVATE v7_val_t get_scope(struct v7 *v7) {
16303   struct v7_call_frame_private *call_frame =
16304       (struct v7_call_frame_private *) find_call_frame(
16305           v7, V7_CALL_FRAME_MASK_PRIVATE);
16306 
16307   if (call_frame != NULL) {
16308     return call_frame->vals.scope;
16309   } else {
16310     /* No active call frame, return global object */
16311     return v7->vals.global_object;
16312   }
16313 }
16314 
16315 V7_PRIVATE uint8_t is_strict_mode(struct v7 *v7) {
16316   struct v7_call_frame_bcode *call_frame =
16317       (struct v7_call_frame_bcode *) find_call_frame(v7,
16318                                                      V7_CALL_FRAME_MASK_BCODE);
16319 
16320   if (call_frame != NULL) {
16321     return call_frame->bcode->strict_mode;
16322   } else {
16323     /* No active call frame, assume no strict mode */
16324     return 0;
16325   }
16326 }
16327 
16328 v7_val_t v7_get_arguments(struct v7 *v7) {
16329   return v7->vals.arguments;
16330 }
16331 
16332 v7_val_t v7_arg(struct v7 *v7, unsigned long n) {
16333   return v7_array_get(v7, v7->vals.arguments, n);
16334 }
16335 
16336 unsigned long v7_argc(struct v7 *v7) {
16337   return v7_array_length(v7, v7->vals.arguments);
16338 }
16339 
16340 void v7_own(struct v7 *v7, v7_val_t *v) {
16341   heapusage_dont_count(1);
16342   mbuf_append(&v7->owned_values, &v, sizeof(v));
16343   heapusage_dont_count(0);
16344 }
16345 
16346 int v7_disown(struct v7 *v7, v7_val_t *v) {
16347   v7_val_t **vp =
16348       (v7_val_t **) (v7->owned_values.buf + v7->owned_values.len - sizeof(v));
16349 
16350   for (; (char *) vp >= v7->owned_values.buf; vp--) {
16351     if (*vp == v) {
16352       *vp = *(v7_val_t **) (v7->owned_values.buf + v7->owned_values.len -
16353                             sizeof(v));
16354       v7->owned_values.len -= sizeof(v);
16355       return 1;
16356     }
16357   }
16358 
16359   return 0;
16360 }
16361 
16362 void v7_set_gc_enabled(struct v7 *v7, int enabled) {
16363   v7->inhibit_gc = !enabled;
16364 }
16365 
16366 void v7_interrupt(struct v7 *v7) {
16367   v7->interrupted = 1;
16368 }
16369 
16370 const char *v7_get_parser_error(struct v7 *v7) {
16371   return v7->error_msg;
16372 }
16373 
16374 #if defined(V7_ENABLE_STACK_TRACKING)
16375 
16376 int v7_stack_stat(struct v7 *v7, enum v7_stack_stat_what what) {
16377   assert(what < V7_STACK_STATS_CNT);
16378   return v7->stack_stat[what];
16379 }
16380 
16381 void v7_stack_stat_clean(struct v7 *v7) {
16382   memset(v7->stack_stat, 0x00, sizeof(v7->stack_stat));
16383 }
16384 
16385 #endif /* V7_ENABLE_STACK_TRACKING */
16386 #ifdef V7_MODULE_LINES
16387 #line 1 "v7/src/primitive.c"
16388 #endif
16389 /*
16390  * Copyright (c) 2014 Cesanta Software Limited
16391  * All rights reserved
16392  */
16393 
16394 /* Amalgamated: #include "v7/src/internal.h" */
16395 /* Amalgamated: #include "v7/src/core.h" */
16396 /* Amalgamated: #include "v7/src/primitive.h" */
16397 
16398 /* Number {{{ */
16399 
16400 NOINSTR static v7_val_t mk_number(double v) {
16401   val_t res;
16402   /* not every NaN is a JS NaN */
16403   if (isnan(v)) {
16404     res = V7_TAG_NAN;
16405   } else {
16406     union {
16407       double d;
16408       val_t r;
16409     } u;
16410     u.d = v;
16411     res = u.r;
16412   }
16413   return res;
16414 }
16415 
16416 NOINSTR static double get_double(val_t v) {
16417   union {
16418     double d;
16419     val_t v;
16420   } u;
16421   u.v = v;
16422   /* Due to NaN packing, any non-numeric value is already a valid NaN value */
16423   return u.d;
16424 }
16425 
16426 NOINSTR static v7_val_t mk_boolean(int v) {
16427   return (!!v) | V7_TAG_BOOLEAN;
16428 }
16429 
16430 NOINSTR static int get_bool(val_t v) {
16431   if (v7_is_boolean(v)) {
16432     return v & 1;
16433   } else {
16434     return 0;
16435   }
16436 }
16437 
16438 NOINSTR v7_val_t v7_mk_number(struct v7 *v7, double v) {
16439   (void) v7;
16440   return mk_number(v);
16441 }
16442 
16443 NOINSTR double v7_get_double(struct v7 *v7, v7_val_t v) {
16444   (void) v7;
16445   return get_double(v);
16446 }
16447 
16448 NOINSTR int v7_get_int(struct v7 *v7, v7_val_t v) {
16449   (void) v7;
16450   return (int) get_double(v);
16451 }
16452 
16453 int v7_is_number(val_t v) {
16454   return v == V7_TAG_NAN || !isnan(get_double(v));
16455 }
16456 
16457 V7_PRIVATE int is_finite(struct v7 *v7, val_t v) {
16458   return v7_is_number(v) && v != V7_TAG_NAN && !isinf(v7_get_double(v7, v));
16459 }
16460 
16461 /* }}} Number */
16462 
16463 /* Boolean {{{ */
16464 
16465 NOINSTR v7_val_t v7_mk_boolean(struct v7 *v7, int v) {
16466   (void) v7;
16467   return mk_boolean(v);
16468 }
16469 
16470 NOINSTR int v7_get_bool(struct v7 *v7, val_t v) {
16471   (void) v7;
16472   return get_bool(v);
16473 }
16474 
16475 int v7_is_boolean(val_t v) {
16476   return (v & V7_TAG_MASK) == V7_TAG_BOOLEAN;
16477 }
16478 
16479 /* }}} Boolean */
16480 
16481 /* null {{{ */
16482 
16483 NOINSTR v7_val_t v7_mk_null(void) {
16484   return V7_NULL;
16485 }
16486 
16487 int v7_is_null(val_t v) {
16488   return v == V7_NULL;
16489 }
16490 
16491 /* }}} null */
16492 
16493 /* undefined {{{ */
16494 
16495 NOINSTR v7_val_t v7_mk_undefined(void) {
16496   return V7_UNDEFINED;
16497 }
16498 
16499 int v7_is_undefined(val_t v) {
16500   return v == V7_UNDEFINED;
16501 }
16502 
16503 /* }}} undefined */
16504 
16505 /* Foreign {{{ */
16506 
16507 V7_PRIVATE val_t pointer_to_value(void *p) {
16508   uint64_t n = ((uint64_t)(uintptr_t) p);
16509 
16510   assert((n & V7_TAG_MASK) == 0 || (n & V7_TAG_MASK) == (~0 & V7_TAG_MASK));
16511   return n & ~V7_TAG_MASK;
16512 }
16513 
16514 V7_PRIVATE void *get_ptr(val_t v) {
16515   return (void *) (uintptr_t)(v & 0xFFFFFFFFFFFFUL);
16516 }
16517 
16518 NOINSTR void *v7_get_ptr(struct v7 *v7, val_t v) {
16519   (void) v7;
16520   if (!v7_is_foreign(v)) {
16521     return NULL;
16522   }
16523   return get_ptr(v);
16524 }
16525 
16526 NOINSTR v7_val_t v7_mk_foreign(struct v7 *v7, void *p) {
16527   (void) v7;
16528   return pointer_to_value(p) | V7_TAG_FOREIGN;
16529 }
16530 
16531 int v7_is_foreign(val_t v) {
16532   return (v & V7_TAG_MASK) == V7_TAG_FOREIGN;
16533 }
16534 
16535 /* }}} Foreign */
16536 #ifdef V7_MODULE_LINES
16537 #line 1 "v7/src/function.c"
16538 #endif
16539 /*
16540  * Copyright (c) 2014 Cesanta Software Limited
16541  * All rights reserved
16542  */
16543 
16544 /* Amalgamated: #include "v7/src/internal.h" */
16545 /* Amalgamated: #include "v7/src/primitive.h" */
16546 /* Amalgamated: #include "v7/src/core.h" */
16547 /* Amalgamated: #include "v7/src/function.h" */
16548 /* Amalgamated: #include "v7/src/gc.h" */
16549 /* Amalgamated: #include "v7/src/object.h" */
16550 
16551 static val_t js_function_to_value(struct v7_js_function *o) {
16552   return pointer_to_value(o) | V7_TAG_FUNCTION;
16553 }
16554 
16555 V7_PRIVATE struct v7_js_function *get_js_function_struct(val_t v) {
16556   struct v7_js_function *ret = NULL;
16557   assert(is_js_function(v));
16558   ret = (struct v7_js_function *) get_ptr(v);
16559 #if defined(V7_ENABLE_ENTITY_IDS)
16560   if (ret->base.entity_id_spec != V7_ENTITY_ID_PART_JS_FUNC) {
16561     fprintf(stderr, "entity_id: not a function!\n");
16562     abort();
16563   } else if (ret->base.entity_id_base != V7_ENTITY_ID_PART_OBJ) {
16564     fprintf(stderr, "entity_id: not an object!\n");
16565     abort();
16566   }
16567 #endif
16568   return ret;
16569 }
16570 
16571 V7_PRIVATE
16572 val_t mk_js_function(struct v7 *v7, struct v7_generic_object *scope,
16573                      val_t proto) {
16574   struct v7_js_function *f;
16575   val_t fval = V7_NULL;
16576   struct gc_tmp_frame tf = new_tmp_frame(v7);
16577   tmp_stack_push(&tf, &proto);
16578   tmp_stack_push(&tf, &fval);
16579 
16580   f = new_function(v7);
16581 
16582   if (f == NULL) {
16583     /* fval is left `null` */
16584     goto cleanup;
16585   }
16586 
16587 #if defined(V7_ENABLE_ENTITY_IDS)
16588   f->base.entity_id_base = V7_ENTITY_ID_PART_OBJ;
16589   f->base.entity_id_spec = V7_ENTITY_ID_PART_JS_FUNC;
16590 #endif
16591 
16592   fval = js_function_to_value(f);
16593 
16594   f->base.properties = NULL;
16595   f->scope = scope;
16596 
16597   /*
16598    * Before setting a `V7_OBJ_FUNCTION` flag, make sure we don't have
16599    * `V7_OBJ_DENSE_ARRAY` flag set
16600    */
16601   assert(!(f->base.attributes & V7_OBJ_DENSE_ARRAY));
16602   f->base.attributes |= V7_OBJ_FUNCTION;
16603 
16604   /* TODO(mkm): lazily create these properties on first access */
16605   if (v7_is_object(proto)) {
16606     v7_def(v7, proto, "constructor", 11, V7_DESC_ENUMERABLE(0), fval);
16607     v7_def(v7, fval, "prototype", 9,
16608            V7_DESC_ENUMERABLE(0) | V7_DESC_CONFIGURABLE(0), proto);
16609   }
16610 
16611 cleanup:
16612   tmp_frame_cleanup(&tf);
16613   return fval;
16614 }
16615 
16616 V7_PRIVATE int is_js_function(val_t v) {
16617   return (v & V7_TAG_MASK) == V7_TAG_FUNCTION;
16618 }
16619 
16620 V7_PRIVATE
16621 v7_val_t mk_cfunction_obj(struct v7 *v7, v7_cfunction_t *f, int num_args) {
16622   val_t obj = mk_object(v7, v7->vals.function_prototype);
16623   struct gc_tmp_frame tf = new_tmp_frame(v7);
16624   tmp_stack_push(&tf, &obj);
16625   v7_def(v7, obj, "", 0, _V7_DESC_HIDDEN(1), v7_mk_cfunction(f));
16626   if (num_args >= 0) {
16627     v7_def(v7, obj, "length", 6, (V7_DESC_ENUMERABLE(0) | V7_DESC_WRITABLE(0) |
16628                                   V7_DESC_CONFIGURABLE(0)),
16629            v7_mk_number(v7, num_args));
16630   }
16631   tmp_frame_cleanup(&tf);
16632   return obj;
16633 }
16634 
16635 V7_PRIVATE v7_val_t mk_cfunction_obj_with_proto(struct v7 *v7,
16636                                                 v7_cfunction_t *f, int num_args,
16637                                                 v7_val_t proto) {
16638   struct gc_tmp_frame tf = new_tmp_frame(v7);
16639   v7_val_t res = mk_cfunction_obj(v7, f, num_args);
16640 
16641   tmp_stack_push(&tf, &res);
16642 
16643   v7_def(v7, res, "prototype", 9, (V7_DESC_ENUMERABLE(0) | V7_DESC_WRITABLE(0) |
16644                                    V7_DESC_CONFIGURABLE(0)),
16645          proto);
16646   v7_def(v7, proto, "constructor", 11, V7_DESC_ENUMERABLE(0), res);
16647   tmp_frame_cleanup(&tf);
16648   return res;
16649 }
16650 
16651 V7_PRIVATE v7_val_t mk_cfunction_lite(v7_cfunction_t *f) {
16652   union {
16653     void *p;
16654     v7_cfunction_t *f;
16655   } u;
16656   u.f = f;
16657   return pointer_to_value(u.p) | V7_TAG_CFUNCTION;
16658 }
16659 
16660 V7_PRIVATE v7_cfunction_t *get_cfunction_ptr(struct v7 *v7, val_t v) {
16661   v7_cfunction_t *ret = NULL;
16662 
16663   if (is_cfunction_lite(v)) {
16664     /* Implementation is identical to get_ptr but is separate since
16665      * object pointers are not directly convertible to function pointers
16666      * according to ISO C and generates a warning in -Wpedantic mode. */
16667     ret = (v7_cfunction_t *) (uintptr_t)(v & 0xFFFFFFFFFFFFUL);
16668   } else {
16669     /* maybe cfunction object */
16670 
16671     /* extract the hidden property from a cfunction_object */
16672     struct v7_property *p;
16673     p = v7_get_own_property2(v7, v, "", 0, _V7_PROPERTY_HIDDEN);
16674     if (p != NULL) {
16675       /* yes, it's cfunction object. Extract cfunction pointer from it */
16676       ret = get_cfunction_ptr(v7, p->value);
16677     }
16678   }
16679 
16680   return ret;
16681 }
16682 
16683 V7_PRIVATE int is_cfunction_lite(val_t v) {
16684   return (v & V7_TAG_MASK) == V7_TAG_CFUNCTION;
16685 }
16686 
16687 V7_PRIVATE int is_cfunction_obj(struct v7 *v7, val_t v) {
16688   int ret = 0;
16689   if (v7_is_object(v)) {
16690     /* extract the hidden property from a cfunction_object */
16691     struct v7_property *p;
16692     p = v7_get_own_property2(v7, v, "", 0, _V7_PROPERTY_HIDDEN);
16693     if (p != NULL) {
16694       v = p->value;
16695     }
16696 
16697     ret = is_cfunction_lite(v);
16698   }
16699   return ret;
16700 }
16701 
16702 v7_val_t v7_mk_function(struct v7 *v7, v7_cfunction_t *f) {
16703   return mk_cfunction_obj(v7, f, -1);
16704 }
16705 
16706 v7_val_t v7_mk_function_with_proto(struct v7 *v7, v7_cfunction_t *f,
16707                                    v7_val_t proto) {
16708   return mk_cfunction_obj_with_proto(v7, f, ~0, proto);
16709 }
16710 
16711 v7_val_t v7_mk_cfunction(v7_cfunction_t *f) {
16712   return mk_cfunction_lite(f);
16713 }
16714 
16715 int v7_is_callable(struct v7 *v7, val_t v) {
16716   return is_js_function(v) || is_cfunction_lite(v) || is_cfunction_obj(v7, v);
16717 }
16718 #ifdef V7_MODULE_LINES
16719 #line 1 "v7/src/exec.c"
16720 #endif
16721 /*
16722  * Copyright (c) 2014 Cesanta Software Limited
16723  * All rights reserved
16724  */
16725 
16726 /* osdep.h must be included before `cs_file.h` TODO(dfrank) : fix this */
16727 /* Amalgamated: #include "common/cs_file.h" */
16728 /* Amalgamated: #include "v7/src/internal.h" */
16729 /* Amalgamated: #include "v7/src/core.h" */
16730 /* Amalgamated: #include "v7/src/eval.h" */
16731 /* Amalgamated: #include "v7/src/exec.h" */
16732 /* Amalgamated: #include "v7/src/ast.h" */
16733 /* Amalgamated: #include "v7/src/compiler.h" */
16734 /* Amalgamated: #include "v7/src/exceptions.h" */
16735 
16736 enum v7_err v7_exec(struct v7 *v7, const char *js_code, v7_val_t *res) {
16737   return b_exec(v7, js_code, strlen(js_code), NULL, V7_UNDEFINED, V7_UNDEFINED,
16738                 V7_UNDEFINED, 0, 0, 0, res);
16739 }
16740 
16741 enum v7_err v7_exec_opt(struct v7 *v7, const char *js_code,
16742                         const struct v7_exec_opts *opts, v7_val_t *res) {
16743   return b_exec(v7, js_code, strlen(js_code), opts->filename, V7_UNDEFINED,
16744                 V7_UNDEFINED,
16745                 (opts->this_obj == 0 ? V7_UNDEFINED : opts->this_obj),
16746                 opts->is_json, 0, 0, res);
16747 }
16748 
16749 enum v7_err v7_parse_json(struct v7 *v7, const char *str, v7_val_t *res) {
16750   return b_exec(v7, str, strlen(str), NULL, V7_UNDEFINED, V7_UNDEFINED,
16751                 V7_UNDEFINED, 1, 0, 0, res);
16752 }
16753 
16754 #ifndef V7_NO_FS
16755 static enum v7_err exec_file(struct v7 *v7, const char *path, val_t *res,
16756                              int is_json) {
16757   enum v7_err rcode = V7_OK;
16758   char *p;
16759   size_t file_size;
16760   char *(*rd)(const char *, size_t *);
16761 
16762   rd = cs_read_file;
16763 #ifdef V7_MMAP_EXEC
16764   rd = cs_mmap_file;
16765 #ifdef V7_MMAP_EXEC_ONLY
16766 #define I_STRINGIFY(x) #x
16767 #define I_STRINGIFY2(x) I_STRINGIFY(x)
16768 
16769   /* use mmap only for .js files */
16770   if (strlen(path) <= 3 || strcmp(path + strlen(path) - 3, ".js") != 0) {
16771     rd = cs_read_file;
16772   }
16773 #endif
16774 #endif
16775 
16776   if ((p = rd(path, &file_size)) == NULL) {
16777     rcode = v7_throwf(v7, SYNTAX_ERROR, "cannot open [%s]", path);
16778     /*
16779      * In order to maintain compat with existing API, we should save the
16780      * current exception value into `*res`
16781      *
16782      * TODO(dfrank): probably change API: clients can use
16783      *`v7_get_thrown_value()` now.
16784      */
16785     if (res != NULL) *res = v7_get_thrown_value(v7, NULL);
16786     goto clean;
16787   } else {
16788 #ifndef V7_MMAP_EXEC
16789     int fr = 1;
16790 #else
16791     int fr = 0;
16792 #endif
16793     rcode = b_exec(v7, p, file_size, path, V7_UNDEFINED, V7_UNDEFINED,
16794                    V7_UNDEFINED, is_json, fr, 0, res);
16795     if (rcode != V7_OK) {
16796       goto clean;
16797     }
16798   }
16799 
16800 clean:
16801   return rcode;
16802 }
16803 
16804 enum v7_err v7_exec_file(struct v7 *v7, const char *path, val_t *res) {
16805   return exec_file(v7, path, res, 0);
16806 }
16807 
16808 enum v7_err v7_parse_json_file(struct v7 *v7, const char *path, v7_val_t *res) {
16809   return exec_file(v7, path, res, 1);
16810 }
16811 #endif /* V7_NO_FS */
16812 
16813 enum v7_err v7_apply(struct v7 *v7, v7_val_t func, v7_val_t this_obj,
16814                      v7_val_t args, v7_val_t *res) {
16815   return b_apply(v7, func, this_obj, args, 0, res);
16816 }
16817 
16818 #ifndef NO_LIBC
16819 #if !defined(V7_NO_COMPILER)
16820 enum v7_err _v7_compile(const char *src, size_t js_code_size, int binary,
16821                         int use_bcode, FILE *fp) {
16822   struct ast ast;
16823   struct v7 *v7 = v7_create();
16824   ast_off_t pos = 0;
16825   enum v7_err err;
16826 
16827   v7->is_precompiling = 1;
16828 
16829   ast_init(&ast, 0);
16830   err = parse(v7, &ast, src, js_code_size, 0);
16831   if (err == V7_OK) {
16832     if (use_bcode) {
16833       struct bcode bcode;
16834       /*
16835        * We don't set filename here, because the bcode will be just serialized
16836        * and then freed. We don't currently serialize filename. If we ever do,
16837        * we'll have to make `_v7_compile()` to also take a filename argument,
16838        * and use it here.
16839        */
16840       bcode_init(&bcode, 0, NULL, 0);
16841       err = compile_script(v7, &ast, &bcode);
16842       if (err != V7_OK) {
16843         goto cleanup_bcode;
16844       }
16845 
16846       if (binary) {
16847         bcode_serialize(v7, &bcode, fp);
16848       } else {
16849 #ifdef V7_BCODE_DUMP
16850         dump_bcode(v7, fp, &bcode);
16851 #else
16852         fprintf(stderr, "build flag V7_BCODE_DUMP not enabled\n");
16853 #endif
16854       }
16855     cleanup_bcode:
16856       bcode_free(v7, &bcode);
16857     } else {
16858       if (binary) {
16859         fwrite(BIN_AST_SIGNATURE, sizeof(BIN_AST_SIGNATURE), 1, fp);
16860         fwrite(ast.mbuf.buf, ast.mbuf.len, 1, fp);
16861       } else {
16862         ast_dump_tree(fp, &ast, &pos, 0);
16863       }
16864     }
16865   }
16866 
16867   ast_free(&ast);
16868   v7_destroy(v7);
16869   return err;
16870 }
16871 
16872 enum v7_err v7_compile(const char *src, int binary, int use_bcode, FILE *fp) {
16873   return _v7_compile(src, strlen(src), binary, use_bcode, fp);
16874 }
16875 #endif /* V7_NO_COMPILER */
16876 #endif
16877 #ifdef V7_MODULE_LINES
16878 #line 1 "v7/src/util.c"
16879 #endif
16880 /*
16881  * Copyright (c) 2014 Cesanta Software Limited
16882  * All rights reserved
16883  */
16884 
16885 /* Amalgamated: #include "v7/src/internal.h" */
16886 /* Amalgamated: #include "v7/src/core.h" */
16887 /* Amalgamated: #include "v7/src/object.h" */
16888 /* Amalgamated: #include "v7/src/util.h" */
16889 /* Amalgamated: #include "v7/src/string.h" */
16890 /* Amalgamated: #include "v7/src/array.h" */
16891 /* Amalgamated: #include "v7/src/eval.h" */
16892 /* Amalgamated: #include "v7/src/conversion.h" */
16893 /* Amalgamated: #include "v7/src/exceptions.h" */
16894 /* Amalgamated: #include "v7/src/primitive.h" */
16895 /* Amalgamated: #include "v7/src/std_proxy.h" */
16896 
16897 void v7_print(struct v7 *v7, v7_val_t v) {
16898   v7_fprint(stdout, v7, v);
16899 }
16900 
16901 void v7_fprint(FILE *f, struct v7 *v7, val_t v) {
16902   char buf[16];
16903   char *s = v7_stringify(v7, v, buf, sizeof(buf), V7_STRINGIFY_DEBUG);
16904   fprintf(f, "%s", s);
16905   if (buf != s) free(s);
16906 }
16907 
16908 void v7_println(struct v7 *v7, v7_val_t v) {
16909   v7_fprintln(stdout, v7, v);
16910 }
16911 
16912 void v7_fprintln(FILE *f, struct v7 *v7, val_t v) {
16913   v7_fprint(f, v7, v);
16914   fprintf(f, ENDL);
16915 }
16916 
16917 void v7_fprint_stack_trace(FILE *f, struct v7 *v7, val_t e) {
16918   size_t s;
16919   val_t strace_v = v7_get(v7, e, "stack", ~0);
16920   const char *strace = NULL;
16921   if (v7_is_string(strace_v)) {
16922     strace = v7_get_string(v7, &strace_v, &s);
16923     fprintf(f, "%s\n", strace);
16924   }
16925 }
16926 
16927 void v7_print_error(FILE *f, struct v7 *v7, const char *ctx, val_t e) {
16928   /* TODO(mkm): figure out if this is an error object and which kind */
16929   v7_val_t msg;
16930   if (v7_is_undefined(e)) {
16931     fprintf(f, "undefined error [%s]\n ", ctx);
16932     return;
16933   }
16934   msg = v7_get(v7, e, "message", ~0);
16935   if (v7_is_undefined(msg)) {
16936     msg = e;
16937   }
16938   fprintf(f, "Exec error [%s]: ", ctx);
16939   v7_fprintln(f, v7, msg);
16940   v7_fprint_stack_trace(f, v7, e);
16941 }
16942 
16943 #if V7_ENABLE__Proxy
16944 
16945 v7_val_t v7_mk_proxy(struct v7 *v7, v7_val_t target,
16946                      const v7_proxy_hnd_t *handler) {
16947   enum v7_err rcode = V7_OK;
16948   v7_val_t res = V7_UNDEFINED;
16949   v7_val_t args = V7_UNDEFINED;
16950   v7_val_t handler_v = V7_UNDEFINED;
16951 
16952   v7_own(v7, &res);
16953   v7_own(v7, &args);
16954   v7_own(v7, &handler_v);
16955   v7_own(v7, &target);
16956 
16957   /* if target is not an object, create one */
16958   if (!v7_is_object(target)) {
16959     target = v7_mk_object(v7);
16960   }
16961 
16962   /* prepare handler object with necessary properties */
16963   handler_v = v7_mk_object(v7);
16964   if (handler->get != NULL) {
16965     set_cfunc_prop(v7, handler_v, "get", handler->get);
16966   }
16967   if (handler->set != NULL) {
16968     set_cfunc_prop(v7, handler_v, "set", handler->set);
16969   }
16970   if (handler->own_keys != NULL) {
16971     set_cfunc_prop(v7, handler_v, "ownKeys", handler->own_keys);
16972   }
16973   if (handler->get_own_prop_desc != NULL) {
16974     v7_def(v7, handler_v, "_gpdc", ~0, V7_DESC_ENUMERABLE(0),
16975            v7_mk_foreign(v7, (void *) handler->get_own_prop_desc));
16976   }
16977 
16978   /* prepare args */
16979   args = v7_mk_dense_array(v7);
16980   v7_array_set(v7, args, 0, target);
16981   v7_array_set(v7, args, 1, handler_v);
16982 
16983   /* call Proxy constructor */
16984   V7_TRY(b_apply(v7, v7_get(v7, v7->vals.global_object, "Proxy", ~0),
16985                  v7_mk_object(v7), args, 1 /* as ctor */, &res));
16986 
16987 clean:
16988   if (rcode != V7_OK) {
16989     fprintf(stderr, "error during v7_mk_proxy()");
16990     res = V7_UNDEFINED;
16991   }
16992 
16993   v7_disown(v7, &target);
16994   v7_disown(v7, &handler_v);
16995   v7_disown(v7, &args);
16996   v7_disown(v7, &res);
16997   return res;
16998 }
16999 
17000 #endif /* V7_ENABLE__Proxy */
17001 
17002 V7_PRIVATE enum v7_type val_type(struct v7 *v7, val_t v) {
17003   int tag;
17004   if (v7_is_number(v)) {
17005     return V7_TYPE_NUMBER;
17006   }
17007   tag = (v & V7_TAG_MASK) >> 48;
17008   switch (tag) {
17009     case V7_TAG_FOREIGN >> 48:
17010       if (v7_is_null(v)) {
17011         return V7_TYPE_NULL;
17012       }
17013       return V7_TYPE_FOREIGN;
17014     case V7_TAG_UNDEFINED >> 48:
17015       return V7_TYPE_UNDEFINED;
17016     case V7_TAG_OBJECT >> 48:
17017       if (v7_get_proto(v7, v) == v7->vals.array_prototype) {
17018         return V7_TYPE_ARRAY_OBJECT;
17019       } else if (v7_get_proto(v7, v) == v7->vals.boolean_prototype) {
17020         return V7_TYPE_BOOLEAN_OBJECT;
17021       } else if (v7_get_proto(v7, v) == v7->vals.string_prototype) {
17022         return V7_TYPE_STRING_OBJECT;
17023       } else if (v7_get_proto(v7, v) == v7->vals.number_prototype) {
17024         return V7_TYPE_NUMBER_OBJECT;
17025       } else if (v7_get_proto(v7, v) == v7->vals.function_prototype) {
17026         return V7_TYPE_CFUNCTION_OBJECT;
17027       } else if (v7_get_proto(v7, v) == v7->vals.date_prototype) {
17028         return V7_TYPE_DATE_OBJECT;
17029       } else {
17030         return V7_TYPE_GENERIC_OBJECT;
17031       }
17032     case V7_TAG_STRING_I >> 48:
17033     case V7_TAG_STRING_O >> 48:
17034     case V7_TAG_STRING_F >> 48:
17035     case V7_TAG_STRING_D >> 48:
17036     case V7_TAG_STRING_5 >> 48:
17037       return V7_TYPE_STRING;
17038     case V7_TAG_BOOLEAN >> 48:
17039       return V7_TYPE_BOOLEAN;
17040     case V7_TAG_FUNCTION >> 48:
17041       return V7_TYPE_FUNCTION_OBJECT;
17042     case V7_TAG_CFUNCTION >> 48:
17043       return V7_TYPE_CFUNCTION;
17044     case V7_TAG_REGEXP >> 48:
17045       return V7_TYPE_REGEXP_OBJECT;
17046     default:
17047       abort();
17048       return V7_TYPE_UNDEFINED;
17049   }
17050 }
17051 
17052 #ifndef V7_DISABLE_LINE_NUMBERS
17053 V7_PRIVATE uint8_t msb_lsb_swap(uint8_t b) {
17054   if ((b & 0x01) != (b >> 7)) {
17055     b ^= 0x81;
17056   }
17057   return b;
17058 }
17059 #endif
17060 #ifdef V7_MODULE_LINES
17061 #line 1 "v7/src/string.c"
17062 #endif
17063 /*
17064  * Copyright (c) 2014 Cesanta Software Limited
17065  * All rights reserved
17066  */
17067 
17068 /* Amalgamated: #include "common/utf.h" */
17069 /* Amalgamated: #include "v7/src/string.h" */
17070 /* Amalgamated: #include "v7/src/exceptions.h" */
17071 /* Amalgamated: #include "v7/src/conversion.h" */
17072 /* Amalgamated: #include "v7/src/varint.h" */
17073 /* Amalgamated: #include "v7/src/gc.h" */
17074 /* Amalgamated: #include "v7/src/core.h" */
17075 /* Amalgamated: #include "v7/src/primitive.h" */
17076 /* Amalgamated: #include "v7/src/slre.h" */
17077 /* Amalgamated: #include "v7/src/heapusage.h" */
17078 
17079 /* TODO(lsm): NaN payload location depends on endianness, make crossplatform */
17080 #define GET_VAL_NAN_PAYLOAD(v) ((char *) &(v))
17081 
17082 /*
17083  * Dictionary of read-only strings with length > 5.
17084  * NOTE(lsm): must be sorted lexicographically, because
17085  * v_find_string_in_dictionary performs binary search over this list.
17086  */
17087 /* clang-format off */
17088 static const struct v7_vec_const v_dictionary_strings[] = {
17089     V7_VEC(" is not a function"),
17090     V7_VEC("Boolean"),
17091     V7_VEC("Crypto"),
17092     V7_VEC("EvalError"),
17093     V7_VEC("Function"),
17094     V7_VEC("Infinity"),
17095     V7_VEC("InternalError"),
17096     V7_VEC("LOG10E"),
17097     V7_VEC("MAX_VALUE"),
17098     V7_VEC("MIN_VALUE"),
17099     V7_VEC("NEGATIVE_INFINITY"),
17100     V7_VEC("Number"),
17101     V7_VEC("Object"),
17102     V7_VEC("POSITIVE_INFINITY"),
17103     V7_VEC("RangeError"),
17104     V7_VEC("ReferenceError"),
17105     V7_VEC("RegExp"),
17106     V7_VEC("SQRT1_2"),
17107     V7_VEC("Socket"),
17108     V7_VEC("String"),
17109     V7_VEC("SyntaxError"),
17110     V7_VEC("TypeError"),
17111     V7_VEC("UBJSON"),
17112     V7_VEC("_modcache"),
17113     V7_VEC("accept"),
17114     V7_VEC("arguments"),
17115     V7_VEC("base64_decode"),
17116     V7_VEC("base64_encode"),
17117     V7_VEC("boolean"),
17118     V7_VEC("charAt"),
17119     V7_VEC("charCodeAt"),
17120     V7_VEC("concat"),
17121     V7_VEC("configurable"),
17122     V7_VEC("connect"),
17123     V7_VEC("constructor"),
17124     V7_VEC("create"),
17125     V7_VEC("defineProperties"),
17126     V7_VEC("defineProperty"),
17127     V7_VEC("every"),
17128     V7_VEC("exists"),
17129     V7_VEC("exports"),
17130     V7_VEC("filter"),
17131     V7_VEC("forEach"),
17132     V7_VEC("fromCharCode"),
17133     V7_VEC("function"),
17134     V7_VEC("getDate"),
17135     V7_VEC("getDay"),
17136     V7_VEC("getFullYear"),
17137     V7_VEC("getHours"),
17138     V7_VEC("getMilliseconds"),
17139     V7_VEC("getMinutes"),
17140     V7_VEC("getMonth"),
17141     V7_VEC("getOwnPropertyDescriptor"),
17142     V7_VEC("getOwnPropertyNames"),
17143     V7_VEC("getPrototypeOf"),
17144     V7_VEC("getSeconds"),
17145     V7_VEC("getTime"),
17146     V7_VEC("getTimezoneOffset"),
17147     V7_VEC("getUTCDate"),
17148     V7_VEC("getUTCDay"),
17149     V7_VEC("getUTCFullYear"),
17150     V7_VEC("getUTCHours"),
17151     V7_VEC("getUTCMilliseconds"),
17152     V7_VEC("getUTCMinutes"),
17153     V7_VEC("getUTCMonth"),
17154     V7_VEC("getUTCSeconds"),
17155     V7_VEC("global"),
17156     V7_VEC("hasOwnProperty"),
17157     V7_VEC("ignoreCase"),
17158     V7_VEC("indexOf"),
17159     V7_VEC("isArray"),
17160     V7_VEC("isExtensible"),
17161     V7_VEC("isFinite"),
17162     V7_VEC("isPrototypeOf"),
17163     V7_VEC("lastIndex"),
17164     V7_VEC("lastIndexOf"),
17165     V7_VEC("length"),
17166     V7_VEC("listen"),
17167     V7_VEC("loadJSON"),
17168     V7_VEC("localeCompare"),
17169     V7_VEC("md5_hex"),
17170     V7_VEC("module"),
17171     V7_VEC("multiline"),
17172     V7_VEC("number"),
17173     V7_VEC("parseFloat"),
17174     V7_VEC("parseInt"),
17175     V7_VEC("preventExtensions"),
17176     V7_VEC("propertyIsEnumerable"),
17177     V7_VEC("prototype"),
17178     V7_VEC("random"),
17179     V7_VEC("recvAll"),
17180     V7_VEC("reduce"),
17181     V7_VEC("remove"),
17182     V7_VEC("rename"),
17183     V7_VEC("render"),
17184     V7_VEC("replace"),
17185     V7_VEC("require"),
17186     V7_VEC("reverse"),
17187     V7_VEC("search"),
17188     V7_VEC("setDate"),
17189     V7_VEC("setFullYear"),
17190     V7_VEC("setHours"),
17191     V7_VEC("setMilliseconds"),
17192     V7_VEC("setMinutes"),
17193     V7_VEC("setMonth"),
17194     V7_VEC("setSeconds"),
17195     V7_VEC("setTime"),
17196     V7_VEC("setUTCDate"),
17197     V7_VEC("setUTCFullYear"),
17198     V7_VEC("setUTCHours"),
17199     V7_VEC("setUTCMilliseconds"),
17200     V7_VEC("setUTCMinutes"),
17201     V7_VEC("setUTCMonth"),
17202     V7_VEC("setUTCSeconds"),
17203     V7_VEC("sha1_hex"),
17204     V7_VEC("source"),
17205     V7_VEC("splice"),
17206     V7_VEC("string"),
17207     V7_VEC("stringify"),
17208     V7_VEC("substr"),
17209     V7_VEC("substring"),
17210     V7_VEC("toDateString"),
17211     V7_VEC("toExponential"),
17212     V7_VEC("toFixed"),
17213     V7_VEC("toISOString"),
17214     V7_VEC("toJSON"),
17215     V7_VEC("toLocaleDateString"),
17216     V7_VEC("toLocaleLowerCase"),
17217     V7_VEC("toLocaleString"),
17218     V7_VEC("toLocaleTimeString"),
17219     V7_VEC("toLocaleUpperCase"),
17220     V7_VEC("toLowerCase"),
17221     V7_VEC("toPrecision"),
17222     V7_VEC("toString"),
17223     V7_VEC("toTimeString"),
17224     V7_VEC("toUTCString"),
17225     V7_VEC("toUpperCase"),
17226     V7_VEC("valueOf"),
17227     V7_VEC("writable"),
17228 };
17229 /* clang-format on */
17230 
17231 int nextesc(const char **p); /* from SLRE */
17232 V7_PRIVATE size_t unescape(const char *s, size_t len, char *to) {
17233   const char *end = s + len;
17234   size_t n = 0;
17235   char tmp[4];
17236   Rune r;
17237 
17238   while (s < end) {
17239     s += chartorune(&r, s);
17240     if (r == '\\' && s < end) {
17241       switch (*s) {
17242         case '"':
17243           s++, r = '"';
17244           break;
17245         case '\'':
17246           s++, r = '\'';
17247           break;
17248         case '\n':
17249           s++, r = '\n';
17250           break;
17251         default: {
17252           const char *tmp_s = s;
17253           int i = nextesc(&s);
17254           switch (i) {
17255             case -SLRE_INVALID_ESC_CHAR:
17256               r = '\\';
17257               s = tmp_s;
17258               n += runetochar(to == NULL ? tmp : to + n, &r);
17259               s += chartorune(&r, s);
17260               break;
17261             case -SLRE_INVALID_HEX_DIGIT:
17262             default:
17263               r = i;
17264           }
17265         }
17266       }
17267     }
17268     n += runetochar(to == NULL ? tmp : to + n, &r);
17269   }
17270 
17271   return n;
17272 }
17273 
17274 static int v_find_string_in_dictionary(const char *s, size_t len) {
17275   size_t start = 0, end = ARRAY_SIZE(v_dictionary_strings);
17276 
17277   while (s != NULL && start < end) {
17278     size_t mid = start + (end - start) / 2;
17279     const struct v7_vec_const *v = &v_dictionary_strings[mid];
17280     size_t min_len = len < v->len ? len : v->len;
17281     int comparison_result = memcmp(s, v->p, min_len);
17282     if (comparison_result == 0) {
17283       comparison_result = len - v->len;
17284     }
17285     if (comparison_result < 0) {
17286       end = mid;
17287     } else if (comparison_result > 0) {
17288       start = mid + 1;
17289     } else {
17290       return mid;
17291     }
17292   }
17293   return -1;
17294 }
17295 
17296 WARN_UNUSED_RESULT
17297 V7_PRIVATE enum v7_err v7_char_code_at(struct v7 *v7, val_t obj, val_t arg,
17298                                        double *res) {
17299   enum v7_err rcode = V7_OK;
17300   size_t n;
17301   val_t s = V7_UNDEFINED;
17302   const char *p = NULL;
17303   double at = v7_get_double(v7, arg);
17304 
17305   *res = 0;
17306 
17307   rcode = to_string(v7, obj, &s, NULL, 0, NULL);
17308   if (rcode != V7_OK) {
17309     goto clean;
17310   }
17311 
17312   p = v7_get_string(v7, &s, &n);
17313 
17314   n = utfnlen(p, n);
17315   if (v7_is_number(arg) && at >= 0 && at < n) {
17316     Rune r = 0;
17317     p = utfnshift(p, at);
17318     chartorune(&r, (char *) p);
17319     *res = r;
17320     goto clean;
17321   } else {
17322     *res = NAN;
17323     goto clean;
17324   }
17325 
17326 clean:
17327   return rcode;
17328 }
17329 
17330 V7_PRIVATE int s_cmp(struct v7 *v7, val_t a, val_t b) {
17331   size_t a_len, b_len;
17332   const char *a_ptr, *b_ptr;
17333 
17334   a_ptr = v7_get_string(v7, &a, &a_len);
17335   b_ptr = v7_get_string(v7, &b, &b_len);
17336 
17337   if (a_len == b_len) {
17338     return memcmp(a_ptr, b_ptr, a_len);
17339   }
17340   if (a_len > b_len) {
17341     return 1;
17342   } else if (a_len < b_len) {
17343     return -1;
17344   } else {
17345     return 0;
17346   }
17347 }
17348 
17349 V7_PRIVATE val_t s_concat(struct v7 *v7, val_t a, val_t b) {
17350   size_t a_len, b_len, res_len;
17351   const char *a_ptr, *b_ptr, *res_ptr;
17352   val_t res;
17353 
17354   /* Find out lengths of both srtings */
17355   a_ptr = v7_get_string(v7, &a, &a_len);
17356   b_ptr = v7_get_string(v7, &b, &b_len);
17357 
17358   /* Create an placeholder string */
17359   res = v7_mk_string(v7, NULL, a_len + b_len, 1);
17360 
17361   /* v7_mk_string() may have reallocated mbuf - revalidate pointers */
17362   a_ptr = v7_get_string(v7, &a, &a_len);
17363   b_ptr = v7_get_string(v7, &b, &b_len);
17364 
17365   /* Copy strings into the placeholder */
17366   res_ptr = v7_get_string(v7, &res, &res_len);
17367   memcpy((char *) res_ptr, a_ptr, a_len);
17368   memcpy((char *) res_ptr + a_len, b_ptr, b_len);
17369 
17370   return res;
17371 }
17372 
17373 V7_PRIVATE unsigned long cstr_to_ulong(const char *s, size_t len, int *ok) {
17374   char *e;
17375   unsigned long res = strtoul(s, &e, 10);
17376   *ok = (e == s + len) && len != 0;
17377   return res;
17378 }
17379 
17380 WARN_UNUSED_RESULT
17381 V7_PRIVATE enum v7_err str_to_ulong(struct v7 *v7, val_t v, int *ok,
17382                                     unsigned long *res) {
17383   enum v7_err rcode = V7_OK;
17384   char buf[100];
17385   size_t len = 0;
17386 
17387   V7_TRY(to_string(v7, v, NULL, buf, sizeof(buf), &len));
17388 
17389   *res = cstr_to_ulong(buf, len, ok);
17390 
17391 clean:
17392   return rcode;
17393 }
17394 
17395 /* Insert a string into mbuf at specified offset */
17396 V7_PRIVATE void embed_string(struct mbuf *m, size_t offset, const char *p,
17397                              size_t len, uint8_t /*enum embstr_flags*/ flags) {
17398   char *old_base = m->buf;
17399   uint8_t p_backed_by_mbuf = p >= old_base && p < old_base + m->len;
17400   size_t n = (flags & EMBSTR_UNESCAPE) ? unescape(p, len, NULL) : len;
17401 
17402   /* Calculate how many bytes length takes */
17403   int k = calc_llen(n);
17404 
17405   /* total length: varing length + string len + zero-term */
17406   size_t tot_len = k + n + !!(flags & EMBSTR_ZERO_TERM);
17407 
17408   /* Allocate buffer */
17409   heapusage_dont_count(1);
17410   mbuf_insert(m, offset, NULL, tot_len);
17411   heapusage_dont_count(0);
17412 
17413   /* Fixup p if it was relocated by mbuf_insert() above */
17414   if (p_backed_by_mbuf) {
17415     p += m->buf - old_base;
17416   }
17417 
17418   /* Write length */
17419   encode_varint(n, (unsigned char *) m->buf + offset);
17420 
17421   /* Write string */
17422   if (p != 0) {
17423     if (flags & EMBSTR_UNESCAPE) {
17424       unescape(p, len, m->buf + offset + k);
17425     } else {
17426       memcpy(m->buf + offset + k, p, len);
17427     }
17428   }
17429 
17430   /* add NULL-terminator if needed */
17431   if (flags & EMBSTR_ZERO_TERM) {
17432     m->buf[offset + tot_len - 1] = '\0';
17433   }
17434 }
17435 
17436 /* Create a string */
17437 v7_val_t v7_mk_string(struct v7 *v7, const char *p, size_t len, int copy) {
17438   struct mbuf *m = copy ? &v7->owned_strings : &v7->foreign_strings;
17439   val_t offset = m->len, tag = V7_TAG_STRING_F;
17440   int dict_index;
17441 
17442 #ifdef V7_GC_AFTER_STRING_ALLOC
17443   v7->need_gc = 1;
17444 #endif
17445 
17446   if (len == ~((size_t) 0)) len = strlen(p);
17447 
17448   if (len <= 4) {
17449     char *s = GET_VAL_NAN_PAYLOAD(offset) + 1;
17450     offset = 0;
17451     if (p != 0) {
17452       memcpy(s, p, len);
17453     }
17454     s[-1] = len;
17455     tag = V7_TAG_STRING_I;
17456   } else if (len == 5) {
17457     char *s = GET_VAL_NAN_PAYLOAD(offset);
17458     offset = 0;
17459     if (p != 0) {
17460       memcpy(s, p, len);
17461     }
17462     tag = V7_TAG_STRING_5;
17463   } else if ((dict_index = v_find_string_in_dictionary(p, len)) >= 0) {
17464     offset = 0;
17465     GET_VAL_NAN_PAYLOAD(offset)[0] = dict_index;
17466     tag = V7_TAG_STRING_D;
17467   } else if (copy) {
17468     compute_need_gc(v7);
17469 
17470     /*
17471      * Before embedding new string, check if the reallocation is needed.  If
17472      * so, perform the reallocation by calling `mbuf_resize` manually, since we
17473      * need to preallocate some extra space (`_V7_STRING_BUF_RESERVE`)
17474      */
17475     if ((m->len + len) > m->size) {
17476       heapusage_dont_count(1);
17477       mbuf_resize(m, m->len + len + _V7_STRING_BUF_RESERVE);
17478       heapusage_dont_count(0);
17479     }
17480     embed_string(m, m->len, p, len, EMBSTR_ZERO_TERM);
17481     tag = V7_TAG_STRING_O;
17482 #ifndef V7_DISABLE_STR_ALLOC_SEQ
17483     /* TODO(imax): panic if offset >= 2^32. */
17484     offset |= ((val_t) gc_next_allocation_seqn(v7, p, len)) << 32;
17485 #endif
17486   } else {
17487     /* foreign string */
17488     if (sizeof(void *) <= 4 && len <= UINT16_MAX) {
17489       /* small foreign strings can fit length and ptr in the val_t */
17490       offset = (uint64_t) len << 32 | (uint64_t)(uintptr_t) p;
17491     } else {
17492       /* bigger strings need indirection that uses ram */
17493       size_t pos = m->len;
17494       int llen = calc_llen(len);
17495 
17496       /* allocate space for len and ptr */
17497       heapusage_dont_count(1);
17498       mbuf_insert(m, pos, NULL, llen + sizeof(p));
17499       heapusage_dont_count(0);
17500 
17501       encode_varint(len, (uint8_t *) (m->buf + pos));
17502       memcpy(m->buf + pos + llen, &p, sizeof(p));
17503     }
17504     tag = V7_TAG_STRING_F;
17505   }
17506 
17507   /* NOTE(lsm): don't use pointer_to_value, 32-bit ptrs will truncate */
17508   return (offset & ~V7_TAG_MASK) | tag;
17509 }
17510 
17511 int v7_is_string(val_t v) {
17512   uint64_t t = v & V7_TAG_MASK;
17513   return t == V7_TAG_STRING_I || t == V7_TAG_STRING_F || t == V7_TAG_STRING_O ||
17514          t == V7_TAG_STRING_5 || t == V7_TAG_STRING_D;
17515 }
17516 
17517 /* Get a pointer to string and string length. */
17518 const char *v7_get_string(struct v7 *v7, val_t *v, size_t *sizep) {
17519   uint64_t tag = v[0] & V7_TAG_MASK;
17520   const char *p = NULL;
17521   int llen;
17522   size_t size = 0;
17523 
17524   if (!v7_is_string(*v)) {
17525     goto clean;
17526   }
17527 
17528   if (tag == V7_TAG_STRING_I) {
17529     p = GET_VAL_NAN_PAYLOAD(*v) + 1;
17530     size = p[-1];
17531   } else if (tag == V7_TAG_STRING_5) {
17532     p = GET_VAL_NAN_PAYLOAD(*v);
17533     size = 5;
17534   } else if (tag == V7_TAG_STRING_D) {
17535     int index = ((unsigned char *) GET_VAL_NAN_PAYLOAD(*v))[0];
17536     size = v_dictionary_strings[index].len;
17537     p = v_dictionary_strings[index].p;
17538   } else if (tag == V7_TAG_STRING_O) {
17539     size_t offset = (size_t) gc_string_val_to_offset(*v);
17540     char *s = v7->owned_strings.buf + offset;
17541 
17542 #ifndef V7_DISABLE_STR_ALLOC_SEQ
17543     gc_check_valid_allocation_seqn(v7, (*v >> 32) & 0xFFFF);
17544 #endif
17545 
17546     size = decode_varint((uint8_t *) s, &llen);
17547     p = s + llen;
17548   } else if (tag == V7_TAG_STRING_F) {
17549     /*
17550      * short foreign strings on <=32-bit machines can be encoded in a compact
17551      * form:
17552      *
17553      *     7         6        5        4        3        2        1        0
17554      *  11111111|1111tttt|llllllll|llllllll|ssssssss|ssssssss|ssssssss|ssssssss
17555      *
17556      * Strings longer than 2^26 will be indireceted through the foreign_strings
17557      * mbuf.
17558      *
17559      * We don't use a different tag to represent those two cases. Instead, all
17560      * foreign strings represented with the help of the foreign_strings mbuf
17561      * will have the upper 16-bits of the payload set to zero. This allows us to
17562      * represent up to 477 million foreign strings longer than 64k.
17563      */
17564     uint16_t len = (*v >> 32) & 0xFFFF;
17565     if (sizeof(void *) <= 4 && len != 0) {
17566       size = (size_t) len;
17567       p = (const char *) (uintptr_t) *v;
17568     } else {
17569       size_t offset = (size_t) gc_string_val_to_offset(*v);
17570       char *s = v7->foreign_strings.buf + offset;
17571 
17572       size = decode_varint((uint8_t *) s, &llen);
17573       memcpy(&p, s + llen, sizeof(p));
17574     }
17575   } else {
17576     assert(0);
17577   }
17578 
17579 clean:
17580   if (sizep != NULL) {
17581     *sizep = size;
17582   }
17583   return p;
17584 }
17585 
17586 const char *v7_get_cstring(struct v7 *v7, v7_val_t *value) {
17587   size_t size;
17588   const char *s = v7_get_string(v7, value, &size);
17589   if (s == NULL) return NULL;
17590   if (s[size] != 0 || strlen(s) != size) {
17591     return NULL;
17592   }
17593   return s;
17594 }
17595 #ifdef V7_MODULE_LINES
17596 #line 1 "v7/src/array.c"
17597 #endif
17598 /*
17599  * Copyright (c) 2014 Cesanta Software Limited
17600  * All rights reserved
17601  */
17602 
17603 /* Amalgamated: #include "common/str_util.h" */
17604 /* Amalgamated: #include "v7/src/internal.h" */
17605 /* Amalgamated: #include "v7/src/array.h" */
17606 /* Amalgamated: #include "v7/src/string.h" */
17607 /* Amalgamated: #include "v7/src/object.h" */
17608 /* Amalgamated: #include "v7/src/exceptions.h" */
17609 /* Amalgamated: #include "v7/src/primitive.h" */
17610 /* Amalgamated: #include "v7/src/core.h" */
17611 
17612 /* like c_snprintf but returns `size` if write is truncated */
17613 static int v_sprintf_s(char *buf, size_t size, const char *fmt, ...) {
17614   size_t n;
17615   va_list ap;
17616   va_start(ap, fmt);
17617   n = c_vsnprintf(buf, size, fmt, ap);
17618   if (n > size) {
17619     return size;
17620   }
17621   return n;
17622 }
17623 
17624 v7_val_t v7_mk_array(struct v7 *v7) {
17625   val_t a = mk_object(v7, v7->vals.array_prototype);
17626 #if 0
17627   v7_def(v7, a, "", 0, _V7_DESC_HIDDEN(1), V7_NULL);
17628 #endif
17629   return a;
17630 }
17631 
17632 int v7_is_array(struct v7 *v7, val_t v) {
17633   return v7_is_generic_object(v) &&
17634          is_prototype_of(v7, v, v7->vals.array_prototype);
17635 }
17636 
17637 /*
17638  * Dense arrays are backed by mbuf. Currently the array can only grow by
17639  * appending (i.e. setting an element whose index == array.length)
17640  *
17641  * TODO(mkm): automatically promote dense arrays to normal objects
17642  *            when they are used as sparse arrays or to store arbitrary keys
17643  *            (perhaps a hybrid approach)
17644  * TODO(mkm): small sparsness doesn't have to promote the array,
17645  *            we can just fill empty slots with a tag. In JS missing array
17646  *            indices are subtly different from indices with an undefined value
17647  *            (key iteration).
17648  * TODO(mkm): change the interpreter so it can set elements in dense arrays
17649  */
17650 V7_PRIVATE val_t v7_mk_dense_array(struct v7 *v7) {
17651   val_t a = v7_mk_array(v7);
17652 #ifdef V7_ENABLE_DENSE_ARRAYS
17653   v7_own(v7, &a);
17654   v7_def(v7, a, "", 0, _V7_DESC_HIDDEN(1), V7_NULL);
17655 
17656   /*
17657    * Before setting a `V7_OBJ_DENSE_ARRAY` flag, make sure we don't have
17658    * `V7_OBJ_FUNCTION` flag set
17659    */
17660   assert(!(get_object_struct(a)->attributes & V7_OBJ_FUNCTION));
17661   get_object_struct(a)->attributes |= V7_OBJ_DENSE_ARRAY;
17662 
17663   v7_disown(v7, &a);
17664 #endif
17665   return a;
17666 }
17667 
17668 /* TODO_V7_ERR */
17669 val_t v7_array_get(struct v7 *v7, val_t arr, unsigned long index) {
17670   return v7_array_get2(v7, arr, index, NULL);
17671 }
17672 
17673 /* TODO_V7_ERR */
17674 val_t v7_array_get2(struct v7 *v7, val_t arr, unsigned long index, int *has) {
17675   enum v7_err rcode = V7_OK;
17676   val_t res;
17677 
17678   if (has != NULL) {
17679     *has = 0;
17680   }
17681   if (v7_is_object(arr)) {
17682     if (get_object_struct(arr)->attributes & V7_OBJ_DENSE_ARRAY) {
17683       struct v7_property *p =
17684           v7_get_own_property2(v7, arr, "", 0, _V7_PROPERTY_HIDDEN);
17685       struct mbuf *abuf = NULL;
17686       unsigned long len;
17687       if (p != NULL) {
17688         abuf = (struct mbuf *) v7_get_ptr(v7, p->value);
17689       }
17690       if (abuf == NULL) {
17691         res = V7_UNDEFINED;
17692         goto clean;
17693       }
17694       len = abuf->len / sizeof(val_t);
17695       if (index >= len) {
17696         res = V7_UNDEFINED;
17697         goto clean;
17698       } else {
17699         memcpy(&res, abuf->buf + index * sizeof(val_t), sizeof(val_t));
17700         if (has != NULL && res != V7_TAG_NOVALUE) *has = 1;
17701         if (res == V7_TAG_NOVALUE) {
17702           res = V7_UNDEFINED;
17703         }
17704         goto clean;
17705       }
17706     } else {
17707       struct v7_property *p;
17708       char buf[20];
17709       int n = v_sprintf_s(buf, sizeof(buf), "%lu", index);
17710       p = v7_get_property(v7, arr, buf, n);
17711       if (has != NULL && p != NULL) *has = 1;
17712       V7_TRY(v7_property_value(v7, arr, p, &res));
17713       goto clean;
17714     }
17715   } else {
17716     res = V7_UNDEFINED;
17717     goto clean;
17718   }
17719 
17720 clean:
17721   (void) rcode;
17722   return res;
17723 }
17724 
17725 #if V7_ENABLE_DENSE_ARRAYS
17726 
17727 /* Create V7 strings for integers such as array indices */
17728 static val_t ulong_to_str(struct v7 *v7, unsigned long n) {
17729   char buf[100];
17730   int len;
17731   len = c_snprintf(buf, sizeof(buf), "%lu", n);
17732   return v7_mk_string(v7, buf, len, 1);
17733 }
17734 
17735 /*
17736  * Pack 15-bit length and 15 bit index, leaving 2 bits for tag. the LSB has to
17737  * be set to distinguish it from a prop pointer.
17738  * In alternative we just fetch the length from obj at each call to v7_next_prop
17739  * and just stuff the index here (e.g. on 8/16-bit platforms).
17740  * TODO(mkm): conditional for 16-bit platforms
17741  */
17742 #define PACK_ITER(len, idx) \
17743   ((struct v7_property *) ((len) << 17 | (idx) << 1 | 1))
17744 
17745 #define UNPACK_ITER_LEN(p) (((uintptr_t) p) >> 17)
17746 #define UNPACK_ITER_IDX(p) ((((uintptr_t) p) >> 1) & 0x7FFF)
17747 #define IS_PACKED_ITER(p) ((uintptr_t) p & 1)
17748 
17749 void *v7_next_prop(struct v7 *v7, val_t obj, void *h, val_t *name, val_t *val,
17750                    v7_prop_attr_t *attrs) {
17751   struct v7_property *p = (struct v7_property *) h;
17752 
17753   if (get_object_struct(obj)->attributes & V7_OBJ_DENSE_ARRAY) {
17754     /* This is a dense array. Find backing mbuf and fetch values from there */
17755     struct v7_property *hp =
17756         v7_get_own_property2(v7, obj, "", 0, _V7_PROPERTY_HIDDEN);
17757     struct mbuf *abuf = NULL;
17758     unsigned long len, idx;
17759     if (hp != NULL) {
17760       abuf = (struct mbuf *) v7_get_ptr(v7, hp->value);
17761     }
17762     if (abuf == NULL) return NULL;
17763     len = abuf->len / sizeof(val_t);
17764     if (len == 0) return NULL;
17765     idx = (p == NULL) ? 0 : UNPACK_ITER_IDX(p) + 1;
17766     p = (idx == len) ? get_object_struct(obj)->properties : PACK_ITER(len, idx);
17767     if (val != NULL) *val = ((val_t *) abuf->buf)[idx];
17768     if (attrs != NULL) *attrs = 0;
17769     if (name != NULL) {
17770       char buf[20];
17771       int n = v_sprintf_s(buf, sizeof(buf), "%lu", index);
17772       *name = v7_mk_string(v7, buf, n, 1);
17773     }
17774   } else {
17775     /* Ordinary object */
17776     p = (p == NULL) ? get_object_struct(obj)->properties : p->next;
17777     if (p != NULL) {
17778       if (name != NULL) *name = p->name;
17779       if (val != NULL) *val = p->value;
17780       if (attrs != NULL) *attrs = p->attributes;
17781     }
17782   }
17783 
17784   return p;
17785 }
17786 
17787 V7_PRIVATE val_t
17788 v7_iter_get_value(struct v7 *v7, val_t obj, struct v7_property *p) {
17789   return IS_PACKED_ITER(p) ? v7_array_get(v7, obj, UNPACK_ITER_IDX(p))
17790                            : p->value;
17791 }
17792 
17793 V7_PRIVATE val_t v7_iter_get_name(struct v7 *v7, struct v7_property *p) {
17794   return IS_PACKED_ITER(p) ? ulong_to_str(v7, UNPACK_ITER_IDX(p)) : p->name;
17795 }
17796 
17797 V7_PRIVATE uint8_t v7_iter_get_attrs(struct v7_property *p) {
17798   return IS_PACKED_ITER(p) ? 0 : p->attributes;
17799 }
17800 
17801 /* return array index as number or undefined. works with iterators */
17802 V7_PRIVATE enum v7_err v7_iter_get_index(struct v7 *v7, struct v7_property *p,
17803                                          val_t *res) {
17804   enum v7_err rcode = V7_OK;
17805   int ok;
17806   unsigned long res;
17807   if (IS_PACKED_ITER(p)) {
17808     *res = v7_mk_number(v7, UNPACK_ITER_IDX(p));
17809     goto clean;
17810   }
17811   V7_TRY(str_to_ulong(v7, p->name, &ok, &res));
17812   if (!ok || res >= UINT32_MAX) {
17813     goto clean;
17814   }
17815   *res = v7_mk_number(v7, res);
17816   goto clean;
17817 
17818 clean:
17819   return rcode;
17820 }
17821 #endif
17822 
17823 /* TODO_V7_ERR */
17824 unsigned long v7_array_length(struct v7 *v7, val_t v) {
17825   enum v7_err rcode = V7_OK;
17826   struct v7_property *p;
17827   unsigned long len = 0;
17828 
17829   if (!v7_is_object(v)) {
17830     len = 0;
17831     goto clean;
17832   }
17833 
17834 #if V7_ENABLE_DENSE_ARRAYS
17835   if (get_object_struct(v)->attributes & V7_OBJ_DENSE_ARRAY) {
17836     struct v7_property *p =
17837         v7_get_own_property2(v7, v, "", 0, _V7_PROPERTY_HIDDEN);
17838     struct mbuf *abuf;
17839     if (p == NULL) {
17840       len = 0;
17841       goto clean;
17842     }
17843     abuf = (struct mbuf *) v7_get_ptr(v7, p->value);
17844     if (abuf == NULL) {
17845       len = 0;
17846       goto clean;
17847     }
17848     len = abuf->len / sizeof(val_t);
17849     goto clean;
17850   }
17851 #endif
17852 
17853   for (p = get_object_struct(v)->properties; p != NULL; p = p->next) {
17854     int ok = 0;
17855     unsigned long n = 0;
17856     V7_TRY(str_to_ulong(v7, p->name, &ok, &n));
17857     if (ok && n >= len && n < UINT32_MAX) {
17858       len = n + 1;
17859     }
17860   }
17861 
17862 clean:
17863   (void) rcode;
17864   return len;
17865 }
17866 
17867 int v7_array_set(struct v7 *v7, val_t arr, unsigned long index, val_t v) {
17868   enum v7_err rcode = V7_OK;
17869   uint8_t saved_is_thrown = 0;
17870   val_t saved_thrown = v7_get_thrown_value(v7, &saved_is_thrown);
17871   int ret = -1;
17872 
17873   rcode = v7_array_set_throwing(v7, arr, index, v, &ret);
17874   if (rcode != V7_OK) {
17875     rcode = V7_OK;
17876     if (saved_is_thrown) {
17877       rcode = v7_throw(v7, saved_thrown);
17878     } else {
17879       v7_clear_thrown_value(v7);
17880     }
17881     ret = -1;
17882   }
17883 
17884   return ret;
17885 }
17886 
17887 enum v7_err v7_array_set_throwing(struct v7 *v7, val_t arr, unsigned long index,
17888                                   val_t v, int *res) {
17889   enum v7_err rcode = V7_OK;
17890   int ires = -1;
17891 
17892   if (v7_is_object(arr)) {
17893     if (get_object_struct(arr)->attributes & V7_OBJ_DENSE_ARRAY) {
17894       struct v7_property *p =
17895           v7_get_own_property2(v7, arr, "", 0, _V7_PROPERTY_HIDDEN);
17896       struct mbuf *abuf;
17897       unsigned long len;
17898       assert(p != NULL);
17899       abuf = (struct mbuf *) v7_get_ptr(v7, p->value);
17900 
17901       if (get_object_struct(arr)->attributes & V7_OBJ_NOT_EXTENSIBLE) {
17902         if (is_strict_mode(v7)) {
17903           rcode = v7_throwf(v7, TYPE_ERROR, "Object is not extensible");
17904           goto clean;
17905         }
17906 
17907         goto clean;
17908       }
17909 
17910       if (abuf == NULL) {
17911         abuf = (struct mbuf *) malloc(sizeof(*abuf));
17912         mbuf_init(abuf, sizeof(val_t) * (index + 1));
17913         p->value = v7_mk_foreign(v7, abuf);
17914       }
17915       len = abuf->len / sizeof(val_t);
17916       /* TODO(mkm): possibly promote to sparse array */
17917       if (index > len) {
17918         unsigned long i;
17919         val_t s = V7_TAG_NOVALUE;
17920         for (i = len; i < index; i++) {
17921           mbuf_append(abuf, (char *) &s, sizeof(val_t));
17922         }
17923         len = index;
17924       }
17925 
17926       if (index == len) {
17927         mbuf_append(abuf, (char *) &v, sizeof(val_t));
17928       } else {
17929         memcpy(abuf->buf + index * sizeof(val_t), &v, sizeof(val_t));
17930       }
17931     } else {
17932       char buf[20];
17933       int n = v_sprintf_s(buf, sizeof(buf), "%lu", index);
17934       {
17935         struct v7_property *tmp = NULL;
17936         rcode = set_property(v7, arr, buf, n, v, &tmp);
17937         ires = (tmp == NULL) ? -1 : 0;
17938       }
17939       if (rcode != V7_OK) {
17940         goto clean;
17941       }
17942     }
17943   }
17944 
17945 clean:
17946   if (res != NULL) {
17947     *res = ires;
17948   }
17949   return rcode;
17950 }
17951 
17952 void v7_array_del(struct v7 *v7, val_t arr, unsigned long index) {
17953   char buf[20];
17954   int n = v_sprintf_s(buf, sizeof(buf), "%lu", index);
17955   v7_del(v7, arr, buf, n);
17956 }
17957 
17958 int v7_array_push(struct v7 *v7, v7_val_t arr, v7_val_t v) {
17959   return v7_array_set(v7, arr, v7_array_length(v7, arr), v);
17960 }
17961 
17962 WARN_UNUSED_RESULT
17963 enum v7_err v7_array_push_throwing(struct v7 *v7, v7_val_t arr, v7_val_t v,
17964                                    int *res) {
17965   return v7_array_set_throwing(v7, arr, v7_array_length(v7, arr), v, res);
17966 }
17967 #ifdef V7_MODULE_LINES
17968 #line 1 "v7/src/object.c"
17969 #endif
17970 /*
17971  * Copyright (c) 2014 Cesanta Software Limited
17972  * All rights reserved
17973  */
17974 
17975 /* Amalgamated: #include "v7/src/internal.h" */
17976 /* Amalgamated: #include "v7/src/core.h" */
17977 /* Amalgamated: #include "v7/src/primitive.h" */
17978 /* Amalgamated: #include "v7/src/function.h" */
17979 /* Amalgamated: #include "v7/src/gc.h" */
17980 /* Amalgamated: #include "v7/src/object.h" */
17981 /* Amalgamated: #include "v7/src/string.h" */
17982 /* Amalgamated: #include "v7/src/array.h" */
17983 /* Amalgamated: #include "v7/src/eval.h" */
17984 /* Amalgamated: #include "v7/src/exceptions.h" */
17985 /* Amalgamated: #include "v7/src/conversion.h" */
17986 /* Amalgamated: #include "v7/src/std_proxy.h" */
17987 /* Amalgamated: #include "v7/src/util.h" */
17988 
17989 /*
17990  * Default property attributes (see `v7_prop_attr_t`)
17991  */
17992 #define V7_DEFAULT_PROPERTY_ATTRS 0
17993 
17994 V7_PRIVATE val_t mk_object(struct v7 *v7, val_t prototype) {
17995   struct v7_generic_object *o = new_generic_object(v7);
17996   if (o == NULL) {
17997     return V7_NULL;
17998   }
17999   (void) v7;
18000 #if defined(V7_ENABLE_ENTITY_IDS)
18001   o->base.entity_id_base = V7_ENTITY_ID_PART_OBJ;
18002   o->base.entity_id_spec = V7_ENTITY_ID_PART_GEN_OBJ;
18003 #endif
18004   o->base.properties = NULL;
18005   obj_prototype_set(v7, &o->base, get_object_struct(prototype));
18006   return v7_object_to_value(&o->base);
18007 }
18008 
18009 v7_val_t v7_mk_object(struct v7 *v7) {
18010   return mk_object(v7, v7->vals.object_prototype);
18011 }
18012 
18013 V7_PRIVATE val_t v7_object_to_value(struct v7_object *o) {
18014   if (o == NULL) {
18015     return V7_NULL;
18016   } else if (o->attributes & V7_OBJ_FUNCTION) {
18017     return pointer_to_value(o) | V7_TAG_FUNCTION;
18018   } else {
18019     return pointer_to_value(o) | V7_TAG_OBJECT;
18020   }
18021 }
18022 
18023 V7_PRIVATE struct v7_generic_object *get_generic_object_struct(val_t v) {
18024   struct v7_generic_object *ret = NULL;
18025   if (v7_is_null(v)) {
18026     ret = NULL;
18027   } else {
18028     assert(v7_is_generic_object(v));
18029     ret = (struct v7_generic_object *) get_ptr(v);
18030 #if defined(V7_ENABLE_ENTITY_IDS)
18031     if (ret->base.entity_id_base != V7_ENTITY_ID_PART_OBJ) {
18032       fprintf(stderr, "not a generic object!\n");
18033       abort();
18034     } else if (ret->base.entity_id_spec != V7_ENTITY_ID_PART_GEN_OBJ) {
18035       fprintf(stderr, "not an object (but is a generic object)!\n");
18036       abort();
18037     }
18038 #endif
18039   }
18040   return ret;
18041 }
18042 
18043 V7_PRIVATE struct v7_object *get_object_struct(val_t v) {
18044   struct v7_object *ret = NULL;
18045   if (v7_is_null(v)) {
18046     ret = NULL;
18047   } else {
18048     assert(v7_is_object(v));
18049     ret = (struct v7_object *) get_ptr(v);
18050 #if defined(V7_ENABLE_ENTITY_IDS)
18051     if (ret->entity_id_base != V7_ENTITY_ID_PART_OBJ) {
18052       fprintf(stderr, "not an object!\n");
18053       abort();
18054     }
18055 #endif
18056   }
18057   return ret;
18058 }
18059 
18060 int v7_is_object(val_t v) {
18061   return (v & V7_TAG_MASK) == V7_TAG_OBJECT ||
18062          (v & V7_TAG_MASK) == V7_TAG_FUNCTION;
18063 }
18064 
18065 V7_PRIVATE int v7_is_generic_object(val_t v) {
18066   return (v & V7_TAG_MASK) == V7_TAG_OBJECT;
18067 }
18068 
18069 /* Object properties {{{ */
18070 
18071 V7_PRIVATE struct v7_property *v7_mk_property(struct v7 *v7) {
18072   struct v7_property *p = new_property(v7);
18073 #if defined(V7_ENABLE_ENTITY_IDS)
18074   p->entity_id = V7_ENTITY_ID_PROP;
18075 #endif
18076   p->next = NULL;
18077   p->name = V7_UNDEFINED;
18078   p->value = V7_UNDEFINED;
18079   p->attributes = 0;
18080   return p;
18081 }
18082 
18083 V7_PRIVATE struct v7_property *v7_get_own_property2(struct v7 *v7, val_t obj,
18084                                                     const char *name,
18085                                                     size_t len,
18086                                                     v7_prop_attr_t attrs) {
18087   struct v7_property *p;
18088   struct v7_object *o;
18089   val_t ss;
18090   if (!v7_is_object(obj)) {
18091     return NULL;
18092   }
18093   if (len == (size_t) ~0) {
18094     len = strlen(name);
18095   }
18096 
18097   o = get_object_struct(obj);
18098   /*
18099    * len check is needed to allow getting the mbuf from the hidden property.
18100    * TODO(mkm): however hidden properties cannot be safely represented with
18101    * a zero length string anyway, so this will change.
18102    */
18103   if (o->attributes & V7_OBJ_DENSE_ARRAY && len > 0) {
18104     int ok, has;
18105     unsigned long i = cstr_to_ulong(name, len, &ok);
18106     if (ok) {
18107       v7->cur_dense_prop->value = v7_array_get2(v7, obj, i, &has);
18108       return has ? v7->cur_dense_prop : NULL;
18109     }
18110   }
18111 
18112   if (len <= 5) {
18113     ss = v7_mk_string(v7, name, len, 1);
18114     for (p = o->properties; p != NULL; p = p->next) {
18115 #if defined(V7_ENABLE_ENTITY_IDS)
18116       if (p->entity_id != V7_ENTITY_ID_PROP) {
18117         fprintf(stderr, "not a prop!=0x%x\n", p->entity_id);
18118         abort();
18119       }
18120 #endif
18121       if (p->name == ss && (attrs == 0 || (p->attributes & attrs))) {
18122         return p;
18123       }
18124     }
18125   } else {
18126     for (p = o->properties; p != NULL; p = p->next) {
18127       size_t n;
18128       const char *s = v7_get_string(v7, &p->name, &n);
18129 #if defined(V7_ENABLE_ENTITY_IDS)
18130       if (p->entity_id != V7_ENTITY_ID_PROP) {
18131         fprintf(stderr, "not a prop!=0x%x\n", p->entity_id);
18132         abort();
18133       }
18134 #endif
18135       if (n == len && strncmp(s, name, len) == 0 &&
18136           (attrs == 0 || (p->attributes & attrs))) {
18137         return p;
18138       }
18139     }
18140   }
18141   return NULL;
18142 }
18143 
18144 V7_PRIVATE struct v7_property *v7_get_own_property(struct v7 *v7, val_t obj,
18145                                                    const char *name,
18146                                                    size_t len) {
18147   return v7_get_own_property2(v7, obj, name, len, 0);
18148 }
18149 
18150 V7_PRIVATE struct v7_property *v7_get_property(struct v7 *v7, val_t obj,
18151                                                const char *name, size_t len) {
18152   if (!v7_is_object(obj)) {
18153     return NULL;
18154   }
18155   for (; obj != V7_NULL; obj = v7_get_proto(v7, obj)) {
18156     struct v7_property *prop;
18157     if ((prop = v7_get_own_property(v7, obj, name, len)) != NULL) {
18158       return prop;
18159     }
18160   }
18161   return NULL;
18162 }
18163 
18164 V7_PRIVATE enum v7_err v7_get_property_v(struct v7 *v7, val_t obj,
18165                                          v7_val_t name,
18166                                          struct v7_property **res) {
18167   enum v7_err rcode = V7_OK;
18168   size_t name_len;
18169   STATIC char buf[8];
18170   const char *s = buf;
18171   uint8_t fr = 0;
18172 
18173   if (v7_is_string(name)) {
18174     s = v7_get_string(v7, &name, &name_len);
18175   } else {
18176     char *stmp;
18177     V7_TRY(v7_stringify_throwing(v7, name, buf, sizeof(buf),
18178                                  V7_STRINGIFY_DEFAULT, &stmp));
18179     s = stmp;
18180     if (s != buf) {
18181       fr = 1;
18182     }
18183     name_len = strlen(s);
18184   }
18185 
18186   *res = v7_get_property(v7, obj, s, name_len);
18187 
18188 clean:
18189   if (fr) {
18190     free((void *) s);
18191   }
18192   return rcode;
18193 }
18194 
18195 WARN_UNUSED_RESULT
18196 enum v7_err v7_get_throwing(struct v7 *v7, val_t obj, const char *name,
18197                             size_t name_len, val_t *res) {
18198   enum v7_err rcode = V7_OK;
18199   val_t v = obj;
18200 
18201   v7_own(v7, &v);
18202 
18203   if (name_len == (size_t) ~0) {
18204     name_len = strlen(name);
18205   }
18206 
18207   if (v7_is_string(obj)) {
18208     v = v7->vals.string_prototype;
18209   } else if (v7_is_number(obj)) {
18210     v = v7->vals.number_prototype;
18211   } else if (v7_is_boolean(obj)) {
18212     v = v7->vals.boolean_prototype;
18213   } else if (v7_is_undefined(obj)) {
18214     rcode =
18215         v7_throwf(v7, TYPE_ERROR, "cannot read property '%.*s' of undefined",
18216                   (int) name_len, name);
18217     goto clean;
18218   } else if (v7_is_null(obj)) {
18219     rcode = v7_throwf(v7, TYPE_ERROR, "cannot read property '%.*s' of null",
18220                       (int) name_len, name);
18221     goto clean;
18222   } else if (is_cfunction_lite(obj)) {
18223     v = v7->vals.function_prototype;
18224   }
18225 
18226 #if V7_ENABLE__Proxy
18227   {
18228     struct v7_object *o = NULL;
18229     if (v7_is_object(obj)) {
18230       o = get_object_struct(obj);
18231     }
18232 
18233     if (o != NULL && (o->attributes & V7_OBJ_PROXY) &&
18234         !is_special_proxy_name(name, name_len)) {
18235       /* we need to access the target object through a proxy */
18236 
18237       val_t target_v = V7_UNDEFINED;
18238       val_t handler_v = V7_UNDEFINED;
18239       val_t name_v = V7_UNDEFINED;
18240       val_t get_v = V7_UNDEFINED;
18241       val_t get_args_v = V7_UNDEFINED;
18242 
18243       /*
18244        * we need to create a copy of the name, because the given `name` might
18245        * be returned by v7_get_string(), and any object creation might
18246        * invalidate this pointer. Below, we're going to create some objects.
18247        *
18248        * It would probably be cleaner to always create a copy before calling
18249        * v7_get_throwing if the name was returned by v7_get_string(), but that
18250        * would cause additional pressure on the heap, so let's not do that
18251        */
18252       char *name_copy = (char *) calloc(1, name_len + 1 /* null-term */);
18253       memcpy(name_copy, name, name_len);
18254 
18255       v7_own(v7, &target_v);
18256       v7_own(v7, &handler_v);
18257       v7_own(v7, &name_v);
18258       v7_own(v7, &get_v);
18259       v7_own(v7, &get_args_v);
18260 
18261       V7_TRY2(v7_get_throwing(v7, obj, _V7_PROXY_TARGET_NAME, ~0, &target_v),
18262               clean_proxy);
18263       V7_TRY2(v7_get_throwing(v7, obj, _V7_PROXY_HANDLER_NAME, ~0, &handler_v),
18264               clean_proxy);
18265       V7_TRY2(v7_get_throwing(v7, handler_v, "get", ~0, &get_v), clean_proxy);
18266 
18267       if (v7_is_callable(v7, get_v)) {
18268         /* The `get` callback is actually callable, so, use it */
18269 
18270         /* prepare arguments for the callback */
18271         get_args_v = v7_mk_dense_array(v7);
18272         /*
18273          * TODO(dfrank): don't copy string in case we already have val_t (we
18274          * need some generic function which will take both `const char *` and
18275          * val_t)
18276          */
18277         v7_array_set(v7, get_args_v, 0, target_v);
18278         v7_array_set(v7, get_args_v, 1,
18279                      v7_mk_string(v7, name_copy, name_len, 1));
18280 
18281         /* call `get` callback */
18282         V7_TRY2(b_apply(v7, get_v, V7_UNDEFINED, get_args_v, 0, res),
18283                 clean_proxy);
18284       } else {
18285         /*
18286          * there's no `get` callback: then, get property from the target object
18287          * (not from the proxy object)
18288          */
18289         V7_TRY2(v7_get_throwing(v7, target_v, name_copy, name_len, res),
18290                 clean_proxy);
18291       }
18292 
18293     clean_proxy:
18294 
18295       free(name_copy);
18296 
18297       v7_disown(v7, &get_args_v);
18298       v7_disown(v7, &get_v);
18299       v7_disown(v7, &name_v);
18300       v7_disown(v7, &handler_v);
18301       v7_disown(v7, &target_v);
18302       goto clean;
18303     }
18304   }
18305 #endif
18306 
18307   /* regular (non-proxy) property access */
18308   V7_TRY(
18309       v7_property_value(v7, obj, v7_get_property(v7, v, name, name_len), res));
18310 
18311 clean:
18312   v7_disown(v7, &v);
18313   return rcode;
18314 }
18315 
18316 v7_val_t v7_get(struct v7 *v7, val_t obj, const char *name, size_t name_len) {
18317   enum v7_err rcode = V7_OK;
18318   uint8_t saved_is_thrown = 0;
18319   val_t saved_thrown = v7_get_thrown_value(v7, &saved_is_thrown);
18320   v7_val_t ret = V7_UNDEFINED;
18321 
18322   rcode = v7_get_throwing(v7, obj, name, name_len, &ret);
18323   if (rcode != V7_OK) {
18324     rcode = V7_OK;
18325     if (saved_is_thrown) {
18326       rcode = v7_throw(v7, saved_thrown);
18327     } else {
18328       v7_clear_thrown_value(v7);
18329     }
18330     ret = V7_UNDEFINED;
18331   }
18332 
18333   return ret;
18334 }
18335 
18336 WARN_UNUSED_RESULT
18337 V7_PRIVATE enum v7_err v7_get_throwing_v(struct v7 *v7, v7_val_t obj,
18338                                          v7_val_t name, v7_val_t *res) {
18339   enum v7_err rcode = V7_OK;
18340   size_t name_len;
18341   STATIC char buf[8];
18342   const char *s = buf;
18343   uint8_t fr = 0;
18344 
18345   /* subscripting strings */
18346   if (v7_is_string(obj)) {
18347     char ch;
18348     double dch = 0;
18349 
18350     rcode = v7_char_code_at(v7, obj, name, &dch);
18351     if (rcode != V7_OK) {
18352       goto clean;
18353     }
18354 
18355     if (!isnan(dch)) {
18356       ch = dch;
18357       *res = v7_mk_string(v7, &ch, 1, 1);
18358       goto clean;
18359     }
18360   }
18361 
18362   if (v7_is_string(name)) {
18363     s = v7_get_string(v7, &name, &name_len);
18364   } else {
18365     char *stmp;
18366     V7_TRY(v7_stringify_throwing(v7, name, buf, sizeof(buf),
18367                                  V7_STRINGIFY_DEFAULT, &stmp));
18368     s = stmp;
18369     if (s != buf) {
18370       fr = 1;
18371     }
18372     name_len = strlen(s);
18373   }
18374   V7_TRY(v7_get_throwing(v7, obj, s, name_len, res));
18375 
18376 clean:
18377   if (fr) {
18378     free((void *) s);
18379   }
18380   return rcode;
18381 }
18382 
18383 V7_PRIVATE void v7_destroy_property(struct v7_property **p) {
18384   *p = NULL;
18385 }
18386 
18387 WARN_UNUSED_RESULT
18388 V7_PRIVATE enum v7_err v7_invoke_setter(struct v7 *v7, struct v7_property *prop,
18389                                         val_t obj, val_t val) {
18390   enum v7_err rcode = V7_OK;
18391   val_t setter = prop->value, args;
18392   v7_own(v7, &val);
18393   args = v7_mk_dense_array(v7);
18394   v7_own(v7, &args);
18395   if (prop->attributes & V7_PROPERTY_GETTER) {
18396     setter = v7_array_get(v7, prop->value, 1);
18397   }
18398   v7_array_set(v7, args, 0, val);
18399   v7_disown(v7, &args);
18400   v7_disown(v7, &val);
18401   {
18402     val_t val = V7_UNDEFINED;
18403     V7_TRY(b_apply(v7, setter, obj, args, 0, &val));
18404   }
18405 
18406 clean:
18407   return rcode;
18408 }
18409 
18410 static v7_prop_attr_t apply_attrs_desc(v7_prop_attr_desc_t attrs_desc,
18411                                        v7_prop_attr_t old_attrs) {
18412   v7_prop_attr_t ret = old_attrs;
18413   if (old_attrs & V7_PROPERTY_NON_CONFIGURABLE) {
18414     /*
18415      * The property is non-configurable: we can only change it from being
18416      * writable to non-writable
18417      */
18418 
18419     if ((attrs_desc >> _V7_DESC_SHIFT) & V7_PROPERTY_NON_WRITABLE &&
18420         (attrs_desc & V7_PROPERTY_NON_WRITABLE)) {
18421       ret |= V7_PROPERTY_NON_WRITABLE;
18422     }
18423 
18424   } else {
18425     /* The property is configurable: we can change any attributes */
18426     ret = (old_attrs & ~(attrs_desc >> _V7_DESC_SHIFT)) |
18427           (attrs_desc & _V7_DESC_MASK);
18428   }
18429 
18430   return ret;
18431 }
18432 
18433 int v7_def(struct v7 *v7, val_t obj, const char *name, size_t len,
18434            v7_prop_attr_desc_t attrs_desc, v7_val_t val) {
18435   enum v7_err rcode = V7_OK;
18436   uint8_t saved_is_thrown = 0;
18437   val_t saved_thrown = v7_get_thrown_value(v7, &saved_is_thrown);
18438   int ret = -1;
18439 
18440   {
18441     struct v7_property *tmp = NULL;
18442     rcode = def_property(v7, obj, name, len, attrs_desc, val, 0 /*not assign*/,
18443                          &tmp);
18444     ret = (tmp == NULL) ? -1 : 0;
18445   }
18446 
18447   if (rcode != V7_OK) {
18448     rcode = V7_OK;
18449     if (saved_is_thrown) {
18450       rcode = v7_throw(v7, saved_thrown);
18451     } else {
18452       v7_clear_thrown_value(v7);
18453     }
18454     ret = -1;
18455   }
18456 
18457   return ret;
18458 }
18459 
18460 int v7_set(struct v7 *v7, val_t obj, const char *name, size_t len,
18461            v7_val_t val) {
18462   enum v7_err rcode = V7_OK;
18463   uint8_t saved_is_thrown = 0;
18464   val_t saved_thrown = v7_get_thrown_value(v7, &saved_is_thrown);
18465   int ret = -1;
18466 
18467   {
18468     struct v7_property *tmp = NULL;
18469     rcode = set_property(v7, obj, name, len, val, &tmp);
18470     ret = (tmp == NULL) ? -1 : 0;
18471   }
18472 
18473   if (rcode != V7_OK) {
18474     rcode = V7_OK;
18475     if (saved_is_thrown) {
18476       rcode = v7_throw(v7, saved_thrown);
18477     } else {
18478       v7_clear_thrown_value(v7);
18479     }
18480     ret = -1;
18481   }
18482 
18483   return ret;
18484 }
18485 
18486 WARN_UNUSED_RESULT
18487 V7_PRIVATE enum v7_err set_property_v(struct v7 *v7, val_t obj, val_t name,
18488                                       val_t val, struct v7_property **res) {
18489   return def_property_v(v7, obj, name, 0, val, 1 /*as_assign*/, res);
18490 }
18491 
18492 WARN_UNUSED_RESULT
18493 V7_PRIVATE enum v7_err set_property(struct v7 *v7, val_t obj, const char *name,
18494                                     size_t len, v7_val_t val,
18495                                     struct v7_property **res) {
18496   return def_property(v7, obj, name, len, 0, val, 1 /*as_assign*/, res);
18497 }
18498 
18499 WARN_UNUSED_RESULT
18500 V7_PRIVATE enum v7_err def_property_v(struct v7 *v7, val_t obj, val_t name,
18501                                       v7_prop_attr_desc_t attrs_desc, val_t val,
18502                                       uint8_t as_assign,
18503                                       struct v7_property **res) {
18504   enum v7_err rcode = V7_OK;
18505   struct v7_property *prop = NULL;
18506   size_t len;
18507   const char *n = v7_get_string(v7, &name, &len);
18508 
18509   v7_own(v7, &name);
18510   v7_own(v7, &val);
18511 
18512   if (!v7_is_object(obj)) {
18513     prop = NULL;
18514     goto clean;
18515   }
18516 
18517 #if V7_ENABLE__Proxy
18518   if ((get_object_struct(obj)->attributes & V7_OBJ_PROXY) &&
18519       !is_special_proxy_name(n, len)) {
18520     /* we need to access the target object through a proxy */
18521 
18522     val_t target_v = V7_UNDEFINED;
18523     val_t handler_v = V7_UNDEFINED;
18524     val_t set_v = V7_UNDEFINED;
18525     val_t set_args_v = V7_UNDEFINED;
18526 
18527     v7_own(v7, &target_v);
18528     v7_own(v7, &handler_v);
18529     v7_own(v7, &set_v);
18530     v7_own(v7, &set_args_v);
18531 
18532     V7_TRY2(v7_get_throwing(v7, obj, _V7_PROXY_TARGET_NAME, ~0, &target_v),
18533             clean_proxy);
18534     V7_TRY2(v7_get_throwing(v7, obj, _V7_PROXY_HANDLER_NAME, ~0, &handler_v),
18535             clean_proxy);
18536     /*
18537      * We'll consult "set" property in case of the plain assignment only;
18538      * Object.defineProperty() has its own trap `defineProperty` which is not
18539      * yet implemented in v7
18540      */
18541     if (as_assign) {
18542       V7_TRY2(v7_get_throwing(v7, handler_v, "set", ~0, &set_v), clean_proxy);
18543     }
18544 
18545     if (v7_is_callable(v7, set_v)) {
18546       /* The `set` callback is actually callable, so, use it */
18547 
18548       /* prepare arguments for the callback */
18549       set_args_v = v7_mk_dense_array(v7);
18550       /*
18551        * TODO(dfrank): don't copy string in case we already have val_t
18552        * (we need some generic function which will take both const char * and
18553        * val_t for that)
18554        */
18555       v7_array_set(v7, set_args_v, 0, target_v);
18556       v7_array_set(v7, set_args_v, 1, name);
18557       v7_array_set(v7, set_args_v, 2, val);
18558 
18559       /* call `set` callback */
18560       V7_TRY2(b_apply(v7, set_v, V7_UNDEFINED, set_args_v, 0, &val),
18561               clean_proxy);
18562 
18563       /* in strict mode, we should throw if trap returned falsy value */
18564       if (is_strict_mode(v7) && !v7_is_truthy(v7, val)) {
18565         V7_THROW2(
18566             v7_throwf(v7, TYPE_ERROR, "Trap returned falsy for property '%s'",
18567                       v7_get_string(v7, &name, NULL)),
18568             clean_proxy);
18569       }
18570 
18571     } else {
18572       /*
18573        * there's no `set` callback: then, set property on the target object
18574        * (not on the proxy object)
18575        */
18576       V7_TRY2(
18577           def_property_v(v7, target_v, name, attrs_desc, val, as_assign, res),
18578           clean_proxy);
18579     }
18580 
18581   clean_proxy:
18582     v7_disown(v7, &set_args_v);
18583     v7_disown(v7, &set_v);
18584     v7_disown(v7, &handler_v);
18585     v7_disown(v7, &target_v);
18586     goto clean;
18587   }
18588 #endif
18589 
18590   /* regular (non-proxy) property access */
18591   prop = v7_get_own_property(v7, obj, n, len);
18592   if (prop == NULL) {
18593     /*
18594      * The own property with given `name` doesn't exist yet: try to create it,
18595      * set requested `name` and `attributes`, and append to the object's
18596      * properties
18597      */
18598 
18599     /* make sure the object is extensible */
18600     if (get_object_struct(obj)->attributes & V7_OBJ_NOT_EXTENSIBLE) {
18601       /*
18602        * We should throw if we use `Object.defineProperty`, or if we're in
18603        * strict mode.
18604        */
18605       if (is_strict_mode(v7) || !as_assign) {
18606         V7_THROW(v7_throwf(v7, TYPE_ERROR, "Object is not extensible"));
18607       }
18608       prop = NULL;
18609       goto clean;
18610     }
18611 
18612     if ((prop = v7_mk_property(v7)) == NULL) {
18613       prop = NULL; /* LCOV_EXCL_LINE */
18614       goto clean;
18615     }
18616     prop->name = name;
18617     prop->value = val;
18618     prop->attributes = apply_attrs_desc(attrs_desc, V7_DEFAULT_PROPERTY_ATTRS);
18619 
18620     prop->next = get_object_struct(obj)->properties;
18621     get_object_struct(obj)->properties = prop;
18622     goto clean;
18623   } else {
18624     /* Property already exists */
18625 
18626     if (prop->attributes & V7_PROPERTY_NON_WRITABLE) {
18627       /* The property is read-only */
18628 
18629       if (as_assign) {
18630         /* Plain assignment: in strict mode throw, otherwise ignore */
18631         if (is_strict_mode(v7)) {
18632           V7_THROW(
18633               v7_throwf(v7, TYPE_ERROR, "Cannot assign to read-only property"));
18634         } else {
18635           prop = NULL;
18636           goto clean;
18637         }
18638       } else if (prop->attributes & V7_PROPERTY_NON_CONFIGURABLE) {
18639         /*
18640          * Use `Object.defineProperty` semantic, and the property is
18641          * non-configurable: if no value is provided, or if new value is equal
18642          * to the existing one, then just fall through to change attributes;
18643          * otherwise, throw.
18644          */
18645 
18646         if (!(attrs_desc & V7_DESC_PRESERVE_VALUE)) {
18647           uint8_t equal = 0;
18648           if (v7_is_string(val) && v7_is_string(prop->value)) {
18649             equal = (s_cmp(v7, val, prop->value) == 0);
18650           } else {
18651             equal = (val == prop->value);
18652           }
18653 
18654           if (!equal) {
18655             /* Values are not equal: should throw */
18656             V7_THROW(v7_throwf(v7, TYPE_ERROR,
18657                                "Cannot redefine read-only property"));
18658           } else {
18659             /*
18660              * Values are equal. Will fall through so that attributes might
18661              * change.
18662              */
18663           }
18664         } else {
18665           /*
18666            * No value is provided. Will fall through so that attributes might
18667            * change.
18668            */
18669         }
18670       } else {
18671         /*
18672          * Use `Object.defineProperty` semantic, and the property is
18673          * configurable: will fall through and assign new value, effectively
18674          * ignoring non-writable flag. This is the same as making a property
18675          * writable, then assigning a new value, and making a property
18676          * non-writable again.
18677          */
18678       }
18679     } else if (prop->attributes & V7_PROPERTY_SETTER) {
18680       /* Invoke setter */
18681       V7_TRY(v7_invoke_setter(v7, prop, obj, val));
18682       prop = NULL;
18683       goto clean;
18684     }
18685 
18686     /* Set value and apply attrs delta */
18687     if (!(attrs_desc & V7_DESC_PRESERVE_VALUE)) {
18688       prop->value = val;
18689     }
18690     prop->attributes = apply_attrs_desc(attrs_desc, prop->attributes);
18691   }
18692 
18693 clean:
18694 
18695   if (res != NULL) {
18696     *res = prop;
18697   }
18698 
18699   v7_disown(v7, &val);
18700   v7_disown(v7, &name);
18701 
18702   return rcode;
18703 }
18704 
18705 WARN_UNUSED_RESULT
18706 V7_PRIVATE enum v7_err def_property(struct v7 *v7, val_t obj, const char *name,
18707                                     size_t len, v7_prop_attr_desc_t attrs_desc,
18708                                     v7_val_t val, uint8_t as_assign,
18709                                     struct v7_property **res) {
18710   enum v7_err rcode = V7_OK;
18711   val_t name_val = V7_UNDEFINED;
18712 
18713   v7_own(v7, &obj);
18714   v7_own(v7, &val);
18715   v7_own(v7, &name_val);
18716 
18717   if (len == (size_t) ~0) {
18718     len = strlen(name);
18719   }
18720 
18721   name_val = v7_mk_string(v7, name, len, 1);
18722   V7_TRY(def_property_v(v7, obj, name_val, attrs_desc, val, as_assign, res));
18723 
18724 clean:
18725   v7_disown(v7, &name_val);
18726   v7_disown(v7, &val);
18727   v7_disown(v7, &obj);
18728 
18729   return rcode;
18730 }
18731 
18732 V7_PRIVATE int set_method(struct v7 *v7, v7_val_t obj, const char *name,
18733                           v7_cfunction_t *func, int num_args) {
18734   return v7_def(v7, obj, name, strlen(name), V7_DESC_ENUMERABLE(0),
18735                 mk_cfunction_obj(v7, func, num_args));
18736 }
18737 
18738 int v7_set_method(struct v7 *v7, v7_val_t obj, const char *name,
18739                   v7_cfunction_t *func) {
18740   return set_method(v7, obj, name, func, ~0);
18741 }
18742 
18743 V7_PRIVATE int set_cfunc_prop(struct v7 *v7, val_t o, const char *name,
18744                               v7_cfunction_t *f) {
18745   return v7_def(v7, o, name, strlen(name), V7_DESC_ENUMERABLE(0),
18746                 v7_mk_cfunction(f));
18747 }
18748 
18749 /*
18750  * See comments in `object_public.h`
18751  */
18752 int v7_del(struct v7 *v7, val_t obj, const char *name, size_t len) {
18753   struct v7_property *prop, *prev;
18754 
18755   if (!v7_is_object(obj)) {
18756     return -1;
18757   }
18758   if (len == (size_t) ~0) {
18759     len = strlen(name);
18760   }
18761   for (prev = NULL, prop = get_object_struct(obj)->properties; prop != NULL;
18762        prev = prop, prop = prop->next) {
18763     size_t n;
18764     const char *s = v7_get_string(v7, &prop->name, &n);
18765     if (n == len && strncmp(s, name, len) == 0) {
18766       if (prev) {
18767         prev->next = prop->next;
18768       } else {
18769         get_object_struct(obj)->properties = prop->next;
18770       }
18771       v7_destroy_property(&prop);
18772       return 0;
18773     }
18774   }
18775   return -1;
18776 }
18777 
18778 WARN_UNUSED_RESULT
18779 V7_PRIVATE enum v7_err v7_property_value(struct v7 *v7, val_t obj,
18780                                          struct v7_property *p, val_t *res) {
18781   enum v7_err rcode = V7_OK;
18782   if (p == NULL) {
18783     *res = V7_UNDEFINED;
18784     goto clean;
18785   }
18786   if (p->attributes & V7_PROPERTY_GETTER) {
18787     val_t getter = p->value;
18788     if (p->attributes & V7_PROPERTY_SETTER) {
18789       getter = v7_array_get(v7, p->value, 0);
18790     }
18791     {
18792       V7_TRY(b_apply(v7, getter, obj, V7_UNDEFINED, 0, res));
18793       goto clean;
18794     }
18795   }
18796 
18797   *res = p->value;
18798   goto clean;
18799 
18800 clean:
18801   return rcode;
18802 }
18803 
18804 enum v7_err v7_init_prop_iter_ctx(struct v7 *v7, v7_val_t obj,
18805                                   struct prop_iter_ctx *ctx) {
18806   return init_prop_iter_ctx(v7, obj, 1 /*proxy-transparent*/, ctx);
18807 }
18808 
18809 WARN_UNUSED_RESULT
18810 V7_PRIVATE enum v7_err init_prop_iter_ctx(struct v7 *v7, v7_val_t obj,
18811                                           int proxy_transp,
18812                                           struct prop_iter_ctx *ctx) {
18813   enum v7_err rcode = V7_OK;
18814 
18815   v7_own(v7, &obj);
18816 
18817   memset(ctx, 0x00, sizeof(*ctx));
18818 
18819   if (v7_is_object(obj)) {
18820 #if V7_ENABLE__Proxy
18821     if (proxy_transp && get_object_struct(obj)->attributes & V7_OBJ_PROXY) {
18822       v7_val_t ownKeys_v = V7_UNDEFINED;
18823       v7_val_t args_v = V7_UNDEFINED;
18824 
18825       v7_own(v7, &ownKeys_v);
18826       v7_own(v7, &args_v);
18827 
18828       ctx->proxy_ctx =
18829           (struct prop_iter_proxy_ctx *) calloc(1, sizeof(*ctx->proxy_ctx));
18830 
18831       ctx->proxy_ctx->target_obj = V7_UNDEFINED;
18832       ctx->proxy_ctx->handler_obj = V7_UNDEFINED;
18833       ctx->proxy_ctx->own_keys = V7_UNDEFINED;
18834       ctx->proxy_ctx->get_own_prop_desc = V7_UNDEFINED;
18835 
18836       v7_own(v7, &ctx->proxy_ctx->target_obj);
18837       v7_own(v7, &ctx->proxy_ctx->handler_obj);
18838       v7_own(v7, &ctx->proxy_ctx->own_keys);
18839       v7_own(v7, &ctx->proxy_ctx->get_own_prop_desc);
18840 
18841       V7_TRY2(v7_get_throwing(v7, obj, _V7_PROXY_TARGET_NAME, ~0,
18842                               &ctx->proxy_ctx->target_obj),
18843               clean_proxy);
18844       V7_TRY2(v7_get_throwing(v7, obj, _V7_PROXY_HANDLER_NAME, ~0,
18845                               &ctx->proxy_ctx->handler_obj),
18846               clean_proxy);
18847 
18848       V7_TRY2(v7_get_throwing(v7, ctx->proxy_ctx->handler_obj, "ownKeys", ~0,
18849                               &ownKeys_v),
18850               clean_proxy);
18851 
18852       if (v7_is_callable(v7, ownKeys_v)) {
18853         /* prepare arguments for the ownKeys callback */
18854         args_v = v7_mk_dense_array(v7);
18855         v7_array_set(v7, args_v, 0, ctx->proxy_ctx->target_obj);
18856 
18857         /* call `ownKeys` callback, and save the result in context */
18858         V7_TRY2(b_apply(v7, ownKeys_v, V7_UNDEFINED, args_v, 0,
18859                         &ctx->proxy_ctx->own_keys),
18860                 clean_proxy);
18861 
18862         ctx->proxy_ctx->has_own_keys = 1;
18863         ctx->proxy_ctx->own_key_idx = 0;
18864 
18865       } else {
18866         /*
18867          * No ownKeys callback, so we'll iterate real properties of the target
18868          * object
18869          */
18870 
18871         /*
18872          * TODO(dfrank): add support for the target object which is a proxy as
18873          * well
18874          */
18875         ctx->cur_prop =
18876             get_object_struct(ctx->proxy_ctx->target_obj)->properties;
18877       }
18878 
18879       V7_TRY2(v7_get_throwing(v7, ctx->proxy_ctx->handler_obj, "_gpdc", ~0,
18880                               &ctx->proxy_ctx->get_own_prop_desc),
18881               clean_proxy);
18882       if (v7_is_foreign(ctx->proxy_ctx->get_own_prop_desc)) {
18883         /*
18884          * C callback for getting property descriptor is provided: will use it
18885          */
18886         ctx->proxy_ctx->has_get_own_prop_desc = 1;
18887         ctx->proxy_ctx->has_get_own_prop_desc_C = 1;
18888       } else {
18889         /*
18890          * No C callback for getting property descriptor is provided, let's
18891          * check if there is a JS one..
18892          */
18893         V7_TRY2(v7_get_throwing(v7, ctx->proxy_ctx->handler_obj,
18894                                 "getOwnPropertyDescriptor", ~0,
18895                                 &ctx->proxy_ctx->get_own_prop_desc),
18896                 clean_proxy);
18897 
18898         if (v7_is_callable(v7, ctx->proxy_ctx->get_own_prop_desc)) {
18899           /* Yes there is, we'll use it */
18900           ctx->proxy_ctx->has_get_own_prop_desc = 1;
18901         }
18902       }
18903 
18904     clean_proxy:
18905       v7_disown(v7, &args_v);
18906       v7_disown(v7, &ownKeys_v);
18907 
18908       if (rcode != V7_OK) {
18909         /* something went wrong, so, disown values in the context and free it */
18910         v7_disown(v7, &ctx->proxy_ctx->get_own_prop_desc);
18911         v7_disown(v7, &ctx->proxy_ctx->own_keys);
18912         v7_disown(v7, &ctx->proxy_ctx->handler_obj);
18913         v7_disown(v7, &ctx->proxy_ctx->target_obj);
18914 
18915         free(ctx->proxy_ctx);
18916         ctx->proxy_ctx = NULL;
18917 
18918         goto clean;
18919       }
18920     } else {
18921 #else
18922     (void) proxy_transp;
18923 #endif
18924 
18925       /* Object is not a proxy: we'll iterate real properties */
18926       ctx->cur_prop = get_object_struct(obj)->properties;
18927 
18928 #if V7_ENABLE__Proxy
18929     }
18930 #endif
18931   }
18932 
18933 #if V7_ENABLE__Proxy
18934 clean:
18935 #endif
18936   v7_disown(v7, &obj);
18937   if (rcode == V7_OK) {
18938     ctx->init = 1;
18939   }
18940   return rcode;
18941 }
18942 
18943 void v7_destruct_prop_iter_ctx(struct v7 *v7, struct prop_iter_ctx *ctx) {
18944   if (ctx->init) {
18945 #if V7_ENABLE__Proxy
18946     if (ctx->proxy_ctx != NULL) {
18947       v7_disown(v7, &ctx->proxy_ctx->target_obj);
18948       v7_disown(v7, &ctx->proxy_ctx->handler_obj);
18949       v7_disown(v7, &ctx->proxy_ctx->own_keys);
18950       v7_disown(v7, &ctx->proxy_ctx->get_own_prop_desc);
18951     }
18952     free(ctx->proxy_ctx);
18953     ctx->proxy_ctx = NULL;
18954 #else
18955     (void) v7;
18956 #endif
18957     ctx->init = 0;
18958   }
18959 }
18960 
18961 int v7_next_prop(struct v7 *v7, struct prop_iter_ctx *ctx, v7_val_t *name,
18962                  v7_val_t *value, v7_prop_attr_t *attrs) {
18963   int ok = 0;
18964   if (next_prop(v7, ctx, name, value, attrs, &ok) != V7_OK) {
18965     fprintf(stderr, "next_prop failed\n");
18966     ok = 0;
18967   }
18968   return ok;
18969 }
18970 
18971 #if V7_ENABLE__Proxy
18972 WARN_UNUSED_RESULT
18973 static enum v7_err get_custom_prop_desc(struct v7 *v7, v7_val_t name,
18974                                         struct prop_iter_ctx *ctx,
18975                                         struct v7_property *res_prop, int *ok) {
18976   enum v7_err rcode = V7_OK;
18977 
18978   v7_val_t args_v = V7_UNDEFINED;
18979   v7_val_t desc_v = V7_UNDEFINED;
18980   v7_val_t tmpflag_v = V7_UNDEFINED;
18981 
18982   v7_own(v7, &name);
18983   v7_own(v7, &args_v);
18984   v7_own(v7, &desc_v);
18985   v7_own(v7, &tmpflag_v);
18986 
18987   *ok = 0;
18988 
18989   if (ctx->proxy_ctx->has_get_own_prop_desc_C) {
18990     /*
18991      * There is a C callback which should fill the property descriptor
18992      * structure, see `v7_get_own_prop_desc_cb_t`
18993      */
18994     v7_get_own_prop_desc_cb_t *cb = NULL;
18995     memset(res_prop, 0, sizeof(*res_prop));
18996     cb = (v7_get_own_prop_desc_cb_t *) v7_get_ptr(
18997         v7, ctx->proxy_ctx->get_own_prop_desc);
18998 
18999     res_prop->attributes = 0;
19000     res_prop->value = V7_UNDEFINED;
19001 
19002     *ok = !!cb(v7, ctx->proxy_ctx->target_obj, name, &res_prop->attributes,
19003                &res_prop->value);
19004   } else {
19005     /* prepare arguments for the getOwnPropertyDescriptor callback */
19006     args_v = v7_mk_dense_array(v7);
19007     v7_array_set(v7, args_v, 0, ctx->proxy_ctx->target_obj);
19008     v7_array_set(v7, args_v, 1, name);
19009 
19010     /* call getOwnPropertyDescriptor callback */
19011     V7_TRY(b_apply(v7, ctx->proxy_ctx->get_own_prop_desc, V7_UNDEFINED, args_v,
19012                    0, &desc_v));
19013 
19014     if (v7_is_object(desc_v)) {
19015       res_prop->attributes = 0;
19016 
19017       V7_TRY(v7_get_throwing(v7, desc_v, "writable", ~0, &tmpflag_v));
19018       if (!v7_is_truthy(v7, tmpflag_v)) {
19019         res_prop->attributes |= V7_PROPERTY_NON_WRITABLE;
19020       }
19021 
19022       V7_TRY(v7_get_throwing(v7, desc_v, "configurable", ~0, &tmpflag_v));
19023       if (!v7_is_truthy(v7, tmpflag_v)) {
19024         res_prop->attributes |= V7_PROPERTY_NON_CONFIGURABLE;
19025       }
19026 
19027       V7_TRY(v7_get_throwing(v7, desc_v, "enumerable", ~0, &tmpflag_v));
19028       if (!v7_is_truthy(v7, tmpflag_v)) {
19029         res_prop->attributes |= V7_PROPERTY_NON_ENUMERABLE;
19030       }
19031 
19032       V7_TRY(v7_get_throwing(v7, desc_v, "value", ~0, &res_prop->value));
19033 
19034       *ok = 1;
19035     }
19036   }
19037 
19038   /* We always set the name in the property descriptor to the actual name */
19039   res_prop->name = name;
19040 
19041 clean:
19042   v7_disown(v7, &tmpflag_v);
19043   v7_disown(v7, &desc_v);
19044   v7_disown(v7, &args_v);
19045   v7_disown(v7, &name);
19046 
19047   return rcode;
19048 }
19049 #endif
19050 
19051 WARN_UNUSED_RESULT
19052 V7_PRIVATE enum v7_err next_prop(struct v7 *v7, struct prop_iter_ctx *ctx,
19053                                  v7_val_t *name, v7_val_t *value,
19054                                  v7_prop_attr_t *attrs, int *ok) {
19055   enum v7_err rcode = V7_OK;
19056   struct v7_property p;
19057 
19058   (void) v7;
19059 
19060   memset(&p, 0, sizeof(p));
19061   p.name = V7_UNDEFINED;
19062   p.value = V7_UNDEFINED;
19063 
19064   v7_own(v7, &p.name);
19065   v7_own(v7, &p.value);
19066 
19067   assert(ctx->init);
19068 
19069   *ok = 0;
19070 
19071 #if V7_ENABLE__Proxy
19072   if (ctx->proxy_ctx == NULL || !ctx->proxy_ctx->has_own_keys) {
19073     /*
19074      * No `ownKeys` callback, so we'll iterate real properties of the object
19075      * (either the given object or, if it's a proxy, the proxy's target object)
19076      */
19077 
19078     if (ctx->cur_prop != NULL) {
19079       if (ctx->proxy_ctx == NULL || !ctx->proxy_ctx->has_get_own_prop_desc) {
19080         /*
19081          * There is no `getOwnPropertyDescriptor` callback, so, use the current
19082          * real property
19083          */
19084         memcpy(&p, ctx->cur_prop, sizeof(p));
19085         *ok = 1;
19086       } else {
19087         /*
19088          * There is a `getOwnPropertyDescriptor` callback, so call it for the
19089          * name of the current real property
19090          */
19091         V7_TRY(get_custom_prop_desc(v7, ctx->cur_prop->name, ctx, &p, ok));
19092       }
19093 
19094       ctx->cur_prop = ctx->cur_prop->next;
19095     }
19096   } else {
19097     /* We have custom own keys */
19098     v7_val_t cur_key = V7_UNDEFINED;
19099     size_t len = v7_array_length(v7, ctx->proxy_ctx->own_keys);
19100 
19101     v7_own(v7, &cur_key);
19102 
19103     /*
19104      * Iterate through the custom own keys until we can get the proper property
19105      * descriptor for the given key
19106      */
19107     while (!*ok && (size_t) ctx->proxy_ctx->own_key_idx < len) {
19108       cur_key = v7_array_get(v7, ctx->proxy_ctx->own_keys,
19109                              ctx->proxy_ctx->own_key_idx);
19110       ctx->proxy_ctx->own_key_idx++;
19111 
19112       if (ctx->proxy_ctx->has_get_own_prop_desc) {
19113         /*
19114          * There is a `getOwnPropertyDescriptor` callback, so, call it for the
19115          * current custom key and get all descriptor data from the object
19116          * returned. The `ok` variable will be updated appropriately (it will
19117          * be 0 if the callback did not return a proper descriptor)
19118          */
19119         V7_TRY2(get_custom_prop_desc(v7, cur_key, ctx, &p, ok), clean_custom);
19120       } else {
19121         /*
19122          * There is no `getOwnPropertyDescriptor` callback, so, try to get
19123          * real property with the name equal to the current key
19124          */
19125         size_t len = 0;
19126         const char *name = v7_get_string(v7, &cur_key, &len);
19127 
19128         struct v7_property *real_prop =
19129             v7_get_own_property(v7, ctx->proxy_ctx->target_obj, name, len);
19130         if (real_prop != NULL) {
19131           /* Property exists, so use data from its descriptor */
19132           memcpy(&p, real_prop, sizeof(p));
19133           *ok = 1;
19134         }
19135       }
19136     }
19137   clean_custom:
19138     v7_disown(v7, &cur_key);
19139     if (rcode != V7_OK) {
19140       goto clean;
19141     }
19142   }
19143 
19144 #else
19145   /*
19146    * Proxy is disabled: just get the next property
19147    */
19148   if (ctx->cur_prop != NULL) {
19149     memcpy(&p, ctx->cur_prop, sizeof(p));
19150     *ok = 1;
19151     ctx->cur_prop = ctx->cur_prop->next;
19152   }
19153 #endif
19154 
19155   /* If we have a valid property descriptor, use data from it */
19156   if (*ok) {
19157     if (name != NULL) *name = p.name;
19158     if (value != NULL) *value = p.value;
19159     if (attrs != NULL) *attrs = p.attributes;
19160   }
19161 
19162 #if V7_ENABLE__Proxy
19163 clean:
19164 #endif
19165   v7_disown(v7, &p.value);
19166   v7_disown(v7, &p.name);
19167   return rcode;
19168 }
19169 
19170 /* }}} Object properties */
19171 
19172 /* Object prototypes {{{ */
19173 
19174 V7_PRIVATE int obj_prototype_set(struct v7 *v7, struct v7_object *obj,
19175                                  struct v7_object *proto) {
19176   int ret = -1;
19177   (void) v7;
19178 
19179   if (obj->attributes & V7_OBJ_FUNCTION) {
19180     ret = -1;
19181   } else {
19182     ((struct v7_generic_object *) obj)->prototype = proto;
19183     ret = 0;
19184   }
19185 
19186   return ret;
19187 }
19188 
19189 V7_PRIVATE struct v7_object *obj_prototype(struct v7 *v7,
19190                                            struct v7_object *obj) {
19191   if (obj->attributes & V7_OBJ_FUNCTION) {
19192     return get_object_struct(v7->vals.function_prototype);
19193   } else {
19194     return ((struct v7_generic_object *) obj)->prototype;
19195   }
19196 }
19197 
19198 V7_PRIVATE int is_prototype_of(struct v7 *v7, val_t o, val_t p) {
19199   if (!v7_is_object(o) || !v7_is_object(p)) {
19200     return 0;
19201   }
19202 
19203   /* walk the prototype chain */
19204   for (; !v7_is_null(o); o = v7_get_proto(v7, o)) {
19205     if (v7_get_proto(v7, o) == p) {
19206       return 1;
19207     }
19208   }
19209   return 0;
19210 }
19211 
19212 int v7_is_instanceof(struct v7 *v7, val_t o, const char *c) {
19213   return v7_is_instanceof_v(v7, o, v7_get(v7, v7->vals.global_object, c, ~0));
19214 }
19215 
19216 int v7_is_instanceof_v(struct v7 *v7, val_t o, val_t c) {
19217   return is_prototype_of(v7, o, v7_get(v7, c, "prototype", 9));
19218 }
19219 
19220 v7_val_t v7_set_proto(struct v7 *v7, v7_val_t obj, v7_val_t proto) {
19221   if (v7_is_generic_object(obj)) {
19222     v7_val_t old_proto =
19223         v7_object_to_value(obj_prototype(v7, get_object_struct(obj)));
19224     obj_prototype_set(v7, get_object_struct(obj), get_object_struct(proto));
19225     return old_proto;
19226   } else {
19227     return V7_UNDEFINED;
19228   }
19229 }
19230 
19231 val_t v7_get_proto(struct v7 *v7, val_t obj) {
19232   /*
19233    * NOTE: we don't use v7_is_callable() here, because it involves walking
19234    * through the object's properties, which may be expensive. And it's done
19235    * anyway for cfunction objects as it would for any other generic objects by
19236    * the call to `obj_prototype()`.
19237    *
19238    * Since this function is called quite often (at least, GC walks the
19239    * prototype chain), it's better to just handle cfunction objects as generic
19240    * objects.
19241    */
19242   if (is_js_function(obj) || is_cfunction_lite(obj)) {
19243     return v7->vals.function_prototype;
19244   }
19245   return v7_object_to_value(obj_prototype(v7, get_object_struct(obj)));
19246 }
19247 
19248 V7_PRIVATE struct v7_property *get_user_data_property(v7_val_t obj) {
19249   struct v7_property *p;
19250   struct v7_object *o;
19251   if (!v7_is_object(obj)) return NULL;
19252   o = get_object_struct(obj);
19253 
19254   for (p = o->properties; p != NULL; p = p->next) {
19255     if (p->attributes & _V7_PROPERTY_USER_DATA_AND_DESTRUCTOR) {
19256       return p;
19257     }
19258   }
19259 
19260   return NULL;
19261 }
19262 
19263 /*
19264  * Returns the user data property structure associated with obj, or NULL if
19265  * `obj` is not an object.
19266  */
19267 static struct v7_property *get_or_create_user_data_property(struct v7 *v7,
19268                                                             v7_val_t obj) {
19269   struct v7_property *p = get_user_data_property(obj);
19270   struct v7_object *o;
19271 
19272   if (p != NULL) return p;
19273 
19274   if (!v7_is_object(obj)) return NULL;
19275   o = get_object_struct(obj);
19276   v7_own(v7, &obj);
19277   p = v7_mk_property(v7);
19278   v7_disown(v7, &obj);
19279 
19280   p->attributes |= _V7_PROPERTY_USER_DATA_AND_DESTRUCTOR | _V7_PROPERTY_HIDDEN;
19281 
19282   p->next = o->properties;
19283   o->properties = p;
19284 
19285   return p;
19286 }
19287 
19288 void v7_set_user_data(struct v7 *v7, v7_val_t obj, void *ud) {
19289   struct v7_property *p = get_or_create_user_data_property(v7, obj);
19290   if (p == NULL) return;
19291   p->value = v7_mk_foreign(v7, ud);
19292 }
19293 
19294 void *v7_get_user_data(struct v7 *v7, v7_val_t obj) {
19295   struct v7_property *p = get_user_data_property(obj);
19296   (void) v7;
19297   if (p == NULL) return NULL;
19298   return v7_get_ptr(v7, p->value);
19299 }
19300 
19301 void v7_set_destructor_cb(struct v7 *v7, v7_val_t obj, v7_destructor_cb_t *d) {
19302   struct v7_property *p = get_or_create_user_data_property(v7, obj);
19303   struct v7_object *o;
19304   union {
19305     void *v;
19306     v7_destructor_cb_t *f;
19307   } fu;
19308 
19309   if (p == NULL) return;
19310 
19311   o = get_object_struct(obj);
19312   if (d != NULL) {
19313     o->attributes |= V7_OBJ_HAS_DESTRUCTOR;
19314     fu.f = d;
19315     p->name = v7_mk_foreign(v7, fu.v);
19316   } else {
19317     o->attributes &= ~V7_OBJ_HAS_DESTRUCTOR;
19318     p->name = V7_UNDEFINED;
19319   }
19320 }
19321 
19322 /* }}} Object prototypes */
19323 #ifdef V7_MODULE_LINES
19324 #line 1 "v7/src/regexp.c"
19325 #endif
19326 /*
19327  * Copyright (c) 2014 Cesanta Software Limited
19328  * All rights reserved
19329  */
19330 
19331 /* Amalgamated: #include "v7/src/internal.h" */
19332 /* Amalgamated: #include "v7/src/core.h" */
19333 /* Amalgamated: #include "v7/src/primitive.h" */
19334 /* Amalgamated: #include "v7/src/object.h" */
19335 /* Amalgamated: #include "v7/src/regexp.h" */
19336 /* Amalgamated: #include "v7/src/exceptions.h" */
19337 /* Amalgamated: #include "v7/src/string.h" */
19338 /* Amalgamated: #include "v7/src/slre.h" */
19339 
19340 #if V7_ENABLE__RegExp
19341 enum v7_err v7_mk_regexp(struct v7 *v7, const char *re, size_t re_len,
19342                          const char *flags, size_t flags_len, v7_val_t *res) {
19343   enum v7_err rcode = V7_OK;
19344   struct slre_prog *p = NULL;
19345   struct v7_regexp *rp;
19346 
19347   if (re_len == ~((size_t) 0)) re_len = strlen(re);
19348 
19349   if (slre_compile(re, re_len, flags, flags_len, &p, 1) != SLRE_OK ||
19350       p == NULL) {
19351     rcode = v7_throwf(v7, TYPE_ERROR, "Invalid regex");
19352     goto clean;
19353   } else {
19354     *res = mk_object(v7, v7->vals.regexp_prototype);
19355     rp = (struct v7_regexp *) malloc(sizeof(*rp));
19356     rp->regexp_string = v7_mk_string(v7, re, re_len, 1);
19357     v7_own(v7, &rp->regexp_string);
19358     rp->compiled_regexp = p;
19359     rp->lastIndex = 0;
19360 
19361     v7_def(v7, *res, "", 0, _V7_DESC_HIDDEN(1),
19362            pointer_to_value(rp) | V7_TAG_REGEXP);
19363   }
19364 
19365 clean:
19366   return rcode;
19367 }
19368 
19369 V7_PRIVATE struct v7_regexp *v7_get_regexp_struct(struct v7 *v7, val_t v) {
19370   struct v7_property *p;
19371   int is = v7_is_regexp(v7, v);
19372   (void) is;
19373   assert(is == 1);
19374   /* TODO(mkm): make regexp use user data API */
19375   p = v7_get_own_property2(v7, v, "", 0, _V7_PROPERTY_HIDDEN);
19376   assert(p != NULL);
19377   return (struct v7_regexp *) get_ptr(p->value);
19378 }
19379 
19380 int v7_is_regexp(struct v7 *v7, val_t v) {
19381   struct v7_property *p;
19382   if (!v7_is_generic_object(v)) return 0;
19383   /* TODO(mkm): make regexp use user data API */
19384   p = v7_get_own_property2(v7, v, "", 0, _V7_PROPERTY_HIDDEN);
19385   if (p == NULL) return 0;
19386   return (p->value & V7_TAG_MASK) == V7_TAG_REGEXP;
19387 }
19388 
19389 V7_PRIVATE size_t
19390 get_regexp_flags_str(struct v7 *v7, struct v7_regexp *rp, char *buf) {
19391   int re_flags = slre_get_flags(rp->compiled_regexp);
19392   size_t n = 0;
19393 
19394   (void) v7;
19395   if (re_flags & SLRE_FLAG_G) buf[n++] = 'g';
19396   if (re_flags & SLRE_FLAG_I) buf[n++] = 'i';
19397   if (re_flags & SLRE_FLAG_M) buf[n++] = 'm';
19398 
19399   assert(n <= _V7_REGEXP_MAX_FLAGS_LEN);
19400 
19401   return n;
19402 }
19403 
19404 #else /* V7_ENABLE__RegExp */
19405 
19406 /*
19407  * Dummy implementation when RegExp support is disabled: just return 0
19408  */
19409 int v7_is_regexp(struct v7 *v7, val_t v) {
19410   (void) v7;
19411   (void) v;
19412   return 0;
19413 }
19414 
19415 #endif /* V7_ENABLE__RegExp */
19416 #ifdef V7_MODULE_LINES
19417 #line 1 "v7/src/exceptions.c"
19418 #endif
19419 /*
19420  * Copyright (c) 2014 Cesanta Software Limited
19421  * All rights reserved
19422  */
19423 
19424 /* Amalgamated: #include "common/str_util.h" */
19425 /* Amalgamated: #include "v7/src/internal.h" */
19426 /* Amalgamated: #include "v7/src/exceptions.h" */
19427 /* Amalgamated: #include "v7/src/array.h" */
19428 /* Amalgamated: #include "v7/src/core.h" */
19429 /* Amalgamated: #include "v7/src/eval.h" */
19430 /* Amalgamated: #include "v7/src/object.h" */
19431 
19432 enum v7_err v7_throw(struct v7 *v7, v7_val_t val) {
19433   v7->vals.thrown_error = val;
19434   v7->is_thrown = 1;
19435   return V7_EXEC_EXCEPTION;
19436 }
19437 
19438 void v7_clear_thrown_value(struct v7 *v7) {
19439   v7->vals.thrown_error = V7_UNDEFINED;
19440   v7->is_thrown = 0;
19441 }
19442 
19443 enum v7_err v7_throwf(struct v7 *v7, const char *typ, const char *err_fmt,
19444                       ...) {
19445   /* TODO(dfrank) : get rid of v7->error_msg, allocate mem right here */
19446   enum v7_err rcode = V7_OK;
19447   va_list ap;
19448   val_t e = V7_UNDEFINED;
19449   va_start(ap, err_fmt);
19450   c_vsnprintf(v7->error_msg, sizeof(v7->error_msg), err_fmt, ap);
19451   va_end(ap);
19452 
19453   v7_own(v7, &e);
19454   rcode = create_exception(v7, typ, v7->error_msg, &e);
19455   if (rcode != V7_OK) {
19456     goto clean;
19457   }
19458 
19459   rcode = v7_throw(v7, e);
19460 
19461 clean:
19462   v7_disown(v7, &e);
19463   return rcode;
19464 }
19465 
19466 enum v7_err v7_rethrow(struct v7 *v7) {
19467   assert(v7->is_thrown);
19468 #ifdef NDEBUG
19469   (void) v7;
19470 #endif
19471   return V7_EXEC_EXCEPTION;
19472 }
19473 
19474 v7_val_t v7_get_thrown_value(struct v7 *v7, uint8_t *is_thrown) {
19475   if (is_thrown != NULL) {
19476     *is_thrown = v7->is_thrown;
19477   }
19478   return v7->vals.thrown_error;
19479 }
19480 
19481 /*
19482  * Create an instance of the exception with type `typ` (see `TYPE_ERROR`,
19483  * `SYNTAX_ERROR`, etc) and message `msg`.
19484  */
19485 V7_PRIVATE enum v7_err create_exception(struct v7 *v7, const char *typ,
19486                                         const char *msg, val_t *res) {
19487   enum v7_err rcode = V7_OK;
19488   uint8_t saved_creating_exception = v7->creating_exception;
19489   val_t ctor_args = V7_UNDEFINED, ctor_func = V7_UNDEFINED;
19490 #if 0
19491   assert(v7_is_undefined(v7->vals.thrown_error));
19492 #endif
19493 
19494   *res = V7_UNDEFINED;
19495 
19496   v7_own(v7, &ctor_args);
19497   v7_own(v7, &ctor_func);
19498 
19499   if (v7->creating_exception) {
19500 #ifndef NO_LIBC
19501     fprintf(stderr, "Exception creation throws an exception %s: %s\n", typ,
19502             msg);
19503 #endif
19504   } else {
19505     v7->creating_exception = 1;
19506 
19507     /* Prepare arguments for the `Error` constructor */
19508     ctor_args = v7_mk_dense_array(v7);
19509     v7_array_set(v7, ctor_args, 0, v7_mk_string(v7, msg, strlen(msg), 1));
19510 
19511     /* Get constructor for the given error `typ` */
19512     ctor_func = v7_get(v7, v7->vals.global_object, typ, ~0);
19513     if (v7_is_undefined(ctor_func)) {
19514       fprintf(stderr, "cannot find exception %s\n", typ);
19515     }
19516 
19517     /* Create an error object, with prototype from constructor function */
19518     *res = mk_object(v7, v7_get(v7, ctor_func, "prototype", 9));
19519 
19520     /*
19521      * Finally, call the error constructor, passing an error object as `this`
19522      */
19523     V7_TRY(b_apply(v7, ctor_func, *res, ctor_args, 0, NULL));
19524   }
19525 
19526 clean:
19527   v7->creating_exception = saved_creating_exception;
19528 
19529   v7_disown(v7, &ctor_func);
19530   v7_disown(v7, &ctor_args);
19531 
19532   return rcode;
19533 }
19534 #ifdef V7_MODULE_LINES
19535 #line 1 "v7/src/conversion.c"
19536 #endif
19537 /*
19538  * Copyright (c) 2014 Cesanta Software Limited
19539  * All rights reserved
19540  */
19541 
19542 /* Amalgamated: #include "common/cs_strtod.h" */
19543 /* Amalgamated: #include "common/str_util.h" */
19544 
19545 /* Amalgamated: #include "v7/src/internal.h" */
19546 /* Amalgamated: #include "v7/src/core.h" */
19547 /* Amalgamated: #include "v7/src/util.h" */
19548 /* Amalgamated: #include "v7/src/primitive.h" */
19549 /* Amalgamated: #include "v7/src/function.h" */
19550 /* Amalgamated: #include "v7/src/conversion.h" */
19551 /* Amalgamated: #include "v7/src/exceptions.h" */
19552 /* Amalgamated: #include "v7/src/eval.h" */
19553 /* Amalgamated: #include "v7/src/gc.h" */
19554 /* Amalgamated: #include "v7/src/array.h" */
19555 /* Amalgamated: #include "v7/src/object.h" */
19556 
19557 static void save_val(struct v7 *v7, const char *str, size_t str_len,
19558                      val_t *dst_v, char *dst, size_t dst_size, int wanted_len,
19559                      size_t *res_wanted_len) {
19560   if (dst_v != NULL) {
19561     *dst_v = v7_mk_string(v7, str, str_len, 1);
19562   }
19563 
19564   if (dst != NULL && dst_size > 0) {
19565     size_t size = str_len + 1 /*null-term*/;
19566     if (size > dst_size) {
19567       size = dst_size;
19568     }
19569     memcpy(dst, str, size);
19570 
19571     /* make sure we have null-term */
19572     dst[dst_size - 1] = '\0';
19573   }
19574 
19575   if (res_wanted_len != NULL) {
19576     *res_wanted_len = (wanted_len >= 0) ? (size_t) wanted_len : str_len;
19577   }
19578 }
19579 
19580 WARN_UNUSED_RESULT
19581 V7_PRIVATE enum v7_err primitive_to_str(struct v7 *v7, val_t v, val_t *res,
19582                                         char *buf, size_t buf_size,
19583                                         size_t *res_len) {
19584   enum v7_err rcode = V7_OK;
19585   char tmp_buf[25];
19586   double num;
19587   size_t wanted_len;
19588 
19589   assert(!v7_is_object(v));
19590 
19591   memset(tmp_buf, 0x00, sizeof(tmp_buf));
19592 
19593   v7_own(v7, &v);
19594 
19595   switch (val_type(v7, v)) {
19596     case V7_TYPE_STRING: {
19597       /* if `res` provided, set it to source value */
19598       if (res != NULL) {
19599         *res = v;
19600       }
19601 
19602       /* if buf provided, copy string data there */
19603       if (buf != NULL && buf_size > 0) {
19604         size_t size;
19605         const char *str = v7_get_string(v7, &v, &size);
19606         size += 1 /*null-term*/;
19607 
19608         if (size > buf_size) {
19609           size = buf_size;
19610         }
19611 
19612         memcpy(buf, str, size);
19613 
19614         /* make sure we have a null-term */
19615         buf[buf_size - 1] = '\0';
19616       }
19617 
19618       if (res_len != NULL) {
19619         v7_get_string(v7, &v, res_len);
19620       }
19621 
19622       goto clean;
19623     }
19624     case V7_TYPE_NULL:
19625       strncpy(tmp_buf, "null", sizeof(tmp_buf) - 1);
19626       save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
19627       goto clean;
19628     case V7_TYPE_UNDEFINED:
19629       strncpy(tmp_buf, "undefined", sizeof(tmp_buf) - 1);
19630       save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
19631       goto clean;
19632     case V7_TYPE_BOOLEAN:
19633       if (v7_get_bool(v7, v)) {
19634         strncpy(tmp_buf, "true", sizeof(tmp_buf) - 1);
19635         save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
19636         goto clean;
19637       } else {
19638         strncpy(tmp_buf, "false", sizeof(tmp_buf) - 1);
19639         save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
19640         goto clean;
19641       }
19642     case V7_TYPE_NUMBER:
19643       if (v == V7_TAG_NAN) {
19644         strncpy(tmp_buf, "NaN", sizeof(tmp_buf) - 1);
19645         save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
19646         goto clean;
19647       }
19648       num = v7_get_double(v7, v);
19649       if (isinf(num)) {
19650         if (num < 0.0) {
19651           strncpy(tmp_buf, "-Infinity", sizeof(tmp_buf) - 1);
19652         } else {
19653           strncpy(tmp_buf, "Infinity", sizeof(tmp_buf) - 1);
19654         }
19655         save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, -1, res_len);
19656         goto clean;
19657       }
19658       {
19659         const char *fmt = num > 1e10 ? "%.21g" : "%.10g";
19660         wanted_len = snprintf(tmp_buf, sizeof(tmp_buf), fmt, num);
19661         save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, wanted_len,
19662                  res_len);
19663         goto clean;
19664       }
19665     case V7_TYPE_CFUNCTION:
19666 #ifdef V7_UNIT_TEST
19667       wanted_len = c_snprintf(tmp_buf, sizeof(tmp_buf), "cfunc_xxxxxx");
19668       save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, wanted_len,
19669                res_len);
19670       goto clean;
19671 #else
19672       wanted_len = c_snprintf(tmp_buf, sizeof(tmp_buf), "cfunc_%p", get_ptr(v));
19673       save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, wanted_len,
19674                res_len);
19675       goto clean;
19676 #endif
19677     case V7_TYPE_FOREIGN:
19678       wanted_len = c_snprintf(tmp_buf, sizeof(tmp_buf), "[foreign_%p]",
19679                               v7_get_ptr(v7, v));
19680       save_val(v7, tmp_buf, strlen(tmp_buf), res, buf, buf_size, wanted_len,
19681                res_len);
19682       goto clean;
19683     default:
19684       abort();
19685   }
19686 
19687 clean:
19688 
19689   v7_disown(v7, &v);
19690   return rcode;
19691 }
19692 
19693 WARN_UNUSED_RESULT
19694 V7_PRIVATE enum v7_err primitive_to_number(struct v7 *v7, val_t v, val_t *res) {
19695   enum v7_err rcode = V7_OK;
19696 
19697   assert(!v7_is_object(v));
19698 
19699   *res = v;
19700 
19701   if (v7_is_number(*res)) {
19702     goto clean;
19703   }
19704 
19705   if (v7_is_undefined(*res)) {
19706     *res = V7_TAG_NAN;
19707     goto clean;
19708   }
19709 
19710   if (v7_is_null(*res)) {
19711     *res = v7_mk_number(v7, 0.0);
19712     goto clean;
19713   }
19714 
19715   if (v7_is_boolean(*res)) {
19716     *res = v7_mk_number(v7, !!v7_get_bool(v7, v));
19717     goto clean;
19718   }
19719 
19720   if (is_cfunction_lite(*res)) {
19721     *res = v7_mk_number(v7, 0.0);
19722     goto clean;
19723   }
19724 
19725   if (v7_is_string(*res)) {
19726     double d;
19727     size_t n;
19728     char *e, *s = (char *) v7_get_string(v7, res, &n);
19729     if (n != 0) {
19730       d = cs_strtod(s, &e);
19731       if (e - n != s) {
19732         d = NAN;
19733       }
19734     } else {
19735       /* empty string: convert to 0 */
19736       d = 0.0;
19737     }
19738     *res = v7_mk_number(v7, d);
19739     goto clean;
19740   }
19741 
19742   assert(0);
19743 
19744 clean:
19745   return rcode;
19746 }
19747 
19748 WARN_UNUSED_RESULT
19749 enum v7_err to_primitive(struct v7 *v7, val_t v, enum to_primitive_hint hint,
19750                          val_t *res) {
19751   enum v7_err rcode = V7_OK;
19752   enum v7_err (*p_func)(struct v7 *v7, val_t v, val_t *res);
19753 
19754   v7_own(v7, &v);
19755 
19756   *res = v;
19757 
19758   /*
19759    * If given value is an object, try to convert it to string by calling first
19760    * preferred function (`toString()` or `valueOf()`, depending on the `hint`
19761    * argument)
19762    */
19763   if (v7_is_object(*res)) {
19764     /* Handle special case for Date object */
19765     if (hint == V7_TO_PRIMITIVE_HINT_AUTO) {
19766       hint = (v7_get_proto(v7, *res) == v7->vals.date_prototype)
19767                  ? V7_TO_PRIMITIVE_HINT_STRING
19768                  : V7_TO_PRIMITIVE_HINT_NUMBER;
19769     }
19770 
19771     p_func =
19772         (hint == V7_TO_PRIMITIVE_HINT_NUMBER) ? obj_value_of : obj_to_string;
19773     rcode = p_func(v7, *res, res);
19774     if (rcode != V7_OK) {
19775       goto clean;
19776     }
19777 
19778     /*
19779      * If returned value is still an object, get original argument value
19780      */
19781     if (v7_is_object(*res)) {
19782       *res = v;
19783     }
19784   }
19785 
19786   /*
19787    * If the value is still an object, try to call second function (`valueOf()`
19788    * or `toString()`)
19789    */
19790   if (v7_is_object(*res)) {
19791     p_func =
19792         (hint == V7_TO_PRIMITIVE_HINT_NUMBER) ? obj_to_string : obj_value_of;
19793     rcode = p_func(v7, *res, res);
19794     if (rcode != V7_OK) {
19795       goto clean;
19796     }
19797   }
19798 
19799   /*
19800    * If the value is still an object, then throw.
19801    */
19802   if (v7_is_object(*res)) {
19803     rcode =
19804         v7_throwf(v7, TYPE_ERROR, "Cannot convert object to primitive value");
19805     goto clean;
19806   }
19807 
19808 clean:
19809   v7_disown(v7, &v);
19810   return rcode;
19811 }
19812 
19813 WARN_UNUSED_RESULT
19814 V7_PRIVATE enum v7_err to_string(struct v7 *v7, val_t v, val_t *res, char *buf,
19815                                  size_t buf_size, size_t *res_len) {
19816   enum v7_err rcode = V7_OK;
19817 
19818   v7_own(v7, &v);
19819 
19820   /*
19821    * Convert value to primitive if needed, calling `toString()` first
19822    */
19823   V7_TRY(to_primitive(v7, v, V7_TO_PRIMITIVE_HINT_STRING, &v));
19824 
19825   /*
19826    * Now, we're guaranteed to have a primitive here. Convert it to string.
19827    */
19828   V7_TRY(primitive_to_str(v7, v, res, buf, buf_size, res_len));
19829 
19830 clean:
19831   v7_disown(v7, &v);
19832   return rcode;
19833 }
19834 
19835 WARN_UNUSED_RESULT
19836 V7_PRIVATE enum v7_err to_number_v(struct v7 *v7, val_t v, val_t *res) {
19837   enum v7_err rcode = V7_OK;
19838 
19839   *res = v;
19840 
19841   /*
19842    * Convert value to primitive if needed, calling `valueOf()` first
19843    */
19844   rcode = to_primitive(v7, *res, V7_TO_PRIMITIVE_HINT_NUMBER, res);
19845   if (rcode != V7_OK) {
19846     goto clean;
19847   }
19848 
19849   /*
19850    * Now, we're guaranteed to have a primitive here. Convert it to number.
19851    */
19852   rcode = primitive_to_number(v7, *res, res);
19853   if (rcode != V7_OK) {
19854     goto clean;
19855   }
19856 
19857 clean:
19858   return rcode;
19859 }
19860 
19861 WARN_UNUSED_RESULT
19862 V7_PRIVATE enum v7_err to_long(struct v7 *v7, val_t v, long default_value,
19863                                long *res) {
19864   enum v7_err rcode = V7_OK;
19865   double d;
19866 
19867   /* if value is `undefined`, just return `default_value` */
19868   if (v7_is_undefined(v)) {
19869     *res = default_value;
19870     goto clean;
19871   }
19872 
19873   /* Try to convert value to number */
19874   rcode = to_number_v(v7, v, &v);
19875   if (rcode != V7_OK) {
19876     goto clean;
19877   }
19878 
19879   /*
19880    * Conversion to number succeeded, so, convert it to long
19881    */
19882 
19883   d = v7_get_double(v7, v);
19884   /* We want to return LONG_MAX if d is positive Inf, thus d < 0 check */
19885   if (isnan(d) || (isinf(d) && d < 0)) {
19886     *res = 0;
19887     goto clean;
19888   } else if (d > LONG_MAX) {
19889     *res = LONG_MAX;
19890     goto clean;
19891   }
19892   *res = (long) d;
19893   goto clean;
19894 
19895 clean:
19896   return rcode;
19897 }
19898 
19899 V7_PRIVATE enum v7_err obj_value_of(struct v7 *v7, val_t v, val_t *res) {
19900   enum v7_err rcode = V7_OK;
19901   val_t func_valueOf = V7_UNDEFINED;
19902 
19903   v7_own(v7, &func_valueOf);
19904   v7_own(v7, &v);
19905 
19906   /*
19907    * TODO(dfrank): use `assert(v7_is_object(v))` instead, like `obj_to_string()`
19908    * does, and fix all callers to ensure it's an object before calling.
19909    *
19910    * Or, conversely, make `obj_to_string()` to accept objects.
19911    */
19912   if (!v7_is_object(v)) {
19913     *res = v;
19914     goto clean;
19915   }
19916 
19917   V7_TRY(v7_get_throwing(v7, v, "valueOf", 7, &func_valueOf));
19918 
19919   if (v7_is_callable(v7, func_valueOf)) {
19920     V7_TRY(b_apply(v7, func_valueOf, v, V7_UNDEFINED, 0, res));
19921   }
19922 
19923 clean:
19924   if (rcode != V7_OK) {
19925     *res = v;
19926   }
19927 
19928   v7_disown(v7, &v);
19929   v7_disown(v7, &func_valueOf);
19930 
19931   return rcode;
19932 }
19933 
19934 /*
19935  * Caller should ensure that `v` is an object
19936  */
19937 WARN_UNUSED_RESULT
19938 V7_PRIVATE enum v7_err obj_to_string(struct v7 *v7, val_t v, val_t *res) {
19939   enum v7_err rcode = V7_OK;
19940   val_t to_string_func = V7_UNDEFINED;
19941 
19942   /* Caller should ensure that `v` is an object */
19943   assert(v7_is_object(v));
19944 
19945   v7_own(v7, &to_string_func);
19946   v7_own(v7, &v);
19947 
19948   /*
19949    * If `toString` is callable, then call it; otherwise, just return source
19950    * value
19951    */
19952   V7_TRY(v7_get_throwing(v7, v, "toString", 8, &to_string_func));
19953   if (v7_is_callable(v7, to_string_func)) {
19954     V7_TRY(b_apply(v7, to_string_func, v, V7_UNDEFINED, 0, res));
19955   } else {
19956     *res = v;
19957   }
19958 
19959 clean:
19960   v7_disown(v7, &v);
19961   v7_disown(v7, &to_string_func);
19962 
19963   return rcode;
19964 }
19965 
19966 static const char *hex_digits = "0123456789abcdef";
19967 static char *append_hex(char *buf, char *limit, uint8_t c) {
19968   if (buf < limit) *buf++ = 'u';
19969   if (buf < limit) *buf++ = '0';
19970   if (buf < limit) *buf++ = '0';
19971   if (buf < limit) *buf++ = hex_digits[(int) ((c >> 4) % 0xf)];
19972   if (buf < limit) *buf++ = hex_digits[(int) (c & 0xf)];
19973   return buf;
19974 }
19975 
19976 /*
19977  * Appends quoted s to buf. Any double quote contained in s will be escaped.
19978  * Returns the number of characters that would have been added,
19979  * like snprintf.
19980  * If size is zero it doesn't output anything but keeps counting.
19981  */
19982 static int snquote(char *buf, size_t size, const char *s, size_t len) {
19983   char *limit = buf + size - 1;
19984   const char *end;
19985   /*
19986    * String single character escape sequence:
19987    * http://www.ecma-international.org/ecma-262/6.0/index.html#table-34
19988    *
19989    * 0x8 -> \b
19990    * 0x9 -> \t
19991    * 0xa -> \n
19992    * 0xb -> \v
19993    * 0xc -> \f
19994    * 0xd -> \r
19995    */
19996   const char *specials = "btnvfr";
19997   size_t i = 0;
19998 
19999   i++;
20000   if (buf < limit) *buf++ = '"';
20001 
20002   for (end = s + len; s < end; s++) {
20003     if (*s == '"' || *s == '\\') {
20004       i++;
20005       if (buf < limit) *buf++ = '\\';
20006     } else if (*s >= '\b' && *s <= '\r') {
20007       i += 2;
20008       if (buf < limit) *buf++ = '\\';
20009       if (buf < limit) *buf++ = specials[*s - '\b'];
20010       continue;
20011     } else if ((unsigned char) *s < '\b' || (*s > '\r' && *s < ' ')) {
20012       i += 6 /* \uXXXX */;
20013       if (buf < limit) *buf++ = '\\';
20014       buf = append_hex(buf, limit, (uint8_t) *s);
20015       continue;
20016     }
20017     i++;
20018     if (buf < limit) *buf++ = *s;
20019   }
20020 
20021   i++;
20022   if (buf < limit) *buf++ = '"';
20023 
20024   if (size != 0) {
20025     *buf = '\0';
20026   }
20027   return i;
20028 }
20029 
20030 /*
20031  * Returns whether the value of given type should be skipped when generating
20032  * JSON output
20033  */
20034 static int should_skip_for_json(enum v7_type type) {
20035   int ret;
20036   switch (type) {
20037     /* All permitted values */
20038     case V7_TYPE_NULL:
20039     case V7_TYPE_BOOLEAN:
20040     case V7_TYPE_BOOLEAN_OBJECT:
20041     case V7_TYPE_NUMBER:
20042     case V7_TYPE_NUMBER_OBJECT:
20043     case V7_TYPE_STRING:
20044     case V7_TYPE_STRING_OBJECT:
20045     case V7_TYPE_GENERIC_OBJECT:
20046     case V7_TYPE_ARRAY_OBJECT:
20047     case V7_TYPE_DATE_OBJECT:
20048     case V7_TYPE_REGEXP_OBJECT:
20049     case V7_TYPE_ERROR_OBJECT:
20050       ret = 0;
20051       break;
20052     default:
20053       ret = 1;
20054       break;
20055   }
20056   return ret;
20057 }
20058 
20059 WARN_UNUSED_RESULT
20060 V7_PRIVATE enum v7_err to_json_or_debug(struct v7 *v7, val_t v, char *buf,
20061                                         size_t size, size_t *res_len,
20062                                         uint8_t is_debug) {
20063   val_t el;
20064   char *vp;
20065   enum v7_err rcode = V7_OK;
20066   size_t len = 0;
20067   struct gc_tmp_frame tf = new_tmp_frame(v7);
20068 
20069   tmp_stack_push(&tf, &v);
20070   tmp_stack_push(&tf, &el);
20071   /*
20072    * TODO(dfrank) : also push all `v7_val_t`s that are declared below
20073    */
20074 
20075   if (size > 0) *buf = '\0';
20076 
20077   if (!is_debug && should_skip_for_json(val_type(v7, v))) {
20078     goto clean;
20079   }
20080 
20081   for (vp = v7->json_visited_stack.buf;
20082        vp < v7->json_visited_stack.buf + v7->json_visited_stack.len;
20083        vp += sizeof(val_t)) {
20084     if (*(val_t *) vp == v) {
20085       strncpy(buf, "[Circular]", size);
20086       len = 10;
20087       goto clean;
20088     }
20089   }
20090 
20091   switch (val_type(v7, v)) {
20092     case V7_TYPE_NULL:
20093     case V7_TYPE_BOOLEAN:
20094     case V7_TYPE_NUMBER:
20095     case V7_TYPE_UNDEFINED:
20096     case V7_TYPE_CFUNCTION:
20097     case V7_TYPE_FOREIGN:
20098       /* For those types, regular `primitive_to_str()` works */
20099       V7_TRY(primitive_to_str(v7, v, NULL, buf, size, &len));
20100       goto clean;
20101 
20102     case V7_TYPE_STRING: {
20103       /*
20104        * For strings we can't just use `primitive_to_str()`, because we need
20105        * quoted value
20106        */
20107       size_t n;
20108       const char *str = v7_get_string(v7, &v, &n);
20109       len = snquote(buf, size, str, n);
20110       goto clean;
20111     }
20112 
20113     case V7_TYPE_DATE_OBJECT: {
20114       v7_val_t func = V7_UNDEFINED, val = V7_UNDEFINED;
20115       V7_TRY(v7_get_throwing(v7, v, "toString", 8, &func));
20116 #if V7_ENABLE__Date__toJSON
20117       if (!is_debug) {
20118         V7_TRY(v7_get_throwing(v7, v, "toJSON", 6, &func));
20119       }
20120 #endif
20121       V7_TRY(b_apply(v7, func, v, V7_UNDEFINED, 0, &val));
20122       V7_TRY(to_json_or_debug(v7, val, buf, size, &len, is_debug));
20123       goto clean;
20124     }
20125     case V7_TYPE_GENERIC_OBJECT:
20126     case V7_TYPE_BOOLEAN_OBJECT:
20127     case V7_TYPE_STRING_OBJECT:
20128     case V7_TYPE_NUMBER_OBJECT:
20129     case V7_TYPE_REGEXP_OBJECT:
20130     case V7_TYPE_ERROR_OBJECT: {
20131       /* TODO(imax): make it return the desired size of the buffer */
20132       char *b = buf;
20133       v7_val_t name = V7_UNDEFINED, val = V7_UNDEFINED;
20134       v7_prop_attr_t attrs = 0;
20135       const char *pname;
20136       size_t nlen;
20137       int ok = 0;
20138       struct prop_iter_ctx ctx;
20139       memset(&ctx, 0, sizeof(ctx));
20140 
20141       mbuf_append(&v7->json_visited_stack, (char *) &v, sizeof(v));
20142       b += c_snprintf(b, BUF_LEFT(size, b - buf), "{");
20143       V7_TRY2(init_prop_iter_ctx(v7, v, 1 /*proxy-transparent*/, &ctx),
20144               clean_iter);
20145       while (1) {
20146         size_t n;
20147         const char *s;
20148         V7_TRY2(next_prop(v7, &ctx, &name, &val, &attrs, &ok), clean_iter);
20149         if (!ok) {
20150           break;
20151         } else if (attrs & (_V7_PROPERTY_HIDDEN | V7_PROPERTY_NON_ENUMERABLE)) {
20152           continue;
20153         }
20154         pname = v7_get_string(v7, &name, &nlen);
20155         V7_TRY(v7_get_throwing(v7, v, pname, nlen, &val));
20156         if (!is_debug && should_skip_for_json(val_type(v7, val))) {
20157           continue;
20158         }
20159         if (b - buf != 1) { /* Not the first property to be printed */
20160           b += c_snprintf(b, BUF_LEFT(size, b - buf), ",");
20161         }
20162         s = v7_get_string(v7, &name, &n);
20163         b += c_snprintf(b, BUF_LEFT(size, b - buf), "\"%.*s\":", (int) n, s);
20164         {
20165           size_t tmp = 0;
20166           V7_TRY2(to_json_or_debug(v7, val, b, BUF_LEFT(size, b - buf), &tmp,
20167                                    is_debug),
20168                   clean_iter);
20169           b += tmp;
20170         }
20171       }
20172       b += c_snprintf(b, BUF_LEFT(size, b - buf), "}");
20173       v7->json_visited_stack.len -= sizeof(v);
20174 
20175     clean_iter:
20176       v7_destruct_prop_iter_ctx(v7, &ctx);
20177 
20178       len = b - buf;
20179       goto clean;
20180     }
20181     case V7_TYPE_ARRAY_OBJECT: {
20182       int has;
20183       char *b = buf;
20184       size_t i, alen = v7_array_length(v7, v);
20185       mbuf_append(&v7->json_visited_stack, (char *) &v, sizeof(v));
20186       b += c_snprintf(b, BUF_LEFT(size, b - buf), "[");
20187       for (i = 0; i < alen; i++) {
20188         el = v7_array_get2(v7, v, i, &has);
20189         if (has) {
20190           size_t tmp = 0;
20191           if (!is_debug && should_skip_for_json(val_type(v7, el))) {
20192             b += c_snprintf(b, BUF_LEFT(size, b - buf), "null");
20193           } else {
20194             V7_TRY(to_json_or_debug(v7, el, b, BUF_LEFT(size, b - buf), &tmp,
20195                                     is_debug));
20196           }
20197           b += tmp;
20198         }
20199         if (i != alen - 1) {
20200           b += c_snprintf(b, BUF_LEFT(size, b - buf), ",");
20201         }
20202       }
20203       b += c_snprintf(b, BUF_LEFT(size, b - buf), "]");
20204       v7->json_visited_stack.len -= sizeof(v);
20205       len = b - buf;
20206       goto clean;
20207     }
20208     case V7_TYPE_CFUNCTION_OBJECT:
20209       V7_TRY(obj_value_of(v7, v, &v));
20210       len = c_snprintf(buf, size, "Function cfunc_%p", get_ptr(v));
20211       goto clean;
20212     case V7_TYPE_FUNCTION_OBJECT:
20213       V7_TRY(to_string(v7, v, NULL, buf, size, &len));
20214       goto clean;
20215 
20216     case V7_TYPE_MAX_OBJECT_TYPE:
20217     case V7_NUM_TYPES:
20218       abort();
20219   }
20220 
20221   abort();
20222 
20223   len = 0; /* for compilers that don't know about abort() */
20224   goto clean;
20225 
20226 clean:
20227   if (rcode != V7_OK) {
20228     len = 0;
20229   }
20230   if (res_len != NULL) {
20231     *res_len = len;
20232   }
20233   tmp_frame_cleanup(&tf);
20234   return rcode;
20235 }
20236 
20237 WARN_UNUSED_RESULT
20238 V7_PRIVATE val_t to_boolean_v(struct v7 *v7, val_t v) {
20239   size_t len;
20240   int is_truthy;
20241 
20242   is_truthy = ((v7_is_boolean(v) && v7_get_bool(v7, v)) ||
20243                (v7_is_number(v) && v7_get_double(v7, v) != 0.0) ||
20244                (v7_is_string(v) && v7_get_string(v7, &v, &len) && len > 0) ||
20245                (v7_is_object(v))) &&
20246               v != V7_TAG_NAN;
20247 
20248   return v7_mk_boolean(v7, is_truthy);
20249 }
20250 
20251 /*
20252  * v7_stringify allocates a new buffer if value representation doesn't fit into
20253  * buf. Caller is responsible for freeing that buffer.
20254  */
20255 char *v7_stringify(struct v7 *v7, val_t v, char *buf, size_t size,
20256                    enum v7_stringify_mode mode) {
20257   enum v7_err rcode = V7_OK;
20258   uint8_t saved_is_thrown = 0;
20259   val_t saved_thrown = v7_get_thrown_value(v7, &saved_is_thrown);
20260   char *ret = NULL;
20261 
20262   rcode = v7_stringify_throwing(v7, v, buf, size, mode, &ret);
20263   if (rcode != V7_OK) {
20264     rcode = V7_OK;
20265     if (saved_is_thrown) {
20266       rcode = v7_throw(v7, saved_thrown);
20267     } else {
20268       v7_clear_thrown_value(v7);
20269     }
20270 
20271     buf[0] = '\0';
20272     ret = buf;
20273   }
20274 
20275   return ret;
20276 }
20277 
20278 enum v7_err v7_stringify_throwing(struct v7 *v7, val_t v, char *buf,
20279                                   size_t size, enum v7_stringify_mode mode,
20280                                   char **res) {
20281   enum v7_err rcode = V7_OK;
20282   char *p = buf;
20283   size_t len;
20284 
20285   switch (mode) {
20286     case V7_STRINGIFY_DEFAULT:
20287       V7_TRY(to_string(v7, v, NULL, buf, size, &len));
20288       break;
20289 
20290     case V7_STRINGIFY_JSON:
20291       V7_TRY(to_json_or_debug(v7, v, buf, size, &len, 0));
20292       break;
20293 
20294     case V7_STRINGIFY_DEBUG:
20295       V7_TRY(to_json_or_debug(v7, v, buf, size, &len, 1));
20296       break;
20297   }
20298 
20299   /* fit null terminating byte */
20300   if (len >= size) {
20301     /* Buffer is not large enough. Allocate a bigger one */
20302     p = (char *) malloc(len + 1);
20303     V7_TRY(v7_stringify_throwing(v7, v, p, len + 1, mode, res));
20304     assert(*res == p);
20305     goto clean;
20306   } else {
20307     *res = p;
20308     goto clean;
20309   }
20310 
20311 clean:
20312   /*
20313    * If we're going to throw, and we allocated a buffer, then free it.
20314    * But if we don't throw, then the caller will free it.
20315    */
20316   if (rcode != V7_OK && p != buf) {
20317     free(p);
20318   }
20319   return rcode;
20320 }
20321 
20322 int v7_is_truthy(struct v7 *v7, val_t v) {
20323   return v7_get_bool(v7, to_boolean_v(v7, v));
20324 }
20325 #ifdef V7_MODULE_LINES
20326 #line 1 "v7/src/shdata.c"
20327 #endif
20328 /*
20329  * Copyright (c) 2014 Cesanta Software Limited
20330  * All rights reserved
20331  */
20332 
20333 /* Amalgamated: #include "v7/src/internal.h" */
20334 /* Amalgamated: #include "v7/src/shdata.h" */
20335 
20336 #if !defined(V7_DISABLE_FILENAMES) && !defined(V7_DISABLE_LINE_NUMBERS)
20337 V7_PRIVATE struct shdata *shdata_create(const void *payload, size_t size) {
20338   struct shdata *ret =
20339       (struct shdata *) calloc(1, sizeof(struct shdata) + size);
20340   shdata_retain(ret);
20341   if (payload != NULL) {
20342     memcpy((char *) shdata_get_payload(ret), (char *) payload, size);
20343   }
20344   return ret;
20345 }
20346 
20347 V7_PRIVATE struct shdata *shdata_create_from_string(const char *src) {
20348   return shdata_create(src, strlen(src) + 1 /*null-term*/);
20349 }
20350 
20351 V7_PRIVATE void shdata_retain(struct shdata *p) {
20352   p->refcnt++;
20353   assert(p->refcnt > 0);
20354 }
20355 
20356 V7_PRIVATE void shdata_release(struct shdata *p) {
20357   assert(p->refcnt > 0);
20358   p->refcnt--;
20359   if (p->refcnt == 0) {
20360     free(p);
20361   }
20362 }
20363 
20364 V7_PRIVATE void *shdata_get_payload(struct shdata *p) {
20365   return (char *) p + sizeof(*p);
20366 }
20367 #endif
20368 #ifdef V7_MODULE_LINES
20369 #line 1 "v7/src/gc.c"
20370 #endif
20371 /*
20372  * Copyright (c) 2014 Cesanta Software Limited
20373  * All rights reserved
20374  */
20375 
20376 /* Amalgamated: #include "v7/src/internal.h" */
20377 /* Amalgamated: #include "v7/src/bcode.h" */
20378 /* Amalgamated: #include "v7/src/varint.h" */
20379 /* Amalgamated: #include "v7/src/gc.h" */
20380 /* Amalgamated: #include "v7/src/freeze.h" */
20381 /* Amalgamated: #include "v7/src/core.h" */
20382 /* Amalgamated: #include "v7/src/function.h" */
20383 /* Amalgamated: #include "v7/src/primitive.h" */
20384 /* Amalgamated: #include "v7/src/object.h" */
20385 /* Amalgamated: #include "v7/src/string.h" */
20386 /* Amalgamated: #include "v7/src/util.h" */
20387 /* Amalgamated: #include "v7/src/primitive.h" */
20388 /* Amalgamated: #include "v7/src/heapusage.h" */
20389 
20390 #include <stdio.h>
20391 
20392 #ifdef V7_STACK_GUARD_MIN_SIZE
20393 void *v7_sp_limit = NULL;
20394 #endif
20395 
20396 void gc_mark_string(struct v7 *, val_t *);
20397 
20398 static struct gc_block *gc_new_block(struct gc_arena *a, size_t size);
20399 static void gc_free_block(struct gc_block *b);
20400 static void gc_mark_mbuf_pt(struct v7 *v7, const struct mbuf *mbuf);
20401 static void gc_mark_mbuf_val(struct v7 *v7, const struct mbuf *mbuf);
20402 static void gc_mark_vec_val(struct v7 *v7, const struct v7_vec *vec);
20403 
20404 V7_PRIVATE struct v7_generic_object *new_generic_object(struct v7 *v7) {
20405   return (struct v7_generic_object *) gc_alloc_cell(v7,
20406                                                     &v7->generic_object_arena);
20407 }
20408 
20409 V7_PRIVATE struct v7_property *new_property(struct v7 *v7) {
20410   return (struct v7_property *) gc_alloc_cell(v7, &v7->property_arena);
20411 }
20412 
20413 V7_PRIVATE struct v7_js_function *new_function(struct v7 *v7) {
20414   return (struct v7_js_function *) gc_alloc_cell(v7, &v7->function_arena);
20415 }
20416 
20417 V7_PRIVATE struct gc_tmp_frame new_tmp_frame(struct v7 *v7) {
20418   struct gc_tmp_frame frame;
20419   frame.v7 = v7;
20420   frame.pos = v7->tmp_stack.len;
20421   return frame;
20422 }
20423 
20424 V7_PRIVATE void tmp_frame_cleanup(struct gc_tmp_frame *tf) {
20425   tf->v7->tmp_stack.len = tf->pos;
20426 }
20427 
20428 /*
20429  * TODO(mkm): perhaps it's safer to keep val_t in the temporary
20430  * roots stack, instead of keeping val_t*, in order to be better
20431  * able to debug the relocating GC.
20432  */
20433 V7_PRIVATE void tmp_stack_push(struct gc_tmp_frame *tf, val_t *vp) {
20434   mbuf_append(&tf->v7->tmp_stack, (char *) &vp, sizeof(val_t *));
20435 }
20436 
20437 /* Initializes a new arena. */
20438 V7_PRIVATE void gc_arena_init(struct gc_arena *a, size_t cell_size,
20439                               size_t initial_size, size_t size_increment,
20440                               const char *name) {
20441   assert(cell_size >= sizeof(uintptr_t));
20442 
20443   memset(a, 0, sizeof(*a));
20444   a->cell_size = cell_size;
20445   a->name = name;
20446   a->size_increment = size_increment;
20447   a->blocks = gc_new_block(a, initial_size);
20448 }
20449 
20450 V7_PRIVATE void gc_arena_destroy(struct v7 *v7, struct gc_arena *a) {
20451   struct gc_block *b;
20452 
20453   if (a->blocks != NULL) {
20454     gc_sweep(v7, a, 0);
20455     for (b = a->blocks; b != NULL;) {
20456       struct gc_block *tmp;
20457       tmp = b;
20458       b = b->next;
20459       gc_free_block(tmp);
20460     }
20461   }
20462 }
20463 
20464 static void gc_free_block(struct gc_block *b) {
20465   free(b->base);
20466   free(b);
20467 }
20468 
20469 static struct gc_block *gc_new_block(struct gc_arena *a, size_t size) {
20470   struct gc_cell *cur;
20471   struct gc_block *b;
20472 
20473   heapusage_dont_count(1);
20474   b = (struct gc_block *) calloc(1, sizeof(*b));
20475   heapusage_dont_count(0);
20476   if (b == NULL) abort();
20477 
20478   b->size = size;
20479   heapusage_dont_count(1);
20480   b->base = (struct gc_cell *) calloc(a->cell_size, b->size);
20481   heapusage_dont_count(0);
20482   if (b->base == NULL) abort();
20483 
20484   for (cur = GC_CELL_OP(a, b->base, +, 0);
20485        cur < GC_CELL_OP(a, b->base, +, b->size);
20486        cur = GC_CELL_OP(a, cur, +, 1)) {
20487     cur->head.link = a->free;
20488     a->free = cur;
20489   }
20490 
20491   return b;
20492 }
20493 
20494 V7_PRIVATE void *gc_alloc_cell(struct v7 *v7, struct gc_arena *a) {
20495 #if V7_MALLOC_GC
20496   struct gc_cell *r;
20497   maybe_gc(v7);
20498   heapusage_dont_count(1);
20499   r = (struct gc_cell *) calloc(1, a->cell_size);
20500   heapusage_dont_count(0);
20501   mbuf_append(&v7->malloc_trace, &r, sizeof(r));
20502   return r;
20503 #else
20504   struct gc_cell *r;
20505   if (a->free == NULL) {
20506     if (!maybe_gc(v7)) {
20507       /* GC is inhibited, so, schedule invocation for later */
20508       v7->need_gc = 1;
20509     }
20510 
20511     if (a->free == NULL) {
20512       struct gc_block *b = gc_new_block(a, a->size_increment);
20513       b->next = a->blocks;
20514       a->blocks = b;
20515     }
20516   }
20517   r = a->free;
20518 
20519   UNMARK(r);
20520 
20521   a->free = r->head.link;
20522 
20523 #if V7_ENABLE__Memory__stats
20524   a->allocations++;
20525   a->alive++;
20526 #endif
20527 
20528   /*
20529    * TODO(mkm): minor opt possible since most of the fields
20530    * are overwritten downstream, but not worth the yak shave time
20531    * when fields are added to GC-able structures */
20532   memset(r, 0, a->cell_size);
20533   return (void *) r;
20534 #endif
20535 }
20536 
20537 #ifdef V7_MALLOC_GC
20538 /*
20539  * Scans trough the memory blocks registered in the malloc trace.
20540  * Free the unmarked ones and reset the mark on the rest.
20541  */
20542 void gc_sweep_malloc(struct v7 *v7) {
20543   struct gc_cell **cur;
20544   for (cur = (struct gc_cell **) v7->malloc_trace.buf;
20545        cur < (struct gc_cell **) (v7->malloc_trace.buf + v7->malloc_trace.len);
20546        cur++) {
20547     if (*cur == NULL) continue;
20548 
20549     if (MARKED(*cur)) {
20550       UNMARK(*cur);
20551     } else {
20552       free(*cur);
20553       /* TODO(mkm): compact malloc trace buffer */
20554       *cur = NULL;
20555     }
20556   }
20557 }
20558 #endif
20559 
20560 /*
20561  * Scans the arena and add all unmarked cells to the free list.
20562  *
20563  * Empty blocks get deallocated. The head of the free list will contais cells
20564  * from the last (oldest) block. Cells will thus be allocated in block order.
20565  */
20566 void gc_sweep(struct v7 *v7, struct gc_arena *a, size_t start) {
20567   struct gc_block *b;
20568   struct gc_cell *cur;
20569   struct gc_block **prevp = &a->blocks;
20570 #if V7_ENABLE__Memory__stats
20571   a->alive = 0;
20572 #endif
20573 
20574   /*
20575    * Before we sweep, we should mark all free cells in a way that is
20576    * distinguishable from marked used cells.
20577    */
20578   {
20579     struct gc_cell *next;
20580     for (cur = a->free; cur != NULL; cur = next) {
20581       next = cur->head.link;
20582       MARK_FREE(cur);
20583     }
20584   }
20585 
20586   /*
20587    * We'll rebuild the whole `free` list, so initially we just reset it
20588    */
20589   a->free = NULL;
20590 
20591   for (b = a->blocks; b != NULL;) {
20592     size_t freed_in_block = 0;
20593     /*
20594      * if it turns out that this block is 100% garbage
20595      * we can release the whole block, but the addition
20596      * of it's cells to the free list has to be undone.
20597      */
20598     struct gc_cell *prev_free = a->free;
20599 
20600     for (cur = GC_CELL_OP(a, b->base, +, start);
20601          cur < GC_CELL_OP(a, b->base, +, b->size);
20602          cur = GC_CELL_OP(a, cur, +, 1)) {
20603       if (MARKED(cur)) {
20604         /* The cell is used and marked  */
20605         UNMARK(cur);
20606 #if V7_ENABLE__Memory__stats
20607         a->alive++;
20608 #endif
20609       } else {
20610         /*
20611          * The cell is either:
20612          * - free
20613          * - garbage that's about to be freed
20614          */
20615 
20616         if (MARKED_FREE(cur)) {
20617           /* The cell is free, so, just unmark it */
20618           UNMARK_FREE(cur);
20619         } else {
20620           /*
20621            * The cell is used and should be freed: call the destructor and
20622            * reset the memory
20623            */
20624           if (a->destructor != NULL) {
20625             a->destructor(v7, cur);
20626           }
20627           memset(cur, 0, a->cell_size);
20628         }
20629 
20630         /* Add this cell to the `free` list */
20631         cur->head.link = a->free;
20632         a->free = cur;
20633         freed_in_block++;
20634 #if V7_ENABLE__Memory__stats
20635         a->garbage++;
20636 #endif
20637       }
20638     }
20639 
20640     /*
20641      * don't free the initial block, which is at the tail
20642      * because it has a special size aimed at reducing waste
20643      * and simplifying initial startup. TODO(mkm): improve
20644      * */
20645     if (b->next != NULL && freed_in_block == b->size) {
20646       *prevp = b->next;
20647       gc_free_block(b);
20648       b = *prevp;
20649       a->free = prev_free;
20650     } else {
20651       prevp = &b->next;
20652       b = b->next;
20653     }
20654   }
20655 }
20656 
20657 /*
20658  * dense arrays contain only one property pointing to an mbuf with array values.
20659  */
20660 V7_PRIVATE void gc_mark_dense_array(struct v7 *v7,
20661                                     struct v7_generic_object *obj) {
20662   val_t v;
20663   struct mbuf *mbuf;
20664   val_t *vp;
20665 
20666 #if 0
20667   /* TODO(mkm): use this when dense array promotion is implemented */
20668   v = obj->properties->value;
20669 #else
20670   v = v7_get(v7, v7_object_to_value(&obj->base), "", 0);
20671 #endif
20672 
20673   mbuf = (struct mbuf *) v7_get_ptr(v7, v);
20674 
20675   /* function scope pointer is aliased to the object's prototype pointer */
20676   gc_mark(v7, v7_object_to_value(obj_prototype(v7, &obj->base)));
20677   MARK(obj);
20678 
20679   if (mbuf == NULL) return;
20680   for (vp = (val_t *) mbuf->buf; (char *) vp < mbuf->buf + mbuf->len; vp++) {
20681     gc_mark(v7, *vp);
20682     gc_mark_string(v7, vp);
20683   }
20684   UNMARK(obj);
20685 }
20686 
20687 V7_PRIVATE void gc_mark(struct v7 *v7, val_t v) {
20688   struct v7_object *obj_base;
20689   struct v7_property *prop;
20690   struct v7_property *next;
20691 
20692   if (!v7_is_object(v)) {
20693     return;
20694   }
20695   obj_base = get_object_struct(v);
20696 
20697   /*
20698    * we ignore objects that are not managed by V7 heap, such as frozen
20699    * objects, especially when on flash.
20700    */
20701   if (obj_base->attributes & V7_OBJ_OFF_HEAP) {
20702     return;
20703   }
20704 
20705   /*
20706    * we treat all object like things like objects but they might be functions,
20707    * gc_gheck_val checks the appropriate arena per actual value type.
20708    */
20709   if (!gc_check_val(v7, v)) {
20710     abort();
20711   }
20712 
20713   if (MARKED(obj_base)) return;
20714 
20715 #ifdef V7_FREEZE
20716   if (v7->freeze_file != NULL) {
20717     freeze_obj(v7, v7->freeze_file, v);
20718   }
20719 #endif
20720 
20721   if (obj_base->attributes & V7_OBJ_DENSE_ARRAY) {
20722     struct v7_generic_object *obj = get_generic_object_struct(v);
20723     gc_mark_dense_array(v7, obj);
20724   }
20725 
20726   /* mark object itself, and its properties */
20727   for ((prop = obj_base->properties), MARK(obj_base); prop != NULL;
20728        prop = next) {
20729     if (prop->attributes & _V7_PROPERTY_OFF_HEAP) {
20730       break;
20731     }
20732 
20733     if (!gc_check_ptr(&v7->property_arena, prop)) {
20734       abort();
20735     }
20736 
20737 #ifdef V7_FREEZE
20738     if (v7->freeze_file != NULL) {
20739       freeze_prop(v7, v7->freeze_file, prop);
20740     }
20741 #endif
20742 
20743     gc_mark_string(v7, &prop->value);
20744     gc_mark_string(v7, &prop->name);
20745     gc_mark(v7, prop->value);
20746 
20747     next = prop->next;
20748     MARK(prop);
20749   }
20750 
20751   /* mark object's prototype */
20752   gc_mark(v7, v7_get_proto(v7, v));
20753 
20754   if (is_js_function(v)) {
20755     struct v7_js_function *func = get_js_function_struct(v);
20756 
20757     /* mark function's scope */
20758     gc_mark(v7, v7_object_to_value(&func->scope->base));
20759 
20760     if (func->bcode != NULL) {
20761       gc_mark_vec_val(v7, &func->bcode->lit);
20762     }
20763   }
20764 }
20765 
20766 #if V7_ENABLE__Memory__stats
20767 
20768 V7_PRIVATE size_t gc_arena_size(struct gc_arena *a) {
20769   size_t size = 0;
20770   struct gc_block *b;
20771   for (b = a->blocks; b != NULL; b = b->next) {
20772     size += b->size;
20773   }
20774   return size;
20775 }
20776 
20777 /*
20778  * TODO(dfrank): move to core
20779  */
20780 int v7_heap_stat(struct v7 *v7, enum v7_heap_stat_what what) {
20781   switch (what) {
20782     case V7_HEAP_STAT_HEAP_SIZE:
20783       return gc_arena_size(&v7->generic_object_arena) *
20784                  v7->generic_object_arena.cell_size +
20785              gc_arena_size(&v7->function_arena) * v7->function_arena.cell_size +
20786              gc_arena_size(&v7->property_arena) * v7->property_arena.cell_size;
20787     case V7_HEAP_STAT_HEAP_USED:
20788       return v7->generic_object_arena.alive *
20789                  v7->generic_object_arena.cell_size +
20790              v7->function_arena.alive * v7->function_arena.cell_size +
20791              v7->property_arena.alive * v7->property_arena.cell_size;
20792     case V7_HEAP_STAT_STRING_HEAP_RESERVED:
20793       return v7->owned_strings.size;
20794     case V7_HEAP_STAT_STRING_HEAP_USED:
20795       return v7->owned_strings.len;
20796     case V7_HEAP_STAT_OBJ_HEAP_MAX:
20797       return gc_arena_size(&v7->generic_object_arena);
20798     case V7_HEAP_STAT_OBJ_HEAP_FREE:
20799       return gc_arena_size(&v7->generic_object_arena) -
20800              v7->generic_object_arena.alive;
20801     case V7_HEAP_STAT_OBJ_HEAP_CELL_SIZE:
20802       return v7->generic_object_arena.cell_size;
20803     case V7_HEAP_STAT_FUNC_HEAP_MAX:
20804       return gc_arena_size(&v7->function_arena);
20805     case V7_HEAP_STAT_FUNC_HEAP_FREE:
20806       return gc_arena_size(&v7->function_arena) - v7->function_arena.alive;
20807     case V7_HEAP_STAT_FUNC_HEAP_CELL_SIZE:
20808       return v7->function_arena.cell_size;
20809     case V7_HEAP_STAT_PROP_HEAP_MAX:
20810       return gc_arena_size(&v7->property_arena);
20811     case V7_HEAP_STAT_PROP_HEAP_FREE:
20812       return gc_arena_size(&v7->property_arena) - v7->property_arena.alive;
20813     case V7_HEAP_STAT_PROP_HEAP_CELL_SIZE:
20814       return v7->property_arena.cell_size;
20815     case V7_HEAP_STAT_FUNC_AST_SIZE:
20816       return v7->function_arena_ast_size;
20817     case V7_HEAP_STAT_BCODE_OPS_SIZE:
20818       return v7->bcode_ops_size;
20819     case V7_HEAP_STAT_BCODE_LIT_TOTAL_SIZE:
20820       return v7->bcode_lit_total_size;
20821     case V7_HEAP_STAT_BCODE_LIT_DESER_SIZE:
20822       return v7->bcode_lit_deser_size;
20823     case V7_HEAP_STAT_FUNC_OWNED:
20824       return v7->owned_values.len / sizeof(val_t *);
20825     case V7_HEAP_STAT_FUNC_OWNED_MAX:
20826       return v7->owned_values.size / sizeof(val_t *);
20827   }
20828 
20829   return -1;
20830 }
20831 #endif
20832 
20833 V7_PRIVATE void gc_dump_arena_stats(const char *msg, struct gc_arena *a) {
20834   (void) msg;
20835   (void) a;
20836 #ifndef NO_LIBC
20837 #if V7_ENABLE__Memory__stats
20838   if (a->verbose) {
20839     fprintf(stderr, "%s: total allocations %lu, max %lu, alive %lu\n", msg,
20840             (long unsigned int) a->allocations,
20841             (long unsigned int) gc_arena_size(a), (long unsigned int) a->alive);
20842   }
20843 #endif
20844 #endif
20845 }
20846 
20847 V7_PRIVATE uint64_t gc_string_val_to_offset(val_t v) {
20848   return (((uint64_t)(uintptr_t) get_ptr(v)) & ~V7_TAG_MASK)
20849 #ifndef V7_DISABLE_STR_ALLOC_SEQ
20850          & 0xFFFFFFFF
20851 #endif
20852       ;
20853 }
20854 
20855 V7_PRIVATE val_t gc_string_val_from_offset(uint64_t s) {
20856   return s | V7_TAG_STRING_O;
20857 }
20858 
20859 #ifndef V7_DISABLE_STR_ALLOC_SEQ
20860 
20861 static uint16_t next_asn(struct v7 *v7) {
20862   if (v7->gc_next_asn == 0xFFFF) {
20863     /* Wrap around explicitly. */
20864     v7->gc_next_asn = 0;
20865     return 0xFFFF;
20866   }
20867   return v7->gc_next_asn++;
20868 }
20869 
20870 uint16_t gc_next_allocation_seqn(struct v7 *v7, const char *str, size_t len) {
20871   uint16_t asn = next_asn(v7);
20872   (void) str;
20873   (void) len;
20874 #ifdef V7_GC_VERBOSE
20875   /*
20876    * ESP SDK printf cannot cope with null strings
20877    * as created by s_concat.
20878    */
20879   if (str == NULL) {
20880     fprintf(stderr, "GC ASN %d: <nil>\n", asn);
20881   } else {
20882     fprintf(stderr, "GC ASN %d: \"%.*s\"\n", asn, (int) len, str);
20883   }
20884 #endif
20885 #ifdef V7_GC_PANIC_ON_ASN
20886   if (asn == (V7_GC_PANIC_ON_ASN)) {
20887     abort();
20888   }
20889 #endif
20890   return asn;
20891 }
20892 
20893 int gc_is_valid_allocation_seqn(struct v7 *v7, uint16_t n) {
20894   /*
20895    * This functions attempts to handle integer wraparound in a naive way and
20896    * will give false positives when more than 65536 strings are allocated
20897    * between GC runs.
20898    */
20899   int r = (n >= v7->gc_min_asn && n < v7->gc_next_asn) ||
20900           (v7->gc_min_asn > v7->gc_next_asn &&
20901            (n >= v7->gc_min_asn || n < v7->gc_next_asn));
20902   if (!r) {
20903     fprintf(stderr, "GC ASN %d is not in [%d,%d)\n", n, v7->gc_min_asn,
20904             v7->gc_next_asn);
20905   }
20906   return r;
20907 }
20908 
20909 void gc_check_valid_allocation_seqn(struct v7 *v7, uint16_t n) {
20910   if (!gc_is_valid_allocation_seqn(v7, n)) {
20911 /*
20912  * TODO(dfrank) throw exception if V7_GC_ASN_PANIC is not defined.
20913  */
20914 #if 0 && !defined(V7_GC_ASN_PANIC)
20915     throw_exception(v7, INTERNAL_ERROR, "Invalid ASN: %d", (int) n);
20916 #else
20917     fprintf(stderr, "Invalid ASN: %d\n", (int) n);
20918     abort();
20919 #endif
20920   }
20921 }
20922 
20923 #endif /* V7_DISABLE_STR_ALLOC_SEQ */
20924 
20925 /* Mark a string value */
20926 void gc_mark_string(struct v7 *v7, val_t *v) {
20927   val_t h, tmp = 0;
20928   char *s;
20929 
20930   /* clang-format off */
20931 
20932   /*
20933    * If a value points to an unmarked string we shall:
20934    *  1. save the first 6 bytes of the string
20935    *     since we need to be able to distinguish real values from
20936    *     the saved first 6 bytes of the string, we need to tag the chunk
20937    *     as V7_TAG_STRING_C
20938    *  2. encode value's address (v) into the first 6 bytes of the string.
20939    *  3. put the saved 8 bytes (tag + chunk) back into the value.
20940    *  4. mark the string by putting '\1' in the NUL terminator of the previous
20941    *     string chunk.
20942    *
20943    * If a value points to an already marked string we shall:
20944    *     (0, <6 bytes of a pointer to a val_t>), hence we have to skip
20945    *     the first byte. We tag the value pointer as a V7_TAG_FOREIGN
20946    *     so that it won't be followed during recursive mark.
20947    *
20948    *  ... the rest is the same
20949    *
20950    *  Note: 64-bit pointers can be represented with 48-bits
20951    */
20952 
20953   /* clang-format on */
20954 
20955   if ((*v & V7_TAG_MASK) != V7_TAG_STRING_O) {
20956     return;
20957   }
20958 
20959 #ifdef V7_FREEZE
20960   if (v7->freeze_file != NULL) {
20961     return;
20962   }
20963 #endif
20964 
20965 #ifdef V7_GC_VERBOSE
20966   {
20967     uint16_t asn = (*v >> 32) & 0xFFFF;
20968     size_t size;
20969     fprintf(stderr, "GC marking ASN %d: '%s'\n", asn,
20970             v7_get_string(v7, v, &size));
20971   }
20972 #endif
20973 
20974 #ifndef V7_DISABLE_STR_ALLOC_SEQ
20975   gc_check_valid_allocation_seqn(v7, (*v >> 32) & 0xFFFF);
20976 #endif
20977 
20978   s = v7->owned_strings.buf + gc_string_val_to_offset(*v);
20979   assert(s < v7->owned_strings.buf + v7->owned_strings.len);
20980   if (s[-1] == '\0') {
20981     memcpy(&tmp, s, sizeof(tmp) - 2);
20982     tmp |= V7_TAG_STRING_C;
20983   } else {
20984     memcpy(&tmp, s, sizeof(tmp) - 2);
20985     tmp |= V7_TAG_FOREIGN;
20986   }
20987 
20988   h = (val_t)(uintptr_t) v;
20989   s[-1] = 1;
20990   memcpy(s, &h, sizeof(h) - 2);
20991   memcpy(v, &tmp, sizeof(tmp));
20992 }
20993 
20994 void gc_compact_strings(struct v7 *v7) {
20995   char *p = v7->owned_strings.buf + 1;
20996   uint64_t h, next, head = 1;
20997   int len, llen;
20998 
20999 #ifndef V7_DISABLE_STR_ALLOC_SEQ
21000   v7->gc_min_asn = v7->gc_next_asn;
21001 #endif
21002   while (p < v7->owned_strings.buf + v7->owned_strings.len) {
21003     if (p[-1] == '\1') {
21004 #ifndef V7_DISABLE_STR_ALLOC_SEQ
21005       /* Not using gc_next_allocation_seqn() as we don't have full string. */
21006       uint16_t asn = next_asn(v7);
21007 #endif
21008       /* relocate and update ptrs */
21009       h = 0;
21010       memcpy(&h, p, sizeof(h) - 2);
21011 
21012       /*
21013        * relocate pointers until we find the tail.
21014        * The tail is marked with V7_TAG_STRING_C,
21015        * while val_t link pointers are tagged with V7_TAG_FOREIGN
21016        */
21017       for (; (h & V7_TAG_MASK) != V7_TAG_STRING_C; h = next) {
21018         h &= ~V7_TAG_MASK;
21019         memcpy(&next, (char *) (uintptr_t) h, sizeof(h));
21020 
21021         *(val_t *) (uintptr_t) h = gc_string_val_from_offset(head)
21022 #ifndef V7_DISABLE_STR_ALLOC_SEQ
21023                                    | ((val_t) asn << 32)
21024 #endif
21025             ;
21026       }
21027       h &= ~V7_TAG_MASK;
21028 
21029       /*
21030        * the tail contains the first 6 bytes we stole from
21031        * the actual string.
21032        */
21033       len = decode_varint((unsigned char *) &h, &llen);
21034       len += llen + 1;
21035 
21036       /*
21037        * restore the saved 6 bytes
21038        * TODO(mkm): think about endianness
21039        */
21040       memcpy(p, &h, sizeof(h) - 2);
21041 
21042       /*
21043        * and relocate the string data by packing it to the left.
21044        */
21045       memmove(v7->owned_strings.buf + head, p, len);
21046       v7->owned_strings.buf[head - 1] = 0x0;
21047 #if defined(V7_GC_VERBOSE) && !defined(V7_DISABLE_STR_ALLOC_SEQ)
21048       fprintf(stderr, "GC updated ASN %d: \"%.*s\"\n", asn, len - llen - 1,
21049               v7->owned_strings.buf + head + llen);
21050 #endif
21051       p += len;
21052       head += len;
21053     } else {
21054       len = decode_varint((unsigned char *) p, &llen);
21055       len += llen + 1;
21056 
21057       p += len;
21058     }
21059   }
21060 
21061 #if defined(V7_GC_VERBOSE) && !defined(V7_DISABLE_STR_ALLOC_SEQ)
21062   fprintf(stderr, "GC valid ASN range: [%d,%d)\n", v7->gc_min_asn,
21063           v7->gc_next_asn);
21064 #endif
21065 
21066   v7->owned_strings.len = head;
21067 }
21068 
21069 void gc_dump_owned_strings(struct v7 *v7) {
21070   size_t i;
21071   for (i = 0; i < v7->owned_strings.len; i++) {
21072     if (isprint((unsigned char) v7->owned_strings.buf[i])) {
21073       fputc(v7->owned_strings.buf[i], stderr);
21074     } else {
21075       fputc('.', stderr);
21076     }
21077   }
21078   fputc('\n', stderr);
21079 }
21080 
21081 /*
21082  * builting on gcc, tried out by redefining it.
21083  * Using null pointer as base can trigger undefined behavior, hence
21084  * a portable workaround that involves a valid yet dummy pointer.
21085  * It's meant to be used as a contant expression.
21086  */
21087 #ifndef offsetof
21088 #define offsetof(st, m) (((ptrdiff_t)(&((st *) 32)->m)) - 32)
21089 #endif
21090 
21091 V7_PRIVATE void compute_need_gc(struct v7 *v7) {
21092   struct mbuf *m = &v7->owned_strings;
21093   if ((double) m->len / (double) m->size > 0.9) {
21094     v7->need_gc = 1;
21095   }
21096   /* TODO(mkm): check free heap */
21097 }
21098 
21099 V7_PRIVATE int maybe_gc(struct v7 *v7) {
21100   if (!v7->inhibit_gc) {
21101     v7_gc(v7, 0);
21102     return 1;
21103   }
21104   return 0;
21105 }
21106 #if defined(V7_GC_VERBOSE)
21107 static int gc_pass = 0;
21108 #endif
21109 
21110 /*
21111  * mark an array of `val_t` values (*not pointers* to them)
21112  */
21113 static void gc_mark_val_array(struct v7 *v7, val_t *vals, size_t len) {
21114   val_t *vp;
21115   for (vp = vals; vp < vals + len; vp++) {
21116     gc_mark(v7, *vp);
21117     gc_mark_string(v7, vp);
21118   }
21119 }
21120 
21121 /*
21122  * mark an mbuf containing *pointers* to `val_t` values
21123  */
21124 static void gc_mark_mbuf_pt(struct v7 *v7, const struct mbuf *mbuf) {
21125   val_t **vp;
21126   for (vp = (val_t **) mbuf->buf; (char *) vp < mbuf->buf + mbuf->len; vp++) {
21127     gc_mark(v7, **vp);
21128     gc_mark_string(v7, *vp);
21129   }
21130 }
21131 
21132 /*
21133  * mark an mbuf containing `val_t` values (*not pointers* to them)
21134  */
21135 static void gc_mark_mbuf_val(struct v7 *v7, const struct mbuf *mbuf) {
21136   gc_mark_val_array(v7, (val_t *) mbuf->buf, mbuf->len / sizeof(val_t));
21137 }
21138 
21139 /*
21140  * mark a vector containing `val_t` values (*not pointers* to them)
21141  */
21142 static void gc_mark_vec_val(struct v7 *v7, const struct v7_vec *vec) {
21143   gc_mark_val_array(v7, (val_t *) vec->p, vec->len / sizeof(val_t));
21144 }
21145 
21146 /*
21147  * mark an mbuf containing foreign pointers to `struct bcode`
21148  */
21149 static void gc_mark_mbuf_bcode_pt(struct v7 *v7, const struct mbuf *mbuf) {
21150   struct bcode **vp;
21151   for (vp = (struct bcode **) mbuf->buf; (char *) vp < mbuf->buf + mbuf->len;
21152        vp++) {
21153     gc_mark_vec_val(v7, &(*vp)->lit);
21154   }
21155 }
21156 
21157 static void gc_mark_call_stack_private(
21158     struct v7 *v7, struct v7_call_frame_private *call_stack) {
21159   gc_mark_val_array(v7, (val_t *) &call_stack->vals,
21160                     sizeof(call_stack->vals) / sizeof(val_t));
21161 }
21162 
21163 static void gc_mark_call_stack_cfunc(struct v7 *v7,
21164                                      struct v7_call_frame_cfunc *call_stack) {
21165   gc_mark_val_array(v7, (val_t *) &call_stack->vals,
21166                     sizeof(call_stack->vals) / sizeof(val_t));
21167 }
21168 
21169 static void gc_mark_call_stack_bcode(struct v7 *v7,
21170                                      struct v7_call_frame_bcode *call_stack) {
21171   gc_mark_val_array(v7, (val_t *) &call_stack->vals,
21172                     sizeof(call_stack->vals) / sizeof(val_t));
21173 }
21174 
21175 /*
21176  * mark `struct v7_call_frame` and all its back-linked frames
21177  */
21178 static void gc_mark_call_stack(struct v7 *v7,
21179                                struct v7_call_frame_base *call_stack) {
21180   while (call_stack != NULL) {
21181     if (call_stack->type_mask & V7_CALL_FRAME_MASK_BCODE) {
21182       gc_mark_call_stack_bcode(v7, (struct v7_call_frame_bcode *) call_stack);
21183     }
21184 
21185     if (call_stack->type_mask & V7_CALL_FRAME_MASK_PRIVATE) {
21186       gc_mark_call_stack_private(v7,
21187                                  (struct v7_call_frame_private *) call_stack);
21188     }
21189 
21190     if (call_stack->type_mask & V7_CALL_FRAME_MASK_CFUNC) {
21191       gc_mark_call_stack_cfunc(v7, (struct v7_call_frame_cfunc *) call_stack);
21192     }
21193 
21194     call_stack = call_stack->prev;
21195   }
21196 }
21197 
21198 /* Perform garbage collection */
21199 void v7_gc(struct v7 *v7, int full) {
21200 #ifdef V7_DISABLE_GC
21201   (void) v7;
21202   (void) full;
21203   return;
21204 #else
21205 
21206 #if defined(V7_GC_VERBOSE)
21207   fprintf(stderr, "V7 GC pass %d\n", ++gc_pass);
21208 #endif
21209 
21210   gc_dump_arena_stats("Before GC objects", &v7->generic_object_arena);
21211   gc_dump_arena_stats("Before GC functions", &v7->function_arena);
21212   gc_dump_arena_stats("Before GC properties", &v7->property_arena);
21213 
21214   gc_mark_call_stack(v7, v7->call_stack);
21215 
21216   gc_mark_val_array(v7, (val_t *) &v7->vals, sizeof(v7->vals) / sizeof(val_t));
21217   /* mark all items on bcode stack */
21218   gc_mark_mbuf_val(v7, &v7->stack);
21219 
21220   /* mark literals and names of all the active bcodes */
21221   gc_mark_mbuf_bcode_pt(v7, &v7->act_bcodes);
21222 
21223   gc_mark_mbuf_pt(v7, &v7->tmp_stack);
21224   gc_mark_mbuf_pt(v7, &v7->owned_values);
21225 
21226   gc_compact_strings(v7);
21227 
21228 #ifdef V7_MALLOC_GC
21229   gc_sweep_malloc(v7);
21230 #else
21231   gc_sweep(v7, &v7->generic_object_arena, 0);
21232   gc_sweep(v7, &v7->function_arena, 0);
21233   gc_sweep(v7, &v7->property_arena, 0);
21234 #endif
21235 
21236   gc_dump_arena_stats("After GC objects", &v7->generic_object_arena);
21237   gc_dump_arena_stats("After GC functions", &v7->function_arena);
21238   gc_dump_arena_stats("After GC properties", &v7->property_arena);
21239 
21240   if (full) {
21241     /*
21242      * In case of full GC, we also resize strings buffer, but we still leave
21243      * some extra space (at most, `_V7_STRING_BUF_RESERVE`) in order to avoid
21244      * frequent reallocations
21245      */
21246     size_t trimmed_size = v7->owned_strings.len + _V7_STRING_BUF_RESERVE;
21247     if (trimmed_size < v7->owned_strings.size) {
21248       heapusage_dont_count(1);
21249       mbuf_resize(&v7->owned_strings, trimmed_size);
21250       heapusage_dont_count(0);
21251     }
21252   }
21253 #endif /* V7_DISABLE_GC */
21254 }
21255 
21256 V7_PRIVATE int gc_check_val(struct v7 *v7, val_t v) {
21257   if (is_js_function(v)) {
21258     return gc_check_ptr(&v7->function_arena, get_js_function_struct(v));
21259   } else if (v7_is_object(v)) {
21260     return gc_check_ptr(&v7->generic_object_arena, get_object_struct(v));
21261   }
21262   return 1;
21263 }
21264 
21265 V7_PRIVATE int gc_check_ptr(const struct gc_arena *a, const void *ptr) {
21266 #ifdef V7_MALLOC_GC
21267   (void) a;
21268   (void) ptr;
21269   return 1;
21270 #else
21271   const struct gc_cell *p = (const struct gc_cell *) ptr;
21272   struct gc_block *b;
21273   for (b = a->blocks; b != NULL; b = b->next) {
21274     if (p >= b->base && p < GC_CELL_OP(a, b->base, +, b->size)) {
21275       return 1;
21276     }
21277   }
21278   return 0;
21279 #endif
21280 }
21281 #ifdef V7_MODULE_LINES
21282 #line 1 "v7/src/freeze.c"
21283 #endif
21284 /*
21285  * Copyright (c) 2014 Cesanta Software Limited
21286  * All rights reserved
21287  */
21288 
21289 /* Amalgamated: #include "v7/src/core.h" */
21290 /* Amalgamated: #include "v7/src/function.h" */
21291 /* Amalgamated: #include "v7/src/util.h" */
21292 /* Amalgamated: #include "v7/src/freeze.h" */
21293 /* Amalgamated: #include "v7/src/bcode.h" */
21294 /* Amalgamated: #include "v7/src/gc.h" */
21295 /* Amalgamated: #include "common/base64.h" */
21296 /* Amalgamated: #include "v7/src/object.h" */
21297 
21298 #include <stdio.h>
21299 
21300 #ifdef V7_FREEZE
21301 
21302 V7_PRIVATE void freeze(struct v7 *v7, char *filename) {
21303   size_t i;
21304 
21305   v7->freeze_file = fopen(filename, "w");
21306   assert(v7->freeze_file != NULL);
21307 
21308 #ifndef V7_FREEZE_NOT_READONLY
21309   /*
21310    * We have to remove `global` from the global object since
21311    * when thawing global will actually be a new mutable object
21312    * living on the heap.
21313    */
21314   v7_del(v7, v7->vals.global_object, "global", 6);
21315 #endif
21316 
21317   for (i = 0; i < sizeof(v7->vals) / sizeof(val_t); i++) {
21318     val_t v = ((val_t *) &v7->vals)[i];
21319     fprintf(v7->freeze_file,
21320             "{\"type\":\"global\", \"idx\":%zu, \"value\":\"%p\"}\n", i,
21321             (void *) (v7_is_object(v) ? get_object_struct(v) : 0x0));
21322   }
21323 
21324   /*
21325    * since v7->freeze_file is not NULL this will cause freeze_obj and
21326    * freeze_prop to be called for each reachable object and property.
21327    */
21328   v7_gc(v7, 1);
21329   assert(v7->stack.len == 0);
21330 
21331   fclose(v7->freeze_file);
21332   v7->freeze_file = NULL;
21333 }
21334 
21335 static char *freeze_vec(struct v7_vec *vec) {
21336   char *res = (char *) malloc(512 + vec->len);
21337   res[0] = '"';
21338   cs_base64_encode((const unsigned char *) vec->p, vec->len, &res[1]);
21339   strcat(res, "\"");
21340   return res;
21341 }
21342 
21343 V7_PRIVATE void freeze_obj(struct v7 *v7, FILE *f, v7_val_t v) {
21344   struct v7_object *obj_base = get_object_struct(v);
21345   unsigned int attrs = V7_OBJ_OFF_HEAP;
21346 
21347 #ifndef V7_FREEZE_NOT_READONLY
21348   attrs |= V7_OBJ_NOT_EXTENSIBLE;
21349 #endif
21350 
21351   if (is_js_function(v)) {
21352     struct v7_js_function *func = get_js_function_struct(v);
21353     struct bcode *bcode = func->bcode;
21354     char *jops = freeze_vec(&bcode->ops);
21355     int i;
21356 
21357     fprintf(f,
21358             "{\"type\":\"func\", \"addr\":\"%p\", \"props\":\"%p\", "
21359             "\"attrs\":%d, \"scope\":\"%p\", \"bcode\":\"%p\""
21360 #if defined(V7_ENABLE_ENTITY_IDS)
21361             ", \"entity_id_base\":%d, \"entity_id_spec\":\"%d\" "
21362 #endif
21363             "}\n",
21364             (void *) obj_base,
21365             (void *) ((uintptr_t) obj_base->properties & ~0x1),
21366             obj_base->attributes | attrs, (void *) func->scope, (void *) bcode
21367 #if defined(V7_ENABLE_ENTITY_IDS)
21368             ,
21369             obj_base->entity_id_base, obj_base->entity_id_spec
21370 #endif
21371             );
21372     fprintf(f,
21373             "{\"type\":\"bcode\", \"addr\":\"%p\", \"args_cnt\":%d, "
21374             "\"names_cnt\":%d, "
21375             "\"strict_mode\": %d, \"func_name_present\": %d, \"ops\":%s, "
21376             "\"lit\": [",
21377             (void *) bcode, bcode->args_cnt, bcode->names_cnt,
21378             bcode->strict_mode, bcode->func_name_present, jops);
21379 
21380     for (i = 0; (size_t) i < bcode->lit.len / sizeof(val_t); i++) {
21381       val_t v = ((val_t *) bcode->lit.p)[i];
21382       const char *str;
21383 
21384       if (((v & V7_TAG_MASK) == V7_TAG_STRING_O ||
21385            (v & V7_TAG_MASK) == V7_TAG_STRING_F) &&
21386           (str = v7_get_cstring(v7, &v)) != NULL) {
21387         fprintf(f, "{\"str\": \"%s\"}", str);
21388       } else {
21389         fprintf(f, "{\"val\": \"0x%" INT64_X_FMT "\"}", v);
21390       }
21391       if ((size_t) i != bcode->lit.len / sizeof(val_t) - 1) {
21392         fprintf(f, ",");
21393       }
21394     }
21395 
21396     fprintf(f, "]}\n");
21397     free(jops);
21398   } else {
21399     struct v7_generic_object *gob = get_generic_object_struct(v);
21400     fprintf(f,
21401             "{\"type\":\"obj\", \"addr\":\"%p\", \"props\":\"%p\", "
21402             "\"attrs\":%d, \"proto\":\"%p\""
21403 #if defined(V7_ENABLE_ENTITY_IDS)
21404             ", \"entity_id_base\":%d, \"entity_id_spec\":\"%d\" "
21405 #endif
21406             "}\n",
21407             (void *) obj_base,
21408             (void *) ((uintptr_t) obj_base->properties & ~0x1),
21409             obj_base->attributes | attrs, (void *) gob->prototype
21410 #if defined(V7_ENABLE_ENTITY_IDS)
21411             ,
21412             obj_base->entity_id_base, obj_base->entity_id_spec
21413 #endif
21414             );
21415   }
21416 }
21417 
21418 V7_PRIVATE void freeze_prop(struct v7 *v7, FILE *f, struct v7_property *prop) {
21419   unsigned int attrs = _V7_PROPERTY_OFF_HEAP;
21420 #ifndef V7_FREEZE_NOT_READONLY
21421   attrs |= V7_PROPERTY_NON_WRITABLE | V7_PROPERTY_NON_CONFIGURABLE;
21422 #endif
21423 
21424   fprintf(f,
21425           "{\"type\":\"prop\","
21426           " \"addr\":\"%p\","
21427           " \"next\":\"%p\","
21428           " \"attrs\":%d,"
21429           " \"name\":\"0x%" INT64_X_FMT
21430           "\","
21431           " \"value_type\":%d,"
21432           " \"value\":\"0x%" INT64_X_FMT
21433           "\","
21434           " \"name_str\":\"%s\""
21435 #if defined(V7_ENABLE_ENTITY_IDS)
21436           ", \"entity_id\":\"%d\""
21437 #endif
21438           "}\n",
21439           (void *) prop, (void *) prop->next, prop->attributes | attrs,
21440           prop->name, val_type(v7, prop->value), prop->value,
21441           v7_get_cstring(v7, &prop->name)
21442 #if defined(V7_ENABLE_ENTITY_IDS)
21443               ,
21444           prop->entity_id
21445 #endif
21446           );
21447 }
21448 
21449 #endif
21450 #ifdef V7_MODULE_LINES
21451 #line 1 "v7/src/parser.c"
21452 #endif
21453 /*
21454  * Copyright (c) 2014 Cesanta Software Limited
21455  * All rights reserved
21456  */
21457 
21458 /* Amalgamated: #include "common/coroutine.h" */
21459 /* Amalgamated: #include "v7/src/internal.h" */
21460 /* Amalgamated: #include "v7/src/parser.h" */
21461 /* Amalgamated: #include "v7/src/tokenizer.h" */
21462 /* Amalgamated: #include "v7/src/core.h" */
21463 /* Amalgamated: #include "v7/src/exceptions.h" */
21464 /* Amalgamated: #include "v7/src/ast.h" */
21465 /* Amalgamated: #include "v7/src/primitive.h" */
21466 /* Amalgamated: #include "v7/src/cyg_profile.h" */
21467 
21468 #if !defined(V7_NO_COMPILER)
21469 
21470 #define ACCEPT(t) (((v7)->cur_tok == (t)) ? next_tok((v7)), 1 : 0)
21471 
21472 #define EXPECT(t)                            \
21473   do {                                       \
21474     if ((v7)->cur_tok != (t)) {              \
21475       CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR); \
21476     }                                        \
21477     next_tok(v7);                            \
21478   } while (0)
21479 
21480 #define PARSE_WITH_OPT_ARG(tag, arg_tag, arg_parser, label) \
21481   do {                                                      \
21482     if (end_of_statement(v7) == V7_OK) {                    \
21483       add_node(v7, a, (tag));                               \
21484     } else {                                                \
21485       add_node(v7, a, (arg_tag));                           \
21486       arg_parser(label);                                    \
21487     }                                                       \
21488   } while (0)
21489 
21490 #define N (CR_ARG_RET_PT()->arg)
21491 
21492 /*
21493  * User functions
21494  * (as well as other in-function entry points)
21495  */
21496 enum my_fid {
21497   fid_none = CR_FID__NONE,
21498 
21499   /* parse_script function */
21500   fid_parse_script = CR_FID__USER,
21501   fid_p_script_1,
21502   fid_p_script_2,
21503   fid_p_script_3,
21504   fid_p_script_4,
21505 
21506   /* parse_use_strict function */
21507   fid_parse_use_strict,
21508 
21509   /* parse_body function */
21510   fid_parse_body,
21511   fid_p_body_1,
21512   fid_p_body_2,
21513 
21514   /* parse_statement function */
21515   fid_parse_statement,
21516   fid_p_stat_1,
21517   fid_p_stat_2,
21518   fid_p_stat_3,
21519   fid_p_stat_4,
21520   fid_p_stat_5,
21521   fid_p_stat_6,
21522   fid_p_stat_7,
21523   fid_p_stat_8,
21524   fid_p_stat_9,
21525   fid_p_stat_10,
21526   fid_p_stat_11,
21527   fid_p_stat_12,
21528   fid_p_stat_13,
21529   fid_p_stat_14,
21530 
21531   /* parse_expression function */
21532   fid_parse_expression,
21533   fid_p_expr_1,
21534 
21535   /* parse_assign function */
21536   fid_parse_assign,
21537   fid_p_assign_1,
21538 
21539   /* parse_binary function */
21540   fid_parse_binary,
21541   fid_p_binary_1,
21542   fid_p_binary_2,
21543   fid_p_binary_3,
21544   fid_p_binary_4,
21545   fid_p_binary_5,
21546   fid_p_binary_6,
21547 
21548   /* parse_prefix function */
21549   fid_parse_prefix,
21550   fid_p_prefix_1,
21551 
21552   /* parse_postfix function */
21553   fid_parse_postfix,
21554   fid_p_postfix_1,
21555 
21556   /* parse_callexpr function */
21557   fid_parse_callexpr,
21558   fid_p_callexpr_1,
21559   fid_p_callexpr_2,
21560   fid_p_callexpr_3,
21561 
21562   /* parse_newexpr function */
21563   fid_parse_newexpr,
21564   fid_p_newexpr_1,
21565   fid_p_newexpr_2,
21566   fid_p_newexpr_3,
21567   fid_p_newexpr_4,
21568 
21569   /* parse_terminal function */
21570   fid_parse_terminal,
21571   fid_p_terminal_1,
21572   fid_p_terminal_2,
21573   fid_p_terminal_3,
21574   fid_p_terminal_4,
21575 
21576   /* parse_block function */
21577   fid_parse_block,
21578   fid_p_block_1,
21579 
21580   /* parse_if function */
21581   fid_parse_if,
21582   fid_p_if_1,
21583   fid_p_if_2,
21584   fid_p_if_3,
21585 
21586   /* parse_while function */
21587   fid_parse_while,
21588   fid_p_while_1,
21589   fid_p_while_2,
21590 
21591   /* parse_ident function */
21592   fid_parse_ident,
21593 
21594   /* parse_ident_allow_reserved_words function */
21595   fid_parse_ident_allow_reserved_words,
21596   fid_p_ident_arw_1,
21597 
21598   /* parse_funcdecl function */
21599   fid_parse_funcdecl,
21600   fid_p_funcdecl_1,
21601   fid_p_funcdecl_2,
21602   fid_p_funcdecl_3,
21603   fid_p_funcdecl_4,
21604   fid_p_funcdecl_5,
21605   fid_p_funcdecl_6,
21606   fid_p_funcdecl_7,
21607   fid_p_funcdecl_8,
21608   fid_p_funcdecl_9,
21609 
21610   /* parse_arglist function */
21611   fid_parse_arglist,
21612   fid_p_arglist_1,
21613 
21614   /* parse_member function */
21615   fid_parse_member,
21616   fid_p_member_1,
21617 
21618   /* parse_memberexpr function */
21619   fid_parse_memberexpr,
21620   fid_p_memberexpr_1,
21621   fid_p_memberexpr_2,
21622 
21623   /* parse_var function */
21624   fid_parse_var,
21625   fid_p_var_1,
21626 
21627   /* parse_prop function */
21628   fid_parse_prop,
21629 #ifdef V7_ENABLE_JS_GETTERS
21630   fid_p_prop_1_getter,
21631 #endif
21632   fid_p_prop_2,
21633 #ifdef V7_ENABLE_JS_SETTERS
21634   fid_p_prop_3_setter,
21635 #endif
21636   fid_p_prop_4,
21637 
21638   /* parse_dowhile function */
21639   fid_parse_dowhile,
21640   fid_p_dowhile_1,
21641   fid_p_dowhile_2,
21642 
21643   /* parse_for function */
21644   fid_parse_for,
21645   fid_p_for_1,
21646   fid_p_for_2,
21647   fid_p_for_3,
21648   fid_p_for_4,
21649   fid_p_for_5,
21650   fid_p_for_6,
21651 
21652   /* parse_try function */
21653   fid_parse_try,
21654   fid_p_try_1,
21655   fid_p_try_2,
21656   fid_p_try_3,
21657   fid_p_try_4,
21658 
21659   /* parse_switch function */
21660   fid_parse_switch,
21661   fid_p_switch_1,
21662   fid_p_switch_2,
21663   fid_p_switch_3,
21664   fid_p_switch_4,
21665 
21666   /* parse_with function */
21667   fid_parse_with,
21668   fid_p_with_1,
21669   fid_p_with_2,
21670 
21671   MY_FID_CNT
21672 };
21673 
21674 /*
21675  * User exception IDs. The first one should have value `CR_EXC_ID__USER`
21676  */
21677 enum parser_exc_id {
21678   PARSER_EXC_ID__NONE = CR_EXC_ID__NONE,
21679   PARSER_EXC_ID__SYNTAX_ERROR = CR_EXC_ID__USER,
21680 };
21681 
21682 /* structures with locals and args {{{ */
21683 
21684 /* parse_script {{{ */
21685 
21686 /* parse_script's arguments */
21687 #if 0
21688 typedef struct fid_parse_script_arg {
21689 } fid_parse_script_arg_t;
21690 #else
21691 typedef cr_zero_size_type_t fid_parse_script_arg_t;
21692 #endif
21693 
21694 /* parse_script's data on stack */
21695 typedef struct fid_parse_script_locals {
21696 #if 0
21697   struct fid_parse_script_arg arg;
21698 #endif
21699 
21700   ast_off_t start;
21701   ast_off_t outer_last_var_node;
21702   int saved_in_strict;
21703 } fid_parse_script_locals_t;
21704 
21705 /* }}} */
21706 
21707 /* parse_use_strict {{{ */
21708 /* parse_use_strict's arguments */
21709 #if 0
21710 typedef struct fid_parse_use_strict_arg {
21711 } fid_parse_use_strict_arg_t;
21712 #else
21713 typedef cr_zero_size_type_t fid_parse_use_strict_arg_t;
21714 #endif
21715 
21716 /* parse_use_strict's data on stack */
21717 #if 0
21718 typedef struct fid_parse_use_strict_locals {
21719   struct fid_parse_use_strict_arg arg;
21720 } fid_parse_use_strict_locals_t;
21721 #else
21722 typedef cr_zero_size_type_t fid_parse_use_strict_locals_t;
21723 #endif
21724 
21725 #define CALL_PARSE_USE_STRICT(_label)      \
21726   do {                                     \
21727     CR_CALL(fid_parse_use_strict, _label); \
21728   } while (0)
21729 
21730 /* }}} */
21731 
21732 /* parse_body {{{ */
21733 /* parse_body's arguments */
21734 typedef struct fid_parse_body_arg { enum v7_tok end; } fid_parse_body_arg_t;
21735 
21736 /* parse_body's data on stack */
21737 typedef struct fid_parse_body_locals {
21738   struct fid_parse_body_arg arg;
21739 
21740   ast_off_t start;
21741 } fid_parse_body_locals_t;
21742 
21743 #define CALL_PARSE_BODY(_end, _label) \
21744   do {                                \
21745     N.fid_parse_body.end = (_end);    \
21746     CR_CALL(fid_parse_body, _label);  \
21747   } while (0)
21748 /* }}} */
21749 
21750 /* parse_statement {{{ */
21751 /* parse_statement's arguments */
21752 #if 0
21753 typedef struct fid_parse_statement_arg {
21754 } fid_parse_statement_arg_t;
21755 #else
21756 typedef cr_zero_size_type_t fid_parse_statement_arg_t;
21757 #endif
21758 
21759 /* parse_statement's data on stack */
21760 #if 0
21761 typedef struct fid_parse_statement_locals {
21762   struct fid_parse_statement_arg arg;
21763 } fid_parse_statement_locals_t;
21764 #else
21765 typedef cr_zero_size_type_t fid_parse_statement_locals_t;
21766 #endif
21767 
21768 #define CALL_PARSE_STATEMENT(_label)      \
21769   do {                                    \
21770     CR_CALL(fid_parse_statement, _label); \
21771   } while (0)
21772 /* }}} */
21773 
21774 /* parse_expression {{{ */
21775 /* parse_expression's arguments */
21776 #if 0
21777 typedef struct fid_parse_expression_arg {
21778 } fid_parse_expression_arg_t;
21779 #else
21780 typedef cr_zero_size_type_t fid_parse_expression_arg_t;
21781 #endif
21782 
21783 /* parse_expression's data on stack */
21784 typedef struct fid_parse_expression_locals {
21785 #if 0
21786   struct fid_parse_expression_arg arg;
21787 #endif
21788 
21789   ast_off_t pos;
21790   int group;
21791 } fid_parse_expression_locals_t;
21792 
21793 #define CALL_PARSE_EXPRESSION(_label)      \
21794   do {                                     \
21795     CR_CALL(fid_parse_expression, _label); \
21796   } while (0)
21797 /* }}} */
21798 
21799 /* parse_assign {{{ */
21800 /* parse_assign's arguments */
21801 #if 0
21802 typedef struct fid_parse_assign_arg {
21803 } fid_parse_assign_arg_t;
21804 #else
21805 typedef cr_zero_size_type_t fid_parse_assign_arg_t;
21806 #endif
21807 
21808 /* parse_assign's data on stack */
21809 #if 0
21810 typedef struct fid_parse_assign_locals {
21811   struct fid_parse_assign_arg arg;
21812 } fid_parse_assign_locals_t;
21813 #else
21814 typedef cr_zero_size_type_t fid_parse_assign_locals_t;
21815 #endif
21816 
21817 #define CALL_PARSE_ASSIGN(_label)      \
21818   do {                                 \
21819     CR_CALL(fid_parse_assign, _label); \
21820   } while (0)
21821 /* }}} */
21822 
21823 /* parse_binary {{{ */
21824 /* parse_binary's arguments */
21825 typedef struct fid_parse_binary_arg {
21826   ast_off_t pos;
21827   uint8_t min_level;
21828 } fid_parse_binary_arg_t;
21829 
21830 /* parse_binary's data on stack */
21831 typedef struct fid_parse_binary_locals {
21832   struct fid_parse_binary_arg arg;
21833 
21834   uint8_t i;
21835   /* during iteration, it becomes negative, so should be signed */
21836   int8_t level;
21837   uint8_t /*enum v7_tok*/ tok;
21838   uint8_t /*enum ast_tag*/ ast;
21839   ast_off_t saved_mbuf_len;
21840 } fid_parse_binary_locals_t;
21841 
21842 #define CALL_PARSE_BINARY(_level, _pos, _label) \
21843   do {                                          \
21844     N.fid_parse_binary.min_level = (_level);    \
21845     N.fid_parse_binary.pos = (_pos);            \
21846     CR_CALL(fid_parse_binary, _label);          \
21847   } while (0)
21848 /* }}} */
21849 
21850 /* parse_prefix {{{ */
21851 /* parse_prefix's arguments */
21852 #if 0
21853 typedef struct fid_parse_prefix_arg {
21854 } fid_parse_prefix_arg_t;
21855 #else
21856 typedef cr_zero_size_type_t fid_parse_prefix_arg_t;
21857 #endif
21858 
21859 /* parse_prefix's data on stack */
21860 #if 0
21861 typedef struct fid_parse_prefix_locals {
21862   struct fid_parse_prefix_arg arg;
21863 } fid_parse_prefix_locals_t;
21864 #else
21865 typedef cr_zero_size_type_t fid_parse_prefix_locals_t;
21866 #endif
21867 
21868 #define CALL_PARSE_PREFIX(_label)      \
21869   do {                                 \
21870     CR_CALL(fid_parse_prefix, _label); \
21871   } while (0)
21872 /* }}} */
21873 
21874 /* parse_postfix {{{ */
21875 /* parse_postfix's arguments */
21876 #if 0
21877 typedef struct fid_parse_postfix_arg {
21878 } fid_parse_postfix_arg_t;
21879 #else
21880 typedef cr_zero_size_type_t fid_parse_postfix_arg_t;
21881 #endif
21882 
21883 /* parse_postfix's data on stack */
21884 typedef struct fid_parse_postfix_locals {
21885 #if 0
21886   struct fid_parse_postfix_arg arg;
21887 #endif
21888 
21889   ast_off_t pos;
21890 } fid_parse_postfix_locals_t;
21891 
21892 #define CALL_PARSE_POSTFIX(_label)      \
21893   do {                                  \
21894     CR_CALL(fid_parse_postfix, _label); \
21895   } while (0)
21896 /* }}} */
21897 
21898 /* parse_callexpr {{{ */
21899 /* parse_callexpr's arguments */
21900 #if 0
21901 typedef struct fid_parse_callexpr_arg {
21902 } fid_parse_callexpr_arg_t;
21903 #else
21904 typedef cr_zero_size_type_t fid_parse_callexpr_arg_t;
21905 #endif
21906 
21907 /* parse_callexpr's data on stack */
21908 typedef struct fid_parse_callexpr_locals {
21909 #if 0
21910   struct fid_parse_callexpr_arg arg;
21911 #endif
21912 
21913   ast_off_t pos;
21914 } fid_parse_callexpr_locals_t;
21915 
21916 #define CALL_PARSE_CALLEXPR(_label)      \
21917   do {                                   \
21918     CR_CALL(fid_parse_callexpr, _label); \
21919   } while (0)
21920 /* }}} */
21921 
21922 /* parse_newexpr {{{ */
21923 /* parse_newexpr's arguments */
21924 #if 0
21925 typedef struct fid_parse_newexpr_arg {
21926 } fid_parse_newexpr_arg_t;
21927 #else
21928 typedef cr_zero_size_type_t fid_parse_newexpr_arg_t;
21929 #endif
21930 
21931 /* parse_newexpr's data on stack */
21932 typedef struct fid_parse_newexpr_locals {
21933 #if 0
21934   struct fid_parse_newexpr_arg arg;
21935 #endif
21936 
21937   ast_off_t start;
21938 } fid_parse_newexpr_locals_t;
21939 
21940 #define CALL_PARSE_NEWEXPR(_label)      \
21941   do {                                  \
21942     CR_CALL(fid_parse_newexpr, _label); \
21943   } while (0)
21944 /* }}} */
21945 
21946 /* parse_terminal {{{ */
21947 /* parse_terminal's arguments */
21948 #if 0
21949 typedef struct fid_parse_terminal_arg {
21950 } fid_parse_terminal_arg_t;
21951 #else
21952 typedef cr_zero_size_type_t fid_parse_terminal_arg_t;
21953 #endif
21954 
21955 /* parse_terminal's data on stack */
21956 typedef struct fid_parse_terminal_locals {
21957 #if 0
21958   struct fid_parse_terminal_arg arg;
21959 #endif
21960 
21961   ast_off_t start;
21962 } fid_parse_terminal_locals_t;
21963 
21964 #define CALL_PARSE_TERMINAL(_label)      \
21965   do {                                   \
21966     CR_CALL(fid_parse_terminal, _label); \
21967   } while (0)
21968 /* }}} */
21969 
21970 /* parse_block {{{ */
21971 /* parse_block's arguments */
21972 #if 0
21973 typedef struct fid_parse_block_arg {
21974 } fid_parse_block_arg_t;
21975 #else
21976 typedef cr_zero_size_type_t fid_parse_block_arg_t;
21977 #endif
21978 
21979 /* parse_block's data on stack */
21980 #if 0
21981 typedef struct fid_parse_block_locals {
21982   struct fid_parse_block_arg arg;
21983 } fid_parse_block_locals_t;
21984 #else
21985 typedef cr_zero_size_type_t fid_parse_block_locals_t;
21986 #endif
21987 
21988 #define CALL_PARSE_BLOCK(_label)      \
21989   do {                                \
21990     CR_CALL(fid_parse_block, _label); \
21991   } while (0)
21992 /* }}} */
21993 
21994 /* parse_if {{{ */
21995 /* parse_if's arguments */
21996 #if 0
21997 typedef struct fid_parse_if_arg {
21998 } fid_parse_if_arg_t;
21999 #else
22000 typedef cr_zero_size_type_t fid_parse_if_arg_t;
22001 #endif
22002 
22003 /* parse_if's data on stack */
22004 typedef struct fid_parse_if_locals {
22005 #if 0
22006   struct fid_parse_if_arg arg;
22007 #endif
22008 
22009   ast_off_t start;
22010 } fid_parse_if_locals_t;
22011 
22012 #define CALL_PARSE_IF(_label)      \
22013   do {                             \
22014     CR_CALL(fid_parse_if, _label); \
22015   } while (0)
22016 /* }}} */
22017 
22018 /* parse_while {{{ */
22019 /* parse_while's arguments */
22020 #if 0
22021 typedef struct fid_parse_while_arg {
22022 } fid_parse_while_arg_t;
22023 #else
22024 typedef cr_zero_size_type_t fid_parse_while_arg_t;
22025 #endif
22026 
22027 /* parse_while's data on stack */
22028 typedef struct fid_parse_while_locals {
22029 #if 0
22030   struct fid_parse_while_arg arg;
22031 #endif
22032 
22033   ast_off_t start;
22034   uint8_t saved_in_loop;
22035 } fid_parse_while_locals_t;
22036 
22037 #define CALL_PARSE_WHILE(_label)      \
22038   do {                                \
22039     CR_CALL(fid_parse_while, _label); \
22040   } while (0)
22041 /* }}} */
22042 
22043 /* parse_ident {{{ */
22044 /* parse_ident's arguments */
22045 #if 0
22046 typedef struct fid_parse_ident_arg {
22047 } fid_parse_ident_arg_t;
22048 #else
22049 typedef cr_zero_size_type_t fid_parse_ident_arg_t;
22050 #endif
22051 
22052 /* parse_ident's data on stack */
22053 #if 0
22054 typedef struct fid_parse_ident_locals {
22055   struct fid_parse_ident_arg arg;
22056 } fid_parse_ident_locals_t;
22057 #else
22058 typedef cr_zero_size_type_t fid_parse_ident_locals_t;
22059 #endif
22060 
22061 #define CALL_PARSE_IDENT(_label)      \
22062   do {                                \
22063     CR_CALL(fid_parse_ident, _label); \
22064   } while (0)
22065 /* }}} */
22066 
22067 /* parse_ident_allow_reserved_words {{{ */
22068 /* parse_ident_allow_reserved_words's arguments */
22069 #if 0
22070 typedef struct fid_parse_ident_allow_reserved_words_arg {
22071 } fid_parse_ident_allow_reserved_words_arg_t;
22072 #else
22073 typedef cr_zero_size_type_t fid_parse_ident_allow_reserved_words_arg_t;
22074 #endif
22075 
22076 /* parse_ident_allow_reserved_words's data on stack */
22077 #if 0
22078 typedef struct fid_parse_ident_allow_reserved_words_locals {
22079   struct fid_parse_ident_allow_reserved_words_arg arg;
22080 } fid_parse_ident_allow_reserved_words_locals_t;
22081 #else
22082 typedef cr_zero_size_type_t fid_parse_ident_allow_reserved_words_locals_t;
22083 #endif
22084 
22085 #define CALL_PARSE_IDENT_ALLOW_RESERVED_WORDS(_label)      \
22086   do {                                                     \
22087     CR_CALL(fid_parse_ident_allow_reserved_words, _label); \
22088   } while (0)
22089 /* }}} */
22090 
22091 /* parse_funcdecl {{{ */
22092 /* parse_funcdecl's arguments */
22093 typedef struct fid_parse_funcdecl_arg {
22094   uint8_t require_named;
22095   uint8_t reserved_name;
22096 } fid_parse_funcdecl_arg_t;
22097 
22098 /* parse_funcdecl's data on stack */
22099 typedef struct fid_parse_funcdecl_locals {
22100   struct fid_parse_funcdecl_arg arg;
22101 
22102   ast_off_t start;
22103   ast_off_t outer_last_var_node;
22104   uint8_t saved_in_function;
22105   uint8_t saved_in_strict;
22106 } fid_parse_funcdecl_locals_t;
22107 
22108 #define CALL_PARSE_FUNCDECL(_require_named, _reserved_name, _label) \
22109   do {                                                              \
22110     N.fid_parse_funcdecl.require_named = (_require_named);          \
22111     N.fid_parse_funcdecl.reserved_name = (_reserved_name);          \
22112     CR_CALL(fid_parse_funcdecl, _label);                            \
22113   } while (0)
22114 /* }}} */
22115 
22116 /* parse_arglist {{{ */
22117 /* parse_arglist's arguments */
22118 #if 0
22119 typedef struct fid_parse_arglist_arg {
22120 } fid_parse_arglist_arg_t;
22121 #else
22122 typedef cr_zero_size_type_t fid_parse_arglist_arg_t;
22123 #endif
22124 
22125 /* parse_arglist's data on stack */
22126 #if 0
22127 typedef struct fid_parse_arglist_locals {
22128   struct fid_parse_arglist_arg arg;
22129 } fid_parse_arglist_locals_t;
22130 #else
22131 typedef cr_zero_size_type_t fid_parse_arglist_locals_t;
22132 #endif
22133 
22134 #define CALL_PARSE_ARGLIST(_label)      \
22135   do {                                  \
22136     CR_CALL(fid_parse_arglist, _label); \
22137   } while (0)
22138 /* }}} */
22139 
22140 /* parse_member {{{ */
22141 /* parse_member's arguments */
22142 typedef struct fid_parse_member_arg { ast_off_t pos; } fid_parse_member_arg_t;
22143 
22144 /* parse_member's data on stack */
22145 typedef struct fid_parse_member_locals {
22146   struct fid_parse_member_arg arg;
22147 } fid_parse_member_locals_t;
22148 
22149 #define CALL_PARSE_MEMBER(_pos, _label) \
22150   do {                                  \
22151     N.fid_parse_member.pos = (_pos);    \
22152     CR_CALL(fid_parse_member, _label);  \
22153   } while (0)
22154 /* }}} */
22155 
22156 /* parse_memberexpr {{{ */
22157 /* parse_memberexpr's arguments */
22158 #if 0
22159 typedef struct fid_parse_memberexpr_arg {
22160 } fid_parse_memberexpr_arg_t;
22161 #else
22162 typedef cr_zero_size_type_t fid_parse_memberexpr_arg_t;
22163 #endif
22164 
22165 /* parse_memberexpr's data on stack */
22166 typedef struct fid_parse_memberexpr_locals {
22167 #if 0
22168   struct fid_parse_memberexpr_arg arg;
22169 #endif
22170 
22171   ast_off_t pos;
22172 } fid_parse_memberexpr_locals_t;
22173 
22174 #define CALL_PARSE_MEMBEREXPR(_label)      \
22175   do {                                     \
22176     CR_CALL(fid_parse_memberexpr, _label); \
22177   } while (0)
22178 /* }}} */
22179 
22180 /* parse_var {{{ */
22181 /* parse_var's arguments */
22182 #if 0
22183 typedef struct fid_parse_var_arg {
22184 } fid_parse_var_arg_t;
22185 #else
22186 typedef cr_zero_size_type_t fid_parse_var_arg_t;
22187 #endif
22188 
22189 /* parse_var's data on stack */
22190 typedef struct fid_parse_var_locals {
22191 #if 0
22192   struct fid_parse_var_arg arg;
22193 #endif
22194 
22195   ast_off_t start;
22196 } fid_parse_var_locals_t;
22197 
22198 #define CALL_PARSE_VAR(_label)      \
22199   do {                              \
22200     CR_CALL(fid_parse_var, _label); \
22201   } while (0)
22202 /* }}} */
22203 
22204 /* parse_prop {{{ */
22205 /* parse_prop's arguments */
22206 #if 0
22207 typedef struct fid_parse_prop_arg {
22208 } fid_parse_prop_arg_t;
22209 #else
22210 typedef cr_zero_size_type_t fid_parse_prop_arg_t;
22211 #endif
22212 
22213 /* parse_prop's data on stack */
22214 #if 0
22215 typedef struct fid_parse_prop_locals {
22216   struct fid_parse_prop_arg arg;
22217 } fid_parse_prop_locals_t;
22218 #else
22219 typedef cr_zero_size_type_t fid_parse_prop_locals_t;
22220 #endif
22221 
22222 #define CALL_PARSE_PROP(_label)      \
22223   do {                               \
22224     CR_CALL(fid_parse_prop, _label); \
22225   } while (0)
22226 /* }}} */
22227 
22228 /* parse_dowhile {{{ */
22229 /* parse_dowhile's arguments */
22230 #if 0
22231 typedef struct fid_parse_dowhile_arg {
22232 } fid_parse_dowhile_arg_t;
22233 #else
22234 typedef cr_zero_size_type_t fid_parse_dowhile_arg_t;
22235 #endif
22236 
22237 /* parse_dowhile's data on stack */
22238 typedef struct fid_parse_dowhile_locals {
22239 #if 0
22240   struct fid_parse_dowhile_arg arg;
22241 #endif
22242 
22243   ast_off_t start;
22244   uint8_t saved_in_loop;
22245 } fid_parse_dowhile_locals_t;
22246 
22247 #define CALL_PARSE_DOWHILE(_label)      \
22248   do {                                  \
22249     CR_CALL(fid_parse_dowhile, _label); \
22250   } while (0)
22251 /* }}} */
22252 
22253 /* parse_for {{{ */
22254 /* parse_for's arguments */
22255 #if 0
22256 typedef struct fid_parse_for_arg {
22257 } fid_parse_for_arg_t;
22258 #else
22259 typedef cr_zero_size_type_t fid_parse_for_arg_t;
22260 #endif
22261 
22262 /* parse_for's data on stack */
22263 typedef struct fid_parse_for_locals {
22264 #if 0
22265   struct fid_parse_for_arg arg;
22266 #endif
22267 
22268   ast_off_t start;
22269   uint8_t saved_in_loop;
22270 } fid_parse_for_locals_t;
22271 
22272 #define CALL_PARSE_FOR(_label)      \
22273   do {                              \
22274     CR_CALL(fid_parse_for, _label); \
22275   } while (0)
22276 /* }}} */
22277 
22278 /* parse_try {{{ */
22279 /* parse_try's arguments */
22280 #if 0
22281 typedef struct fid_parse_try_arg {
22282 } fid_parse_try_arg_t;
22283 #else
22284 typedef cr_zero_size_type_t fid_parse_try_arg_t;
22285 #endif
22286 
22287 /* parse_try's data on stack */
22288 typedef struct fid_parse_try_locals {
22289 #if 0
22290   struct fid_parse_try_arg arg;
22291 #endif
22292 
22293   ast_off_t start;
22294   uint8_t catch_or_finally;
22295 } fid_parse_try_locals_t;
22296 
22297 #define CALL_PARSE_TRY(_label)      \
22298   do {                              \
22299     CR_CALL(fid_parse_try, _label); \
22300   } while (0)
22301 /* }}} */
22302 
22303 /* parse_switch {{{ */
22304 /* parse_switch's arguments */
22305 #if 0
22306 typedef struct fid_parse_switch_arg {
22307 } fid_parse_switch_arg_t;
22308 #else
22309 typedef cr_zero_size_type_t fid_parse_switch_arg_t;
22310 #endif
22311 
22312 /* parse_switch's data on stack */
22313 typedef struct fid_parse_switch_locals {
22314 #if 0
22315   struct fid_parse_switch_arg arg;
22316 #endif
22317 
22318   ast_off_t start;
22319   int saved_in_switch;
22320   ast_off_t case_start;
22321 } fid_parse_switch_locals_t;
22322 
22323 #define CALL_PARSE_SWITCH(_label)      \
22324   do {                                 \
22325     CR_CALL(fid_parse_switch, _label); \
22326   } while (0)
22327 /* }}} */
22328 
22329 /* parse_with {{{ */
22330 /* parse_with's arguments */
22331 #if 0
22332 typedef struct fid_parse_with_arg {
22333 } fid_parse_with_arg_t;
22334 #else
22335 typedef cr_zero_size_type_t fid_parse_with_arg_t;
22336 #endif
22337 
22338 /* parse_with's data on stack */
22339 typedef struct fid_parse_with_locals {
22340 #if 0
22341   struct fid_parse_with_arg arg;
22342 #endif
22343 
22344   ast_off_t start;
22345 } fid_parse_with_locals_t;
22346 
22347 #define CALL_PARSE_WITH(_label)      \
22348   do {                               \
22349     CR_CALL(fid_parse_with, _label); \
22350   } while (0)
22351 /* }}} */
22352 
22353 /* }}} */
22354 
22355 /*
22356  * Array of "function" descriptors. Each descriptor contains just a size
22357  * of "function"'s locals.
22358  */
22359 static const struct cr_func_desc _fid_descrs[MY_FID_CNT] = {
22360 
22361     /* fid_none */
22362     {0},
22363 
22364     /* fid_parse_script ----------------------------------------- */
22365     /* fid_parse_script */
22366     {CR_LOCALS_SIZEOF(fid_parse_script_locals_t)},
22367     /* fid_p_script_1 */
22368     {CR_LOCALS_SIZEOF(fid_parse_script_locals_t)},
22369     /* fid_p_script_2 */
22370     {CR_LOCALS_SIZEOF(fid_parse_script_locals_t)},
22371     /* fid_p_script_3 */
22372     {CR_LOCALS_SIZEOF(fid_parse_script_locals_t)},
22373     /* fid_p_script_4 */
22374     {CR_LOCALS_SIZEOF(fid_parse_script_locals_t)},
22375 
22376     /* fid_parse_use_strict ----------------------------------------- */
22377     /* fid_parse_use_strict */
22378     {CR_LOCALS_SIZEOF(fid_parse_use_strict_locals_t)},
22379 
22380     /* fid_parse_body ----------------------------------------- */
22381     /* fid_parse_body */
22382     {CR_LOCALS_SIZEOF(fid_parse_body_locals_t)},
22383     /* fid_p_body_1 */
22384     {CR_LOCALS_SIZEOF(fid_parse_body_locals_t)},
22385     /* fid_p_body_2 */
22386     {CR_LOCALS_SIZEOF(fid_parse_body_locals_t)},
22387 
22388     /* fid_parse_statement ----------------------------------------- */
22389     /* fid_parse_statement */
22390     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22391     /* fid_p_stat_1 */
22392     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22393     /* fid_p_stat_2 */
22394     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22395     /* fid_p_stat_3 */
22396     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22397     /* fid_p_stat_4 */
22398     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22399     /* fid_p_stat_5 */
22400     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22401     /* fid_p_stat_6 */
22402     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22403     /* fid_p_stat_7 */
22404     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22405     /* fid_p_stat_8 */
22406     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22407     /* fid_p_stat_9 */
22408     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22409     /* fid_p_stat_10 */
22410     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22411     /* fid_p_stat_11 */
22412     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22413     /* fid_p_stat_12 */
22414     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22415     /* fid_p_stat_13 */
22416     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22417     /* fid_p_stat_14 */
22418     {CR_LOCALS_SIZEOF(fid_parse_statement_locals_t)},
22419 
22420     /* fid_parse_expression ----------------------------------------- */
22421     /* fid_parse_expression */
22422     {CR_LOCALS_SIZEOF(fid_parse_expression_locals_t)},
22423     /* fid_p_expr_1 */
22424     {CR_LOCALS_SIZEOF(fid_parse_expression_locals_t)},
22425 
22426     /* fid_parse_assign ----------------------------------------- */
22427     /* fid_parse_assign */
22428     {CR_LOCALS_SIZEOF(fid_parse_assign_locals_t)},
22429     /* fid_p_assign_1 */
22430     {CR_LOCALS_SIZEOF(fid_parse_assign_locals_t)},
22431 
22432     /* fid_parse_binary ----------------------------------------- */
22433     /* fid_parse_binary */
22434     {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
22435     /* fid_p_binary_1 */
22436     {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
22437     /* fid_p_binary_2 */
22438     {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
22439     /* fid_p_binary_3 */
22440     {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
22441     /* fid_p_binary_4 */
22442     {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
22443     /* fid_p_binary_5 */
22444     {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
22445     /* fid_p_binary_6 */
22446     {CR_LOCALS_SIZEOF(fid_parse_binary_locals_t)},
22447 
22448     /* fid_parse_prefix ----------------------------------------- */
22449     /* fid_parse_prefix */
22450     {CR_LOCALS_SIZEOF(fid_parse_prefix_locals_t)},
22451     /* fid_p_prefix_1 */
22452     {CR_LOCALS_SIZEOF(fid_parse_prefix_locals_t)},
22453 
22454     /* fid_parse_postfix ----------------------------------------- */
22455     /* fid_parse_postfix */
22456     {CR_LOCALS_SIZEOF(fid_parse_postfix_locals_t)},
22457     /* fid_p_postfix_1 */
22458     {CR_LOCALS_SIZEOF(fid_parse_postfix_locals_t)},
22459 
22460     /* fid_parse_callexpr ----------------------------------------- */
22461     /* fid_parse_callexpr */
22462     {CR_LOCALS_SIZEOF(fid_parse_callexpr_locals_t)},
22463     /* fid_p_callexpr_1 */
22464     {CR_LOCALS_SIZEOF(fid_parse_callexpr_locals_t)},
22465     /* fid_p_callexpr_2 */
22466     {CR_LOCALS_SIZEOF(fid_parse_callexpr_locals_t)},
22467     /* fid_p_callexpr_3 */
22468     {CR_LOCALS_SIZEOF(fid_parse_callexpr_locals_t)},
22469 
22470     /* fid_parse_newexpr ----------------------------------------- */
22471     /* fid_parse_newexpr */
22472     {CR_LOCALS_SIZEOF(fid_parse_newexpr_locals_t)},
22473     /* fid_p_newexpr_1 */
22474     {CR_LOCALS_SIZEOF(fid_parse_newexpr_locals_t)},
22475     /* fid_p_newexpr_2 */
22476     {CR_LOCALS_SIZEOF(fid_parse_newexpr_locals_t)},
22477     /* fid_p_newexpr_3 */
22478     {CR_LOCALS_SIZEOF(fid_parse_newexpr_locals_t)},
22479     /* fid_p_newexpr_4 */
22480     {CR_LOCALS_SIZEOF(fid_parse_newexpr_locals_t)},
22481 
22482     /* fid_parse_terminal ----------------------------------------- */
22483     /* fid_parse_terminal */
22484     {CR_LOCALS_SIZEOF(fid_parse_terminal_locals_t)},
22485     /* fid_p_terminal_1 */
22486     {CR_LOCALS_SIZEOF(fid_parse_terminal_locals_t)},
22487     /* fid_p_terminal_2 */
22488     {CR_LOCALS_SIZEOF(fid_parse_terminal_locals_t)},
22489     /* fid_p_terminal_3 */
22490     {CR_LOCALS_SIZEOF(fid_parse_terminal_locals_t)},
22491     /* fid_p_terminal_4 */
22492     {CR_LOCALS_SIZEOF(fid_parse_terminal_locals_t)},
22493 
22494     /* fid_parse_block ----------------------------------------- */
22495     /* fid_parse_block */
22496     {CR_LOCALS_SIZEOF(fid_parse_block_locals_t)},
22497     /* fid_p_block_1 */
22498     {CR_LOCALS_SIZEOF(fid_parse_block_locals_t)},
22499 
22500     /* fid_parse_if ----------------------------------------- */
22501     /* fid_parse_if */
22502     {CR_LOCALS_SIZEOF(fid_parse_if_locals_t)},
22503     /* fid_p_if_1 */
22504     {CR_LOCALS_SIZEOF(fid_parse_if_locals_t)},
22505     /* fid_p_if_2 */
22506     {CR_LOCALS_SIZEOF(fid_parse_if_locals_t)},
22507     /* fid_p_if_3 */
22508     {CR_LOCALS_SIZEOF(fid_parse_if_locals_t)},
22509 
22510     /* fid_parse_while ----------------------------------------- */
22511     /* fid_parse_while */
22512     {CR_LOCALS_SIZEOF(fid_parse_while_locals_t)},
22513     /* fid_p_while_1 */
22514     {CR_LOCALS_SIZEOF(fid_parse_while_locals_t)},
22515     /* fid_p_while_2 */
22516     {CR_LOCALS_SIZEOF(fid_parse_while_locals_t)},
22517 
22518     /* fid_parse_ident ----------------------------------------- */
22519     /* fid_parse_ident */
22520     {CR_LOCALS_SIZEOF(fid_parse_ident_locals_t)},
22521 
22522     /* fid_parse_ident_allow_reserved_words -------------------- */
22523     /* fid_parse_ident_allow_reserved_words */
22524     {CR_LOCALS_SIZEOF(fid_parse_ident_allow_reserved_words_locals_t)},
22525     /* fid_p_ident_allow_reserved_words_1 */
22526     {CR_LOCALS_SIZEOF(fid_parse_ident_allow_reserved_words_locals_t)},
22527 
22528     /* fid_parse_funcdecl ----------------------------------------- */
22529     /* fid_parse_funcdecl */
22530     {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
22531     /* fid_p_funcdecl_1 */
22532     {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
22533     /* fid_p_funcdecl_2 */
22534     {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
22535     /* fid_p_funcdecl_3 */
22536     {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
22537     /* fid_p_funcdecl_4 */
22538     {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
22539     /* fid_p_funcdecl_5 */
22540     {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
22541     /* fid_p_funcdecl_6 */
22542     {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
22543     /* fid_p_funcdecl_7 */
22544     {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
22545     /* fid_p_funcdecl_8 */
22546     {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
22547     /* fid_p_funcdecl_9 */
22548     {CR_LOCALS_SIZEOF(fid_parse_funcdecl_locals_t)},
22549 
22550     /* fid_parse_arglist ----------------------------------------- */
22551     /* fid_parse_arglist */
22552     {CR_LOCALS_SIZEOF(fid_parse_arglist_locals_t)},
22553     /* fid_p_arglist_1 */
22554     {CR_LOCALS_SIZEOF(fid_parse_arglist_locals_t)},
22555 
22556     /* fid_parse_member ----------------------------------------- */
22557     /* fid_parse_member */
22558     {CR_LOCALS_SIZEOF(fid_parse_member_locals_t)},
22559     /* fid_p_member_1 */
22560     {CR_LOCALS_SIZEOF(fid_parse_member_locals_t)},
22561 
22562     /* fid_parse_memberexpr ----------------------------------------- */
22563     /* fid_parse_memberexpr */
22564     {CR_LOCALS_SIZEOF(fid_parse_memberexpr_locals_t)},
22565     /* fid_p_memberexpr_1 */
22566     {CR_LOCALS_SIZEOF(fid_parse_memberexpr_locals_t)},
22567     /* fid_p_memberexpr_2 */
22568     {CR_LOCALS_SIZEOF(fid_parse_memberexpr_locals_t)},
22569 
22570     /* fid_parse_var ----------------------------------------- */
22571     /* fid_parse_var */
22572     {CR_LOCALS_SIZEOF(fid_parse_var_locals_t)},
22573     /* fid_p_var_1 */
22574     {CR_LOCALS_SIZEOF(fid_parse_var_locals_t)},
22575 
22576     /* fid_parse_prop ----------------------------------------- */
22577     /* fid_parse_prop */
22578     {CR_LOCALS_SIZEOF(fid_parse_prop_locals_t)},
22579 #ifdef V7_ENABLE_JS_GETTERS
22580     /* fid_p_prop_1_getter */
22581     {CR_LOCALS_SIZEOF(fid_parse_prop_locals_t)},
22582 #endif
22583     /* fid_p_prop_2 */
22584     {CR_LOCALS_SIZEOF(fid_parse_prop_locals_t)},
22585 #ifdef V7_ENABLE_JS_SETTERS
22586     /* fid_p_prop_3_setter */
22587     {CR_LOCALS_SIZEOF(fid_parse_prop_locals_t)},
22588 #endif
22589     /* fid_p_prop_4 */
22590     {CR_LOCALS_SIZEOF(fid_parse_prop_locals_t)},
22591 
22592     /* fid_parse_dowhile ----------------------------------------- */
22593     /* fid_parse_dowhile */
22594     {CR_LOCALS_SIZEOF(fid_parse_dowhile_locals_t)},
22595     /* fid_p_dowhile_1 */
22596     {CR_LOCALS_SIZEOF(fid_parse_dowhile_locals_t)},
22597     /* fid_p_dowhile_2 */
22598     {CR_LOCALS_SIZEOF(fid_parse_dowhile_locals_t)},
22599 
22600     /* fid_parse_for ----------------------------------------- */
22601     /* fid_parse_for */
22602     {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
22603     /* fid_p_for_1 */
22604     {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
22605     /* fid_p_for_2 */
22606     {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
22607     /* fid_p_for_3 */
22608     {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
22609     /* fid_p_for_4 */
22610     {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
22611     /* fid_p_for_5 */
22612     {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
22613     /* fid_p_for_6 */
22614     {CR_LOCALS_SIZEOF(fid_parse_for_locals_t)},
22615 
22616     /* fid_parse_try ----------------------------------------- */
22617     /* fid_parse_try */
22618     {CR_LOCALS_SIZEOF(fid_parse_try_locals_t)},
22619     /* fid_p_try_1 */
22620     {CR_LOCALS_SIZEOF(fid_parse_try_locals_t)},
22621     /* fid_p_try_2 */
22622     {CR_LOCALS_SIZEOF(fid_parse_try_locals_t)},
22623     /* fid_p_try_3 */
22624     {CR_LOCALS_SIZEOF(fid_parse_try_locals_t)},
22625     /* fid_p_try_4 */
22626     {CR_LOCALS_SIZEOF(fid_parse_try_locals_t)},
22627 
22628     /* fid_parse_switch ----------------------------------------- */
22629     /* fid_parse_switch */
22630     {CR_LOCALS_SIZEOF(fid_parse_switch_locals_t)},
22631     /* fid_p_switch_1 */
22632     {CR_LOCALS_SIZEOF(fid_parse_switch_locals_t)},
22633     /* fid_p_switch_2 */
22634     {CR_LOCALS_SIZEOF(fid_parse_switch_locals_t)},
22635     /* fid_p_switch_3 */
22636     {CR_LOCALS_SIZEOF(fid_parse_switch_locals_t)},
22637     /* fid_p_switch_4 */
22638     {CR_LOCALS_SIZEOF(fid_parse_switch_locals_t)},
22639 
22640     /* fid_parse_with ----------------------------------------- */
22641     /* fid_parse_with */
22642     {CR_LOCALS_SIZEOF(fid_parse_with_locals_t)},
22643     /* fid_p_with_1 */
22644     {CR_LOCALS_SIZEOF(fid_parse_with_locals_t)},
22645     /* fid_p_with_2 */
22646     {CR_LOCALS_SIZEOF(fid_parse_with_locals_t)},
22647 
22648 };
22649 
22650 /*
22651  * Union of arguments and return values for all existing "functions".
22652  *
22653  * Used as an accumulator when we call function, return from function,
22654  * yield, or resume.
22655  */
22656 union user_arg_ret {
22657   /* arguments to the next function */
22658   union {
22659 #if 0
22660     fid_parse_script_arg_t fid_parse_script;
22661     fid_parse_use_strict_arg_t fid_parse_use_strict;
22662     fid_parse_statement_arg_t fid_parse_statement;
22663     fid_parse_expression_arg_t fid_parse_expression;
22664     fid_parse_assign_arg_t fid_parse_assign;
22665     fid_parse_prefix_arg_t fid_parse_prefix;
22666     fid_parse_postfix_arg_t fid_parse_postfix;
22667     fid_parse_callexpr_arg_t fid_parse_callexpr;
22668     fid_parse_newexpr_arg_t fid_parse_newexpr;
22669     fid_parse_terminal_arg_t fid_parse_terminal;
22670     fid_parse_block_arg_t fid_parse_block;
22671     fid_parse_if_arg_t fid_parse_if;
22672     fid_parse_while_arg_t fid_parse_while;
22673     fid_parse_ident_arg_t fid_parse_ident;
22674     fid_parse_ident_allow_reserved_words_arg_t
22675       fid_parse_ident_allow_reserved_words;
22676     fid_parse_arglist_arg_t fid_parse_arglist;
22677     fid_parse_memberexpr_arg_t fid_parse_memberexpr;
22678     fid_parse_var_arg_t fid_parse_var;
22679     fid_parse_prop_arg_t fid_parse_prop;
22680     fid_parse_dowhile_arg_t fid_parse_dowhile;
22681     fid_parse_for_arg_t fid_parse_for;
22682     fid_parse_try_arg_t fid_parse_try;
22683     fid_parse_switch_arg_t fid_parse_switch;
22684     fid_parse_with_arg_t fid_parse_with;
22685 #endif
22686     fid_parse_body_arg_t fid_parse_body;
22687     fid_parse_binary_arg_t fid_parse_binary;
22688     fid_parse_funcdecl_arg_t fid_parse_funcdecl;
22689     fid_parse_member_arg_t fid_parse_member;
22690   } arg;
22691 
22692   /* value returned from function */
22693   /*
22694      union {
22695      } ret;
22696      */
22697 };
22698 
22699 static enum v7_tok next_tok(struct v7 *v7) {
22700   int prev_line_no = v7->pstate.prev_line_no;
22701   v7->pstate.prev_line_no = v7->pstate.line_no;
22702   v7->pstate.line_no += skip_to_next_tok(&v7->pstate.pc, v7->pstate.src_end);
22703   v7->after_newline = prev_line_no != v7->pstate.line_no;
22704   v7->tok = v7->pstate.pc;
22705   v7->cur_tok = get_tok(&v7->pstate.pc, v7->pstate.src_end, &v7->cur_tok_dbl,
22706                         v7->cur_tok);
22707   v7->tok_len = v7->pstate.pc - v7->tok;
22708   v7->pstate.line_no += skip_to_next_tok(&v7->pstate.pc, v7->pstate.src_end);
22709   return v7->cur_tok;
22710 }
22711 
22712 #ifndef V7_DISABLE_LINE_NUMBERS
22713 /*
22714  * Assumes `offset` points to the byte right after a tag
22715  */
22716 static void insert_line_no_if_changed(struct v7 *v7, struct ast *a,
22717                                       ast_off_t offset) {
22718   if (v7->pstate.prev_line_no != v7->line_no) {
22719     v7->line_no = v7->pstate.prev_line_no;
22720     ast_add_line_no(a, offset - 1, v7->line_no);
22721   } else {
22722 #if V7_AST_FORCE_LINE_NUMBERS
22723     /*
22724      * This mode is needed for debug only: to make sure AST consumers correctly
22725      * consume all nodes with line numbers data encoded
22726      */
22727     ast_add_line_no(a, offset - 1, 0);
22728 #endif
22729   }
22730 }
22731 #else
22732 static void insert_line_no_if_changed(struct v7 *v7, struct ast *a,
22733                                       ast_off_t offset) {
22734   (void) v7;
22735   (void) a;
22736   (void) offset;
22737 }
22738 #endif
22739 
22740 static ast_off_t insert_node(struct v7 *v7, struct ast *a, ast_off_t start,
22741                              enum ast_tag tag) {
22742   ast_off_t ret = ast_insert_node(a, start, tag);
22743   insert_line_no_if_changed(v7, a, ret);
22744   return ret;
22745 }
22746 
22747 static ast_off_t add_node(struct v7 *v7, struct ast *a, enum ast_tag tag) {
22748   return insert_node(v7, a, a->mbuf.len, tag);
22749 }
22750 
22751 static ast_off_t insert_inlined_node(struct v7 *v7, struct ast *a,
22752                                      ast_off_t start, enum ast_tag tag,
22753                                      const char *name, size_t len) {
22754   ast_off_t ret = ast_insert_inlined_node(a, start, tag, name, len);
22755   insert_line_no_if_changed(v7, a, ret);
22756   return ret;
22757 }
22758 
22759 static ast_off_t add_inlined_node(struct v7 *v7, struct ast *a,
22760                                   enum ast_tag tag, const char *name,
22761                                   size_t len) {
22762   return insert_inlined_node(v7, a, a->mbuf.len, tag, name, len);
22763 }
22764 
22765 static unsigned long get_column(const char *code, const char *pos) {
22766   const char *p = pos;
22767   while (p > code && *p != '\n') {
22768     p--;
22769   }
22770   return p == code ? pos - p : pos - (p + 1);
22771 }
22772 
22773 static enum v7_err end_of_statement(struct v7 *v7) {
22774   if (v7->cur_tok == TOK_SEMICOLON || v7->cur_tok == TOK_END_OF_INPUT ||
22775       v7->cur_tok == TOK_CLOSE_CURLY || v7->after_newline) {
22776     return V7_OK;
22777   }
22778   return V7_SYNTAX_ERROR;
22779 }
22780 
22781 static enum v7_tok lookahead(const struct v7 *v7) {
22782   const char *s = v7->pstate.pc;
22783   double d;
22784   return get_tok(&s, v7->pstate.src_end, &d, v7->cur_tok);
22785 }
22786 
22787 static int parse_optional(struct v7 *v7, struct ast *a,
22788                           enum v7_tok terminator) {
22789   if (v7->cur_tok != terminator) {
22790     return 1;
22791   }
22792   add_node(v7, a, AST_NOP);
22793   return 0;
22794 }
22795 
22796 /*
22797  * On ESP8266 'levels' declaration have to be outside of 'parse_binary'
22798  * in order to prevent reboot on return from this function
22799  * TODO(alashkin): understand why
22800  */
22801 #define NONE \
22802   { (enum v7_tok) 0, (enum v7_tok) 0, (enum ast_tag) 0 }
22803 
22804 static const struct {
22805   int len, left_to_right;
22806   struct {
22807     enum v7_tok start_tok, end_tok;
22808     enum ast_tag start_ast;
22809   } parts[2];
22810 } levels[] = {
22811     {1, 0, {{TOK_ASSIGN, TOK_URSHIFT_ASSIGN, AST_ASSIGN}, NONE}},
22812     {1, 0, {{TOK_QUESTION, TOK_QUESTION, AST_COND}, NONE}},
22813     {1, 1, {{TOK_LOGICAL_OR, TOK_LOGICAL_OR, AST_LOGICAL_OR}, NONE}},
22814     {1, 1, {{TOK_LOGICAL_AND, TOK_LOGICAL_AND, AST_LOGICAL_AND}, NONE}},
22815     {1, 1, {{TOK_OR, TOK_OR, AST_OR}, NONE}},
22816     {1, 1, {{TOK_XOR, TOK_XOR, AST_XOR}, NONE}},
22817     {1, 1, {{TOK_AND, TOK_AND, AST_AND}, NONE}},
22818     {1, 1, {{TOK_EQ, TOK_NE_NE, AST_EQ}, NONE}},
22819     {2, 1, {{TOK_LE, TOK_GT, AST_LE}, {TOK_IN, TOK_INSTANCEOF, AST_IN}}},
22820     {1, 1, {{TOK_LSHIFT, TOK_URSHIFT, AST_LSHIFT}, NONE}},
22821     {1, 1, {{TOK_PLUS, TOK_MINUS, AST_ADD}, NONE}},
22822     {1, 1, {{TOK_REM, TOK_DIV, AST_REM}, NONE}}};
22823 
22824 enum cr_status parser_cr_exec(struct cr_ctx *p_ctx, struct v7 *v7,
22825                               struct ast *a) {
22826   enum cr_status rc = CR_RES__OK;
22827 
22828 _cr_iter_begin:
22829 
22830   rc = cr_on_iter_begin(p_ctx);
22831   if (rc != CR_RES__OK) {
22832     return rc;
22833   }
22834 
22835   /*
22836    * dispatcher switch: depending on the fid, jump to the corresponding label
22837    */
22838   switch ((enum my_fid) CR_CURR_FUNC()) {
22839     CR_DEFINE_ENTRY_POINT(fid_none);
22840 
22841     CR_DEFINE_ENTRY_POINT(fid_parse_script);
22842     CR_DEFINE_ENTRY_POINT(fid_p_script_1);
22843     CR_DEFINE_ENTRY_POINT(fid_p_script_2);
22844     CR_DEFINE_ENTRY_POINT(fid_p_script_3);
22845     CR_DEFINE_ENTRY_POINT(fid_p_script_4);
22846 
22847     CR_DEFINE_ENTRY_POINT(fid_parse_use_strict);
22848 
22849     CR_DEFINE_ENTRY_POINT(fid_parse_body);
22850     CR_DEFINE_ENTRY_POINT(fid_p_body_1);
22851     CR_DEFINE_ENTRY_POINT(fid_p_body_2);
22852 
22853     CR_DEFINE_ENTRY_POINT(fid_parse_statement);
22854     CR_DEFINE_ENTRY_POINT(fid_p_stat_1);
22855     CR_DEFINE_ENTRY_POINT(fid_p_stat_2);
22856     CR_DEFINE_ENTRY_POINT(fid_p_stat_3);
22857     CR_DEFINE_ENTRY_POINT(fid_p_stat_4);
22858     CR_DEFINE_ENTRY_POINT(fid_p_stat_5);
22859     CR_DEFINE_ENTRY_POINT(fid_p_stat_6);
22860     CR_DEFINE_ENTRY_POINT(fid_p_stat_7);
22861     CR_DEFINE_ENTRY_POINT(fid_p_stat_8);
22862     CR_DEFINE_ENTRY_POINT(fid_p_stat_9);
22863     CR_DEFINE_ENTRY_POINT(fid_p_stat_10);
22864     CR_DEFINE_ENTRY_POINT(fid_p_stat_11);
22865     CR_DEFINE_ENTRY_POINT(fid_p_stat_12);
22866     CR_DEFINE_ENTRY_POINT(fid_p_stat_13);
22867     CR_DEFINE_ENTRY_POINT(fid_p_stat_14);
22868 
22869     CR_DEFINE_ENTRY_POINT(fid_parse_expression);
22870     CR_DEFINE_ENTRY_POINT(fid_p_expr_1);
22871 
22872     CR_DEFINE_ENTRY_POINT(fid_parse_assign);
22873     CR_DEFINE_ENTRY_POINT(fid_p_assign_1);
22874 
22875     CR_DEFINE_ENTRY_POINT(fid_parse_binary);
22876     CR_DEFINE_ENTRY_POINT(fid_p_binary_2);
22877     CR_DEFINE_ENTRY_POINT(fid_p_binary_3);
22878     CR_DEFINE_ENTRY_POINT(fid_p_binary_4);
22879     CR_DEFINE_ENTRY_POINT(fid_p_binary_5);
22880     CR_DEFINE_ENTRY_POINT(fid_p_binary_6);
22881 
22882     CR_DEFINE_ENTRY_POINT(fid_parse_prefix);
22883     CR_DEFINE_ENTRY_POINT(fid_p_prefix_1);
22884 
22885     CR_DEFINE_ENTRY_POINT(fid_parse_postfix);
22886     CR_DEFINE_ENTRY_POINT(fid_p_postfix_1);
22887 
22888     CR_DEFINE_ENTRY_POINT(fid_parse_callexpr);
22889     CR_DEFINE_ENTRY_POINT(fid_p_callexpr_1);
22890     CR_DEFINE_ENTRY_POINT(fid_p_callexpr_2);
22891     CR_DEFINE_ENTRY_POINT(fid_p_callexpr_3);
22892 
22893     CR_DEFINE_ENTRY_POINT(fid_parse_newexpr);
22894     CR_DEFINE_ENTRY_POINT(fid_p_newexpr_1);
22895     CR_DEFINE_ENTRY_POINT(fid_p_newexpr_2);
22896     CR_DEFINE_ENTRY_POINT(fid_p_newexpr_3);
22897     CR_DEFINE_ENTRY_POINT(fid_p_newexpr_4);
22898 
22899     CR_DEFINE_ENTRY_POINT(fid_parse_terminal);
22900     CR_DEFINE_ENTRY_POINT(fid_p_terminal_1);
22901     CR_DEFINE_ENTRY_POINT(fid_p_terminal_2);
22902     CR_DEFINE_ENTRY_POINT(fid_p_terminal_3);
22903     CR_DEFINE_ENTRY_POINT(fid_p_terminal_4);
22904 
22905     CR_DEFINE_ENTRY_POINT(fid_parse_block);
22906     CR_DEFINE_ENTRY_POINT(fid_p_block_1);
22907 
22908     CR_DEFINE_ENTRY_POINT(fid_parse_if);
22909     CR_DEFINE_ENTRY_POINT(fid_p_if_1);
22910     CR_DEFINE_ENTRY_POINT(fid_p_if_2);
22911     CR_DEFINE_ENTRY_POINT(fid_p_if_3);
22912 
22913     CR_DEFINE_ENTRY_POINT(fid_parse_while);
22914     CR_DEFINE_ENTRY_POINT(fid_p_while_1);
22915     CR_DEFINE_ENTRY_POINT(fid_p_while_2);
22916 
22917     CR_DEFINE_ENTRY_POINT(fid_parse_ident);
22918 
22919     CR_DEFINE_ENTRY_POINT(fid_parse_ident_allow_reserved_words);
22920     CR_DEFINE_ENTRY_POINT(fid_p_ident_arw_1);
22921 
22922     CR_DEFINE_ENTRY_POINT(fid_parse_funcdecl);
22923     CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_1);
22924     CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_2);
22925     CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_3);
22926     CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_4);
22927     CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_5);
22928     CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_6);
22929     CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_7);
22930     CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_8);
22931     CR_DEFINE_ENTRY_POINT(fid_p_funcdecl_9);
22932 
22933     CR_DEFINE_ENTRY_POINT(fid_parse_arglist);
22934     CR_DEFINE_ENTRY_POINT(fid_p_arglist_1);
22935 
22936     CR_DEFINE_ENTRY_POINT(fid_parse_member);
22937     CR_DEFINE_ENTRY_POINT(fid_p_member_1);
22938 
22939     CR_DEFINE_ENTRY_POINT(fid_parse_memberexpr);
22940     CR_DEFINE_ENTRY_POINT(fid_p_memberexpr_1);
22941     CR_DEFINE_ENTRY_POINT(fid_p_memberexpr_2);
22942 
22943     CR_DEFINE_ENTRY_POINT(fid_parse_var);
22944     CR_DEFINE_ENTRY_POINT(fid_p_var_1);
22945 
22946     CR_DEFINE_ENTRY_POINT(fid_parse_prop);
22947 #ifdef V7_ENABLE_JS_GETTERS
22948     CR_DEFINE_ENTRY_POINT(fid_p_prop_1_getter);
22949 #endif
22950     CR_DEFINE_ENTRY_POINT(fid_p_prop_2);
22951 #ifdef V7_ENABLE_JS_SETTERS
22952     CR_DEFINE_ENTRY_POINT(fid_p_prop_3_setter);
22953 #endif
22954     CR_DEFINE_ENTRY_POINT(fid_p_prop_4);
22955 
22956     CR_DEFINE_ENTRY_POINT(fid_parse_dowhile);
22957     CR_DEFINE_ENTRY_POINT(fid_p_dowhile_1);
22958     CR_DEFINE_ENTRY_POINT(fid_p_dowhile_2);
22959 
22960     CR_DEFINE_ENTRY_POINT(fid_parse_for);
22961     CR_DEFINE_ENTRY_POINT(fid_p_for_1);
22962     CR_DEFINE_ENTRY_POINT(fid_p_for_2);
22963     CR_DEFINE_ENTRY_POINT(fid_p_for_3);
22964     CR_DEFINE_ENTRY_POINT(fid_p_for_4);
22965     CR_DEFINE_ENTRY_POINT(fid_p_for_5);
22966     CR_DEFINE_ENTRY_POINT(fid_p_for_6);
22967 
22968     CR_DEFINE_ENTRY_POINT(fid_parse_try);
22969     CR_DEFINE_ENTRY_POINT(fid_p_try_1);
22970     CR_DEFINE_ENTRY_POINT(fid_p_try_2);
22971     CR_DEFINE_ENTRY_POINT(fid_p_try_3);
22972     CR_DEFINE_ENTRY_POINT(fid_p_try_4);
22973 
22974     CR_DEFINE_ENTRY_POINT(fid_parse_switch);
22975     CR_DEFINE_ENTRY_POINT(fid_p_switch_1);
22976     CR_DEFINE_ENTRY_POINT(fid_p_switch_2);
22977     CR_DEFINE_ENTRY_POINT(fid_p_switch_3);
22978     CR_DEFINE_ENTRY_POINT(fid_p_switch_4);
22979 
22980     CR_DEFINE_ENTRY_POINT(fid_parse_with);
22981     CR_DEFINE_ENTRY_POINT(fid_p_with_1);
22982     CR_DEFINE_ENTRY_POINT(fid_p_with_2);
22983 
22984     default:
22985       /* should never be here */
22986       printf("fatal: wrong func id: %d", CR_CURR_FUNC());
22987       break;
22988   };
22989 
22990 /* static enum v7_err parse_script(struct v7 *v7, struct ast *a) */
22991 fid_parse_script :
22992 #undef L
22993 #define L CR_CUR_LOCALS_PT(fid_parse_script_locals_t)
22994 {
22995   L->start = add_node(v7, a, AST_SCRIPT);
22996   L->outer_last_var_node = v7->last_var_node;
22997   L->saved_in_strict = v7->pstate.in_strict;
22998 
22999   v7->last_var_node = L->start;
23000   ast_modify_skip(a, L->start, L->start, AST_FUNC_FIRST_VAR_SKIP);
23001 
23002   CR_TRY(fid_p_script_1);
23003   {
23004     CALL_PARSE_USE_STRICT(fid_p_script_3);
23005     v7->pstate.in_strict = 1;
23006   }
23007   CR_CATCH(PARSER_EXC_ID__SYNTAX_ERROR, fid_p_script_1, fid_p_script_2);
23008   CR_ENDCATCH(fid_p_script_2);
23009 
23010   CALL_PARSE_BODY(TOK_END_OF_INPUT, fid_p_script_4);
23011   ast_set_skip(a, L->start, AST_END_SKIP);
23012   v7->pstate.in_strict = L->saved_in_strict;
23013   v7->last_var_node = L->outer_last_var_node;
23014 
23015   CR_RETURN_VOID();
23016 }
23017 
23018 /* static enum v7_err parse_use_strict(struct v7 *v7, struct ast *a) */
23019 fid_parse_use_strict :
23020 #undef L
23021 #define L CR_CUR_LOCALS_PT(fid_parse_use_strict_locals_t)
23022 {
23023   if (v7->cur_tok == TOK_STRING_LITERAL &&
23024       (strncmp(v7->tok, "\"use strict\"", v7->tok_len) == 0 ||
23025        strncmp(v7->tok, "'use strict'", v7->tok_len) == 0)) {
23026     next_tok(v7);
23027     add_node(v7, a, AST_USE_STRICT);
23028     CR_RETURN_VOID();
23029   } else {
23030     CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23031   }
23032 }
23033 
23034 /*
23035  * static enum v7_err parse_body(struct v7 *v7, struct ast *a,
23036  *                               enum v7_tok end)
23037  */
23038 fid_parse_body :
23039 #undef L
23040 #define L CR_CUR_LOCALS_PT(fid_parse_body_locals_t)
23041 {
23042   while (v7->cur_tok != L->arg.end) {
23043     if (ACCEPT(TOK_FUNCTION)) {
23044       if (v7->cur_tok != TOK_IDENTIFIER) {
23045         CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23046       }
23047       L->start = add_node(v7, a, AST_VAR);
23048       ast_modify_skip(a, v7->last_var_node, L->start, AST_FUNC_FIRST_VAR_SKIP);
23049       /* zero out var node pointer */
23050       ast_modify_skip(a, L->start, L->start, AST_FUNC_FIRST_VAR_SKIP);
23051       v7->last_var_node = L->start;
23052       add_inlined_node(v7, a, AST_FUNC_DECL, v7->tok, v7->tok_len);
23053 
23054       CALL_PARSE_FUNCDECL(1, 0, fid_p_body_1);
23055       ast_set_skip(a, L->start, AST_END_SKIP);
23056     } else {
23057       CALL_PARSE_STATEMENT(fid_p_body_2);
23058     }
23059   }
23060   CR_RETURN_VOID();
23061 }
23062 
23063 /* static enum v7_err parse_statement(struct v7 *v7, struct ast *a) */
23064 fid_parse_statement :
23065 #undef L
23066 #define L CR_CUR_LOCALS_PT(fid_parse_statement_locals_t)
23067 {
23068   switch (v7->cur_tok) {
23069     case TOK_SEMICOLON:
23070       next_tok(v7);
23071       /* empty statement */
23072       CR_RETURN_VOID();
23073     case TOK_OPEN_CURLY: /* block */
23074       CALL_PARSE_BLOCK(fid_p_stat_3);
23075       /* returning because no semicolon required */
23076       CR_RETURN_VOID();
23077     case TOK_IF:
23078       next_tok(v7);
23079       CALL_PARSE_IF(fid_p_stat_4);
23080       CR_RETURN_VOID();
23081     case TOK_WHILE:
23082       next_tok(v7);
23083       CALL_PARSE_WHILE(fid_p_stat_5);
23084       CR_RETURN_VOID();
23085     case TOK_DO:
23086       next_tok(v7);
23087       CALL_PARSE_DOWHILE(fid_p_stat_10);
23088       CR_RETURN_VOID();
23089     case TOK_FOR:
23090       next_tok(v7);
23091       CALL_PARSE_FOR(fid_p_stat_11);
23092       CR_RETURN_VOID();
23093     case TOK_TRY:
23094       next_tok(v7);
23095       CALL_PARSE_TRY(fid_p_stat_12);
23096       CR_RETURN_VOID();
23097     case TOK_SWITCH:
23098       next_tok(v7);
23099       CALL_PARSE_SWITCH(fid_p_stat_13);
23100       CR_RETURN_VOID();
23101     case TOK_WITH:
23102       next_tok(v7);
23103       CALL_PARSE_WITH(fid_p_stat_14);
23104       CR_RETURN_VOID();
23105     case TOK_BREAK:
23106       if (!(v7->pstate.in_loop || v7->pstate.in_switch)) {
23107         CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23108       }
23109       next_tok(v7);
23110       PARSE_WITH_OPT_ARG(AST_BREAK, AST_LABELED_BREAK, CALL_PARSE_IDENT,
23111                          fid_p_stat_7);
23112       break;
23113     case TOK_CONTINUE:
23114       if (!v7->pstate.in_loop) {
23115         CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23116       }
23117       next_tok(v7);
23118       PARSE_WITH_OPT_ARG(AST_CONTINUE, AST_LABELED_CONTINUE, CALL_PARSE_IDENT,
23119                          fid_p_stat_8);
23120       break;
23121     case TOK_RETURN:
23122       if (!v7->pstate.in_function) {
23123         CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23124       }
23125       next_tok(v7);
23126       PARSE_WITH_OPT_ARG(AST_RETURN, AST_VALUE_RETURN, CALL_PARSE_EXPRESSION,
23127                          fid_p_stat_6);
23128       break;
23129     case TOK_THROW:
23130       next_tok(v7);
23131       add_node(v7, a, AST_THROW);
23132       CALL_PARSE_EXPRESSION(fid_p_stat_2);
23133       break;
23134     case TOK_DEBUGGER:
23135       next_tok(v7);
23136       add_node(v7, a, AST_DEBUGGER);
23137       break;
23138     case TOK_VAR:
23139       next_tok(v7);
23140       CALL_PARSE_VAR(fid_p_stat_9);
23141       break;
23142     case TOK_IDENTIFIER:
23143       if (lookahead(v7) == TOK_COLON) {
23144         add_inlined_node(v7, a, AST_LABEL, v7->tok, v7->tok_len);
23145         next_tok(v7);
23146         EXPECT(TOK_COLON);
23147         CR_RETURN_VOID();
23148       }
23149     /* fall through */
23150     default:
23151       CALL_PARSE_EXPRESSION(fid_p_stat_1);
23152       break;
23153   }
23154 
23155   if (end_of_statement(v7) != V7_OK) {
23156     CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23157   }
23158   ACCEPT(TOK_SEMICOLON); /* swallow optional semicolon */
23159   CR_RETURN_VOID();
23160 }
23161 
23162 /* static enum v7_err parse_expression(struct v7 *v7, struct ast *a) */
23163 fid_parse_expression :
23164 #undef L
23165 #define L CR_CUR_LOCALS_PT(fid_parse_expression_locals_t)
23166 {
23167   L->pos = a->mbuf.len;
23168   L->group = 0;
23169   while (1) {
23170     CALL_PARSE_ASSIGN(fid_p_expr_1);
23171     if (ACCEPT(TOK_COMMA)) {
23172       L->group = 1;
23173     } else {
23174       break;
23175     }
23176   }
23177   if (L->group) {
23178     insert_node(v7, a, L->pos, AST_SEQ);
23179   }
23180   CR_RETURN_VOID();
23181 }
23182 
23183 /* static enum v7_err parse_assign(struct v7 *v7, struct ast *a) */
23184 fid_parse_assign :
23185 #undef L
23186 #define L CR_CUR_LOCALS_PT(fid_parse_assign_locals_t)
23187 {
23188   CALL_PARSE_BINARY(0, a->mbuf.len, fid_p_assign_1);
23189   CR_RETURN_VOID();
23190 }
23191 
23192 /*
23193  * static enum v7_err parse_binary(struct v7 *v7, struct ast *a, int level,
23194  *                                 ast_off_t pos)
23195  */
23196 #if 1
23197 fid_parse_binary :
23198 #undef L
23199 #define L CR_CUR_LOCALS_PT(fid_parse_binary_locals_t)
23200 {
23201 /*
23202  * Note: we use macro CUR_POS instead of a local variable, since this
23203  * function is called really a lot, so, each byte on stack frame counts.
23204  *
23205  * It will work a bit slower of course, but slowness is not a problem
23206  */
23207 #define CUR_POS ((L->level > L->arg.min_level) ? L->saved_mbuf_len : L->arg.pos)
23208   L->saved_mbuf_len = a->mbuf.len;
23209 
23210   CALL_PARSE_PREFIX(fid_p_binary_6);
23211 
23212   for (L->level = (int) ARRAY_SIZE(levels) - 1; L->level >= L->arg.min_level;
23213        L->level--) {
23214     for (L->i = 0; L->i < levels[L->level].len; L->i++) {
23215       L->tok = levels[L->level].parts[L->i].start_tok;
23216       L->ast = levels[L->level].parts[L->i].start_ast;
23217       do {
23218         if (v7->pstate.inhibit_in && L->tok == TOK_IN) {
23219           continue;
23220         }
23221 
23222         /*
23223          * Ternary operator sits in the middle of the binary operator
23224          * precedence chain. Deal with it as an exception and don't break
23225          * the chain.
23226          */
23227         if (L->tok == TOK_QUESTION && v7->cur_tok == TOK_QUESTION) {
23228           next_tok(v7);
23229           CALL_PARSE_ASSIGN(fid_p_binary_2);
23230           EXPECT(TOK_COLON);
23231           CALL_PARSE_ASSIGN(fid_p_binary_3);
23232           insert_node(v7, a, CUR_POS, AST_COND);
23233           CR_RETURN_VOID();
23234         } else if (ACCEPT(L->tok)) {
23235           if (levels[L->level].left_to_right) {
23236             insert_node(v7, a, CUR_POS, (enum ast_tag) L->ast);
23237             CALL_PARSE_BINARY(L->level, CUR_POS, fid_p_binary_4);
23238           } else {
23239             CALL_PARSE_BINARY(L->level, a->mbuf.len, fid_p_binary_5);
23240             insert_node(v7, a, CUR_POS, (enum ast_tag) L->ast);
23241           }
23242         }
23243       } while (L->ast = (enum ast_tag)(L->ast + 1),
23244                L->tok < levels[L->level].parts[L->i].end_tok &&
23245                    (L->tok = (enum v7_tok)(L->tok + 1)));
23246     }
23247   }
23248 
23249   CR_RETURN_VOID();
23250 #undef CUR_POS
23251 }
23252 #endif
23253 
23254 /* enum v7_err parse_prefix(struct v7 *v7, struct ast *a) */
23255 fid_parse_prefix :
23256 #undef L
23257 #define L CR_CUR_LOCALS_PT(fid_parse_prefix_locals_t)
23258 {
23259   for (;;) {
23260     switch (v7->cur_tok) {
23261       case TOK_PLUS:
23262         next_tok(v7);
23263         add_node(v7, a, AST_POSITIVE);
23264         break;
23265       case TOK_MINUS:
23266         next_tok(v7);
23267         add_node(v7, a, AST_NEGATIVE);
23268         break;
23269       case TOK_PLUS_PLUS:
23270         next_tok(v7);
23271         add_node(v7, a, AST_PREINC);
23272         break;
23273       case TOK_MINUS_MINUS:
23274         next_tok(v7);
23275         add_node(v7, a, AST_PREDEC);
23276         break;
23277       case TOK_TILDA:
23278         next_tok(v7);
23279         add_node(v7, a, AST_NOT);
23280         break;
23281       case TOK_NOT:
23282         next_tok(v7);
23283         add_node(v7, a, AST_LOGICAL_NOT);
23284         break;
23285       case TOK_VOID:
23286         next_tok(v7);
23287         add_node(v7, a, AST_VOID);
23288         break;
23289       case TOK_DELETE:
23290         next_tok(v7);
23291         add_node(v7, a, AST_DELETE);
23292         break;
23293       case TOK_TYPEOF:
23294         next_tok(v7);
23295         add_node(v7, a, AST_TYPEOF);
23296         break;
23297       default:
23298         CALL_PARSE_POSTFIX(fid_p_prefix_1);
23299         CR_RETURN_VOID();
23300     }
23301   }
23302 }
23303 
23304 /* static enum v7_err parse_postfix(struct v7 *v7, struct ast *a) */
23305 fid_parse_postfix :
23306 #undef L
23307 #define L CR_CUR_LOCALS_PT(fid_parse_postfix_locals_t)
23308 {
23309   L->pos = a->mbuf.len;
23310   CALL_PARSE_CALLEXPR(fid_p_postfix_1);
23311 
23312   if (v7->after_newline) {
23313     CR_RETURN_VOID();
23314   }
23315   switch (v7->cur_tok) {
23316     case TOK_PLUS_PLUS:
23317       next_tok(v7);
23318       insert_node(v7, a, L->pos, AST_POSTINC);
23319       break;
23320     case TOK_MINUS_MINUS:
23321       next_tok(v7);
23322       insert_node(v7, a, L->pos, AST_POSTDEC);
23323       break;
23324     default:
23325       break; /* nothing */
23326   }
23327   CR_RETURN_VOID();
23328 }
23329 
23330 /* static enum v7_err parse_callexpr(struct v7 *v7, struct ast *a) */
23331 fid_parse_callexpr :
23332 #undef L
23333 #define L CR_CUR_LOCALS_PT(fid_parse_callexpr_locals_t)
23334 {
23335   L->pos = a->mbuf.len;
23336   CALL_PARSE_NEWEXPR(fid_p_callexpr_1);
23337 
23338   for (;;) {
23339     switch (v7->cur_tok) {
23340       case TOK_DOT:
23341       case TOK_OPEN_BRACKET:
23342         CALL_PARSE_MEMBER(L->pos, fid_p_callexpr_3);
23343         break;
23344       case TOK_OPEN_PAREN:
23345         next_tok(v7);
23346         CALL_PARSE_ARGLIST(fid_p_callexpr_2);
23347         EXPECT(TOK_CLOSE_PAREN);
23348         insert_node(v7, a, L->pos, AST_CALL);
23349         break;
23350       default:
23351         CR_RETURN_VOID();
23352     }
23353   }
23354 }
23355 
23356 /* static enum v7_err parse_newexpr(struct v7 *v7, struct ast *a) */
23357 fid_parse_newexpr :
23358 #undef L
23359 #define L CR_CUR_LOCALS_PT(fid_parse_newexpr_locals_t)
23360 {
23361   switch (v7->cur_tok) {
23362     case TOK_NEW:
23363       next_tok(v7);
23364       L->start = add_node(v7, a, AST_NEW);
23365       CALL_PARSE_MEMBEREXPR(fid_p_newexpr_3);
23366       if (ACCEPT(TOK_OPEN_PAREN)) {
23367         CALL_PARSE_ARGLIST(fid_p_newexpr_4);
23368         EXPECT(TOK_CLOSE_PAREN);
23369       }
23370       ast_set_skip(a, L->start, AST_END_SKIP);
23371       break;
23372     case TOK_FUNCTION:
23373       next_tok(v7);
23374       CALL_PARSE_FUNCDECL(0, 0, fid_p_newexpr_2);
23375       break;
23376     default:
23377       CALL_PARSE_TERMINAL(fid_p_newexpr_1);
23378       break;
23379   }
23380   CR_RETURN_VOID();
23381 }
23382 
23383 /* static enum v7_err parse_terminal(struct v7 *v7, struct ast *a) */
23384 fid_parse_terminal :
23385 #undef L
23386 #define L CR_CUR_LOCALS_PT(fid_parse_terminal_locals_t)
23387 {
23388   switch (v7->cur_tok) {
23389     case TOK_OPEN_PAREN:
23390       next_tok(v7);
23391       CALL_PARSE_EXPRESSION(fid_p_terminal_1);
23392       EXPECT(TOK_CLOSE_PAREN);
23393       break;
23394     case TOK_OPEN_BRACKET:
23395       next_tok(v7);
23396       L->start = add_node(v7, a, AST_ARRAY);
23397       while (v7->cur_tok != TOK_CLOSE_BRACKET) {
23398         if (v7->cur_tok == TOK_COMMA) {
23399           /* Array literals allow missing elements, e.g. [,,1,] */
23400           add_node(v7, a, AST_NOP);
23401         } else {
23402           CALL_PARSE_ASSIGN(fid_p_terminal_2);
23403         }
23404         ACCEPT(TOK_COMMA);
23405       }
23406       EXPECT(TOK_CLOSE_BRACKET);
23407       ast_set_skip(a, L->start, AST_END_SKIP);
23408       break;
23409     case TOK_OPEN_CURLY:
23410       next_tok(v7);
23411       L->start = add_node(v7, a, AST_OBJECT);
23412       if (v7->cur_tok != TOK_CLOSE_CURLY) {
23413         do {
23414           if (v7->cur_tok == TOK_CLOSE_CURLY) {
23415             break;
23416           }
23417           CALL_PARSE_PROP(fid_p_terminal_3);
23418         } while (ACCEPT(TOK_COMMA));
23419       }
23420       EXPECT(TOK_CLOSE_CURLY);
23421       ast_set_skip(a, L->start, AST_END_SKIP);
23422       break;
23423     case TOK_THIS:
23424       next_tok(v7);
23425       add_node(v7, a, AST_THIS);
23426       break;
23427     case TOK_TRUE:
23428       next_tok(v7);
23429       add_node(v7, a, AST_TRUE);
23430       break;
23431     case TOK_FALSE:
23432       next_tok(v7);
23433       add_node(v7, a, AST_FALSE);
23434       break;
23435     case TOK_NULL:
23436       next_tok(v7);
23437       add_node(v7, a, AST_NULL);
23438       break;
23439     case TOK_STRING_LITERAL:
23440       add_inlined_node(v7, a, AST_STRING, v7->tok + 1, v7->tok_len - 2);
23441       next_tok(v7);
23442       break;
23443     case TOK_NUMBER:
23444       add_inlined_node(v7, a, AST_NUM, v7->tok, v7->tok_len);
23445       next_tok(v7);
23446       break;
23447     case TOK_REGEX_LITERAL:
23448       add_inlined_node(v7, a, AST_REGEX, v7->tok, v7->tok_len);
23449       next_tok(v7);
23450       break;
23451     case TOK_IDENTIFIER:
23452       if (v7->tok_len == 9 && strncmp(v7->tok, "undefined", v7->tok_len) == 0) {
23453         add_node(v7, a, AST_UNDEFINED);
23454         next_tok(v7);
23455         break;
23456       }
23457     /* fall through */
23458     default:
23459       CALL_PARSE_IDENT(fid_p_terminal_4);
23460   }
23461   CR_RETURN_VOID();
23462 }
23463 
23464 /* static enum v7_err parse_block(struct v7 *v7, struct ast *a) */
23465 fid_parse_block :
23466 #undef L
23467 #define L CR_CUR_LOCALS_PT(fid_parse_block_locals_t)
23468 {
23469   EXPECT(TOK_OPEN_CURLY);
23470   CALL_PARSE_BODY(TOK_CLOSE_CURLY, fid_p_block_1);
23471   EXPECT(TOK_CLOSE_CURLY);
23472   CR_RETURN_VOID();
23473 }
23474 
23475 /* static enum v7_err parse_if(struct v7 *v7, struct ast *a) */
23476 fid_parse_if :
23477 #undef L
23478 #define L CR_CUR_LOCALS_PT(fid_parse_if_locals_t)
23479 {
23480   L->start = add_node(v7, a, AST_IF);
23481   EXPECT(TOK_OPEN_PAREN);
23482   CALL_PARSE_EXPRESSION(fid_p_if_1);
23483   EXPECT(TOK_CLOSE_PAREN);
23484   CALL_PARSE_STATEMENT(fid_p_if_2);
23485   ast_set_skip(a, L->start, AST_END_IF_TRUE_SKIP);
23486   if (ACCEPT(TOK_ELSE)) {
23487     CALL_PARSE_STATEMENT(fid_p_if_3);
23488   }
23489   ast_set_skip(a, L->start, AST_END_SKIP);
23490   CR_RETURN_VOID();
23491 }
23492 
23493 /* static enum v7_err parse_while(struct v7 *v7, struct ast *a) */
23494 fid_parse_while :
23495 #undef L
23496 #define L CR_CUR_LOCALS_PT(fid_parse_while_locals_t)
23497 {
23498   L->start = add_node(v7, a, AST_WHILE);
23499   L->saved_in_loop = v7->pstate.in_loop;
23500   EXPECT(TOK_OPEN_PAREN);
23501   CALL_PARSE_EXPRESSION(fid_p_while_1);
23502   EXPECT(TOK_CLOSE_PAREN);
23503   v7->pstate.in_loop = 1;
23504   CALL_PARSE_STATEMENT(fid_p_while_2);
23505   ast_set_skip(a, L->start, AST_END_SKIP);
23506   v7->pstate.in_loop = L->saved_in_loop;
23507   CR_RETURN_VOID();
23508 }
23509 
23510 /* static enum v7_err parse_ident(struct v7 *v7, struct ast *a) */
23511 fid_parse_ident :
23512 #undef L
23513 #define L CR_CUR_LOCALS_PT(fid_parse_ident_locals_t)
23514 {
23515   if (v7->cur_tok == TOK_IDENTIFIER) {
23516     add_inlined_node(v7, a, AST_IDENT, v7->tok, v7->tok_len);
23517     next_tok(v7);
23518     CR_RETURN_VOID();
23519   }
23520   CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23521 }
23522 
23523 /*
23524  * static enum v7_err parse_ident_allow_reserved_words(struct v7 *v7,
23525  *                                                     struct ast *a)
23526  *
23527  */
23528 fid_parse_ident_allow_reserved_words :
23529 #undef L
23530 #define L CR_CUR_LOCALS_PT(fid_parse_ident_allow_reserved_words_locals_t)
23531 {
23532   /* Allow reserved words as property names. */
23533   if (is_reserved_word_token(v7->cur_tok)) {
23534     add_inlined_node(v7, a, AST_IDENT, v7->tok, v7->tok_len);
23535     next_tok(v7);
23536   } else {
23537     CALL_PARSE_IDENT(fid_p_ident_arw_1);
23538   }
23539   CR_RETURN_VOID();
23540 }
23541 
23542 /* static enum v7_err parse_funcdecl(struct v7 *, struct ast *, int, int) */
23543 fid_parse_funcdecl :
23544 #undef L
23545 #define L CR_CUR_LOCALS_PT(fid_parse_funcdecl_locals_t)
23546 {
23547   L->start = add_node(v7, a, AST_FUNC);
23548   L->outer_last_var_node = v7->last_var_node;
23549   L->saved_in_function = v7->pstate.in_function;
23550   L->saved_in_strict = v7->pstate.in_strict;
23551 
23552   v7->last_var_node = L->start;
23553   ast_modify_skip(a, L->start, L->start, AST_FUNC_FIRST_VAR_SKIP);
23554 
23555   CR_TRY(fid_p_funcdecl_2);
23556   {
23557     if (L->arg.reserved_name) {
23558       CALL_PARSE_IDENT_ALLOW_RESERVED_WORDS(fid_p_funcdecl_1);
23559     } else {
23560       CALL_PARSE_IDENT(fid_p_funcdecl_9);
23561     }
23562   }
23563   CR_CATCH(PARSER_EXC_ID__SYNTAX_ERROR, fid_p_funcdecl_2, fid_p_funcdecl_3);
23564   {
23565     if (L->arg.require_named) {
23566       /* function name is required, so, rethrow SYNTAX ERROR */
23567       CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23568     } else {
23569       /* it's ok not to have a function name, just insert NOP */
23570       add_node(v7, a, AST_NOP);
23571     }
23572   }
23573   CR_ENDCATCH(fid_p_funcdecl_3);
23574 
23575   EXPECT(TOK_OPEN_PAREN);
23576   CALL_PARSE_ARGLIST(fid_p_funcdecl_4);
23577   EXPECT(TOK_CLOSE_PAREN);
23578   ast_set_skip(a, L->start, AST_FUNC_BODY_SKIP);
23579   v7->pstate.in_function = 1;
23580   EXPECT(TOK_OPEN_CURLY);
23581 
23582   CR_TRY(fid_p_funcdecl_5);
23583   {
23584     CALL_PARSE_USE_STRICT(fid_p_funcdecl_7);
23585     v7->pstate.in_strict = 1;
23586   }
23587   CR_CATCH(PARSER_EXC_ID__SYNTAX_ERROR, fid_p_funcdecl_5, fid_p_funcdecl_6);
23588   CR_ENDCATCH(fid_p_funcdecl_6);
23589 
23590   CALL_PARSE_BODY(TOK_CLOSE_CURLY, fid_p_funcdecl_8);
23591   EXPECT(TOK_CLOSE_CURLY);
23592   v7->pstate.in_strict = L->saved_in_strict;
23593   v7->pstate.in_function = L->saved_in_function;
23594   ast_set_skip(a, L->start, AST_END_SKIP);
23595   v7->last_var_node = L->outer_last_var_node;
23596 
23597   CR_RETURN_VOID();
23598 }
23599 
23600 /* static enum v7_err parse_arglist(struct v7 *v7, struct ast *a) */
23601 fid_parse_arglist :
23602 #undef L
23603 #define L CR_CUR_LOCALS_PT(fid_parse_arglist_locals_t)
23604 {
23605   if (v7->cur_tok != TOK_CLOSE_PAREN) {
23606     do {
23607       CALL_PARSE_ASSIGN(fid_p_arglist_1);
23608     } while (ACCEPT(TOK_COMMA));
23609   }
23610   CR_RETURN_VOID();
23611 }
23612 
23613 /*
23614  * static enum v7_err parse_member(struct v7 *v7, struct ast *a, ast_off_t pos)
23615  */
23616 fid_parse_member :
23617 #undef L
23618 #define L CR_CUR_LOCALS_PT(fid_parse_member_locals_t)
23619 {
23620   switch (v7->cur_tok) {
23621     case TOK_DOT:
23622       next_tok(v7);
23623       /* Allow reserved words as member identifiers */
23624       if (is_reserved_word_token(v7->cur_tok) ||
23625           v7->cur_tok == TOK_IDENTIFIER) {
23626         insert_inlined_node(v7, a, L->arg.pos, AST_MEMBER, v7->tok,
23627                             v7->tok_len);
23628         next_tok(v7);
23629       } else {
23630         CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23631       }
23632       break;
23633     case TOK_OPEN_BRACKET:
23634       next_tok(v7);
23635       CALL_PARSE_EXPRESSION(fid_p_member_1);
23636       EXPECT(TOK_CLOSE_BRACKET);
23637       insert_node(v7, a, L->arg.pos, AST_INDEX);
23638       break;
23639     default:
23640       CR_RETURN_VOID();
23641   }
23642   /* not necessary, but let it be anyway */
23643   CR_RETURN_VOID();
23644 }
23645 
23646 /* static enum v7_err parse_memberexpr(struct v7 *v7, struct ast *a) */
23647 fid_parse_memberexpr :
23648 #undef L
23649 #define L CR_CUR_LOCALS_PT(fid_parse_memberexpr_locals_t)
23650 {
23651   L->pos = a->mbuf.len;
23652   CALL_PARSE_NEWEXPR(fid_p_memberexpr_1);
23653 
23654   for (;;) {
23655     switch (v7->cur_tok) {
23656       case TOK_DOT:
23657       case TOK_OPEN_BRACKET:
23658         CALL_PARSE_MEMBER(L->pos, fid_p_memberexpr_2);
23659         break;
23660       default:
23661         CR_RETURN_VOID();
23662     }
23663   }
23664 }
23665 
23666 /* static enum v7_err parse_var(struct v7 *v7, struct ast *a) */
23667 fid_parse_var :
23668 #undef L
23669 #define L CR_CUR_LOCALS_PT(fid_parse_var_locals_t)
23670 {
23671   L->start = add_node(v7, a, AST_VAR);
23672   ast_modify_skip(a, v7->last_var_node, L->start, AST_FUNC_FIRST_VAR_SKIP);
23673   /* zero out var node pointer */
23674   ast_modify_skip(a, L->start, L->start, AST_FUNC_FIRST_VAR_SKIP);
23675   v7->last_var_node = L->start;
23676   do {
23677     add_inlined_node(v7, a, AST_VAR_DECL, v7->tok, v7->tok_len);
23678     EXPECT(TOK_IDENTIFIER);
23679     if (ACCEPT(TOK_ASSIGN)) {
23680       CALL_PARSE_ASSIGN(fid_p_var_1);
23681     } else {
23682       add_node(v7, a, AST_NOP);
23683     }
23684   } while (ACCEPT(TOK_COMMA));
23685   ast_set_skip(a, L->start, AST_END_SKIP);
23686   CR_RETURN_VOID();
23687 }
23688 
23689 /* static enum v7_err parse_prop(struct v7 *v7, struct ast *a) */
23690 fid_parse_prop :
23691 #undef L
23692 #define L CR_CUR_LOCALS_PT(fid_parse_prop_locals_t)
23693 {
23694 #ifdef V7_ENABLE_JS_GETTERS
23695   if (v7->cur_tok == TOK_IDENTIFIER && v7->tok_len == 3 &&
23696       strncmp(v7->tok, "get", v7->tok_len) == 0 && lookahead(v7) != TOK_COLON) {
23697     next_tok(v7);
23698     add_node(v7, a, AST_GETTER);
23699     CALL_PARSE_FUNCDECL(1, 1, fid_p_prop_1_getter);
23700   } else
23701 #endif
23702       if (v7->cur_tok == TOK_IDENTIFIER && lookahead(v7) == TOK_OPEN_PAREN) {
23703     /* ecmascript 6 feature */
23704     CALL_PARSE_FUNCDECL(1, 1, fid_p_prop_2);
23705 #ifdef V7_ENABLE_JS_SETTERS
23706   } else if (v7->cur_tok == TOK_IDENTIFIER && v7->tok_len == 3 &&
23707              strncmp(v7->tok, "set", v7->tok_len) == 0 &&
23708              lookahead(v7) != TOK_COLON) {
23709     next_tok(v7);
23710     add_node(v7, a, AST_SETTER);
23711     CALL_PARSE_FUNCDECL(1, 1, fid_p_prop_3_setter);
23712 #endif
23713   } else {
23714     /* Allow reserved words as property names. */
23715     if (is_reserved_word_token(v7->cur_tok) || v7->cur_tok == TOK_IDENTIFIER ||
23716         v7->cur_tok == TOK_NUMBER) {
23717       add_inlined_node(v7, a, AST_PROP, v7->tok, v7->tok_len);
23718     } else if (v7->cur_tok == TOK_STRING_LITERAL) {
23719       add_inlined_node(v7, a, AST_PROP, v7->tok + 1, v7->tok_len - 2);
23720     } else {
23721       CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23722     }
23723     next_tok(v7);
23724     EXPECT(TOK_COLON);
23725     CALL_PARSE_ASSIGN(fid_p_prop_4);
23726   }
23727   CR_RETURN_VOID();
23728 }
23729 
23730 /* static enum v7_err parse_dowhile(struct v7 *v7, struct ast *a) */
23731 fid_parse_dowhile :
23732 #undef L
23733 #define L CR_CUR_LOCALS_PT(fid_parse_dowhile_locals_t)
23734 {
23735   L->start = add_node(v7, a, AST_DOWHILE);
23736   L->saved_in_loop = v7->pstate.in_loop;
23737 
23738   v7->pstate.in_loop = 1;
23739   CALL_PARSE_STATEMENT(fid_p_dowhile_1);
23740   v7->pstate.in_loop = L->saved_in_loop;
23741   ast_set_skip(a, L->start, AST_DO_WHILE_COND_SKIP);
23742   EXPECT(TOK_WHILE);
23743   EXPECT(TOK_OPEN_PAREN);
23744   CALL_PARSE_EXPRESSION(fid_p_dowhile_2);
23745   EXPECT(TOK_CLOSE_PAREN);
23746   ast_set_skip(a, L->start, AST_END_SKIP);
23747   CR_RETURN_VOID();
23748 }
23749 
23750 /* static enum v7_err parse_for(struct v7 *v7, struct ast *a) */
23751 fid_parse_for :
23752 #undef L
23753 #define L CR_CUR_LOCALS_PT(fid_parse_for_locals_t)
23754 {
23755   /* TODO(mkm): for of, for each in */
23756   /*
23757   ast_off_t start;
23758   int saved_in_loop;
23759   */
23760 
23761   L->start = add_node(v7, a, AST_FOR);
23762   L->saved_in_loop = v7->pstate.in_loop;
23763 
23764   EXPECT(TOK_OPEN_PAREN);
23765 
23766   if (parse_optional(v7, a, TOK_SEMICOLON)) {
23767     /*
23768      * TODO(mkm): make this reentrant otherwise this pearl won't parse:
23769      * for((function(){return 1 in o.a ? o : x})().a in [1,2,3])
23770      */
23771     v7->pstate.inhibit_in = 1;
23772     if (ACCEPT(TOK_VAR)) {
23773       CALL_PARSE_VAR(fid_p_for_1);
23774     } else {
23775       CALL_PARSE_EXPRESSION(fid_p_for_2);
23776     }
23777     v7->pstate.inhibit_in = 0;
23778 
23779     if (ACCEPT(TOK_IN)) {
23780       CALL_PARSE_EXPRESSION(fid_p_for_3);
23781       add_node(v7, a, AST_NOP);
23782       /*
23783        * Assumes that for and for in have the same AST format which is
23784        * suboptimal but avoids the need of fixing up the var offset chain.
23785        * TODO(mkm) improve this
23786        */
23787       ast_modify_tag(a, L->start - 1, AST_FOR_IN);
23788       goto for_loop_body;
23789     }
23790   }
23791 
23792   EXPECT(TOK_SEMICOLON);
23793   if (parse_optional(v7, a, TOK_SEMICOLON)) {
23794     CALL_PARSE_EXPRESSION(fid_p_for_4);
23795   }
23796   EXPECT(TOK_SEMICOLON);
23797   if (parse_optional(v7, a, TOK_CLOSE_PAREN)) {
23798     CALL_PARSE_EXPRESSION(fid_p_for_5);
23799   }
23800 
23801 for_loop_body:
23802   EXPECT(TOK_CLOSE_PAREN);
23803   ast_set_skip(a, L->start, AST_FOR_BODY_SKIP);
23804   v7->pstate.in_loop = 1;
23805   CALL_PARSE_STATEMENT(fid_p_for_6);
23806   v7->pstate.in_loop = L->saved_in_loop;
23807   ast_set_skip(a, L->start, AST_END_SKIP);
23808   CR_RETURN_VOID();
23809 }
23810 
23811 /* static enum v7_err parse_try(struct v7 *v7, struct ast *a) */
23812 fid_parse_try :
23813 #undef L
23814 #define L CR_CUR_LOCALS_PT(fid_parse_try_locals_t)
23815 {
23816   L->start = add_node(v7, a, AST_TRY);
23817   L->catch_or_finally = 0;
23818   CALL_PARSE_BLOCK(fid_p_try_1);
23819   ast_set_skip(a, L->start, AST_TRY_CATCH_SKIP);
23820   if (ACCEPT(TOK_CATCH)) {
23821     L->catch_or_finally = 1;
23822     EXPECT(TOK_OPEN_PAREN);
23823     CALL_PARSE_IDENT(fid_p_try_2);
23824     EXPECT(TOK_CLOSE_PAREN);
23825     CALL_PARSE_BLOCK(fid_p_try_3);
23826   }
23827   ast_set_skip(a, L->start, AST_TRY_FINALLY_SKIP);
23828   if (ACCEPT(TOK_FINALLY)) {
23829     L->catch_or_finally = 1;
23830     CALL_PARSE_BLOCK(fid_p_try_4);
23831   }
23832   ast_set_skip(a, L->start, AST_END_SKIP);
23833 
23834   /* make sure `catch` and `finally` aren't both missing */
23835   if (!L->catch_or_finally) {
23836     CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23837   }
23838 
23839   CR_RETURN_VOID();
23840 }
23841 
23842 /* static enum v7_err parse_switch(struct v7 *v7, struct ast *a) */
23843 fid_parse_switch :
23844 #undef L
23845 #define L CR_CUR_LOCALS_PT(fid_parse_switch_locals_t)
23846 {
23847   L->start = add_node(v7, a, AST_SWITCH);
23848   L->saved_in_switch = v7->pstate.in_switch;
23849 
23850   ast_set_skip(a, L->start, AST_SWITCH_DEFAULT_SKIP); /* clear out */
23851   EXPECT(TOK_OPEN_PAREN);
23852   CALL_PARSE_EXPRESSION(fid_p_switch_1);
23853   EXPECT(TOK_CLOSE_PAREN);
23854   EXPECT(TOK_OPEN_CURLY);
23855   v7->pstate.in_switch = 1;
23856   while (v7->cur_tok != TOK_CLOSE_CURLY) {
23857     switch (v7->cur_tok) {
23858       case TOK_CASE:
23859         next_tok(v7);
23860         L->case_start = add_node(v7, a, AST_CASE);
23861         CALL_PARSE_EXPRESSION(fid_p_switch_2);
23862         EXPECT(TOK_COLON);
23863         while (v7->cur_tok != TOK_CASE && v7->cur_tok != TOK_DEFAULT &&
23864                v7->cur_tok != TOK_CLOSE_CURLY) {
23865           CALL_PARSE_STATEMENT(fid_p_switch_3);
23866         }
23867         ast_set_skip(a, L->case_start, AST_END_SKIP);
23868         break;
23869       case TOK_DEFAULT:
23870         next_tok(v7);
23871         EXPECT(TOK_COLON);
23872         ast_set_skip(a, L->start, AST_SWITCH_DEFAULT_SKIP);
23873         L->case_start = add_node(v7, a, AST_DEFAULT);
23874         while (v7->cur_tok != TOK_CASE && v7->cur_tok != TOK_DEFAULT &&
23875                v7->cur_tok != TOK_CLOSE_CURLY) {
23876           CALL_PARSE_STATEMENT(fid_p_switch_4);
23877         }
23878         ast_set_skip(a, L->case_start, AST_END_SKIP);
23879         break;
23880       default:
23881         CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23882     }
23883   }
23884   EXPECT(TOK_CLOSE_CURLY);
23885   ast_set_skip(a, L->start, AST_END_SKIP);
23886   v7->pstate.in_switch = L->saved_in_switch;
23887   CR_RETURN_VOID();
23888 }
23889 
23890 /* static enum v7_err parse_with(struct v7 *v7, struct ast *a) */
23891 fid_parse_with :
23892 #undef L
23893 #define L CR_CUR_LOCALS_PT(fid_parse_with_locals_t)
23894 {
23895   L->start = add_node(v7, a, AST_WITH);
23896   if (v7->pstate.in_strict) {
23897     CR_THROW(PARSER_EXC_ID__SYNTAX_ERROR);
23898   }
23899   EXPECT(TOK_OPEN_PAREN);
23900   CALL_PARSE_EXPRESSION(fid_p_with_1);
23901   EXPECT(TOK_CLOSE_PAREN);
23902   CALL_PARSE_STATEMENT(fid_p_with_2);
23903   ast_set_skip(a, L->start, AST_END_SKIP);
23904   CR_RETURN_VOID();
23905 }
23906 
23907 fid_none:
23908   /* stack is empty, so we're done; return */
23909   return rc;
23910 }
23911 
23912 V7_PRIVATE enum v7_err parse(struct v7 *v7, struct ast *a, const char *src,
23913                              size_t src_len, int is_json) {
23914   enum v7_err rcode;
23915   const char *error_msg = NULL;
23916   const char *p;
23917   struct cr_ctx cr_ctx;
23918   union user_arg_ret arg_retval;
23919   enum cr_status rc;
23920 #if defined(V7_ENABLE_STACK_TRACKING)
23921   struct stack_track_ctx stack_track_ctx;
23922 #endif
23923   int saved_line_no = v7->line_no;
23924 
23925 #if defined(V7_ENABLE_STACK_TRACKING)
23926   v7_stack_track_start(v7, &stack_track_ctx);
23927 #endif
23928 
23929   v7->pstate.source_code = v7->pstate.pc = src;
23930   v7->pstate.src_end = src + src_len;
23931   v7->pstate.file_name = "<stdin>";
23932   v7->pstate.line_no = 1;
23933   v7->pstate.in_function = 0;
23934   v7->pstate.in_loop = 0;
23935   v7->pstate.in_switch = 0;
23936 
23937   /*
23938    * TODO(dfrank): `v7->parser.line_no` vs `v7->line_no` is confusing.  probaby
23939    * we need to refactor it.
23940    *
23941    * See comment for v7->line_no in core.h for some details.
23942    */
23943   v7->line_no = 1;
23944 
23945   next_tok(v7);
23946   /*
23947    * setup initial state for "after newline" tracking.
23948    * next_tok will consume our token and position the current line
23949    * position at the beginning of the next token.
23950    * While processing the first token, both the leading and the
23951    * trailing newlines will be counted and thus it will create a spurious
23952    * "after newline" condition at the end of the first token
23953    * regardless if there is actually a newline after it.
23954    */
23955   for (p = src; isspace((int) *p); p++) {
23956     if (*p == '\n') {
23957       v7->pstate.prev_line_no++;
23958     }
23959   }
23960 
23961   /* init cr context */
23962   cr_context_init(&cr_ctx, &arg_retval, sizeof(arg_retval), _fid_descrs);
23963 
23964   /* prepare first function call: fid_mul_sum */
23965   if (is_json) {
23966     CR_FIRST_CALL_PREPARE_C(&cr_ctx, fid_parse_terminal);
23967   } else {
23968     CR_FIRST_CALL_PREPARE_C(&cr_ctx, fid_parse_script);
23969   }
23970 
23971   /* proceed to coroutine execution */
23972   rc = parser_cr_exec(&cr_ctx, v7, a);
23973 
23974   /* set `rcode` depending on coroutine state */
23975   switch (rc) {
23976     case CR_RES__OK:
23977       rcode = V7_OK;
23978       break;
23979     case CR_RES__ERR_UNCAUGHT_EXCEPTION:
23980       switch ((enum parser_exc_id) CR_THROWN_C(&cr_ctx)) {
23981         case PARSER_EXC_ID__SYNTAX_ERROR:
23982           rcode = V7_SYNTAX_ERROR;
23983           error_msg = "Syntax error";
23984           break;
23985 
23986         default:
23987           rcode = V7_INTERNAL_ERROR;
23988           error_msg = "Internal error: no exception id set";
23989           break;
23990       }
23991       break;
23992     default:
23993       rcode = V7_INTERNAL_ERROR;
23994       error_msg = "Internal error: unexpected parser coroutine return code";
23995       break;
23996   }
23997 
23998 #if defined(V7_TRACK_MAX_PARSER_STACK_SIZE)
23999   /* remember how much stack space was consumed */
24000 
24001   if (v7->parser_stack_data_max_size < cr_ctx.stack_data.size) {
24002     v7->parser_stack_data_max_size = cr_ctx.stack_data.size;
24003 #ifndef NO_LIBC
24004     printf("parser_stack_data_max_size=%u\n",
24005            (unsigned int) v7->parser_stack_data_max_size);
24006 #endif
24007   }
24008 
24009   if (v7->parser_stack_ret_max_size < cr_ctx.stack_ret.size) {
24010     v7->parser_stack_ret_max_size = cr_ctx.stack_ret.size;
24011 #ifndef NO_LIBC
24012     printf("parser_stack_ret_max_size=%u\n",
24013            (unsigned int) v7->parser_stack_ret_max_size);
24014 #endif
24015   }
24016 
24017 #if defined(CR_TRACK_MAX_STACK_LEN)
24018   if (v7->parser_stack_data_max_len < cr_ctx.stack_data_max_len) {
24019     v7->parser_stack_data_max_len = cr_ctx.stack_data_max_len;
24020 #ifndef NO_LIBC
24021     printf("parser_stack_data_max_len=%u\n",
24022            (unsigned int) v7->parser_stack_data_max_len);
24023 #endif
24024   }
24025 
24026   if (v7->parser_stack_ret_max_len < cr_ctx.stack_ret_max_len) {
24027     v7->parser_stack_ret_max_len = cr_ctx.stack_ret_max_len;
24028 #ifndef NO_LIBC
24029     printf("parser_stack_ret_max_len=%u\n",
24030            (unsigned int) v7->parser_stack_ret_max_len);
24031 #endif
24032   }
24033 #endif
24034 
24035 #endif
24036 
24037   /* free resources occupied by context (at least, "stack" arrays) */
24038   cr_context_free(&cr_ctx);
24039 
24040 #if defined(V7_ENABLE_STACK_TRACKING)
24041   {
24042     int diff = v7_stack_track_end(v7, &stack_track_ctx);
24043     if (diff > v7->stack_stat[V7_STACK_STAT_PARSER]) {
24044       v7->stack_stat[V7_STACK_STAT_PARSER] = diff;
24045     }
24046   }
24047 #endif
24048 
24049   /* Check if AST was overflown */
24050   if (a->has_overflow) {
24051     rcode = v7_throwf(v7, SYNTAX_ERROR,
24052                       "Script too large (try V7_LARGE_AST build option)");
24053     V7_THROW(V7_AST_TOO_LARGE);
24054   }
24055 
24056   if (rcode == V7_OK && v7->cur_tok != TOK_END_OF_INPUT) {
24057     rcode = V7_SYNTAX_ERROR;
24058     error_msg = "Syntax error";
24059   }
24060 
24061   if (rcode != V7_OK) {
24062     unsigned long col = get_column(v7->pstate.source_code, v7->tok);
24063     int line_len = 0;
24064 
24065     assert(error_msg != NULL);
24066 
24067     for (p = v7->tok - col; p < v7->pstate.src_end && *p != '\0' && *p != '\n';
24068          p++) {
24069       line_len++;
24070     }
24071 
24072     /* fixup line number: line_no points to the beginning of the next token */
24073     for (; p < v7->pstate.pc; p++) {
24074       if (*p == '\n') {
24075         v7->pstate.line_no--;
24076       }
24077     }
24078 
24079     /*
24080      * We already have a proper `rcode`, that's why we discard returned value
24081      * of `v7_throwf()`, which is always `V7_EXEC_EXCEPTION`.
24082      *
24083      * TODO(dfrank): probably get rid of distinct error types, and use just
24084      * `V7_JS_EXCEPTION`. However it would be good to have a way to get exact
24085      * error type, so probably error object should contain some property with
24086      * error code, but it would make exceptions even more expensive, etc, etc.
24087      */
24088     {
24089       enum v7_err _tmp;
24090       _tmp = v7_throwf(v7, SYNTAX_ERROR, "%s at line %d col %lu:\n%.*s\n%*s^",
24091                        error_msg, v7->pstate.line_no, col, line_len,
24092                        v7->tok - col, (int) col - 1, "");
24093       (void) _tmp;
24094     }
24095     V7_THROW(rcode);
24096   }
24097 
24098 clean:
24099   v7->line_no = saved_line_no;
24100   return rcode;
24101 }
24102 
24103 #endif /* V7_NO_COMPILER */
24104 #ifdef V7_MODULE_LINES
24105 #line 1 "v7/src/compiler.c"
24106 #endif
24107 /*
24108  * Copyright (c) 2014 Cesanta Software Limited
24109  * All rights reserved
24110  */
24111 
24112 /* Amalgamated: #include "v7/src/internal.h" */
24113 /* Amalgamated: #include "v7/src/compiler.h" */
24114 /* Amalgamated: #include "v7/src/std_error.h" */
24115 /* Amalgamated: #include "v7/src/core.h" */
24116 /* Amalgamated: #include "v7/src/function.h" */
24117 /* Amalgamated: #include "v7/src/exceptions.h" */
24118 /* Amalgamated: #include "v7/src/conversion.h" */
24119 /* Amalgamated: #include "v7/src/regexp.h" */
24120 
24121 #if !defined(V7_NO_COMPILER)
24122 
24123 /*
24124  * The bytecode compiler takes an AST as input and produces one or more
24125  * bcode structure as output.
24126  *
24127  * Each script or function body is compiled into it's own bcode structure.
24128  *
24129  * Each bcode stream produces a new value on the stack, i.e. its overall
24130  * stack diagram is: `( -- a)`
24131  *
24132  * This value will be then popped by the function caller or by v7_exec in case
24133  * of scripts.
24134  *
24135  * In JS, the value of a script is the value of the last statement.
24136  * A script with no statement has an `undefined` value.
24137  * Functions instead require an explicit return value, so this matters only
24138  * for `v7_exec` and JS `eval`.
24139  *
24140  * Since an empty script has an undefined value, and each script has to
24141  * yield a value, the script/function prologue consists of a PUSH_UNDEFINED.
24142  *
24143  * Each statement will be compiled to push a value on the stack.
24144  * When a statement begins evaluating, the current TOS is thus either
24145  * the value of the previous statement or `undefined` in case of the first
24146  * statement.
24147  *
24148  * Every statement of a given script/function body always evaluates at the same
24149  * stack depth.
24150  *
24151  * In order to achieve that, after a statement is compiled out, a SWAP_DROP
24152  * opcode is emitted, that drops the value of the previous statement (or the
24153  * initial `undefined`). Dropping the value after the next statement is
24154  * evaluated and not before has allows us to correctly implement exception
24155  * behaviour and the break statement.
24156  *
24157  * Compound statements are constructs such as `if`/`while`/`for`/`try`. These
24158  * constructs contain a body consisting of a possibly empty statement list.
24159  *
24160  * Unlike normal statements, compound statements don't produce a value
24161  * themselves. Their value is either the value of their last executed statement
24162  * in their body, or the previous statement in case their body is empty or not
24163  * evaluated at all.
24164  *
24165  * An example is:
24166  *
24167  * [source,js]
24168  * ----
24169  * try {
24170  *   42;
24171  *   someUnexistingVariable;
24172  * } catch(e) {
24173  *   while(true) {}
24174  *     if(true) {
24175  *     }
24176  *     if(false) {
24177  *       2;
24178  *     }
24179  *     break;
24180  *   }
24181  * }
24182  * ----
24183  */
24184 
24185 static const enum ast_tag assign_ast_map[] = {
24186     AST_REM, AST_MUL, AST_DIV,    AST_XOR,    AST_ADD,    AST_SUB,
24187     AST_OR,  AST_AND, AST_LSHIFT, AST_RSHIFT, AST_URSHIFT};
24188 
24189 #ifdef V7_BCODE_DUMP
24190 extern void dump_bcode(struct v7 *v7, FILE *f, struct bcode *bcode);
24191 #endif
24192 
24193 V7_PRIVATE enum v7_err compile_expr_builder(struct bcode_builder *bbuilder,
24194                                             struct ast *a, ast_off_t *ppos);
24195 
24196 V7_PRIVATE enum v7_err compile_function(struct v7 *v7, struct ast *a,
24197                                         ast_off_t *ppos, struct bcode *bcode);
24198 
24199 V7_PRIVATE enum v7_err binary_op(struct bcode_builder *bbuilder,
24200                                  enum ast_tag tag) {
24201   uint8_t op;
24202   enum v7_err rcode = V7_OK;
24203   struct v7 *v7 = bbuilder->v7;
24204 
24205   switch (tag) {
24206     case AST_ADD:
24207       op = OP_ADD;
24208       break;
24209     case AST_SUB:
24210       op = OP_SUB;
24211       break;
24212     case AST_REM:
24213       op = OP_REM;
24214       break;
24215     case AST_MUL:
24216       op = OP_MUL;
24217       break;
24218     case AST_DIV:
24219       op = OP_DIV;
24220       break;
24221     case AST_LSHIFT:
24222       op = OP_LSHIFT;
24223       break;
24224     case AST_RSHIFT:
24225       op = OP_RSHIFT;
24226       break;
24227     case AST_URSHIFT:
24228       op = OP_URSHIFT;
24229       break;
24230     case AST_OR:
24231       op = OP_OR;
24232       break;
24233     case AST_XOR:
24234       op = OP_XOR;
24235       break;
24236     case AST_AND:
24237       op = OP_AND;
24238       break;
24239     case AST_EQ_EQ:
24240       op = OP_EQ_EQ;
24241       break;
24242     case AST_EQ:
24243       op = OP_EQ;
24244       break;
24245     case AST_NE:
24246       op = OP_NE;
24247       break;
24248     case AST_NE_NE:
24249       op = OP_NE_NE;
24250       break;
24251     case AST_LT:
24252       op = OP_LT;
24253       break;
24254     case AST_LE:
24255       op = OP_LE;
24256       break;
24257     case AST_GT:
24258       op = OP_GT;
24259       break;
24260     case AST_GE:
24261       op = OP_GE;
24262       break;
24263     case AST_INSTANCEOF:
24264       op = OP_INSTANCEOF;
24265       break;
24266     default:
24267       rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "unknown binary ast node");
24268       V7_THROW(V7_SYNTAX_ERROR);
24269   }
24270   bcode_op(bbuilder, op);
24271 clean:
24272   return rcode;
24273 }
24274 
24275 V7_PRIVATE enum v7_err compile_binary(struct bcode_builder *bbuilder,
24276                                       struct ast *a, ast_off_t *ppos,
24277                                       enum ast_tag tag) {
24278   enum v7_err rcode = V7_OK;
24279   struct v7 *v7 = bbuilder->v7;
24280   V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24281   V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24282 
24283   V7_TRY(binary_op(bbuilder, tag));
24284 clean:
24285   return rcode;
24286 }
24287 
24288 /*
24289  * `pos` should be an offset of the byte right after a tag
24290  */
24291 static lit_t string_lit(struct bcode_builder *bbuilder, struct ast *a,
24292                         ast_off_t pos) {
24293   size_t i = 0, name_len;
24294   val_t v = V7_UNDEFINED;
24295   struct mbuf *m = &bbuilder->lit;
24296   char *name = ast_get_inlined_data(a, pos, &name_len);
24297 
24298 /* temp disabled because of short lits */
24299 #if 0
24300   for (i = 0; i < m->len / sizeof(val_t); i++) {
24301     v = ((val_t *) m->buf)[i];
24302     if (v7_is_string(v)) {
24303       size_t l;
24304       const char *s = v7_get_string(bbuilder->v7, &v, &l);
24305       if (name_len == l && memcmp(name, s, name_len) == 0) {
24306         lit_t res;
24307         memset(&res, 0, sizeof(res));
24308         res.idx = i + bcode_max_inline_type_tag;
24309         return res;
24310       }
24311     }
24312   }
24313 #else
24314   (void) i;
24315   (void) v;
24316   (void) m;
24317 #endif
24318   return bcode_add_lit(bbuilder, v7_mk_string(bbuilder->v7, name, name_len, 1));
24319 }
24320 
24321 #if V7_ENABLE__RegExp
24322 WARN_UNUSED_RESULT
24323 static enum v7_err regexp_lit(struct bcode_builder *bbuilder, struct ast *a,
24324                               ast_off_t pos, lit_t *res) {
24325   enum v7_err rcode = V7_OK;
24326   size_t name_len;
24327   char *p;
24328   char *name = ast_get_inlined_data(a, pos, &name_len);
24329   val_t tmp = V7_UNDEFINED;
24330   struct v7 *v7 = bbuilder->v7;
24331 
24332   for (p = name + name_len - 1; *p != '/';) p--;
24333 
24334   V7_TRY(v7_mk_regexp(bbuilder->v7, name + 1, p - (name + 1), p + 1,
24335                       (name + name_len) - p - 1, &tmp));
24336 
24337   *res = bcode_add_lit(bbuilder, tmp);
24338 
24339 clean:
24340   return rcode;
24341 }
24342 #endif
24343 
24344 #ifndef V7_DISABLE_LINE_NUMBERS
24345 static void append_lineno_if_changed(struct v7 *v7,
24346                                      struct bcode_builder *bbuilder,
24347                                      int line_no) {
24348   (void) v7;
24349   if (line_no != 0 && line_no != v7->line_no) {
24350     v7->line_no = line_no;
24351     bcode_append_lineno(bbuilder, line_no);
24352   }
24353 }
24354 #else
24355 static void append_lineno_if_changed(struct v7 *v7,
24356                                      struct bcode_builder *bbuilder,
24357                                      int line_no) {
24358   (void) v7;
24359   (void) bbuilder;
24360   (void) line_no;
24361 }
24362 #endif
24363 
24364 static enum ast_tag fetch_tag(struct v7 *v7, struct bcode_builder *bbuilder,
24365                               struct ast *a, ast_off_t *ppos,
24366                               ast_off_t *ppos_after_tag) {
24367   enum ast_tag ret = ast_fetch_tag(a, ppos);
24368   int line_no = ast_get_line_no(a, *ppos);
24369   append_lineno_if_changed(v7, bbuilder, line_no);
24370   if (ppos_after_tag != NULL) {
24371     *ppos_after_tag = *ppos;
24372   }
24373   ast_move_to_children(a, ppos);
24374   return ret;
24375 }
24376 
24377 /*
24378  * a++ and a-- need to ignore the updated value.
24379  *
24380  * Call this before updating the lhs.
24381  */
24382 static void fixup_post_op(struct bcode_builder *bbuilder, enum ast_tag tag) {
24383   if (tag == AST_POSTINC || tag == AST_POSTDEC) {
24384     bcode_op(bbuilder, OP_UNSTASH);
24385   }
24386 }
24387 
24388 /*
24389  * evaluate rhs expression.
24390  * ++a and a++ are equivalent to a+=1
24391  */
24392 static enum v7_err eval_assign_rhs(struct bcode_builder *bbuilder,
24393                                    struct ast *a, ast_off_t *ppos,
24394                                    enum ast_tag tag) {
24395   enum v7_err rcode = V7_OK;
24396   struct v7 *v7 = bbuilder->v7;
24397 
24398   /* a++ and a-- need to preserve initial value. */
24399   if (tag == AST_POSTINC || tag == AST_POSTDEC) {
24400     bcode_op(bbuilder, OP_STASH);
24401   }
24402   if (tag >= AST_PREINC && tag <= AST_POSTDEC) {
24403     bcode_op(bbuilder, OP_PUSH_ONE);
24404   } else {
24405     V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24406   }
24407 
24408   switch (tag) {
24409     case AST_PREINC:
24410     case AST_POSTINC:
24411       bcode_op(bbuilder, OP_ADD);
24412       break;
24413     case AST_PREDEC:
24414     case AST_POSTDEC:
24415       bcode_op(bbuilder, OP_SUB);
24416       break;
24417     case AST_ASSIGN:
24418       /* no operation */
24419       break;
24420     default:
24421       binary_op(bbuilder, assign_ast_map[tag - AST_ASSIGN - 1]);
24422   }
24423 
24424 clean:
24425   return rcode;
24426 }
24427 
24428 static enum v7_err compile_assign(struct bcode_builder *bbuilder, struct ast *a,
24429                                   ast_off_t *ppos, enum ast_tag tag) {
24430   lit_t lit;
24431   enum ast_tag ntag;
24432   enum v7_err rcode = V7_OK;
24433   struct v7 *v7 = bbuilder->v7;
24434   ast_off_t pos_after_tag;
24435 
24436   ntag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
24437 
24438   switch (ntag) {
24439     case AST_IDENT:
24440       lit = string_lit(bbuilder, a, pos_after_tag);
24441       if (tag != AST_ASSIGN) {
24442         bcode_op_lit(bbuilder, OP_GET_VAR, lit);
24443       }
24444 
24445       V7_TRY(eval_assign_rhs(bbuilder, a, ppos, tag));
24446       bcode_op_lit(bbuilder, OP_SET_VAR, lit);
24447 
24448       fixup_post_op(bbuilder, tag);
24449       break;
24450     case AST_MEMBER:
24451     case AST_INDEX:
24452       switch (ntag) {
24453         case AST_MEMBER:
24454           lit = string_lit(bbuilder, a, pos_after_tag);
24455           V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24456           bcode_push_lit(bbuilder, lit);
24457           break;
24458         case AST_INDEX:
24459           V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24460           V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24461           break;
24462         default:
24463           /* unreachable, compilers are dumb */
24464           V7_THROW(V7_SYNTAX_ERROR);
24465       }
24466       if (tag != AST_ASSIGN) {
24467         bcode_op(bbuilder, OP_2DUP);
24468         bcode_op(bbuilder, OP_GET);
24469       }
24470 
24471       V7_TRY(eval_assign_rhs(bbuilder, a, ppos, tag));
24472       bcode_op(bbuilder, OP_SET);
24473 
24474       fixup_post_op(bbuilder, tag);
24475       break;
24476     default:
24477       /* We end up here on expressions like `1 = 2;`, it's a ReferenceError */
24478       rcode = v7_throwf(bbuilder->v7, REFERENCE_ERROR, "unexpected ast node");
24479       V7_THROW(V7_SYNTAX_ERROR);
24480   }
24481 clean:
24482   return rcode;
24483 }
24484 
24485 /*
24486  * Walks through all declarations (`var` and `function`) in the current scope,
24487  * and adds names of all of them to `bcode->ops`. Additionally, `function`
24488  * declarations are compiled right here, since they're hoisted in JS.
24489  */
24490 static enum v7_err compile_local_vars(struct bcode_builder *bbuilder,
24491                                       struct ast *a, ast_off_t start,
24492                                       ast_off_t fvar) {
24493   ast_off_t next, fvar_end;
24494   char *name;
24495   size_t name_len;
24496   lit_t lit;
24497   enum v7_err rcode = V7_OK;
24498   struct v7 *v7 = bbuilder->v7;
24499   size_t names_end = 0;
24500   ast_off_t pos_after_tag;
24501 
24502   /* calculate `names_end`: offset at which names in `bcode->ops` end */
24503   names_end =
24504       (size_t)(bcode_end_names(bbuilder->ops.buf, bbuilder->bcode->names_cnt) -
24505                bbuilder->ops.buf);
24506 
24507   if (fvar != start) {
24508     /* iterate all `AST_VAR`s in the current scope */
24509     do {
24510       V7_CHECK_INTERNAL(fetch_tag(v7, bbuilder, a, &fvar, &pos_after_tag) ==
24511                         AST_VAR);
24512 
24513       next = ast_get_skip(a, pos_after_tag, AST_VAR_NEXT_SKIP);
24514       if (next == pos_after_tag) {
24515         next = 0;
24516       }
24517 
24518       fvar_end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
24519 
24520       /*
24521        * iterate all `AST_VAR_DECL`s and `AST_FUNC_DECL`s in the current
24522        * `AST_VAR`
24523        */
24524       while (fvar < fvar_end) {
24525         enum ast_tag tag = fetch_tag(v7, bbuilder, a, &fvar, &pos_after_tag);
24526         V7_CHECK_INTERNAL(tag == AST_VAR_DECL || tag == AST_FUNC_DECL);
24527         name = ast_get_inlined_data(a, pos_after_tag, &name_len);
24528         if (tag == AST_VAR_DECL) {
24529           /*
24530            * it's a `var` declaration, so, skip the value for now, it'll be set
24531            * to `undefined` initially
24532            */
24533           ast_skip_tree(a, &fvar);
24534         } else {
24535           /*
24536            * tag is an AST_FUNC_DECL: since functions in JS are hoisted,
24537            * we compile it and put `OP_SET_VAR` directly here
24538            */
24539           lit = string_lit(bbuilder, a, pos_after_tag);
24540           V7_TRY(compile_expr_builder(bbuilder, a, &fvar));
24541           bcode_op_lit(bbuilder, OP_SET_VAR, lit);
24542 
24543           /* function declarations are stack-neutral */
24544           bcode_op(bbuilder, OP_DROP);
24545           /*
24546            * Note: the `is_stack_neutral` flag will be set by `compile_stmt`
24547            * later, when it encounters `AST_FUNC_DECL` again.
24548            */
24549         }
24550         V7_TRY(bcode_add_name(bbuilder, name, name_len, &names_end));
24551       }
24552 
24553       if (next > 0) {
24554         fvar = next - 1;
24555       }
24556 
24557     } while (next != 0);
24558   }
24559 
24560 clean:
24561   return rcode;
24562 }
24563 
24564 /*
24565  * Just like `compile_expr_builder`, but it takes additional argument:
24566  *`for_call`.
24567  * If it's non-zero, the stack is additionally populated with `this` value
24568  * for call.
24569  *
24570  * If there is a refinement (a dot, or a subscript), then it'll be the
24571  * appropriate object. Otherwise, it's `undefined`.
24572  *
24573  * In non-strict mode, `undefined` will be changed to Global Object at runtime,
24574  * see `OP_CALL` handling in `eval_bcode()`.
24575  */
24576 V7_PRIVATE enum v7_err compile_expr_ext(struct bcode_builder *bbuilder,
24577                                         struct ast *a, ast_off_t *ppos,
24578                                         uint8_t for_call) {
24579   enum v7_err rcode = V7_OK;
24580   struct v7 *v7 = bbuilder->v7;
24581   ast_off_t pos_after_tag;
24582   enum ast_tag tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
24583 
24584   switch (tag) {
24585     case AST_MEMBER: {
24586       lit_t lit = string_lit(bbuilder, a, pos_after_tag);
24587       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24588       if (for_call) {
24589         /* current TOS will be used as `this` */
24590         bcode_op(bbuilder, OP_DUP);
24591       }
24592       bcode_push_lit(bbuilder, lit);
24593       bcode_op(bbuilder, OP_GET);
24594       break;
24595     }
24596 
24597     case AST_INDEX:
24598       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24599       if (for_call) {
24600         /* current TOS will be used as `this` */
24601         bcode_op(bbuilder, OP_DUP);
24602       }
24603       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24604       bcode_op(bbuilder, OP_GET);
24605       break;
24606 
24607     default:
24608       if (for_call) {
24609         /*
24610          * `this` will be an `undefined` (but it may change to Global Object
24611          * at runtime)
24612          */
24613         bcode_op(bbuilder, OP_PUSH_UNDEFINED);
24614       }
24615       *ppos = pos_after_tag - 1;
24616       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24617       break;
24618   }
24619 
24620 clean:
24621   return rcode;
24622 }
24623 
24624 V7_PRIVATE enum v7_err compile_delete(struct bcode_builder *bbuilder,
24625                                       struct ast *a, ast_off_t *ppos) {
24626   enum v7_err rcode = V7_OK;
24627   struct v7 *v7 = bbuilder->v7;
24628   ast_off_t pos_after_tag;
24629   enum ast_tag tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
24630 
24631   switch (tag) {
24632     case AST_MEMBER: {
24633       /* Delete a specified property of an object */
24634       lit_t lit = string_lit(bbuilder, a, pos_after_tag);
24635       /* put an object to delete property from */
24636       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24637       /* put a property name */
24638       bcode_push_lit(bbuilder, lit);
24639       bcode_op(bbuilder, OP_DELETE);
24640       break;
24641     }
24642 
24643     case AST_INDEX:
24644       /* Delete a specified property of an object */
24645       /* put an object to delete property from */
24646       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24647       /* put a property name */
24648       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24649       bcode_op(bbuilder, OP_DELETE);
24650       break;
24651 
24652     case AST_IDENT:
24653       /* Delete the scope variable (or throw an error if strict mode) */
24654       if (!bbuilder->bcode->strict_mode) {
24655         /* put a property name */
24656         bcode_push_lit(bbuilder, string_lit(bbuilder, a, pos_after_tag));
24657         bcode_op(bbuilder, OP_DELETE_VAR);
24658       } else {
24659         rcode =
24660             v7_throwf(bbuilder->v7, SYNTAX_ERROR,
24661                       "Delete of an unqualified identifier in strict mode.");
24662         V7_THROW(V7_SYNTAX_ERROR);
24663       }
24664       break;
24665 
24666     case AST_UNDEFINED:
24667       /*
24668        * `undefined` should actually be an undeletable property of the Global
24669        * Object, so, trying to delete it just yields `false`
24670        */
24671       bcode_op(bbuilder, OP_PUSH_FALSE);
24672       break;
24673 
24674     default:
24675       /*
24676        * For all other cases, we evaluate the expression given to `delete`
24677        * for side effects, then drop the result, and yield `true`
24678        */
24679       *ppos = pos_after_tag - 1;
24680       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24681       bcode_op(bbuilder, OP_DROP);
24682       bcode_op(bbuilder, OP_PUSH_TRUE);
24683       break;
24684   }
24685 
24686 clean:
24687   return rcode;
24688 }
24689 
24690 V7_PRIVATE enum v7_err compile_expr_builder(struct bcode_builder *bbuilder,
24691                                             struct ast *a, ast_off_t *ppos) {
24692   enum v7_err rcode = V7_OK;
24693   struct v7 *v7 = bbuilder->v7;
24694   ast_off_t pos_after_tag;
24695   enum ast_tag tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
24696 
24697   switch (tag) {
24698     case AST_ADD:
24699     case AST_SUB:
24700     case AST_REM:
24701     case AST_MUL:
24702     case AST_DIV:
24703     case AST_LSHIFT:
24704     case AST_RSHIFT:
24705     case AST_URSHIFT:
24706     case AST_OR:
24707     case AST_XOR:
24708     case AST_AND:
24709     case AST_EQ_EQ:
24710     case AST_EQ:
24711     case AST_NE:
24712     case AST_NE_NE:
24713     case AST_LT:
24714     case AST_LE:
24715     case AST_GT:
24716     case AST_GE:
24717     case AST_INSTANCEOF:
24718       V7_TRY(compile_binary(bbuilder, a, ppos, tag));
24719       break;
24720     case AST_LOGICAL_NOT:
24721       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24722       bcode_op(bbuilder, OP_LOGICAL_NOT);
24723       break;
24724     case AST_NOT:
24725       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24726       bcode_op(bbuilder, OP_NOT);
24727       break;
24728     case AST_POSITIVE:
24729       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24730       bcode_op(bbuilder, OP_POS);
24731       break;
24732     case AST_NEGATIVE:
24733       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24734       bcode_op(bbuilder, OP_NEG);
24735       break;
24736     case AST_IDENT:
24737       bcode_op_lit(bbuilder, OP_GET_VAR,
24738                    string_lit(bbuilder, a, pos_after_tag));
24739       break;
24740     case AST_MEMBER:
24741     case AST_INDEX:
24742       /*
24743        * These two are handled by the "extended" version of this function,
24744        * since we may need to put `this` value on stack, for "method pattern
24745        * invocation".
24746        *
24747        * First of all, restore starting AST position, and then call extended
24748        * function.
24749        */
24750       *ppos = pos_after_tag - 1;
24751       V7_TRY(compile_expr_ext(bbuilder, a, ppos, 0 /*not for call*/));
24752       break;
24753     case AST_IN:
24754       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24755       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24756       bcode_op(bbuilder, OP_IN);
24757       break;
24758     case AST_TYPEOF: {
24759       ast_off_t lookahead = *ppos;
24760       tag = fetch_tag(v7, bbuilder, a, &lookahead, &pos_after_tag);
24761       if (tag == AST_IDENT) {
24762         *ppos = lookahead;
24763         bcode_op_lit(bbuilder, OP_SAFE_GET_VAR,
24764                      string_lit(bbuilder, a, pos_after_tag));
24765       } else {
24766         V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24767       }
24768       bcode_op(bbuilder, OP_TYPEOF);
24769       break;
24770     }
24771     case AST_ASSIGN:
24772     case AST_PREINC:
24773     case AST_PREDEC:
24774     case AST_POSTINC:
24775     case AST_POSTDEC:
24776     case AST_REM_ASSIGN:
24777     case AST_MUL_ASSIGN:
24778     case AST_DIV_ASSIGN:
24779     case AST_XOR_ASSIGN:
24780     case AST_PLUS_ASSIGN:
24781     case AST_MINUS_ASSIGN:
24782     case AST_OR_ASSIGN:
24783     case AST_AND_ASSIGN:
24784     case AST_LSHIFT_ASSIGN:
24785     case AST_RSHIFT_ASSIGN:
24786     case AST_URSHIFT_ASSIGN:
24787       V7_TRY(compile_assign(bbuilder, a, ppos, tag));
24788       break;
24789     case AST_COND: {
24790       /*
24791       * A ? B : C
24792       *
24793       * ->
24794       *
24795       *   <A>
24796       *   JMP_FALSE false
24797       *   <B>
24798       *   JMP end
24799       * false:
24800       *   <C>
24801       * end:
24802       *
24803       */
24804       bcode_off_t false_label, end_label;
24805       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24806       false_label = bcode_op_target(bbuilder, OP_JMP_FALSE);
24807       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24808       end_label = bcode_op_target(bbuilder, OP_JMP);
24809       bcode_patch_target(bbuilder, false_label, bcode_pos(bbuilder));
24810       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24811       bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
24812       break;
24813     }
24814     case AST_LOGICAL_OR:
24815     case AST_LOGICAL_AND: {
24816       /*
24817        * A && B
24818        *
24819        * ->
24820        *
24821        *   <A>
24822        *   JMP_FALSE end
24823        *   POP
24824        *   <B>
24825        * end:
24826        *
24827        */
24828       bcode_off_t end_label;
24829       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24830       bcode_op(bbuilder, OP_DUP);
24831       end_label = bcode_op_target(
24832           bbuilder, tag == AST_LOGICAL_AND ? OP_JMP_FALSE : OP_JMP_TRUE);
24833       bcode_op(bbuilder, OP_DROP);
24834       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24835       bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
24836       break;
24837     }
24838     /*
24839      * A, B, C
24840      *
24841      * ->
24842      *
24843      * <A>
24844      * DROP
24845      * <B>
24846      * DROP
24847      * <C>
24848      */
24849     case AST_SEQ: {
24850       ast_off_t end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
24851       while (*ppos < end) {
24852         V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24853         if (*ppos < end) {
24854           bcode_op(bbuilder, OP_DROP);
24855         }
24856       }
24857       break;
24858     }
24859     case AST_CALL:
24860     case AST_NEW: {
24861       /*
24862        * f()
24863        *
24864        * ->
24865        *
24866        *  PUSH_UNDEFINED (value for `this`)
24867        *  GET_VAR "f"
24868        *  CHECK_CALL
24869        *  CALL 0 args
24870        *
24871        * ---------------
24872        *
24873        * f(a, b)
24874        *
24875        * ->
24876        *
24877        *  PUSH_UNDEFINED (value for `this`)
24878        *  GET_VAR "f"
24879        *  CHECK_CALL
24880        *  GET_VAR "a"
24881        *  GET_VAR "b"
24882        *  CALL 2 args
24883        *
24884        * ---------------
24885        *
24886        * o.f(a, b)
24887        *
24888        * ->
24889        *
24890        *  GET_VAR "o" (so that `this` will be an `o`)
24891        *  DUP         (we'll also need `o` for GET below, so, duplicate it)
24892        *  PUSH_LIT "f"
24893        *  GET         (get property "f" of the object "o")
24894        *  CHECK_CALL
24895        *  GET_VAR "a"
24896        *  GET_VAR "b"
24897        *  CALL 2 args
24898        *
24899        */
24900       int args;
24901       ast_off_t end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
24902 
24903       V7_TRY(compile_expr_ext(bbuilder, a, ppos, 1 /*for call*/));
24904       bcode_op(bbuilder, OP_CHECK_CALL);
24905       for (args = 0; *ppos < end; args++) {
24906         V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24907       }
24908       bcode_op(bbuilder, (tag == AST_CALL ? OP_CALL : OP_NEW));
24909       if (args > 0x7f) {
24910         rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "too many arguments");
24911         V7_THROW(V7_SYNTAX_ERROR);
24912       }
24913       bcode_op(bbuilder, (uint8_t) args);
24914       break;
24915     }
24916     case AST_DELETE: {
24917       V7_TRY(compile_delete(bbuilder, a, ppos));
24918       break;
24919     }
24920     case AST_OBJECT: {
24921       /*
24922        * {a:<B>, ...}
24923        *
24924        * ->
24925        *
24926        *   CREATE_OBJ
24927        *   DUP
24928        *   PUSH_LIT "a"
24929        *   <B>
24930        *   SET
24931        *   POP
24932        *   ...
24933        */
24934 
24935       /*
24936        * Literal indices of property names of current object literal.
24937        * Needed for strict mode: we need to keep track of the added
24938        * properties, since duplicates are not allowed
24939        */
24940       struct mbuf cur_literals;
24941       lit_t lit;
24942       ast_off_t end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
24943       mbuf_init(&cur_literals, 0);
24944 
24945       bcode_op(bbuilder, OP_CREATE_OBJ);
24946       while (*ppos < end) {
24947         tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
24948         switch (tag) {
24949           case AST_PROP:
24950             bcode_op(bbuilder, OP_DUP);
24951             lit = string_lit(bbuilder, a, pos_after_tag);
24952 
24953 /* disabled because we broke get_lit */
24954 #if 0
24955             if (bbuilder->bcode->strict_mode) {
24956               /*
24957                * In strict mode, check for duplicate property names in
24958                * object literals
24959                */
24960               char *plit;
24961               for (plit = (char *) cur_literals.buf;
24962                    (char *) plit < cur_literals.buf + cur_literals.len;
24963                    plit++) {
24964                 const char *str1, *str2;
24965                 size_t size1, size2;
24966                 v7_val_t val1, val2;
24967 
24968                 val1 = bcode_get_lit(bbuilder->bcode, lit);
24969                 str1 = v7_get_string(bbuilder->v7, &val1, &size1);
24970 
24971                 val2 = bcode_get_lit(bbuilder->bcode, *plit);
24972                 str2 = v7_get_string(bbuilder->v7, &val2, &size2);
24973 
24974                 if (size1 == size2 && memcmp(str1, str2, size1) == 0) {
24975                   /* found already existing property of the same name */
24976                   rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR,
24977                                     "duplicate data property in object literal "
24978                                     "is not allowed in strict mode");
24979                   V7_THROW2(V7_SYNTAX_ERROR, ast_object_clean);
24980                 }
24981               }
24982               mbuf_append(&cur_literals, &lit, sizeof(lit));
24983             }
24984 #endif
24985             bcode_push_lit(bbuilder, lit);
24986             V7_TRY(compile_expr_builder(bbuilder, a, ppos));
24987             bcode_op(bbuilder, OP_SET);
24988             bcode_op(bbuilder, OP_DROP);
24989             break;
24990           default:
24991             rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "not implemented");
24992             V7_THROW2(V7_SYNTAX_ERROR, ast_object_clean);
24993         }
24994       }
24995 
24996     ast_object_clean:
24997       mbuf_free(&cur_literals);
24998       if (rcode != V7_OK) {
24999         V7_THROW(rcode);
25000       }
25001       break;
25002     }
25003     case AST_ARRAY: {
25004       /*
25005        * [<A>,,<B>,...]
25006        *
25007        * ->
25008        *
25009        *   CREATE_ARR
25010        *   PUSH_ZERO
25011        *
25012        *   2DUP
25013        *   <A>
25014        *   SET
25015        *   POP
25016        *   PUSH_ONE
25017        *   ADD
25018        *
25019        *   PUSH_ONE
25020        *   ADD
25021        *
25022        *   2DUP
25023        *   <B>
25024        *   ...
25025        *   POP // tmp index
25026        *
25027        * TODO(mkm): optimize this out. we can have more compact array push
25028        * that uses a special marker value for missing array elements
25029        * (which are not the same as undefined btw)
25030        */
25031       ast_off_t end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
25032       bcode_op(bbuilder, OP_CREATE_ARR);
25033       bcode_op(bbuilder, OP_PUSH_ZERO);
25034       while (*ppos < end) {
25035         ast_off_t lookahead = *ppos;
25036         tag = fetch_tag(v7, bbuilder, a, &lookahead, &pos_after_tag);
25037         if (tag != AST_NOP) {
25038           bcode_op(bbuilder, OP_2DUP);
25039           V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25040           bcode_op(bbuilder, OP_SET);
25041           bcode_op(bbuilder, OP_DROP);
25042         } else {
25043           *ppos = lookahead; /* skip nop */
25044         }
25045         bcode_op(bbuilder, OP_PUSH_ONE);
25046         bcode_op(bbuilder, OP_ADD);
25047       }
25048       bcode_op(bbuilder, OP_DROP);
25049       break;
25050     }
25051     case AST_FUNC: {
25052       lit_t flit;
25053 
25054       /*
25055        * Create half-done function: without scope and prototype. The real
25056        * function will be created from this one during bcode evaluation: see
25057        * `bcode_instantiate_function()`.
25058        */
25059       val_t funv = mk_js_function(bbuilder->v7, NULL, V7_UNDEFINED);
25060 
25061       /* Create bcode in this half-done function */
25062       struct v7_js_function *func = get_js_function_struct(funv);
25063       func->bcode = (struct bcode *) calloc(1, sizeof(*bbuilder->bcode));
25064       bcode_init(func->bcode, bbuilder->bcode->strict_mode,
25065                  NULL /* will be set below */, 0);
25066       bcode_copy_filename_from(func->bcode, bbuilder->bcode);
25067       retain_bcode(bbuilder->v7, func->bcode);
25068       flit = bcode_add_lit(bbuilder, funv);
25069 
25070       *ppos = pos_after_tag - 1;
25071       V7_TRY(compile_function(v7, a, ppos, func->bcode));
25072       bcode_push_lit(bbuilder, flit);
25073       bcode_op(bbuilder, OP_FUNC_LIT);
25074       break;
25075     }
25076     case AST_THIS:
25077       bcode_op(bbuilder, OP_PUSH_THIS);
25078       break;
25079     case AST_VOID:
25080       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25081       bcode_op(bbuilder, OP_DROP);
25082       bcode_op(bbuilder, OP_PUSH_UNDEFINED);
25083       break;
25084     case AST_NULL:
25085       bcode_op(bbuilder, OP_PUSH_NULL);
25086       break;
25087     case AST_NOP:
25088     case AST_UNDEFINED:
25089       bcode_op(bbuilder, OP_PUSH_UNDEFINED);
25090       break;
25091     case AST_TRUE:
25092       bcode_op(bbuilder, OP_PUSH_TRUE);
25093       break;
25094     case AST_FALSE:
25095       bcode_op(bbuilder, OP_PUSH_FALSE);
25096       break;
25097     case AST_NUM: {
25098       double dv = ast_get_num(a, pos_after_tag);
25099       if (dv == 0) {
25100         bcode_op(bbuilder, OP_PUSH_ZERO);
25101       } else if (dv == 1) {
25102         bcode_op(bbuilder, OP_PUSH_ONE);
25103       } else {
25104         bcode_push_lit(bbuilder, bcode_add_lit(bbuilder, v7_mk_number(v7, dv)));
25105       }
25106       break;
25107     }
25108     case AST_STRING:
25109       bcode_push_lit(bbuilder, string_lit(bbuilder, a, pos_after_tag));
25110       break;
25111     case AST_REGEX:
25112 #if V7_ENABLE__RegExp
25113     {
25114       lit_t tmp;
25115       rcode = regexp_lit(bbuilder, a, pos_after_tag, &tmp);
25116       if (rcode != V7_OK) {
25117         rcode = V7_SYNTAX_ERROR;
25118         goto clean;
25119       }
25120 
25121       bcode_push_lit(bbuilder, tmp);
25122       break;
25123     }
25124 #else
25125       rcode =
25126           v7_throwf(bbuilder->v7, SYNTAX_ERROR, "Regexp support is disabled");
25127       V7_THROW(V7_SYNTAX_ERROR);
25128 #endif
25129     case AST_LABEL:
25130     case AST_LABELED_BREAK:
25131     case AST_LABELED_CONTINUE:
25132       /* TODO(dfrank): implement */
25133       rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "not implemented");
25134       V7_THROW(V7_SYNTAX_ERROR);
25135     case AST_WITH:
25136       rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "not implemented");
25137       V7_THROW(V7_SYNTAX_ERROR);
25138     default:
25139       /*
25140        * We end up here if the AST is broken.
25141        *
25142        * It might be appropriate to return `V7_INTERNAL_ERROR` here, but since
25143        * we might receive AST from network or something, we just interpret
25144        * it as SyntaxError.
25145        */
25146       rcode = v7_throwf(bbuilder->v7, SYNTAX_ERROR, "unknown ast node %d",
25147                         (int) tag);
25148       V7_THROW(V7_SYNTAX_ERROR);
25149   }
25150 clean:
25151   return rcode;
25152 }
25153 
25154 V7_PRIVATE enum v7_err compile_stmt(struct bcode_builder *bbuilder,
25155                                     struct ast *a, ast_off_t *ppos);
25156 
25157 V7_PRIVATE enum v7_err compile_stmts(struct bcode_builder *bbuilder,
25158                                      struct ast *a, ast_off_t *ppos,
25159                                      ast_off_t end) {
25160   enum v7_err rcode = V7_OK;
25161   struct v7 *v7 = bbuilder->v7;
25162 
25163   while (*ppos < end) {
25164     V7_TRY(compile_stmt(bbuilder, a, ppos));
25165     if (!bbuilder->v7->is_stack_neutral) {
25166       bcode_op(bbuilder, OP_SWAP_DROP);
25167     } else {
25168       bbuilder->v7->is_stack_neutral = 0;
25169     }
25170   }
25171 clean:
25172   return rcode;
25173 }
25174 
25175 V7_PRIVATE enum v7_err compile_stmt(struct bcode_builder *bbuilder,
25176                                     struct ast *a, ast_off_t *ppos) {
25177   ast_off_t end;
25178   enum ast_tag tag;
25179   ast_off_t cond, pos_after_tag;
25180   bcode_off_t body_target, body_label, cond_label;
25181   struct mbuf case_labels;
25182   enum v7_err rcode = V7_OK;
25183   struct v7 *v7 = bbuilder->v7;
25184 
25185   tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
25186 
25187   mbuf_init(&case_labels, 0);
25188 
25189   switch (tag) {
25190     /*
25191      * if(E) {
25192      *   BT...
25193      * } else {
25194      *   BF...
25195      * }
25196      *
25197      * ->
25198      *
25199      *   <E>
25200      *   JMP_FALSE body
25201      *   <BT>
25202      *   JMP end
25203      * body:
25204      *   <BF>
25205      * end:
25206      *
25207      * If else clause is omitted, it will emit output equivalent to:
25208      *
25209      * if(E) {BT} else undefined;
25210      */
25211     case AST_IF: {
25212       ast_off_t if_false;
25213       bcode_off_t end_label, if_false_label;
25214       end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
25215       if_false = ast_get_skip(a, pos_after_tag, AST_END_IF_TRUE_SKIP);
25216 
25217       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25218       if_false_label = bcode_op_target(bbuilder, OP_JMP_FALSE);
25219 
25220       /* body if true */
25221       V7_TRY(compile_stmts(bbuilder, a, ppos, if_false));
25222 
25223       if (if_false != end) {
25224         /* `else` branch is present */
25225         end_label = bcode_op_target(bbuilder, OP_JMP);
25226 
25227         /* will jump here if `false` */
25228         bcode_patch_target(bbuilder, if_false_label, bcode_pos(bbuilder));
25229 
25230         /* body if false */
25231         V7_TRY(compile_stmts(bbuilder, a, ppos, end));
25232 
25233         bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
25234       } else {
25235         /*
25236          * `else` branch is not present: just remember where we should
25237          * jump in case of `false`
25238          */
25239         bcode_patch_target(bbuilder, if_false_label, bcode_pos(bbuilder));
25240       }
25241 
25242       bbuilder->v7->is_stack_neutral = 1;
25243       break;
25244     }
25245     /*
25246      * while(C) {
25247      *   B...
25248      * }
25249      *
25250      * ->
25251      *
25252      *   TRY_PUSH_LOOP end
25253      *   JMP cond
25254      * body:
25255      *   <B>
25256      * cond:
25257      *   <C>
25258      *   JMP_TRUE body
25259      * end:
25260      *   JMP_IF_CONTINUE cond
25261      *   TRY_POP
25262      *
25263      */
25264     case AST_WHILE: {
25265       bcode_off_t end_label, continue_label, continue_target;
25266 
25267       end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
25268       cond = *ppos;
25269       ast_skip_tree(a, ppos);
25270 
25271       end_label = bcode_op_target(bbuilder, OP_TRY_PUSH_LOOP);
25272 
25273       /*
25274        * Condition check is at the end of the loop, this layout
25275        * reduces the number of jumps in the steady state.
25276        */
25277       cond_label = bcode_op_target(bbuilder, OP_JMP);
25278       body_target = bcode_pos(bbuilder);
25279 
25280       V7_TRY(compile_stmts(bbuilder, a, ppos, end));
25281 
25282       continue_target = bcode_pos(bbuilder);
25283       bcode_patch_target(bbuilder, cond_label, continue_target);
25284 
25285       V7_TRY(compile_expr_builder(bbuilder, a, &cond));
25286       body_label = bcode_op_target(bbuilder, OP_JMP_TRUE);
25287       bcode_patch_target(bbuilder, body_label, body_target);
25288 
25289       bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
25290       continue_label = bcode_op_target(bbuilder, OP_JMP_IF_CONTINUE);
25291       bcode_patch_target(bbuilder, continue_label, continue_target);
25292       bcode_op(bbuilder, OP_TRY_POP);
25293 
25294       bbuilder->v7->is_stack_neutral = 1;
25295       break;
25296     }
25297     case AST_BREAK:
25298       bcode_op(bbuilder, OP_BREAK);
25299       break;
25300     case AST_CONTINUE:
25301       bcode_op(bbuilder, OP_CONTINUE);
25302       break;
25303     /*
25304      * Frame objects (`v7->vals.call_stack`) contain one more hidden property:
25305      * `____t`, which is an array of offsets in bcode. Each element of the array
25306      * is an offset of either `catch` or `finally` block (distinguished by the
25307      * tag: `OFFSET_TAG_CATCH` or `OFFSET_TAG_FINALLY`). Let's call this array
25308      * as a "try stack". When evaluator enters new `try` block, it adds
25309      * appropriate offset(s) at the top of "try stack", and when we unwind the
25310      * stack, we can "pop" offsets from "try stack" at each level.
25311      *
25312      * try {
25313      *   TRY_B
25314      * } catch (e) {
25315      *   CATCH_B
25316      * } finally {
25317      *   FIN_B
25318      * }
25319      *
25320      * ->
25321      *    OP_TRY_PUSH_FINALLY finally
25322      *    OP_TRY_PUSH_CATCH catch
25323      *    <TRY_B>
25324      *    OP_TRY_POP
25325      *    JMP finally
25326      *  catch:
25327      *    OP_TRY_POP
25328      *    OP_ENTER_CATCH <e>
25329      *    <CATCH_B>
25330      *    OP_EXIT_CATCH
25331      *  finally:
25332      *    OP_TRY_POP
25333      *    <FIN_B>
25334      *    OP_AFTER_FINALLY
25335      *
25336      * ---------------
25337      *
25338      * try {
25339      *   TRY_B
25340      * } catch (e) {
25341      *   CATCH_B
25342      * }
25343      *
25344      * ->
25345      *    OP_TRY_PUSH_CATCH catch
25346      *    <TRY_B>
25347      *    OP_TRY_POP
25348      *    JMP end
25349      *  catch:
25350      *    OP_TRY_POP
25351      *    OP_ENTER_CATCH <e>
25352      *    <CATCH_B>
25353      *    OP_EXIT_CATCH
25354      *  end:
25355      *
25356      * ---------------
25357      *
25358      * try {
25359      *   TRY_B
25360      * } finally {
25361      *   FIN_B
25362      * }
25363      *
25364      * ->
25365      *    OP_TRY_PUSH_FINALLY finally
25366      *    <TRY_B>
25367      *  finally:
25368      *    OP_TRY_POP
25369      *    <FIN_B>
25370      *    OP_AFTER_FINALLY
25371      */
25372     case AST_TRY: {
25373       ast_off_t acatch, afinally;
25374       bcode_off_t finally_label, catch_label;
25375 
25376       end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
25377       acatch = ast_get_skip(a, pos_after_tag, AST_TRY_CATCH_SKIP);
25378       afinally = ast_get_skip(a, pos_after_tag, AST_TRY_FINALLY_SKIP);
25379 
25380       if (afinally != end) {
25381         /* `finally` clause is present: push its offset */
25382         finally_label = bcode_op_target(bbuilder, OP_TRY_PUSH_FINALLY);
25383       }
25384 
25385       if (acatch != afinally) {
25386         /* `catch` clause is present: push its offset */
25387         catch_label = bcode_op_target(bbuilder, OP_TRY_PUSH_CATCH);
25388       }
25389 
25390       /* compile statements of `try` block */
25391       V7_TRY(compile_stmts(bbuilder, a, ppos, acatch));
25392 
25393       if (acatch != afinally) {
25394         /* `catch` clause is present: compile it */
25395         bcode_off_t after_catch_label;
25396 
25397         /*
25398          * pop offset pushed by OP_TRY_PUSH_CATCH, and jump over the `catch`
25399          * block
25400          */
25401         bcode_op(bbuilder, OP_TRY_POP);
25402         after_catch_label = bcode_op_target(bbuilder, OP_JMP);
25403 
25404         /* --- catch --- */
25405 
25406         /* in case of exception in the `try` block above, we'll get here */
25407         bcode_patch_target(bbuilder, catch_label, bcode_pos(bbuilder));
25408 
25409         /* pop offset pushed by OP_TRY_PUSH_CATCH */
25410         bcode_op(bbuilder, OP_TRY_POP);
25411 
25412         /*
25413          * retrieve identifier where to store thrown error, and make sure
25414          * it is actually an indentifier (AST_IDENT)
25415          */
25416         tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
25417         V7_CHECK(tag == AST_IDENT, V7_SYNTAX_ERROR);
25418 
25419         /*
25420          * when we enter `catch` block, the TOS contains thrown value.
25421          * We should create private frame for the `catch` clause, and populate
25422          * a variable with the thrown value there.
25423          * The `OP_ENTER_CATCH` opcode does just that.
25424          */
25425         bcode_op_lit(bbuilder, OP_ENTER_CATCH,
25426                      string_lit(bbuilder, a, pos_after_tag));
25427 
25428         /*
25429          * compile statements until the end of `catch` clause
25430          * (`afinally` points to the end of the `catch` clause independently
25431          * of whether the `finally` clause is present)
25432          */
25433         V7_TRY(compile_stmts(bbuilder, a, ppos, afinally));
25434 
25435         /* pop private frame */
25436         bcode_op(bbuilder, OP_EXIT_CATCH);
25437 
25438         bcode_patch_target(bbuilder, after_catch_label, bcode_pos(bbuilder));
25439       }
25440 
25441       if (afinally != end) {
25442         /* `finally` clause is present: compile it */
25443 
25444         /* --- finally --- */
25445 
25446         /* after the `try` block above executes, we'll get here */
25447         bcode_patch_target(bbuilder, finally_label, bcode_pos(bbuilder));
25448 
25449         /* pop offset pushed by OP_TRY_PUSH_FINALLY */
25450         bcode_op(bbuilder, OP_TRY_POP);
25451 
25452         /* compile statements until the end of `finally` clause */
25453         V7_TRY(compile_stmts(bbuilder, a, ppos, end));
25454 
25455         bcode_op(bbuilder, OP_AFTER_FINALLY);
25456       }
25457 
25458       bbuilder->v7->is_stack_neutral = 1;
25459       break;
25460     }
25461 
25462     case AST_THROW: {
25463       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25464       bcode_op(bbuilder, OP_THROW);
25465       break;
25466     }
25467 
25468     /*
25469      * switch(E) {
25470      * default:
25471      *   D...
25472      * case C1:
25473      *   B1...
25474      * case C2:
25475      *   B2...
25476      * }
25477      *
25478      * ->
25479      *
25480      *   TRY_PUSH_SWITCH end
25481      *   <E>
25482      *   DUP
25483      *   <C1>
25484      *   EQ
25485      *   JMP_TRUE_DROP l1
25486      *   DUP
25487      *   <C2>
25488      *   EQ
25489      *   JMP_TRUE_DROP l2
25490      *   DROP
25491      *   JMP dfl
25492      *
25493      * dfl:
25494      *   <D>
25495      *
25496      * l1:
25497      *   <B1>
25498      *
25499      * l2:
25500      *   <B2>
25501      *
25502      * end:
25503      *   TRY_POP
25504      *
25505      * If the default case is missing we treat it as if had an empty body and
25506      * placed in last position (i.e. `dfl` label is replaced with `end`).
25507      *
25508      * Before emitting a case/default block (except the first one) we have to
25509      * drop the TOS resulting from evaluating the last expression
25510      */
25511     case AST_SWITCH: {
25512       bcode_off_t dfl_label, end_label;
25513       ast_off_t case_end, case_start;
25514       enum ast_tag case_tag;
25515       int i, has_default = 0, cases = 0;
25516 
25517       end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
25518 
25519       end_label = bcode_op_target(bbuilder, OP_TRY_PUSH_SWITCH);
25520 
25521       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25522 
25523       case_start = *ppos;
25524       /* first pass: evaluate case expression and generate jump table */
25525       while (*ppos < end) {
25526         case_tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
25527         assert(case_tag == AST_DEFAULT || case_tag == AST_CASE);
25528 
25529         case_end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
25530 
25531         switch (case_tag) {
25532           case AST_DEFAULT:
25533             /* default jump table entry must be the last one */
25534             break;
25535           case AST_CASE: {
25536             bcode_off_t case_label;
25537             bcode_op(bbuilder, OP_DUP);
25538             V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25539             bcode_op(bbuilder, OP_EQ);
25540             case_label = bcode_op_target(bbuilder, OP_JMP_TRUE_DROP);
25541             cases++;
25542             mbuf_append(&case_labels, &case_label, sizeof(case_label));
25543             break;
25544           }
25545           default:
25546             assert(case_tag == AST_DEFAULT || case_tag == AST_CASE);
25547         }
25548         *ppos = case_end;
25549       }
25550 
25551       /* jmp table epilogue: unconditional jump to default case */
25552       bcode_op(bbuilder, OP_DROP);
25553       dfl_label = bcode_op_target(bbuilder, OP_JMP);
25554 
25555       *ppos = case_start;
25556       /* second pass: emit case bodies and patch jump table */
25557 
25558       for (i = 0; *ppos < end;) {
25559         case_tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
25560         assert(case_tag == AST_DEFAULT || case_tag == AST_CASE);
25561         assert(i <= cases);
25562 
25563         case_end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
25564 
25565         switch (case_tag) {
25566           case AST_DEFAULT:
25567             has_default = 1;
25568             bcode_patch_target(bbuilder, dfl_label, bcode_pos(bbuilder));
25569             V7_TRY(compile_stmts(bbuilder, a, ppos, case_end));
25570             break;
25571           case AST_CASE: {
25572             bcode_off_t case_label = ((bcode_off_t *) case_labels.buf)[i++];
25573             bcode_patch_target(bbuilder, case_label, bcode_pos(bbuilder));
25574             ast_skip_tree(a, ppos);
25575             V7_TRY(compile_stmts(bbuilder, a, ppos, case_end));
25576             break;
25577           }
25578           default:
25579             assert(case_tag == AST_DEFAULT || case_tag == AST_CASE);
25580         }
25581 
25582         *ppos = case_end;
25583       }
25584       mbuf_free(&case_labels);
25585 
25586       if (!has_default) {
25587         bcode_patch_target(bbuilder, dfl_label, bcode_pos(bbuilder));
25588       }
25589 
25590       bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
25591       bcode_op(bbuilder, OP_TRY_POP);
25592 
25593       bbuilder->v7->is_stack_neutral = 1;
25594       break;
25595     }
25596     /*
25597      * for(INIT,COND,IT) {
25598      *   B...
25599      * }
25600      *
25601      * ->
25602      *
25603      *   <INIT>
25604      *   DROP
25605      *   TRY_PUSH_LOOP end
25606      *   JMP cond
25607      * body:
25608      *   <B>
25609      * next:
25610      *   <IT>
25611      *   DROP
25612      * cond:
25613      *   <COND>
25614      *   JMP_TRUE body
25615      * end:
25616      *   JMP_IF_CONTINUE next
25617      *   TRY_POP
25618      *
25619      */
25620     case AST_FOR: {
25621       ast_off_t iter, body, lookahead;
25622       bcode_off_t end_label, continue_label, continue_target;
25623       end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
25624       body = ast_get_skip(a, pos_after_tag, AST_FOR_BODY_SKIP);
25625 
25626       lookahead = *ppos;
25627       tag = fetch_tag(v7, bbuilder, a, &lookahead, &pos_after_tag);
25628       /*
25629        * Support for `var` declaration in INIT
25630        */
25631       if (tag == AST_VAR) {
25632         ast_off_t fvar_end;
25633         lit_t lit;
25634 
25635         *ppos = lookahead;
25636         fvar_end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
25637 
25638         /*
25639          * Iterate through all vars in the given `var` declaration: they are
25640          * just like assigments here
25641          */
25642         while (*ppos < fvar_end) {
25643           tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
25644           /* Only var declarations are allowed (not function declarations) */
25645           V7_CHECK_INTERNAL(tag == AST_VAR_DECL);
25646           lit = string_lit(bbuilder, a, pos_after_tag);
25647           V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25648 
25649           /* Just like an assigment */
25650           bcode_op_lit(bbuilder, OP_SET_VAR, lit);
25651 
25652           /* INIT is stack-neutral */
25653           bcode_op(bbuilder, OP_DROP);
25654         }
25655       } else {
25656         /* normal expression in INIT (not `var` declaration) */
25657         V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25658         /* INIT is stack-neutral */
25659         bcode_op(bbuilder, OP_DROP);
25660       }
25661       cond = *ppos;
25662       ast_skip_tree(a, ppos);
25663       iter = *ppos;
25664       *ppos = body;
25665 
25666       end_label = bcode_op_target(bbuilder, OP_TRY_PUSH_LOOP);
25667       cond_label = bcode_op_target(bbuilder, OP_JMP);
25668       body_target = bcode_pos(bbuilder);
25669       V7_TRY(compile_stmts(bbuilder, a, ppos, end));
25670 
25671       continue_target = bcode_pos(bbuilder);
25672 
25673       V7_TRY(compile_expr_builder(bbuilder, a, &iter));
25674       bcode_op(bbuilder, OP_DROP);
25675 
25676       bcode_patch_target(bbuilder, cond_label, bcode_pos(bbuilder));
25677 
25678       /*
25679        * Handle for(INIT;;ITER)
25680        */
25681       lookahead = cond;
25682       tag = fetch_tag(v7, bbuilder, a, &lookahead, &pos_after_tag);
25683       if (tag == AST_NOP) {
25684         bcode_op(bbuilder, OP_JMP);
25685       } else {
25686         V7_TRY(compile_expr_builder(bbuilder, a, &cond));
25687         bcode_op(bbuilder, OP_JMP_TRUE);
25688       }
25689       body_label = bcode_add_target(bbuilder);
25690       bcode_patch_target(bbuilder, body_label, body_target);
25691       bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
25692 
25693       continue_label = bcode_op_target(bbuilder, OP_JMP_IF_CONTINUE);
25694       bcode_patch_target(bbuilder, continue_label, continue_target);
25695 
25696       bcode_op(bbuilder, OP_TRY_POP);
25697 
25698       bbuilder->v7->is_stack_neutral = 1;
25699       break;
25700     }
25701     /*
25702      * for(I in O) {
25703      *   B...
25704      * }
25705      *
25706      * ->
25707      *
25708      *   DUP
25709      *   <O>
25710      *   SWAP
25711      *   STASH
25712      *   DROP
25713      *   PUSH_PROP_ITER_CTX   # push initial iteration context
25714      *   TRY_PUSH_LOOP brend
25715      * loop:
25716      *   NEXT_PROP
25717      *   JMP_FALSE end
25718      *   SET_VAR <I>
25719      *   UNSTASH
25720      *   <B>
25721      * next:
25722      *   STASH
25723      *   DROP
25724      *   JMP loop
25725      * end:
25726      *   UNSTASH
25727      *   JMP try_pop:
25728      * brend:
25729      *              # got here after a `break` or `continue` from a loop body:
25730      *   JMP_IF_CONTINUE next
25731      *
25732      *              # we're not going to `continue`, so, need to remove an
25733      *              # extra stuff that was needed for the NEXT_PROP
25734      *
25735      *   SWAP_DROP  # drop iteration context
25736      *   SWAP_DROP  # drop <O>
25737      *   SWAP_DROP  # drop the value preceding the loop
25738      * try_pop:
25739      *   TRY_POP
25740      *
25741      */
25742     case AST_FOR_IN: {
25743       lit_t lit;
25744       bcode_off_t loop_label, loop_target, end_label, brend_label,
25745           continue_label, pop_label, continue_target;
25746       ast_off_t end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
25747 
25748       tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
25749       /* TODO(mkm) accept any l-value */
25750       if (tag == AST_VAR) {
25751         tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
25752         V7_CHECK_INTERNAL(tag == AST_VAR_DECL);
25753         lit = string_lit(bbuilder, a, pos_after_tag);
25754         ast_skip_tree(a, ppos);
25755       } else {
25756         V7_CHECK_INTERNAL(tag == AST_IDENT);
25757         lit = string_lit(bbuilder, a, pos_after_tag);
25758       }
25759 
25760       /*
25761        * preserve previous statement value.
25762        * We need to feed the previous value into the stash
25763        * because it's required for the loop steady state.
25764        *
25765        * The stash register is required to simplify the steady state stack
25766        * management, in particular the removal of value in 3rd position in case
25767        * a of not taken exit.
25768        *
25769        * TODO(mkm): consider having a stash OP that moves a value to the stash
25770        * register instead of copying it. The current behaviour has been
25771        * optimized for the `assign` use case which seems more common.
25772        */
25773       bcode_op(bbuilder, OP_DUP);
25774       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25775       bcode_op(bbuilder, OP_SWAP);
25776       bcode_op(bbuilder, OP_STASH);
25777       bcode_op(bbuilder, OP_DROP);
25778 
25779       /*
25780        * OP_NEXT_PROP needs the iteration context, let's push the initial one.
25781        */
25782       bcode_op(bbuilder, OP_PUSH_PROP_ITER_CTX);
25783 
25784       brend_label = bcode_op_target(bbuilder, OP_TRY_PUSH_LOOP);
25785 
25786       /* loop: */
25787       loop_target = bcode_pos(bbuilder);
25788 
25789       /*
25790        * The loop stead state begins with the following stack layout:
25791        * `( S:v o h )`
25792        */
25793 
25794       bcode_op(bbuilder, OP_NEXT_PROP);
25795       end_label = bcode_op_target(bbuilder, OP_JMP_FALSE);
25796       bcode_op_lit(bbuilder, OP_SET_VAR, lit);
25797 
25798       /*
25799        * The stash register contains the value of the previous statement,
25800        * being it the statement before the for..in statement or
25801        * the previous iteration. We move it to the data stack. It will
25802        * be replaced by the values of the body statements as usual.
25803        */
25804       bcode_op(bbuilder, OP_UNSTASH);
25805 
25806       /*
25807        * This node is always a NOP, for compatibility
25808        * with the layout of the AST_FOR node.
25809        */
25810       ast_skip_tree(a, ppos);
25811 
25812       V7_TRY(compile_stmts(bbuilder, a, ppos, end));
25813 
25814       continue_target = bcode_pos(bbuilder);
25815 
25816       /*
25817        * Save the last body statement. If next evaluation of NEXT_PROP returns
25818        * false, we'll unstash it.
25819        */
25820       bcode_op(bbuilder, OP_STASH);
25821       bcode_op(bbuilder, OP_DROP);
25822 
25823       loop_label = bcode_op_target(bbuilder, OP_JMP);
25824       bcode_patch_target(bbuilder, loop_label, loop_target);
25825 
25826       /* end: */
25827       bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
25828       bcode_op(bbuilder, OP_UNSTASH);
25829 
25830       pop_label = bcode_op_target(bbuilder, OP_JMP);
25831 
25832       /* brend: */
25833       bcode_patch_target(bbuilder, brend_label, bcode_pos(bbuilder));
25834 
25835       continue_label = bcode_op_target(bbuilder, OP_JMP_IF_CONTINUE);
25836       bcode_patch_target(bbuilder, continue_label, continue_target);
25837 
25838       bcode_op(bbuilder, OP_SWAP_DROP);
25839       bcode_op(bbuilder, OP_SWAP_DROP);
25840       bcode_op(bbuilder, OP_SWAP_DROP);
25841 
25842       /* try_pop: */
25843       bcode_patch_target(bbuilder, pop_label, bcode_pos(bbuilder));
25844 
25845       bcode_op(bbuilder, OP_TRY_POP);
25846 
25847       bbuilder->v7->is_stack_neutral = 1;
25848       break;
25849     }
25850     /*
25851      * do {
25852      *   B...
25853      * } while(COND);
25854      *
25855      * ->
25856      *
25857      *   TRY_PUSH_LOOP end
25858      * body:
25859      *   <B>
25860      * cond:
25861      *   <COND>
25862      *   JMP_TRUE body
25863      * end:
25864      *   JMP_IF_CONTINUE cond
25865      *   TRY_POP
25866      *
25867      */
25868     case AST_DOWHILE: {
25869       bcode_off_t end_label, continue_label, continue_target;
25870       end = ast_get_skip(a, pos_after_tag, AST_DO_WHILE_COND_SKIP);
25871       end_label = bcode_op_target(bbuilder, OP_TRY_PUSH_LOOP);
25872       body_target = bcode_pos(bbuilder);
25873       V7_TRY(compile_stmts(bbuilder, a, ppos, end));
25874 
25875       continue_target = bcode_pos(bbuilder);
25876       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25877       body_label = bcode_op_target(bbuilder, OP_JMP_TRUE);
25878       bcode_patch_target(bbuilder, body_label, body_target);
25879 
25880       bcode_patch_target(bbuilder, end_label, bcode_pos(bbuilder));
25881       continue_label = bcode_op_target(bbuilder, OP_JMP_IF_CONTINUE);
25882       bcode_patch_target(bbuilder, continue_label, continue_target);
25883       bcode_op(bbuilder, OP_TRY_POP);
25884 
25885       bbuilder->v7->is_stack_neutral = 1;
25886       break;
25887     }
25888     case AST_VAR: {
25889       /*
25890        * Var decls are hoisted when the function frame is created. Vars
25891        * declared inside a `with` or `catch` block belong to the function
25892        * lexical scope, and although those clauses create an inner frame
25893        * no new variables should be created in it. A var decl thus
25894        * behaves as a normal assignment at runtime.
25895        */
25896       lit_t lit;
25897       end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
25898       while (*ppos < end) {
25899         tag = fetch_tag(v7, bbuilder, a, ppos, &pos_after_tag);
25900         if (tag == AST_FUNC_DECL) {
25901           /*
25902            * function declarations are already set during hoisting (see
25903            * `compile_local_vars()`), so, skip it.
25904            *
25905            * Plus, they are stack-neutral, so don't forget to set
25906            * `is_stack_neutral`.
25907            */
25908           ast_skip_tree(a, ppos);
25909           bbuilder->v7->is_stack_neutral = 1;
25910         } else {
25911           /*
25912            * compile `var` declaration: basically it looks similar to an
25913            * assignment, but it differs from an assignment is that it's
25914            * stack-neutral: `1; var a = 5;` yields `1`, not `5`.
25915            */
25916           V7_CHECK_INTERNAL(tag == AST_VAR_DECL);
25917           lit = string_lit(bbuilder, a, pos_after_tag);
25918           V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25919           bcode_op_lit(bbuilder, OP_SET_VAR, lit);
25920 
25921           /* `var` declaration is stack-neutral */
25922           bcode_op(bbuilder, OP_DROP);
25923           bbuilder->v7->is_stack_neutral = 1;
25924         }
25925       }
25926       break;
25927     }
25928     case AST_RETURN:
25929       bcode_op(bbuilder, OP_PUSH_UNDEFINED);
25930       bcode_op(bbuilder, OP_RET);
25931       break;
25932     case AST_VALUE_RETURN:
25933       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25934       bcode_op(bbuilder, OP_RET);
25935       break;
25936     default:
25937       *ppos = pos_after_tag - 1;
25938       V7_TRY(compile_expr_builder(bbuilder, a, ppos));
25939   }
25940 
25941 clean:
25942   mbuf_free(&case_labels);
25943   return rcode;
25944 }
25945 
25946 static enum v7_err compile_body(struct bcode_builder *bbuilder, struct ast *a,
25947                                 ast_off_t start, ast_off_t end, ast_off_t body,
25948                                 ast_off_t fvar, ast_off_t *ppos) {
25949   enum v7_err rcode = V7_OK;
25950   struct v7 *v7 = bbuilder->v7;
25951 
25952 #ifndef V7_FORCE_STRICT_MODE
25953   /* check 'use strict' */
25954   if (*ppos < end) {
25955     ast_off_t tmp_pos = body;
25956     if (fetch_tag(v7, bbuilder, a, &tmp_pos, NULL) == AST_USE_STRICT) {
25957       bbuilder->bcode->strict_mode = 1;
25958       /* move `body` offset, effectively removing `AST_USE_STRICT` from it */
25959       body = tmp_pos;
25960     }
25961   }
25962 #endif
25963 
25964   /* put initial value for the function body execution */
25965   bcode_op(bbuilder, OP_PUSH_UNDEFINED);
25966 
25967   /*
25968    * populate `bcode->ops` with function's local variable names. Note that we
25969    * should do this *after* `OP_PUSH_UNDEFINED`, since `compile_local_vars`
25970    * emits code that assigns the hoisted functions to local variables, and
25971    * those statements assume that the stack contains `undefined`.
25972    */
25973   V7_TRY(compile_local_vars(bbuilder, a, start, fvar));
25974 
25975   /* compile body */
25976   *ppos = body;
25977   V7_TRY(compile_stmts(bbuilder, a, ppos, end));
25978 
25979 clean:
25980   return rcode;
25981 }
25982 
25983 /*
25984  * Compiles a given script and populates a bcode structure.
25985  * The AST must start with an AST_SCRIPT node.
25986  */
25987 V7_PRIVATE enum v7_err compile_script(struct v7 *v7, struct ast *a,
25988                                       struct bcode *bcode) {
25989   ast_off_t pos_after_tag, end, fvar, pos = 0;
25990   int saved_line_no = v7->line_no;
25991   enum v7_err rcode = V7_OK;
25992   struct bcode_builder bbuilder;
25993   enum ast_tag tag;
25994 
25995   bcode_builder_init(v7, &bbuilder, bcode);
25996   v7->line_no = 1;
25997 
25998   tag = fetch_tag(v7, &bbuilder, a, &pos, &pos_after_tag);
25999 
26000   /* first tag should always be AST_SCRIPT */
26001   assert(tag == AST_SCRIPT);
26002   (void) tag;
26003 
26004   end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
26005   fvar = ast_get_skip(a, pos_after_tag, AST_FUNC_FIRST_VAR_SKIP) - 1;
26006 
26007   V7_TRY(compile_body(&bbuilder, a, pos_after_tag - 1, end, pos /* body */,
26008                       fvar, &pos));
26009 
26010 clean:
26011 
26012   bcode_builder_finalize(&bbuilder);
26013 
26014 #ifdef V7_BCODE_DUMP
26015   if (rcode == V7_OK) {
26016     fprintf(stderr, "--- script ---\n");
26017     dump_bcode(v7, stderr, bcode);
26018   }
26019 #endif
26020 
26021   v7->line_no = saved_line_no;
26022 
26023   return rcode;
26024 }
26025 
26026 /*
26027  * Compiles a given function and populates a bcode structure.
26028  * The AST must contain an AST_FUNC node at offset ast_off.
26029  */
26030 V7_PRIVATE enum v7_err compile_function(struct v7 *v7, struct ast *a,
26031                                         ast_off_t *ppos, struct bcode *bcode) {
26032   ast_off_t pos_after_tag, start, end, body, fvar;
26033   const char *name;
26034   size_t name_len;
26035   size_t args_cnt;
26036   enum v7_err rcode = V7_OK;
26037   struct bcode_builder bbuilder;
26038   enum ast_tag tag;
26039   size_t names_end = 0;
26040   bcode_builder_init(v7, &bbuilder, bcode);
26041   tag = fetch_tag(v7, &bbuilder, a, ppos, &pos_after_tag);
26042   start = pos_after_tag - 1;
26043 
26044   (void) tag;
26045   assert(tag == AST_FUNC);
26046   end = ast_get_skip(a, pos_after_tag, AST_END_SKIP);
26047   body = ast_get_skip(a, pos_after_tag, AST_FUNC_BODY_SKIP);
26048   fvar = ast_get_skip(a, pos_after_tag, AST_FUNC_FIRST_VAR_SKIP) - 1;
26049 
26050   /* retrieve function name */
26051   tag = fetch_tag(v7, &bbuilder, a, ppos, &pos_after_tag);
26052   if (tag == AST_IDENT) {
26053     /* function name is provided */
26054     name = ast_get_inlined_data(a, pos_after_tag, &name_len);
26055     V7_TRY(bcode_add_name(&bbuilder, name, name_len, &names_end));
26056   } else {
26057     /* no name: anonymous function */
26058     V7_TRY(bcode_add_name(&bbuilder, "", 0, &names_end));
26059   }
26060 
26061   /* retrieve function's argument names */
26062   for (args_cnt = 0; *ppos < body; args_cnt++) {
26063     if (args_cnt > V7_ARGS_CNT_MAX) {
26064       /* too many arguments */
26065       rcode = v7_throwf(v7, SYNTAX_ERROR, "Too many arguments");
26066       V7_THROW(V7_SYNTAX_ERROR);
26067     }
26068 
26069     tag = fetch_tag(v7, &bbuilder, a, ppos, &pos_after_tag);
26070     /*
26071      * TODO(dfrank): it's not actually an internal error, we get here if
26072      * we compile e.g. the following: (function(1){})
26073      */
26074     V7_CHECK_INTERNAL(tag == AST_IDENT);
26075     name = ast_get_inlined_data(a, pos_after_tag, &name_len);
26076     V7_TRY(bcode_add_name(&bbuilder, name, name_len, &names_end));
26077   }
26078 
26079   bcode->args_cnt = args_cnt;
26080   bcode->func_name_present = 1;
26081 
26082   V7_TRY(compile_body(&bbuilder, a, start, end, body, fvar, ppos));
26083 
26084 clean:
26085   bcode_builder_finalize(&bbuilder);
26086 
26087 #ifdef V7_BCODE_DUMP
26088   if (rcode == V7_OK) {
26089     fprintf(stderr, "--- function ---\n");
26090     dump_bcode(v7, stderr, bcode);
26091   }
26092 #endif
26093 
26094   return rcode;
26095 }
26096 
26097 V7_PRIVATE enum v7_err compile_expr(struct v7 *v7, struct ast *a,
26098                                     ast_off_t *ppos, struct bcode *bcode) {
26099   enum v7_err rcode = V7_OK;
26100   struct bcode_builder bbuilder;
26101   int saved_line_no = v7->line_no;
26102 
26103   bcode_builder_init(v7, &bbuilder, bcode);
26104   v7->line_no = 1;
26105 
26106   rcode = compile_expr_builder(&bbuilder, a, ppos);
26107 
26108   bcode_builder_finalize(&bbuilder);
26109   v7->line_no = saved_line_no;
26110   return rcode;
26111 }
26112 
26113 #endif /* V7_NO_COMPILER */
26114 #ifdef V7_MODULE_LINES
26115 #line 1 "v7/src/stdlib.c"
26116 #endif
26117 /*
26118  * Copyright (c) 2014 Cesanta Software Limited
26119  * All rights reserved
26120  */
26121 
26122 /* Amalgamated: #include "common/cs_strtod.h" */
26123 
26124 /* Amalgamated: #include "v7/src/internal.h" */
26125 /* Amalgamated: #include "v7/src/core.h" */
26126 /* Amalgamated: #include "v7/src/primitive.h" */
26127 /* Amalgamated: #include "v7/src/conversion.h" */
26128 /* Amalgamated: #include "v7/src/stdlib.h" */
26129 /* Amalgamated: #include "v7/src/std_array.h" */
26130 /* Amalgamated: #include "v7/src/std_boolean.h" */
26131 /* Amalgamated: #include "v7/src/std_date.h" */
26132 /* Amalgamated: #include "v7/src/std_error.h" */
26133 /* Amalgamated: #include "v7/src/std_function.h" */
26134 /* Amalgamated: #include "v7/src/std_json.h" */
26135 /* Amalgamated: #include "v7/src/std_math.h" */
26136 /* Amalgamated: #include "v7/src/std_number.h" */
26137 /* Amalgamated: #include "v7/src/std_object.h" */
26138 /* Amalgamated: #include "v7/src/std_regex.h" */
26139 /* Amalgamated: #include "v7/src/std_string.h" */
26140 /* Amalgamated: #include "v7/src/std_proxy.h" */
26141 /* Amalgamated: #include "v7/src/js_stdlib.h" */
26142 /* Amalgamated: #include "v7/src/object.h" */
26143 /* Amalgamated: #include "v7/src/string.h" */
26144 /* Amalgamated: #include "v7/src/util.h" */
26145 /* Amalgamated: #include "v7/src/exec.h" */
26146 
26147 #ifdef NO_LIBC
26148 void print_str(const char *str);
26149 #endif
26150 
26151 WARN_UNUSED_RESULT
26152 V7_PRIVATE enum v7_err Std_print(struct v7 *v7, v7_val_t *res) {
26153   enum v7_err rcode = V7_OK;
26154   int i, num_args = v7_argc(v7);
26155   val_t v;
26156 
26157   (void) res;
26158 
26159   for (i = 0; i < num_args; i++) {
26160     v = v7_arg(v7, i);
26161     if (v7_is_string(v)) {
26162       size_t n;
26163       const char *s = v7_get_string(v7, &v, &n);
26164       printf("%.*s", (int) n, s);
26165     } else {
26166       v7_print(v7, v);
26167     }
26168     printf(" ");
26169   }
26170   printf(ENDL);
26171 
26172   return rcode;
26173 }
26174 
26175 WARN_UNUSED_RESULT
26176 V7_PRIVATE enum v7_err std_eval(struct v7 *v7, v7_val_t arg, val_t this_obj,
26177                                 int is_json, v7_val_t *res) {
26178   enum v7_err rcode = V7_OK;
26179   char buf[100], *p = buf;
26180   struct v7_exec_opts opts;
26181   memset(&opts, 0x00, sizeof(opts));
26182   opts.filename = "Eval'd code";
26183 
26184   if (arg != V7_UNDEFINED) {
26185     size_t len;
26186     rcode = to_string(v7, arg, NULL, buf, sizeof(buf), &len);
26187     if (rcode != V7_OK) {
26188       goto clean;
26189     }
26190 
26191     /* Fit null terminating byte and quotes */
26192     if (len >= sizeof(buf) - 2) {
26193       /* Buffer is not large enough. Allocate a bigger one */
26194       p = (char *) malloc(len + 3);
26195       rcode = to_string(v7, arg, NULL, p, len + 2, NULL);
26196       if (rcode != V7_OK) {
26197         goto clean;
26198       }
26199     }
26200 
26201     v7_set_gc_enabled(v7, 1);
26202     if (is_json) {
26203       opts.is_json = 1;
26204     } else {
26205       opts.this_obj = this_obj;
26206     }
26207     rcode = v7_exec_opt(v7, p, &opts, res);
26208     if (rcode != V7_OK) {
26209       goto clean;
26210     }
26211   }
26212 
26213 clean:
26214   if (p != buf) {
26215     free(p);
26216   }
26217 
26218   return rcode;
26219 }
26220 
26221 WARN_UNUSED_RESULT
26222 V7_PRIVATE enum v7_err Std_eval(struct v7 *v7, v7_val_t *res) {
26223   val_t this_obj = v7_get_this(v7);
26224   v7_val_t arg = v7_arg(v7, 0);
26225   return std_eval(v7, arg, this_obj, 0, res);
26226 }
26227 
26228 WARN_UNUSED_RESULT
26229 V7_PRIVATE enum v7_err Std_parseInt(struct v7 *v7, v7_val_t *res) {
26230   enum v7_err rcode = V7_OK;
26231   v7_val_t arg0 = V7_UNDEFINED;
26232   v7_val_t arg1 = V7_UNDEFINED;
26233   long sign = 1, base, n;
26234   char buf[20], *p = buf, *end;
26235 
26236   *res = V7_TAG_NAN;
26237 
26238   arg0 = v7_arg(v7, 0);
26239   arg1 = v7_arg(v7, 1);
26240 
26241   rcode = to_string(v7, arg0, &arg0, NULL, 0, NULL);
26242   if (rcode != V7_OK) {
26243     goto clean;
26244   }
26245 
26246   rcode = to_number_v(v7, arg1, &arg1);
26247   if (rcode != V7_OK) {
26248     goto clean;
26249   }
26250 
26251   if (is_finite(v7, arg1)) {
26252     base = v7_get_double(v7, arg1);
26253   } else {
26254     base = 0;
26255   }
26256 
26257   if (base == 0) {
26258     base = 10;
26259   }
26260 
26261   if (base < 2 || base > 36) {
26262     *res = V7_TAG_NAN;
26263     goto clean;
26264   }
26265 
26266   {
26267     size_t str_len;
26268     p = (char *) v7_get_string(v7, &arg0, &str_len);
26269   }
26270 
26271   /* Strip leading whitespaces */
26272   while (*p != '\0' && isspace(*(unsigned char *) p)) {
26273     p++;
26274   }
26275 
26276   if (*p == '+') {
26277     sign = 1;
26278     p++;
26279   } else if (*p == '-') {
26280     sign = -1;
26281     p++;
26282   }
26283 
26284   if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
26285     base = 16;
26286     p += 2;
26287   }
26288 
26289   n = strtol(p, &end, base);
26290 
26291   *res = (p == end) ? V7_TAG_NAN : v7_mk_number(v7, n * sign);
26292 
26293 clean:
26294   return rcode;
26295 }
26296 
26297 WARN_UNUSED_RESULT
26298 V7_PRIVATE enum v7_err Std_parseFloat(struct v7 *v7, v7_val_t *res) {
26299   enum v7_err rcode = V7_OK;
26300   v7_val_t arg0 = V7_UNDEFINED;
26301   char buf[20], *p = buf, *end;
26302   double result;
26303 
26304   rcode = to_primitive(v7, v7_arg(v7, 0), V7_TO_PRIMITIVE_HINT_NUMBER, &arg0);
26305   if (rcode != V7_OK) {
26306     goto clean;
26307   }
26308 
26309   if (v7_is_string(arg0)) {
26310     size_t str_len;
26311     p = (char *) v7_get_string(v7, &arg0, &str_len);
26312   } else {
26313     rcode = to_string(v7, arg0, NULL, buf, sizeof(buf), NULL);
26314     if (rcode != V7_OK) {
26315       goto clean;
26316     }
26317     buf[sizeof(buf) - 1] = '\0';
26318   }
26319 
26320   while (*p != '\0' && isspace(*(unsigned char *) p)) {
26321     p++;
26322   }
26323 
26324   result = cs_strtod(p, &end);
26325 
26326   *res = (p == end) ? V7_TAG_NAN : v7_mk_number(v7, result);
26327 
26328 clean:
26329   return rcode;
26330 }
26331 
26332 WARN_UNUSED_RESULT
26333 V7_PRIVATE enum v7_err Std_isNaN(struct v7 *v7, v7_val_t *res) {
26334   enum v7_err rcode = V7_OK;
26335   v7_val_t arg0 = V7_TAG_NAN;
26336   rcode = to_number_v(v7, v7_arg(v7, 0), &arg0);
26337   if (rcode != V7_OK) {
26338     goto clean;
26339   }
26340 
26341   *res = v7_mk_boolean(v7, isnan(v7_get_double(v7, arg0)));
26342 
26343 clean:
26344   return rcode;
26345 }
26346 
26347 WARN_UNUSED_RESULT
26348 V7_PRIVATE enum v7_err Std_isFinite(struct v7 *v7, v7_val_t *res) {
26349   enum v7_err rcode = V7_OK;
26350   v7_val_t arg0 = V7_TAG_NAN;
26351 
26352   rcode = to_number_v(v7, v7_arg(v7, 0), &arg0);
26353   if (rcode != V7_OK) {
26354     goto clean;
26355   }
26356 
26357   *res = v7_mk_boolean(v7, is_finite(v7, arg0));
26358 
26359 clean:
26360   return rcode;
26361 }
26362 
26363 #ifndef NO_LIBC
26364 WARN_UNUSED_RESULT
26365 V7_PRIVATE enum v7_err Std_exit(struct v7 *v7, v7_val_t *res) {
26366   enum v7_err rcode = V7_OK;
26367   long exit_code;
26368 
26369   (void) res;
26370 
26371   rcode = to_long(v7, v7_arg(v7, 0), 0, &exit_code);
26372   if (rcode != V7_OK) {
26373     /* `to_long` has thrown, so, will return 1 */
26374     exit_code = 1;
26375   }
26376   exit(exit_code);
26377 
26378   return rcode;
26379 }
26380 #endif
26381 
26382 /*
26383  * Initialize standard library.
26384  *
26385  * This function is used only internally, but used in a complicated mix of
26386  * configurations, hence the commented V7_PRIVATE
26387  */
26388 /*V7_PRIVATE*/ void init_stdlib(struct v7 *v7) {
26389   v7_prop_attr_desc_t attr_internal =
26390       (V7_DESC_ENUMERABLE(0) | V7_DESC_WRITABLE(0) | V7_DESC_CONFIGURABLE(0));
26391 
26392   /*
26393    * Ensure the first call to v7_mk_value will use a null proto:
26394    * {}.__proto__.__proto__ == null
26395    */
26396   v7->vals.object_prototype = mk_object(v7, V7_NULL);
26397   v7->vals.array_prototype = v7_mk_object(v7);
26398   v7->vals.boolean_prototype = v7_mk_object(v7);
26399   v7->vals.string_prototype = v7_mk_object(v7);
26400   v7->vals.regexp_prototype = v7_mk_object(v7);
26401   v7->vals.number_prototype = v7_mk_object(v7);
26402   v7->vals.error_prototype = v7_mk_object(v7);
26403   v7->vals.global_object = v7_mk_object(v7);
26404   v7->vals.date_prototype = v7_mk_object(v7);
26405   v7->vals.function_prototype = v7_mk_object(v7);
26406   v7->vals.proxy_prototype = v7_mk_object(v7);
26407 
26408   set_method(v7, v7->vals.global_object, "eval", Std_eval, 1);
26409   set_method(v7, v7->vals.global_object, "print", Std_print, 1);
26410 #ifndef NO_LIBC
26411   set_method(v7, v7->vals.global_object, "exit", Std_exit, 1);
26412 #endif
26413   set_method(v7, v7->vals.global_object, "parseInt", Std_parseInt, 2);
26414   set_method(v7, v7->vals.global_object, "parseFloat", Std_parseFloat, 1);
26415   set_method(v7, v7->vals.global_object, "isNaN", Std_isNaN, 1);
26416   set_method(v7, v7->vals.global_object, "isFinite", Std_isFinite, 1);
26417 
26418   v7_def(v7, v7->vals.global_object, "Infinity", 8, attr_internal,
26419          v7_mk_number(v7, INFINITY));
26420   v7_set(v7, v7->vals.global_object, "global", 6, v7->vals.global_object);
26421 
26422   init_object(v7);
26423   init_array(v7);
26424   init_error(v7);
26425   init_boolean(v7);
26426 #if V7_ENABLE__Math
26427   init_math(v7);
26428 #endif
26429   init_string(v7);
26430 #if V7_ENABLE__RegExp
26431   init_regex(v7);
26432 #endif
26433   init_number(v7);
26434   init_json(v7);
26435 #if V7_ENABLE__Date
26436   init_date(v7);
26437 #endif
26438   init_function(v7);
26439   init_js_stdlib(v7);
26440 
26441 #if V7_ENABLE__Proxy
26442   init_proxy(v7);
26443 #endif
26444 }
26445 #ifdef V7_MODULE_LINES
26446 #line 1 "v7/src/js_stdlib.c"
26447 #endif
26448 /*
26449  * Copyright (c) 2014 Cesanta Software Limited
26450  * All rights reserved
26451  */
26452 
26453 /* clang-format off */
26454 /* because clang-format would break JS code, e.g. === converted to == = ... */
26455 
26456 /* Amalgamated: #include "v7/src/internal.h" */
26457 /* Amalgamated: #include "v7/src/core.h" */
26458 /* Amalgamated: #include "v7/src/exec.h" */
26459 /* Amalgamated: #include "v7/src/util.h" */
26460 
26461 #define STRINGIFY(x) #x
26462 
26463 #if defined(__cplusplus)
26464 extern "C" {
26465 #endif /* __cplusplus */
26466 
26467 static const char js_array_indexOf[] = STRINGIFY(
26468     Object.defineProperty(Array.prototype, "indexOf", {
26469       writable:true,
26470       configurable: true,
26471       value: function(a, x) {
26472         var i; var r = -1; var b = +x;
26473         if (!b || b < 0) b = 0;
26474         for (i in this) if (i >= b && (r < 0 || i < r) && this[i] === a) r = +i;
26475         return r;
26476     }}););
26477 
26478 static const char js_array_lastIndexOf[] = STRINGIFY(
26479     Object.defineProperty(Array.prototype, "lastIndexOf", {
26480       writable:true,
26481       configurable: true,
26482       value: function(a, x) {
26483         var i; var r = -1; var b = +x;
26484         if (isNaN(b) || b < 0 || b >= this.length) b = this.length - 1;
26485         for (i in this) if (i <= b && (r < 0 || i > r) && this[i] === a) r = +i;
26486         return r;
26487     }}););
26488 
26489 #if V7_ENABLE__Array__reduce
26490 static const char js_array_reduce[] = STRINGIFY(
26491     Object.defineProperty(Array.prototype, "reduce", {
26492       writable:true,
26493       configurable: true,
26494       value: function(a, b) {
26495         var f = 0;
26496         if (typeof(a) != "function") {
26497           throw new TypeError(a + " is not a function");
26498         }
26499         for (var k in this) {
26500           if (k > this.length) break;
26501           if (f == 0 && b === undefined) {
26502             b = this[k];
26503             f = 1;
26504           } else {
26505             b = a(b, this[k], k, this);
26506           }
26507         }
26508         return b;
26509     }}););
26510 #endif
26511 
26512 static const char js_array_pop[] = STRINGIFY(
26513     Object.defineProperty(Array.prototype, "pop", {
26514       writable:true,
26515       configurable: true,
26516       value: function() {
26517       var i = this.length - 1;
26518         return this.splice(i, 1)[0];
26519     }}););
26520 
26521 static const char js_array_shift[] = STRINGIFY(
26522     Object.defineProperty(Array.prototype, "shift", {
26523       writable:true,
26524       configurable: true,
26525       value: function() {
26526         return this.splice(0, 1)[0];
26527     }}););
26528 
26529 #if V7_ENABLE__Function__call
26530 static const char js_function_call[] = STRINGIFY(
26531     Object.defineProperty(Function.prototype, "call", {
26532       writable:true,
26533       configurable: true,
26534       value: function() {
26535         var t = arguments.splice(0, 1)[0];
26536         return this.apply(t, arguments);
26537     }}););
26538 #endif
26539 
26540 #if V7_ENABLE__Function__bind
26541 static const char js_function_bind[] = STRINGIFY(
26542     Object.defineProperty(Function.prototype, "bind", {
26543       writable:true,
26544       configurable: true,
26545       value: function(t) {
26546         var f = this;
26547         return function() {
26548           return f.apply(t, arguments);
26549         };
26550     }}););
26551 #endif
26552 
26553 #if V7_ENABLE__Blob
26554 static const char js_Blob[] = STRINGIFY(
26555     function Blob(a) {
26556       this.a = a;
26557     });
26558 #endif
26559 
26560 static const char * const js_functions[] = {
26561 #if V7_ENABLE__Blob
26562   js_Blob,
26563 #endif
26564 #if V7_ENABLE__Function__call
26565   js_function_call,
26566 #endif
26567 #if V7_ENABLE__Function__bind
26568   js_function_bind,
26569 #endif
26570 #if V7_ENABLE__Array__reduce
26571   js_array_reduce,
26572 #endif
26573   js_array_indexOf,
26574   js_array_lastIndexOf,
26575   js_array_pop,
26576   js_array_shift
26577 };
26578 
26579  V7_PRIVATE void init_js_stdlib(struct v7 *v7) {
26580   val_t res;
26581   int i;
26582 
26583   for(i = 0; i < (int) ARRAY_SIZE(js_functions); i++) {
26584     if (v7_exec(v7, js_functions[i], &res) != V7_OK) {
26585       fprintf(stderr, "ex: %s:\n", js_functions[i]);
26586       v7_fprintln(stderr, v7, res);
26587     }
26588   }
26589 
26590   /* TODO(lsm): re-enable in a separate PR */
26591 #if 0
26592   v7_exec(v7, &res, STRINGIFY(
26593     Array.prototype.unshift = function() {
26594       var a = new Array(0, 0);
26595       Array.prototype.push.apply(a, arguments);
26596       Array.prototype.splice.apply(this, a);
26597       return this.length;
26598     };));
26599 #endif
26600 }
26601 
26602 #if defined(__cplusplus)
26603 }
26604 #endif /* __cplusplus */
26605 #ifdef V7_MODULE_LINES
26606 #line 1 "v7/src/slre.c"
26607 #endif
26608 /*
26609  * Copyright (c) 2014 Cesanta Software Limited
26610  * All rights reserved
26611  *
26612  * This software is dual-licensed: you can redistribute it and/or modify
26613  * it under the terms of the GNU General Public License version 2 as
26614  * published by the Free Software Foundation. For the terms of this
26615  * license, see <http://www.gnu.org/licenses/>.
26616  *
26617  * You are free to use this software under the terms of the GNU General
26618  * Public License, but WITHOUT ANY WARRANTY; without even the implied
26619  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26620  * See the GNU General Public License for more details.
26621  *
26622  * Alternatively, you can license this software under a commercial
26623  * license, as set out in <https://www.cesanta.com/license>.
26624  */
26625 
26626 /* Amalgamated: #include "v7/src/v7_features.h" */
26627 
26628 #include <setjmp.h>
26629 #include <stdlib.h>
26630 #include <stdio.h>
26631 #include <string.h>
26632 
26633 #ifndef NO_LIBC
26634 #include <ctype.h>
26635 #endif
26636 
26637 /* Amalgamated: #include "common/utf.h" */
26638 /* Amalgamated: #include "v7/src/slre.h" */
26639 
26640 /* Limitations */
26641 #define SLRE_MAX_RANGES 32
26642 #define SLRE_MAX_SETS 16
26643 #define SLRE_MAX_REP 0xFFFF
26644 
26645 #define SLRE_MALLOC malloc
26646 #define SLRE_FREE free
26647 #define SLRE_THROW(e, err_code) longjmp((e)->jmp_buf, (err_code))
26648 
26649 static int hex(int c) {
26650   if (c >= '0' && c <= '9') return c - '0';
26651   if (c >= 'a' && c <= 'f') return c - 'a' + 10;
26652   if (c >= 'A' && c <= 'F') return c - 'A' + 10;
26653   return -SLRE_INVALID_HEX_DIGIT;
26654 }
26655 
26656 int nextesc(const char **p) {
26657   const unsigned char *s = (unsigned char *) (*p)++;
26658   switch (*s) {
26659     case 0:
26660       return -SLRE_UNTERM_ESC_SEQ;
26661     case 'c':
26662       ++*p;
26663       return *s & 31;
26664     case 'b':
26665       return '\b';
26666     case 't':
26667       return '\t';
26668     case 'n':
26669       return '\n';
26670     case 'v':
26671       return '\v';
26672     case 'f':
26673       return '\f';
26674     case 'r':
26675       return '\r';
26676     case '\\':
26677       return '\\';
26678     case 'u':
26679       if (isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]) &&
26680           isxdigit(s[4])) {
26681         (*p) += 4;
26682         return hex(s[1]) << 12 | hex(s[2]) << 8 | hex(s[3]) << 4 | hex(s[4]);
26683       }
26684       return -SLRE_INVALID_HEX_DIGIT;
26685     case 'x':
26686       if (isxdigit(s[1]) && isxdigit(s[2])) {
26687         (*p) += 2;
26688         return (hex(s[1]) << 4) | hex(s[2]);
26689       }
26690       return -SLRE_INVALID_HEX_DIGIT;
26691     default:
26692       return -SLRE_INVALID_ESC_CHAR;
26693   }
26694 }
26695 
26696 #if V7_ENABLE__RegExp
26697 
26698 /* Parser Information */
26699 struct slre_node {
26700   unsigned char type;
26701   union {
26702     Rune c;                /* character */
26703     struct slre_class *cp; /* class pointer */
26704     struct {
26705       struct slre_node *x;
26706       union {
26707         struct slre_node *y;
26708         unsigned char n;
26709         struct {
26710           unsigned char ng; /* not greedy flag */
26711           unsigned short min;
26712           unsigned short max;
26713         } rp;
26714       } y;
26715     } xy;
26716   } par;
26717 };
26718 
26719 struct slre_range {
26720   unsigned short s, e;
26721 };
26722 
26723 /* character class, each pair of rune's defines a range */
26724 struct slre_class {
26725   struct slre_range *end;
26726   struct slre_range spans[SLRE_MAX_RANGES];
26727 };
26728 
26729 struct slre_instruction {
26730   unsigned char opcode;
26731   union {
26732     unsigned char n;
26733     Rune c;                /* character */
26734     struct slre_class *cp; /* class pointer */
26735     struct {
26736       struct slre_instruction *x;
26737       union {
26738         struct {
26739           unsigned short min;
26740           unsigned short max;
26741         } rp;
26742         struct slre_instruction *y;
26743       } y;
26744     } xy;
26745   } par;
26746 };
26747 
26748 struct slre_prog {
26749   struct slre_instruction *start, *end;
26750   unsigned int num_captures;
26751   int flags;
26752   struct slre_class charset[SLRE_MAX_SETS];
26753 };
26754 
26755 struct slre_env {
26756   int is_regex;
26757   const char *src;
26758   const char *src_end;
26759   Rune curr_rune;
26760 
26761   struct slre_prog *prog;
26762   struct slre_node *pstart, *pend;
26763 
26764   struct slre_node *caps[SLRE_MAX_CAPS];
26765   unsigned int num_captures;
26766   unsigned int sets_num;
26767 
26768   int lookahead;
26769   struct slre_class *curr_set;
26770   int min_rep, max_rep;
26771 
26772 #if defined(__cplusplus)
26773   ::jmp_buf jmp_buf;
26774 #else
26775   jmp_buf jmp_buf;
26776 #endif
26777 };
26778 
26779 struct slre_thread {
26780   struct slre_thread *prev;
26781   struct slre_instruction *pc;
26782   const char *start;
26783   struct slre_loot loot;
26784 };
26785 
26786 enum slre_opcode {
26787   I_END = 10, /* Terminate: match found */
26788   I_ANY,
26789   P_ANY = I_ANY, /* Any character except newline, . */
26790   I_ANYNL,       /* Any character including newline, . */
26791   I_BOL,
26792   P_BOL = I_BOL, /* Beginning of line, ^ */
26793   I_CH,
26794   P_CH = I_CH,
26795   I_EOL,
26796   P_EOL = I_EOL, /* End of line, $ */
26797   I_EOS,
26798   P_EOS = I_EOS, /* End of string, \0 */
26799   I_JUMP,
26800   I_LA,
26801   P_LA = I_LA,
26802   I_LA_N,
26803   P_LA_N = I_LA_N,
26804   I_LBRA,
26805   P_BRA = I_LBRA, /* Left bracket, ( */
26806   I_REF,
26807   P_REF = I_REF,
26808   I_REP,
26809   P_REP = I_REP,
26810   I_REP_INI,
26811   I_RBRA, /* Right bracket, ) */
26812   I_SET,
26813   P_SET = I_SET, /* Character set, [] */
26814   I_SET_N,
26815   P_SET_N = I_SET_N, /* Negated character set, [] */
26816   I_SPLIT,
26817   I_WORD,
26818   P_WORD = I_WORD,
26819   I_WORD_N,
26820   P_WORD_N = I_WORD_N,
26821   P_ALT, /* Alternation, | */
26822   P_CAT, /* Concatentation, implicit operator */
26823   L_CH = 256,
26824   L_COUNT,  /* {M,N} */
26825   L_EOS,    /* End of string, \0 */
26826   L_LA,     /* "(?=" lookahead */
26827   L_LA_CAP, /* "(?:" lookahead, capture */
26828   L_LA_N,   /* "(?!" negative lookahead */
26829   L_REF,    /* "\1" back-reference */
26830   L_CHSET,  /* character set */
26831   L_SET_N,  /* negative character set */
26832   L_WORD,   /* "\b" word boundary */
26833   L_WORD_N  /* "\B" non-word boundary */
26834 };
26835 
26836 static signed char dec(int c) {
26837   if (isdigitrune(c)) return c - '0';
26838   return SLRE_INVALID_DEC_DIGIT;
26839 }
26840 
26841 static unsigned char re_dec_digit(struct slre_env *e, int c) {
26842   signed char ret = dec(c);
26843   if (ret < 0) {
26844     SLRE_THROW(e, SLRE_INVALID_DEC_DIGIT);
26845   }
26846   return ret;
26847 }
26848 
26849 static int re_nextc(Rune *r, const char **src, const char *src_end) {
26850   *r = 0;
26851   if (*src >= src_end) return 0;
26852   *src += chartorune(r, *src);
26853   if (*r == '\\') {
26854     const char *tmp_s = *src;
26855     int i = nextesc(src);
26856     switch (i) {
26857       case -SLRE_INVALID_ESC_CHAR:
26858         *r = '\\';
26859         *src = tmp_s;
26860         *src += chartorune(r, *src);
26861         break;
26862       case -SLRE_INVALID_HEX_DIGIT:
26863       default:
26864         *r = i;
26865     }
26866     return 1;
26867   }
26868   return 0;
26869 }
26870 
26871 static int re_nextc_raw(Rune *r, const char **src, const char *src_end) {
26872   *r = 0;
26873   if (*src >= src_end) return 0;
26874   *src += chartorune(r, *src);
26875   return 0;
26876 }
26877 
26878 static int re_nextc_env(struct slre_env *e) {
26879   return re_nextc(&e->curr_rune, &e->src, e->src_end);
26880 }
26881 
26882 static void re_nchset(struct slre_env *e) {
26883   if (e->sets_num >= nelem(e->prog->charset)) {
26884     SLRE_THROW(e, SLRE_TOO_MANY_CHARSETS);
26885   }
26886   e->curr_set = e->prog->charset + e->sets_num++;
26887   e->curr_set->end = e->curr_set->spans;
26888 }
26889 
26890 static void re_rng2set(struct slre_env *e, Rune start, Rune end) {
26891   if (start > end) {
26892     SLRE_THROW(e, SLRE_INV_CHARSET_RANGE);
26893   }
26894   if (e->curr_set->end + 2 == e->curr_set->spans + nelem(e->curr_set->spans)) {
26895     SLRE_THROW(e, SLRE_CHARSET_TOO_LARGE);
26896   }
26897   e->curr_set->end->s = start;
26898   e->curr_set->end->e = end;
26899   e->curr_set->end++;
26900 }
26901 
26902 #define re_char2set(e, c) re_rng2set(e, c, c)
26903 
26904 #define re_d_2set(e) re_rng2set(e, '0', '9')
26905 
26906 static void re_D_2set(struct slre_env *e) {
26907   re_rng2set(e, 0, '0' - 1);
26908   re_rng2set(e, '9' + 1, 0xFFFF);
26909 }
26910 
26911 static void re_s_2set(struct slre_env *e) {
26912   re_char2set(e, 0x9);
26913   re_rng2set(e, 0xA, 0xD);
26914   re_char2set(e, 0x20);
26915   re_char2set(e, 0xA0);
26916   re_rng2set(e, 0x2028, 0x2029);
26917   re_char2set(e, 0xFEFF);
26918 }
26919 
26920 static void re_S_2set(struct slre_env *e) {
26921   re_rng2set(e, 0, 0x9 - 1);
26922   re_rng2set(e, 0xD + 1, 0x20 - 1);
26923   re_rng2set(e, 0x20 + 1, 0xA0 - 1);
26924   re_rng2set(e, 0xA0 + 1, 0x2028 - 1);
26925   re_rng2set(e, 0x2029 + 1, 0xFEFF - 1);
26926   re_rng2set(e, 0xFEFF + 1, 0xFFFF);
26927 }
26928 
26929 static void re_w_2set(struct slre_env *e) {
26930   re_d_2set(e);
26931   re_rng2set(e, 'A', 'Z');
26932   re_char2set(e, '_');
26933   re_rng2set(e, 'a', 'z');
26934 }
26935 
26936 static void re_W_2set(struct slre_env *e) {
26937   re_rng2set(e, 0, '0' - 1);
26938   re_rng2set(e, '9' + 1, 'A' - 1);
26939   re_rng2set(e, 'Z' + 1, '_' - 1);
26940   re_rng2set(e, '_' + 1, 'a' - 1);
26941   re_rng2set(e, 'z' + 1, 0xFFFF);
26942 }
26943 
26944 static unsigned char re_endofcount(Rune c) {
26945   switch (c) {
26946     case ',':
26947     case '}':
26948       return 1;
26949   }
26950   return 0;
26951 }
26952 
26953 static void re_ex_num_overfl(struct slre_env *e) {
26954   SLRE_THROW(e, SLRE_NUM_OVERFLOW);
26955 }
26956 
26957 static enum slre_opcode re_countrep(struct slre_env *e) {
26958   e->min_rep = 0;
26959   while (e->src < e->src_end && !re_endofcount(e->curr_rune = *e->src++)) {
26960     e->min_rep = e->min_rep * 10 + re_dec_digit(e, e->curr_rune);
26961     if (e->min_rep >= SLRE_MAX_REP) re_ex_num_overfl(e);
26962   }
26963 
26964   if (e->curr_rune != ',') {
26965     e->max_rep = e->min_rep;
26966     return L_COUNT;
26967   }
26968   e->max_rep = 0;
26969   while (e->src < e->src_end && (e->curr_rune = *e->src++) != '}') {
26970     e->max_rep = e->max_rep * 10 + re_dec_digit(e, e->curr_rune);
26971     if (e->max_rep >= SLRE_MAX_REP) re_ex_num_overfl(e);
26972   }
26973   if (!e->max_rep) {
26974     e->max_rep = SLRE_MAX_REP;
26975     return L_COUNT;
26976   }
26977 
26978   return L_COUNT;
26979 }
26980 
26981 static enum slre_opcode re_lexset(struct slre_env *e) {
26982   Rune ch = 0;
26983   unsigned char esc, ch_fl = 0, dash_fl = 0;
26984   enum slre_opcode type = L_CHSET;
26985 
26986   re_nchset(e);
26987 
26988   esc = re_nextc_env(e);
26989   if (!esc && e->curr_rune == '^') {
26990     type = L_SET_N;
26991     esc = re_nextc_env(e);
26992   }
26993 
26994   for (; esc || e->curr_rune != ']'; esc = re_nextc_env(e)) {
26995     if (!e->curr_rune) {
26996       SLRE_THROW(e, SLRE_MALFORMED_CHARSET);
26997     }
26998     if (esc) {
26999       if (strchr("DdSsWw", e->curr_rune)) {
27000         if (ch_fl) {
27001           re_char2set(e, ch);
27002           if (dash_fl) re_char2set(e, '-');
27003         }
27004         switch (e->curr_rune) {
27005           case 'D':
27006             re_D_2set(e);
27007             break;
27008           case 'd':
27009             re_d_2set(e);
27010             break;
27011           case 'S':
27012             re_S_2set(e);
27013             break;
27014           case 's':
27015             re_s_2set(e);
27016             break;
27017           case 'W':
27018             re_W_2set(e);
27019             break;
27020           case 'w':
27021             re_w_2set(e);
27022             break;
27023         }
27024         ch_fl = dash_fl = 0;
27025         continue;
27026       }
27027       switch (e->curr_rune) {
27028         default:
27029           /* case '-':
27030           case '\\':
27031           case '.':
27032           case '/':
27033           case ']':
27034           case '|': */
27035           break;
27036         case '0':
27037           e->curr_rune = 0;
27038           break;
27039         case 'b':
27040           e->curr_rune = '\b';
27041           break;
27042           /* default:
27043             SLRE_THROW(e->catch_point, e->err_msg,
27044             SLRE_INVALID_ESC_CHAR); */
27045       }
27046     } else {
27047       if (e->curr_rune == '-') {
27048         if (ch_fl) {
27049           if (dash_fl) {
27050             re_rng2set(e, ch, '-');
27051             ch_fl = dash_fl = 0;
27052           } else
27053             dash_fl = 1;
27054         } else {
27055           ch = '-';
27056           ch_fl = 1;
27057         }
27058         continue;
27059       }
27060     }
27061     if (ch_fl) {
27062       if (dash_fl) {
27063         re_rng2set(e, ch, e->curr_rune);
27064         ch_fl = dash_fl = 0;
27065       } else {
27066         re_char2set(e, ch);
27067         ch = e->curr_rune;
27068       }
27069     } else {
27070       ch = e->curr_rune;
27071       ch_fl = 1;
27072     }
27073   }
27074   if (ch_fl) {
27075     re_char2set(e, ch);
27076     if (dash_fl) re_char2set(e, '-');
27077   }
27078   return type;
27079 }
27080 
27081 static int re_lexer(struct slre_env *e) {
27082   if (re_nextc_env(e)) {
27083     switch (e->curr_rune) {
27084       case '0':
27085         e->curr_rune = 0;
27086         return L_EOS;
27087       case 'b':
27088         return L_WORD;
27089       case 'B':
27090         return L_WORD_N;
27091       case 'd':
27092         re_nchset(e);
27093         re_d_2set(e);
27094         return L_CHSET;
27095       case 'D':
27096         re_nchset(e);
27097         re_d_2set(e);
27098         return L_SET_N;
27099       case 's':
27100         re_nchset(e);
27101         re_s_2set(e);
27102         return L_CHSET;
27103       case 'S':
27104         re_nchset(e);
27105         re_s_2set(e);
27106         return L_SET_N;
27107       case 'w':
27108         re_nchset(e);
27109         re_w_2set(e);
27110         return L_CHSET;
27111       case 'W':
27112         re_nchset(e);
27113         re_w_2set(e);
27114         return L_SET_N;
27115     }
27116     if (isdigitrune(e->curr_rune)) {
27117       e->curr_rune -= '0';
27118       if (isdigitrune(*e->src))
27119         e->curr_rune = e->curr_rune * 10 + *e->src++ - '0';
27120       return L_REF;
27121     }
27122     return L_CH;
27123   }
27124 
27125   if (e->is_regex) {
27126     switch (e->curr_rune) {
27127       case 0:
27128         return 0;
27129       case '$':
27130       case ')':
27131       case '*':
27132       case '+':
27133       case '.':
27134       case '?':
27135       case '^':
27136       case '|':
27137         return e->curr_rune;
27138       case '{':
27139         return re_countrep(e);
27140       case '[':
27141         return re_lexset(e);
27142       case '(':
27143         if (e->src[0] == '?') switch (e->src[1]) {
27144             case '=':
27145               e->src += 2;
27146               return L_LA;
27147             case ':':
27148               e->src += 2;
27149               return L_LA_CAP;
27150             case '!':
27151               e->src += 2;
27152               return L_LA_N;
27153           }
27154         return '(';
27155     }
27156   } else if (e->curr_rune == 0) {
27157     return 0;
27158   }
27159 
27160   return L_CH;
27161 }
27162 
27163 #define RE_NEXT(env) (env)->lookahead = re_lexer(env)
27164 #define RE_ACCEPT(env, t) ((env)->lookahead == (t) ? RE_NEXT(env), 1 : 0)
27165 
27166 static struct slre_node *re_nnode(struct slre_env *e, int type) {
27167   memset(e->pend, 0, sizeof(struct slre_node));
27168   e->pend->type = type;
27169   return e->pend++;
27170 }
27171 
27172 static unsigned char re_isemptynd(struct slre_node *nd) {
27173   if (!nd) return 1;
27174   switch (nd->type) {
27175     default:
27176       return 1;
27177     case P_ANY:
27178     case P_CH:
27179     case P_SET:
27180     case P_SET_N:
27181       return 0;
27182     case P_BRA:
27183     case P_REF:
27184       return re_isemptynd(nd->par.xy.x);
27185     case P_CAT:
27186       return re_isemptynd(nd->par.xy.x) && re_isemptynd(nd->par.xy.y.y);
27187     case P_ALT:
27188       return re_isemptynd(nd->par.xy.x) || re_isemptynd(nd->par.xy.y.y);
27189     case P_REP:
27190       return re_isemptynd(nd->par.xy.x) || !nd->par.xy.y.rp.min;
27191   }
27192 }
27193 
27194 static struct slre_node *re_nrep(struct slre_env *e, struct slre_node *nd,
27195                                  int ng, unsigned short min,
27196                                  unsigned short max) {
27197   struct slre_node *rep = re_nnode(e, P_REP);
27198   if (max == SLRE_MAX_REP && re_isemptynd(nd)) {
27199     SLRE_THROW(e, SLRE_INF_LOOP_M_EMP_STR);
27200   }
27201   rep->par.xy.y.rp.ng = ng;
27202   rep->par.xy.y.rp.min = min;
27203   rep->par.xy.y.rp.max = max;
27204   rep->par.xy.x = nd;
27205   return rep;
27206 }
27207 
27208 static struct slre_node *re_parser(struct slre_env *e);
27209 
27210 static struct slre_node *re_parse_la(struct slre_env *e) {
27211   struct slre_node *nd;
27212   int min, max;
27213   switch (e->lookahead) {
27214     case '^':
27215       RE_NEXT(e);
27216       return re_nnode(e, P_BOL);
27217     case '$':
27218       RE_NEXT(e);
27219       return re_nnode(e, P_EOL);
27220     case L_EOS:
27221       RE_NEXT(e);
27222       return re_nnode(e, P_EOS);
27223     case L_WORD:
27224       RE_NEXT(e);
27225       return re_nnode(e, P_WORD);
27226     case L_WORD_N:
27227       RE_NEXT(e);
27228       return re_nnode(e, P_WORD_N);
27229   }
27230 
27231   switch (e->lookahead) {
27232     case L_CH:
27233       nd = re_nnode(e, P_CH);
27234       nd->par.c = e->curr_rune;
27235       RE_NEXT(e);
27236       break;
27237     case L_CHSET:
27238       nd = re_nnode(e, P_SET);
27239       nd->par.cp = e->curr_set;
27240       RE_NEXT(e);
27241       break;
27242     case L_SET_N:
27243       nd = re_nnode(e, P_SET_N);
27244       nd->par.cp = e->curr_set;
27245       RE_NEXT(e);
27246       break;
27247     case L_REF:
27248       nd = re_nnode(e, P_REF);
27249       if (!e->curr_rune || e->curr_rune > e->num_captures ||
27250           !e->caps[e->curr_rune]) {
27251         SLRE_THROW(e, SLRE_INVALID_BACK_REFERENCE);
27252       }
27253       nd->par.xy.y.n = e->curr_rune;
27254       nd->par.xy.x = e->caps[e->curr_rune];
27255       RE_NEXT(e);
27256       break;
27257     case '.':
27258       RE_NEXT(e);
27259       nd = re_nnode(e, P_ANY);
27260       break;
27261     case '(':
27262       RE_NEXT(e);
27263       nd = re_nnode(e, P_BRA);
27264       if (e->num_captures == SLRE_MAX_CAPS) {
27265         SLRE_THROW(e, SLRE_TOO_MANY_CAPTURES);
27266       }
27267       nd->par.xy.y.n = e->num_captures++;
27268       nd->par.xy.x = re_parser(e);
27269       e->caps[nd->par.xy.y.n] = nd;
27270       if (!RE_ACCEPT(e, ')')) {
27271         SLRE_THROW(e, SLRE_UNMATCH_LBR);
27272       }
27273       break;
27274     case L_LA:
27275       RE_NEXT(e);
27276       nd = re_nnode(e, P_LA);
27277       nd->par.xy.x = re_parser(e);
27278       if (!RE_ACCEPT(e, ')')) {
27279         SLRE_THROW(e, SLRE_UNMATCH_LBR);
27280       }
27281       break;
27282     case L_LA_CAP:
27283       RE_NEXT(e);
27284       nd = re_parser(e);
27285       if (!RE_ACCEPT(e, ')')) {
27286         SLRE_THROW(e, SLRE_UNMATCH_LBR);
27287       }
27288       break;
27289     case L_LA_N:
27290       RE_NEXT(e);
27291       nd = re_nnode(e, P_LA_N);
27292       nd->par.xy.x = re_parser(e);
27293       if (!RE_ACCEPT(e, ')')) {
27294         SLRE_THROW(e, SLRE_UNMATCH_LBR);
27295       }
27296       break;
27297     default:
27298       SLRE_THROW(e, SLRE_SYNTAX_ERROR);
27299   }
27300 
27301   switch (e->lookahead) {
27302     case '*':
27303       RE_NEXT(e);
27304       return re_nrep(e, nd, RE_ACCEPT(e, '?'), 0, SLRE_MAX_REP);
27305     case '+':
27306       RE_NEXT(e);
27307       return re_nrep(e, nd, RE_ACCEPT(e, '?'), 1, SLRE_MAX_REP);
27308     case '?':
27309       RE_NEXT(e);
27310       return re_nrep(e, nd, RE_ACCEPT(e, '?'), 0, 1);
27311     case L_COUNT:
27312       min = e->min_rep, max = e->max_rep;
27313       RE_NEXT(e);
27314       if (max < min) {
27315         SLRE_THROW(e, SLRE_INVALID_QUANTIFIER);
27316       }
27317       return re_nrep(e, nd, RE_ACCEPT(e, '?'), min, max);
27318   }
27319   return nd;
27320 }
27321 
27322 static unsigned char re_endofcat(Rune c, int is_regex) {
27323   switch (c) {
27324     case 0:
27325       return 1;
27326     case '|':
27327     case ')':
27328       if (is_regex) return 1;
27329   }
27330   return 0;
27331 }
27332 
27333 static struct slre_node *re_parser(struct slre_env *e) {
27334   struct slre_node *alt = NULL, *cat, *nd;
27335   if (!re_endofcat(e->lookahead, e->is_regex)) {
27336     cat = re_parse_la(e);
27337     while (!re_endofcat(e->lookahead, e->is_regex)) {
27338       nd = cat;
27339       cat = re_nnode(e, P_CAT);
27340       cat->par.xy.x = nd;
27341       cat->par.xy.y.y = re_parse_la(e);
27342     }
27343     alt = cat;
27344   }
27345   if (e->lookahead == '|') {
27346     RE_NEXT(e);
27347     nd = alt;
27348     alt = re_nnode(e, P_ALT);
27349     alt->par.xy.x = nd;
27350     alt->par.xy.y.y = re_parser(e);
27351   }
27352   return alt;
27353 }
27354 
27355 static unsigned int re_nodelen(struct slre_node *nd) {
27356   unsigned int n = 0;
27357   if (!nd) return 0;
27358   switch (nd->type) {
27359     case P_ALT:
27360       n = 2;
27361     case P_CAT:
27362       return re_nodelen(nd->par.xy.x) + re_nodelen(nd->par.xy.y.y) + n;
27363     case P_BRA:
27364     case P_LA:
27365     case P_LA_N:
27366       return re_nodelen(nd->par.xy.x) + 2;
27367     case P_REP:
27368       n = nd->par.xy.y.rp.max - nd->par.xy.y.rp.min;
27369       switch (nd->par.xy.y.rp.min) {
27370         case 0:
27371           if (!n) return 0;
27372           if (nd->par.xy.y.rp.max >= SLRE_MAX_REP)
27373             return re_nodelen(nd->par.xy.x) + 2;
27374         case 1:
27375           if (!n) return re_nodelen(nd->par.xy.x);
27376           if (nd->par.xy.y.rp.max >= SLRE_MAX_REP)
27377             return re_nodelen(nd->par.xy.x) + 1;
27378         default:
27379           n = 4;
27380           if (nd->par.xy.y.rp.max >= SLRE_MAX_REP) n++;
27381           return re_nodelen(nd->par.xy.x) + n;
27382       }
27383     default:
27384       return 1;
27385   }
27386 }
27387 
27388 static struct slre_instruction *re_newinst(struct slre_prog *prog, int opcode) {
27389   memset(prog->end, 0, sizeof(struct slre_instruction));
27390   prog->end->opcode = opcode;
27391   return prog->end++;
27392 }
27393 
27394 static void re_compile(struct slre_env *e, struct slre_node *nd) {
27395   struct slre_instruction *inst, *split, *jump, *rep;
27396   unsigned int n;
27397 
27398   if (!nd) return;
27399 
27400   switch (nd->type) {
27401     case P_ALT:
27402       split = re_newinst(e->prog, I_SPLIT);
27403       re_compile(e, nd->par.xy.x);
27404       jump = re_newinst(e->prog, I_JUMP);
27405       re_compile(e, nd->par.xy.y.y);
27406       split->par.xy.x = split + 1;
27407       split->par.xy.y.y = jump + 1;
27408       jump->par.xy.x = e->prog->end;
27409       break;
27410 
27411     case P_ANY:
27412       re_newinst(e->prog, I_ANY);
27413       break;
27414 
27415     case P_BOL:
27416       re_newinst(e->prog, I_BOL);
27417       break;
27418 
27419     case P_BRA:
27420       inst = re_newinst(e->prog, I_LBRA);
27421       inst->par.n = nd->par.xy.y.n;
27422       re_compile(e, nd->par.xy.x);
27423       inst = re_newinst(e->prog, I_RBRA);
27424       inst->par.n = nd->par.xy.y.n;
27425       break;
27426 
27427     case P_CAT:
27428       re_compile(e, nd->par.xy.x);
27429       re_compile(e, nd->par.xy.y.y);
27430       break;
27431 
27432     case P_CH:
27433       inst = re_newinst(e->prog, I_CH);
27434       inst->par.c = nd->par.c;
27435       break;
27436 
27437     case P_EOL:
27438       re_newinst(e->prog, I_EOL);
27439       break;
27440 
27441     case P_EOS:
27442       re_newinst(e->prog, I_EOS);
27443       break;
27444 
27445     case P_LA:
27446       split = re_newinst(e->prog, I_LA);
27447       re_compile(e, nd->par.xy.x);
27448       re_newinst(e->prog, I_END);
27449       split->par.xy.x = split + 1;
27450       split->par.xy.y.y = e->prog->end;
27451       break;
27452     case P_LA_N:
27453       split = re_newinst(e->prog, I_LA_N);
27454       re_compile(e, nd->par.xy.x);
27455       re_newinst(e->prog, I_END);
27456       split->par.xy.x = split + 1;
27457       split->par.xy.y.y = e->prog->end;
27458       break;
27459 
27460     case P_REF:
27461       inst = re_newinst(e->prog, I_REF);
27462       inst->par.n = nd->par.xy.y.n;
27463       break;
27464 
27465     case P_REP:
27466       n = nd->par.xy.y.rp.max - nd->par.xy.y.rp.min;
27467       switch (nd->par.xy.y.rp.min) {
27468         case 0:
27469           if (!n) break;
27470           if (nd->par.xy.y.rp.max >= SLRE_MAX_REP) {
27471             split = re_newinst(e->prog, I_SPLIT);
27472             re_compile(e, nd->par.xy.x);
27473             jump = re_newinst(e->prog, I_JUMP);
27474             jump->par.xy.x = split;
27475             split->par.xy.x = split + 1;
27476             split->par.xy.y.y = e->prog->end;
27477             if (nd->par.xy.y.rp.ng) {
27478               split->par.xy.y.y = split + 1;
27479               split->par.xy.x = e->prog->end;
27480             }
27481             break;
27482           }
27483         case 1:
27484           if (!n) {
27485             re_compile(e, nd->par.xy.x);
27486             break;
27487           }
27488           if (nd->par.xy.y.rp.max >= SLRE_MAX_REP) {
27489             inst = e->prog->end;
27490             re_compile(e, nd->par.xy.x);
27491             split = re_newinst(e->prog, I_SPLIT);
27492             split->par.xy.x = inst;
27493             split->par.xy.y.y = e->prog->end;
27494             if (nd->par.xy.y.rp.ng) {
27495               split->par.xy.y.y = inst;
27496               split->par.xy.x = e->prog->end;
27497             }
27498             break;
27499           }
27500         default:
27501           inst = re_newinst(e->prog, I_REP_INI);
27502           inst->par.xy.y.rp.min = nd->par.xy.y.rp.min;
27503           inst->par.xy.y.rp.max = n;
27504           rep = re_newinst(e->prog, I_REP);
27505           split = re_newinst(e->prog, I_SPLIT);
27506           re_compile(e, nd->par.xy.x);
27507           jump = re_newinst(e->prog, I_JUMP);
27508           jump->par.xy.x = rep;
27509           rep->par.xy.x = e->prog->end;
27510           split->par.xy.x = split + 1;
27511           split->par.xy.y.y = e->prog->end;
27512           if (nd->par.xy.y.rp.ng) {
27513             split->par.xy.y.y = split + 1;
27514             split->par.xy.x = e->prog->end;
27515           }
27516           if (nd->par.xy.y.rp.max >= SLRE_MAX_REP) {
27517             inst = split + 1;
27518             split = re_newinst(e->prog, I_SPLIT);
27519             split->par.xy.x = inst;
27520             split->par.xy.y.y = e->prog->end;
27521             if (nd->par.xy.y.rp.ng) {
27522               split->par.xy.y.y = inst;
27523               split->par.xy.x = e->prog->end;
27524             }
27525             break;
27526           }
27527           break;
27528       }
27529       break;
27530 
27531     case P_SET:
27532       inst = re_newinst(e->prog, I_SET);
27533       inst->par.cp = nd->par.cp;
27534       break;
27535     case P_SET_N:
27536       inst = re_newinst(e->prog, I_SET_N);
27537       inst->par.cp = nd->par.cp;
27538       break;
27539 
27540     case P_WORD:
27541       re_newinst(e->prog, I_WORD);
27542       break;
27543     case P_WORD_N:
27544       re_newinst(e->prog, I_WORD_N);
27545       break;
27546   }
27547 }
27548 
27549 #ifdef RE_TEST
27550 static void print_set(struct slre_class *cp) {
27551   struct slre_range *p;
27552   for (p = cp->spans; p < cp->end; p++) {
27553     printf("%s", p == cp->spans ? "'" : ",'");
27554     printf(
27555         p->s >= 32 && p->s < 127 ? "%c" : (p->s < 256 ? "\\x%02X" : "\\u%04X"),
27556         p->s);
27557     if (p->s != p->e) {
27558       printf(p->e >= 32 && p->e < 127 ? "-%c"
27559                                       : (p->e < 256 ? "-\\x%02X" : "-\\u%04X"),
27560              p->e);
27561     }
27562     printf("'");
27563   }
27564   printf("]");
27565 }
27566 
27567 static void node_print(struct slre_node *nd) {
27568   if (!nd) {
27569     printf("Empty");
27570     return;
27571   }
27572   switch (nd->type) {
27573     case P_ALT:
27574       printf("{");
27575       node_print(nd->par.xy.x);
27576       printf(" | ");
27577       node_print(nd->par.xy.y.y);
27578       printf("}");
27579       break;
27580     case P_ANY:
27581       printf(".");
27582       break;
27583     case P_BOL:
27584       printf("^");
27585       break;
27586     case P_BRA:
27587       node_print(nd->par.xy.x);
27588       printf(")");
27589       break;
27590     case P_CAT:
27591       printf("{");
27592       node_print(nd->par.xy.x);
27593       printf(" & ");
27594       node_print(nd->par.xy.y.y);
27595       printf("}");
27596       break;
27597     case P_CH:
27598       printf(nd->par.c >= 32 && nd->par.c < 127 ? "'%c'" : "'\\u%04X'",
27599              nd->par.c);
27600       break;
27601     case P_EOL:
27602       printf("$");
27603       break;
27604     case P_EOS:
27605       printf("\\0");
27606       break;
27607     case P_LA:
27608       printf("LA(");
27609       node_print(nd->par.xy.x);
27610       printf(")");
27611       break;
27612     case P_LA_N:
27613       printf("LA_N(");
27614       node_print(nd->par.xy.x);
27615       printf(")");
27616       break;
27617     case P_REF:
27618       printf("\\%d", nd->par.xy.y.n);
27619       break;
27620     case P_REP:
27621       node_print(nd->par.xy.x);
27622       printf(nd->par.xy.y.rp.ng ? "{%d,%d}?" : "{%d,%d}", nd->par.xy.y.rp.min,
27623              nd->par.xy.y.rp.max);
27624       break;
27625     case P_SET:
27626       printf("[");
27627       print_set(nd->par.cp);
27628       break;
27629     case P_SET_N:
27630       printf("[^");
27631       print_set(nd->par.cp);
27632       break;
27633     case P_WORD:
27634       printf("\\b");
27635       break;
27636     case P_WORD_N:
27637       printf("\\B");
27638       break;
27639   }
27640 }
27641 
27642 static void program_print(struct slre_prog *prog) {
27643   struct slre_instruction *inst;
27644   for (inst = prog->start; inst < prog->end; ++inst) {
27645     printf("%3d: ", inst - prog->start);
27646     switch (inst->opcode) {
27647       case I_END:
27648         puts("end");
27649         break;
27650       case I_ANY:
27651         puts(".");
27652         break;
27653       case I_ANYNL:
27654         puts(". | '\\r' | '\\n'");
27655         break;
27656       case I_BOL:
27657         puts("^");
27658         break;
27659       case I_CH:
27660         printf(
27661             inst->par.c >= 32 && inst->par.c < 127 ? "'%c'\n" : "'\\u%04X'\n",
27662             inst->par.c);
27663         break;
27664       case I_EOL:
27665         puts("$");
27666         break;
27667       case I_EOS:
27668         puts("\\0");
27669         break;
27670       case I_JUMP:
27671         printf("-->%d\n", inst->par.xy.x - prog->start);
27672         break;
27673       case I_LA:
27674         printf("la %d %d\n", inst->par.xy.x - prog->start,
27675                inst->par.xy.y.y - prog->start);
27676         break;
27677       case I_LA_N:
27678         printf("la_n %d %d\n", inst->par.xy.x - prog->start,
27679                inst->par.xy.y.y - prog->start);
27680         break;
27681       case I_LBRA:
27682         printf("( %d\n", inst->par.n);
27683         break;
27684       case I_RBRA:
27685         printf(") %d\n", inst->par.n);
27686         break;
27687       case I_SPLIT:
27688         printf("-->%d | -->%d\n", inst->par.xy.x - prog->start,
27689                inst->par.xy.y.y - prog->start);
27690         break;
27691       case I_REF:
27692         printf("\\%d\n", inst->par.n);
27693         break;
27694       case I_REP:
27695         printf("repeat -->%d\n", inst->par.xy.x - prog->start);
27696         break;
27697       case I_REP_INI:
27698         printf("init_rep %d %d\n", inst->par.xy.y.rp.min,
27699                inst->par.xy.y.rp.min + inst->par.xy.y.rp.max);
27700         break;
27701       case I_SET:
27702         printf("[");
27703         print_set(inst->par.cp);
27704         puts("");
27705         break;
27706       case I_SET_N:
27707         printf("[^");
27708         print_set(inst->par.cp);
27709         puts("");
27710         break;
27711       case I_WORD:
27712         puts("\\w");
27713         break;
27714       case I_WORD_N:
27715         puts("\\W");
27716         break;
27717     }
27718   }
27719 }
27720 #endif
27721 
27722 int slre_compile(const char *pat, size_t pat_len, const char *flags,
27723                  volatile size_t fl_len, struct slre_prog **pr, int is_regex) {
27724   struct slre_env e;
27725   struct slre_node *nd;
27726   struct slre_instruction *split, *jump;
27727   int err_code;
27728 
27729   e.is_regex = is_regex;
27730   e.prog = (struct slre_prog *) SLRE_MALLOC(sizeof(struct slre_prog));
27731   e.pstart = e.pend =
27732       (struct slre_node *) SLRE_MALLOC(sizeof(struct slre_node) * pat_len * 2);
27733   e.prog->flags = is_regex ? SLRE_FLAG_RE : 0;
27734 
27735   if ((err_code = setjmp(e.jmp_buf)) != SLRE_OK) {
27736     SLRE_FREE(e.pstart);
27737     SLRE_FREE(e.prog);
27738     return err_code;
27739   }
27740 
27741   while (fl_len--) {
27742     switch (flags[fl_len]) {
27743       case 'g':
27744         e.prog->flags |= SLRE_FLAG_G;
27745         break;
27746       case 'i':
27747         e.prog->flags |= SLRE_FLAG_I;
27748         break;
27749       case 'm':
27750         e.prog->flags |= SLRE_FLAG_M;
27751         break;
27752     }
27753   }
27754 
27755   e.src = pat;
27756   e.src_end = pat + pat_len;
27757   e.sets_num = 0;
27758   e.num_captures = 1;
27759   /*e.flags = flags;*/
27760   memset(e.caps, 0, sizeof(e.caps));
27761 
27762   RE_NEXT(&e);
27763   nd = re_parser(&e);
27764   if (e.lookahead == ')') {
27765     SLRE_THROW(&e, SLRE_UNMATCH_RBR);
27766   }
27767   if (e.lookahead != 0) {
27768     SLRE_THROW(&e, SLRE_SYNTAX_ERROR);
27769   }
27770 
27771   e.prog->num_captures = e.num_captures;
27772   e.prog->start = e.prog->end = (struct slre_instruction *) SLRE_MALLOC(
27773       (re_nodelen(nd) + 6) * sizeof(struct slre_instruction));
27774 
27775   split = re_newinst(e.prog, I_SPLIT);
27776   split->par.xy.x = split + 3;
27777   split->par.xy.y.y = split + 1;
27778   re_newinst(e.prog, I_ANYNL);
27779   jump = re_newinst(e.prog, I_JUMP);
27780   jump->par.xy.x = split;
27781   re_newinst(e.prog, I_LBRA);
27782   re_compile(&e, nd);
27783   re_newinst(e.prog, I_RBRA);
27784   re_newinst(e.prog, I_END);
27785 
27786 #ifdef RE_TEST
27787   node_print(nd);
27788   putchar('\n');
27789   program_print(e.prog);
27790 #endif
27791 
27792   SLRE_FREE(e.pstart);
27793 
27794   if (pr != NULL) {
27795     *pr = e.prog;
27796   } else {
27797     slre_free(e.prog);
27798   }
27799 
27800   return err_code;
27801 }
27802 
27803 void slre_free(struct slre_prog *prog) {
27804   if (prog) {
27805     SLRE_FREE(prog->start);
27806     SLRE_FREE(prog);
27807   }
27808 }
27809 
27810 static struct slre_thread *re_newthread(struct slre_thread *t,
27811                                         struct slre_instruction *pc,
27812                                         const char *start,
27813                                         struct slre_loot *loot) {
27814   struct slre_thread *new_thread =
27815       (struct slre_thread *) SLRE_MALLOC(sizeof(struct slre_thread));
27816   if (new_thread != NULL) new_thread->prev = t;
27817   t->pc = pc;
27818   t->start = start;
27819   t->loot = *loot;
27820   return new_thread;
27821 }
27822 
27823 static struct slre_thread *get_prev_thread(struct slre_thread *t) {
27824   struct slre_thread *tmp_thr = t->prev;
27825   SLRE_FREE(t);
27826   return tmp_thr;
27827 }
27828 
27829 static void free_threads(struct slre_thread *t) {
27830   while (t->prev != NULL) t = get_prev_thread(t);
27831 }
27832 
27833 static unsigned char re_match(struct slre_instruction *pc, const char *current,
27834                               const char *end, const char *bol,
27835                               unsigned int flags, struct slre_loot *loot) {
27836   struct slre_loot sub, tmpsub;
27837   Rune c, r;
27838   struct slre_range *p;
27839   size_t i;
27840   struct slre_thread thread, *curr_thread, *tmp_thr;
27841 
27842   /* queue initial thread */
27843   thread.prev = NULL;
27844   curr_thread = re_newthread(&thread, pc, current, loot);
27845 
27846   /* run threads in stack order */
27847   do {
27848     curr_thread = get_prev_thread(curr_thread);
27849     pc = curr_thread->pc;
27850     current = curr_thread->start;
27851     sub = curr_thread->loot;
27852     for (;;) {
27853       switch (pc->opcode) {
27854         case I_END:
27855           memcpy(loot->caps, sub.caps, sizeof loot->caps);
27856           free_threads(curr_thread);
27857           return 1;
27858         case I_ANY:
27859         case I_ANYNL:
27860           if (current < end) {
27861             current += chartorune(&c, current);
27862             if (c && !(pc->opcode == I_ANY && isnewline(c))) break;
27863           }
27864           goto no_match;
27865 
27866         case I_BOL:
27867           if (current == bol) break;
27868           if ((flags & SLRE_FLAG_M) && isnewline(current[-1])) break;
27869           goto no_match;
27870         case I_CH:
27871           if (current < end) {
27872             current += chartorune(&c, current);
27873             if (c &&
27874                 (c == pc->par.c || ((flags & SLRE_FLAG_I) &&
27875                                     tolowerrune(c) == tolowerrune(pc->par.c))))
27876               break;
27877           }
27878           goto no_match;
27879         case I_EOL:
27880           if (current >= end) break;
27881           if ((flags & SLRE_FLAG_M) && isnewline(*current)) break;
27882           goto no_match;
27883         case I_EOS:
27884           if (current >= end) break;
27885           goto no_match;
27886 
27887         case I_JUMP:
27888           pc = pc->par.xy.x;
27889           continue;
27890 
27891         case I_LA:
27892           if (re_match(pc->par.xy.x, current, end, bol, flags, &sub)) {
27893             pc = pc->par.xy.y.y;
27894             continue;
27895           }
27896           goto no_match;
27897         case I_LA_N:
27898           tmpsub = sub;
27899           if (!re_match(pc->par.xy.x, current, end, bol, flags, &tmpsub)) {
27900             pc = pc->par.xy.y.y;
27901             continue;
27902           }
27903           goto no_match;
27904 
27905         case I_LBRA:
27906           sub.caps[pc->par.n].start = current;
27907           break;
27908 
27909         case I_REF:
27910           i = sub.caps[pc->par.n].end - sub.caps[pc->par.n].start;
27911           if (flags & SLRE_FLAG_I) {
27912             int num = i;
27913             const char *s = current, *p = sub.caps[pc->par.n].start;
27914             Rune rr;
27915             for (; num && *s && *p; num--) {
27916               s += chartorune(&r, s);
27917               p += chartorune(&rr, p);
27918               if (tolowerrune(r) != tolowerrune(rr)) break;
27919             }
27920             if (num) goto no_match;
27921           } else if (strncmp(current, sub.caps[pc->par.n].start, i)) {
27922             goto no_match;
27923           }
27924           if (i > 0) current += i;
27925           break;
27926 
27927         case I_REP:
27928           if (pc->par.xy.y.rp.min) {
27929             pc->par.xy.y.rp.min--;
27930             pc++;
27931           } else if (!pc->par.xy.y.rp.max--) {
27932             pc = pc->par.xy.x;
27933             continue;
27934           }
27935           break;
27936 
27937         case I_REP_INI:
27938           (pc + 1)->par.xy.y.rp.min = pc->par.xy.y.rp.min;
27939           (pc + 1)->par.xy.y.rp.max = pc->par.xy.y.rp.max;
27940           break;
27941 
27942         case I_RBRA:
27943           sub.caps[pc->par.n].end = current;
27944           break;
27945 
27946         case I_SET:
27947         case I_SET_N:
27948           if (current >= end) goto no_match;
27949           current += chartorune(&c, current);
27950           if (!c) goto no_match;
27951 
27952           i = 1;
27953           for (p = pc->par.cp->spans; i && p < pc->par.cp->end; p++)
27954             if (flags & SLRE_FLAG_I) {
27955               for (r = p->s; r <= p->e; ++r)
27956                 if (tolowerrune(c) == tolowerrune(r)) {
27957                   i = 0;
27958                   break;
27959                 }
27960             } else if (p->s <= c && c <= p->e)
27961               i = 0;
27962 
27963           if (pc->opcode == I_SET) i = !i;
27964           if (i) break;
27965           goto no_match;
27966 
27967         case I_SPLIT:
27968           tmp_thr = curr_thread;
27969           curr_thread =
27970               re_newthread(curr_thread, pc->par.xy.y.y, current, &sub);
27971           if (curr_thread == NULL) {
27972             fprintf(stderr, "re_match: no memory for thread!\n");
27973             free_threads(tmp_thr);
27974             return 0;
27975           }
27976           pc = pc->par.xy.x;
27977           continue;
27978 
27979         case I_WORD:
27980         case I_WORD_N:
27981           i = (current > bol && iswordchar(current[-1]));
27982           if (iswordchar(current[0])) i = !i;
27983           if (pc->opcode == I_WORD_N) i = !i;
27984           if (i) break;
27985         /* goto no_match; */
27986 
27987         default:
27988           goto no_match;
27989       }
27990       pc++;
27991     }
27992   no_match:
27993     ;
27994   } while (curr_thread->prev != NULL);
27995   return 0;
27996 }
27997 
27998 int slre_exec(struct slre_prog *prog, int flag_g, const char *start,
27999               const char *end, struct slre_loot *loot) {
28000   struct slre_loot tmpsub;
28001   const char *st = start;
28002 
28003   if (!loot) loot = &tmpsub;
28004   memset(loot, 0, sizeof(*loot));
28005 
28006   if (!flag_g) {
28007     loot->num_captures = prog->num_captures;
28008     return !re_match(prog->start, start, end, start, prog->flags, loot);
28009   }
28010 
28011   while (re_match(prog->start, st, end, start, prog->flags, &tmpsub)) {
28012     unsigned int i;
28013     st = tmpsub.caps[0].end;
28014     for (i = 0; i < prog->num_captures; i++) {
28015       struct slre_cap *l = &loot->caps[loot->num_captures + i];
28016       struct slre_cap *s = &tmpsub.caps[i];
28017       l->start = s->start;
28018       l->end = s->end;
28019     }
28020     loot->num_captures += prog->num_captures;
28021   }
28022   return !loot->num_captures;
28023 }
28024 
28025 int slre_replace(struct slre_loot *loot, const char *src, size_t src_len,
28026                  const char *rstr, size_t rstr_len, struct slre_loot *dstsub) {
28027   int size = 0, n;
28028   Rune curr_rune;
28029   const char *const rstr_end = rstr + rstr_len;
28030 
28031   memset(dstsub, 0, sizeof(*dstsub));
28032   while (rstr < rstr_end && !(n = re_nextc_raw(&curr_rune, &rstr, rstr_end)) &&
28033          curr_rune) {
28034     int sz;
28035     if (n < 0) return n;
28036     if (curr_rune == '$') {
28037       n = re_nextc(&curr_rune, &rstr, rstr_end);
28038       if (n < 0) return n;
28039       switch (curr_rune) {
28040         case '&':
28041           sz = loot->caps[0].end - loot->caps[0].start;
28042           size += sz;
28043           dstsub->caps[dstsub->num_captures++] = loot->caps[0];
28044           break;
28045         case '0':
28046         case '1':
28047         case '2':
28048         case '3':
28049         case '4':
28050         case '5':
28051         case '6':
28052         case '7':
28053         case '8':
28054         case '9': {
28055           int sbn = dec(curr_rune);
28056           if (0 == sbn && rstr[0] && isdigitrune(rstr[0])) {
28057             n = re_nextc(&curr_rune, &rstr, rstr_end);
28058             if (n < 0) return n;
28059             sz = dec(curr_rune);
28060             sbn = sbn * 10 + sz;
28061           }
28062           if (sbn >= loot->num_captures) break;
28063           sz = loot->caps[sbn].end - loot->caps[sbn].start;
28064           size += sz;
28065           dstsub->caps[dstsub->num_captures++] = loot->caps[sbn];
28066           break;
28067         }
28068         case '`':
28069           sz = loot->caps[0].start - src;
28070           size += sz;
28071           dstsub->caps[dstsub->num_captures].start = src;
28072           dstsub->caps[dstsub->num_captures++].end = loot->caps[0].start;
28073           break;
28074         case '\'':
28075           sz = src + src_len - loot->caps[0].end;
28076           size += sz;
28077           dstsub->caps[dstsub->num_captures].start = loot->caps[0].end;
28078           dstsub->caps[dstsub->num_captures++].end = loot->caps[0].end + sz;
28079           break;
28080         case '$':
28081           size++;
28082           dstsub->caps[dstsub->num_captures].start = rstr - 1;
28083           dstsub->caps[dstsub->num_captures++].end = rstr;
28084           break;
28085         default:
28086           return SLRE_BAD_CHAR_AFTER_USD;
28087       }
28088     } else {
28089       char tmps[300], *d = tmps;
28090       size += (sz = runetochar(d, &curr_rune));
28091       if (!dstsub->num_captures ||
28092           dstsub->caps[dstsub->num_captures - 1].end != rstr - sz) {
28093         dstsub->caps[dstsub->num_captures].start = rstr - sz;
28094         dstsub->caps[dstsub->num_captures++].end = rstr;
28095       } else
28096         dstsub->caps[dstsub->num_captures - 1].end = rstr;
28097     }
28098   }
28099   return size;
28100 }
28101 
28102 int slre_match(const char *re, size_t re_len, const char *flags, size_t fl_len,
28103                const char *str, size_t str_len, struct slre_loot *loot) {
28104   struct slre_prog *prog = NULL;
28105   int res;
28106 
28107   if ((res = slre_compile(re, re_len, flags, fl_len, &prog, 1)) == SLRE_OK) {
28108     res = slre_exec(prog, prog->flags & SLRE_FLAG_G, str, str + str_len, loot);
28109     slre_free(prog);
28110   }
28111 
28112   return res;
28113 }
28114 
28115 int slre_get_flags(struct slre_prog *crp) {
28116   return crp->flags;
28117 }
28118 
28119 #ifdef SLRE_TEST
28120 
28121 #include <errno.h>
28122 
28123 static const char *err_code_to_str(int err_code) {
28124   static const char *ar[] = {
28125       "no error", "invalid decimal digit", "invalid hex digit",
28126       "invalid escape character", "invalid unterminated escape sequence",
28127       "syntax error", "unmatched left parenthesis",
28128       "unmatched right parenthesis", "numeric overflow",
28129       "infinite loop empty string", "too many charsets",
28130       "invalid charset range", "charset is too large", "malformed charset",
28131       "invalid back reference", "too many captures", "invalid quantifier",
28132       "bad character after $"};
28133 
28134   typedef char static_assertion_err_codes_out_of_sync
28135       [2 * !!(((sizeof(ar) / sizeof(ar[0])) == SLRE_BAD_CHAR_AFTER_USD + 1)) -
28136        1];
28137 
28138   return err_code >= 0 && err_code < (int) (sizeof(ar) / sizeof(ar[0]))
28139              ? ar[err_code]
28140              : "invalid error code";
28141 }
28142 
28143 #define RE_TEST_STR_SIZE 2000
28144 
28145 static unsigned get_flags(const char *ch) {
28146   unsigned int flags = 0;
28147 
28148   while (*ch != '\0') {
28149     switch (*ch) {
28150       case 'g':
28151         flags |= SLRE_FLAG_G;
28152         break;
28153       case 'i':
28154         flags |= SLRE_FLAG_I;
28155         break;
28156       case 'm':
28157         flags |= SLRE_FLAG_M;
28158         break;
28159       case 'r':
28160         flags |= SLRE_FLAG_RE;
28161         break;
28162       default:
28163         return flags;
28164     }
28165     ch++;
28166   }
28167   return flags;
28168 }
28169 
28170 static void show_usage_and_exit(char *argv[]) {
28171   fprintf(stderr, "Usage: %s [OPTIONS]\n", argv[0]);
28172   fprintf(stderr, "%s\n", "OPTIONS:");
28173   fprintf(stderr, "%s\n", "  -p <regex_pattern>     Regex pattern");
28174   fprintf(stderr, "%s\n", "  -o <regex_flags>       Combination of g,i,m");
28175   fprintf(stderr, "%s\n", "  -s <string>            String to match");
28176   fprintf(stderr, "%s\n", "  -f <file_name>         Match lines from file");
28177   fprintf(stderr, "%s\n", "  -n <cap_no>            Show given capture");
28178   fprintf(stderr, "%s\n", "  -r <replace_str>       Replace given capture");
28179   fprintf(stderr, "%s\n", "  -v                     Show verbose stats");
28180   exit(1);
28181 }
28182 
28183 static int process_line(struct slre_prog *pr, const char *flags,
28184                         const char *line, const char *cap_no,
28185                         const char *replace, const char *verbose) {
28186   struct slre_loot loot;
28187   unsigned int fl = flags == NULL ? 0 : get_flags(flags);
28188   int i, n = cap_no == NULL ? -1 : atoi(cap_no), err_code = 0;
28189   struct slre_cap *cap = &loot.caps[n];
28190 
28191   err_code =
28192       slre_exec(pr, pr->flags & SLRE_FLAG_G, line, line + strlen(line), &loot);
28193   if (err_code == SLRE_OK) {
28194     if (n >= 0 && n < loot.num_captures && replace != NULL) {
28195       struct slre_cap *cap = &loot.caps[n];
28196       printf("%.*s", (int) (cap->start - line), line);
28197       printf("%s", replace);
28198       printf("%.*s", (int) ((line + strlen(line)) - cap->end), cap->end);
28199     } else if (n >= 0 && n < loot.num_captures) {
28200       printf("%.*s\n", (int) (cap->end - cap->start), cap->start);
28201     }
28202 
28203     if (verbose != NULL) {
28204       fprintf(stderr, "%s\n", "Captures:");
28205       for (i = 0; i < loot.num_captures; i++) {
28206         fprintf(stderr, "%d [%.*s]\n", i,
28207                 (int) (loot.caps[i].end - loot.caps[i].start),
28208                 loot.caps[i].start);
28209       }
28210     }
28211   }
28212 
28213   return err_code;
28214 }
28215 
28216 int main(int argc, char **argv) {
28217   const char *str = NULL, *pattern = NULL, *replace = NULL;
28218   const char *flags = "", *file_name = NULL, *cap_no = NULL, *verbose = NULL;
28219   struct slre_prog *pr = NULL;
28220   int i, err_code = 0;
28221 
28222   /* Execute inline code */
28223   for (i = 1; i < argc; i++) {
28224     if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
28225       pattern = argv[++i];
28226     } else if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) {
28227       flags = argv[++i];
28228     } else if (strcmp(argv[i], "-s") == 0 && i + 1 < argc) {
28229       str = argv[++i];
28230     } else if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) {
28231       file_name = argv[++i];
28232     } else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) {
28233       cap_no = argv[++i];
28234     } else if (strcmp(argv[i], "-r") == 0 && i + 1 < argc) {
28235       replace = argv[++i];
28236     } else if (strcmp(argv[i], "-v") == 0) {
28237       verbose = "";
28238     } else if (strcmp(argv[i], "-h") == 0) {
28239       show_usage_and_exit(argv);
28240     } else {
28241       show_usage_and_exit(argv);
28242     }
28243   }
28244 
28245   if (pattern == NULL) {
28246     fprintf(stderr, "%s\n", "-p option is mandatory");
28247     exit(1);
28248   } else if ((err_code = slre_compile(pattern, strlen(pattern), flags,
28249                                       strlen(flags), &pr, 1)) != SLRE_OK) {
28250     fprintf(stderr, "slre_compile(%s): %s\n", argv[0],
28251             err_code_to_str(err_code));
28252     exit(1);
28253   } else if (str != NULL) {
28254     err_code = process_line(pr, flags, str, cap_no, replace, verbose);
28255   } else if (file_name != NULL) {
28256     FILE *fp = strcmp(file_name, "-") == 0 ? stdin : fopen(file_name, "rb");
28257     char line[20 * 1024];
28258     if (fp == NULL) {
28259       fprintf(stderr, "Cannot open %s: %s\n", file_name, strerror(errno));
28260       exit(1);
28261     } else {
28262       /* Return success if at least one line matches */
28263       err_code = 1;
28264       while (fgets(line, sizeof(line), fp) != NULL) {
28265         if (process_line(pr, flags, line, cap_no, replace, verbose) ==
28266             SLRE_OK) {
28267           err_code = 0;
28268         }
28269       }
28270       fclose(fp); /* If fp == stdin, it is safe to close, too */
28271     }
28272   } else {
28273     fprintf(stderr, "%s\n", "Please specify one of -s or -f options");
28274     exit(1);
28275   }
28276   slre_free(pr);
28277 
28278   return err_code;
28279 }
28280 #endif /* SLRE_TEST */
28281 
28282 #endif /* V7_ENABLE__RegExp */
28283 #ifdef V7_MODULE_LINES
28284 #line 1 "v7/src/heapusage.c"
28285 #endif
28286 /*
28287  * Copyright (c) 2014-2016 Cesanta Software Limited
28288  * All rights reserved
28289  */
28290 
28291 #include <stdlib.h>
28292 #include <stdio.h>
28293 #include <assert.h>
28294 
28295 #if defined(V7_HEAPUSAGE_ENABLE)
28296 
28297 /*
28298  * A flag that is set by GC before allocating its buffers, so we can
28299  * distinguish these buffers from other allocations
28300  */
28301 volatile int heap_dont_count = 0;
28302 
28303 extern void *__real_malloc(size_t size);
28304 extern void *__real_calloc(size_t num, size_t size);
28305 extern void *__real_realloc(void *p, size_t size);
28306 extern void __real_free(void *p);
28307 
28308 /* TODO(dfrank): make it dynamically allocated from heap */
28309 #define CELLS_CNT (1024 * 32)
28310 
28311 typedef struct cell {
28312   void *p;
28313   unsigned dont_count : 1;
28314   unsigned size : 31;
28315 } cell_t;
28316 
28317 typedef struct alloc_registry {
28318   size_t used_cells_cnt;
28319   size_t allocated_size;
28320   size_t real_used_cells_cnt;
28321   size_t real_allocated_size;
28322   cell_t cells[CELLS_CNT];
28323 } alloc_registry_t;
28324 
28325 static alloc_registry_t registry = {0};
28326 
28327 /*
28328  * Make a record about an allocated buffer `p` of size `size`
28329  */
28330 static void cell_allocated(void *p, size_t size) {
28331   int i;
28332   int cell_num = -1;
28333 
28334   if (p != NULL && size != 0) {
28335     /* TODO(dfrank): make it dynamically allocated from heap */
28336     assert(registry.real_used_cells_cnt < CELLS_CNT);
28337 
28338     for (i = 0; i < CELLS_CNT; ++i) {
28339       if (registry.cells[i].p == NULL) {
28340         cell_num = i;
28341         break;
28342       }
28343     }
28344 
28345     assert(cell_num != -1);
28346 
28347     registry.cells[cell_num].p = p;
28348     registry.cells[cell_num].size = size;
28349     registry.cells[cell_num].dont_count = !!heap_dont_count;
28350 
28351     registry.real_allocated_size += size;
28352     registry.real_used_cells_cnt += 1;
28353 
28354     if (!heap_dont_count) {
28355       registry.allocated_size += size;
28356       registry.used_cells_cnt += 1;
28357     }
28358 
28359 #if 0
28360     printf("alloc=0x%lx, size=%lu, total=%lu\n", (unsigned long)p, size,
28361         registry.allocated_size);
28362 #endif
28363   }
28364 }
28365 
28366 /*
28367  * Delete a record about an allocated buffer `p`. If our registry does not
28368  * contain anything about the given pointer, the call is ignored. We can't
28369  * generate an error because shared libraries still use unwrapped heap
28370  * functions, so we can face "unknown" pointers.
28371  */
28372 static void cell_freed(void *p) {
28373   int i;
28374   int cell_num = -1;
28375 
28376   if (p != NULL) {
28377     assert(registry.real_used_cells_cnt > 0);
28378 
28379     for (i = 0; i < CELLS_CNT; ++i) {
28380       if (registry.cells[i].p == p) {
28381         cell_num = i;
28382         break;
28383       }
28384     }
28385 
28386     /*
28387      * NOTE: it would be nice to have `assert(cell_num != -1);`, but
28388      * unfortunately not all allocations are wrapped: shared libraries will
28389      * still use unwrapped mallocs, so we might get unknown pointers here.
28390      */
28391 
28392     if (cell_num != -1) {
28393       registry.real_allocated_size -= registry.cells[cell_num].size;
28394       registry.real_used_cells_cnt -= 1;
28395 
28396       if (!registry.cells[cell_num].dont_count) {
28397         registry.allocated_size -= registry.cells[cell_num].size;
28398         registry.used_cells_cnt -= 1;
28399       }
28400 
28401       registry.cells[cell_num].p = NULL;
28402       registry.cells[cell_num].size = 0;
28403       registry.cells[cell_num].dont_count = 0;
28404 
28405 #if 0
28406       printf("free=0x%lx, total=%lu\n", (unsigned long)p, registry.allocated_size);
28407 #endif
28408     }
28409   }
28410 }
28411 
28412 /*
28413  * Wrappers of the standard heap functions
28414  */
28415 
28416 void *__wrap_malloc(size_t size) {
28417   void *ret = __real_malloc(size);
28418   cell_allocated(ret, size);
28419   return ret;
28420 }
28421 
28422 void *__wrap_calloc(size_t num, size_t size) {
28423   void *ret = __real_calloc(num, size);
28424   cell_allocated(ret, num * size);
28425   return ret;
28426 }
28427 
28428 void *__wrap_realloc(void *p, size_t size) {
28429   void *ret;
28430   cell_freed(p);
28431   ret = __real_realloc(p, size);
28432   cell_allocated(ret, size);
28433   return ret;
28434 }
28435 
28436 void __wrap_free(void *p) {
28437   __real_free(p);
28438   cell_freed(p);
28439 }
28440 
28441 /*
28442  * Small API to get some stats, see header file for details
28443  */
28444 
28445 size_t heapusage_alloc_size(void) {
28446   return registry.allocated_size;
28447 }
28448 
28449 size_t heapusage_allocs_cnt(void) {
28450   return registry.used_cells_cnt;
28451 }
28452 
28453 #endif /* V7_HEAPUSAGE_ENABLE */
28454 #ifdef V7_MODULE_LINES
28455 #line 1 "v7/src/cyg_profile.c"
28456 #endif
28457 /*
28458  * Copyright (c) 2014 Cesanta Software Limited
28459  * All rights reserved
28460  */
28461 
28462 /*
28463  * This file contains GCC/clang instrumentation callbacks. The actual
28464  * code in these callbacks depends on enabled features.
28465  *
28466  * Currently, the code from different subsystems is embedded right into
28467  * callbacks for performance reasons. It would be probably more elegant
28468  * to have subsystem-specific functions that will be called from these
28469  * callbacks, but since the callbacks are called really a lot (on each v7
28470  * function call), I decided it's better to inline the code right here.
28471  */
28472 
28473 /* Amalgamated: #include "v7/src/internal.h" */
28474 /* Amalgamated: #include "v7/src/cyg_profile.h" */
28475 /* Amalgamated: #include "v7/src/core.h" */
28476 
28477 #if defined(V7_CYG_PROFILE_ON)
28478 
28479 #if defined(V7_ENABLE_CALL_TRACE)
28480 
28481 #define CALL_TRACE_SIZE 32
28482 
28483 typedef struct {
28484   uint16_t size;
28485   uint16_t missed_cnt;
28486   void *addresses[CALL_TRACE_SIZE];
28487 } call_trace_t;
28488 
28489 static call_trace_t call_trace = {0};
28490 
28491 NOINSTR
28492 void call_trace_print(const char *prefix, const char *suffix, size_t skip_cnt,
28493                       size_t max_cnt) {
28494   int i;
28495   if (call_trace.missed_cnt > 0) {
28496     fprintf(stderr, "missed calls! (%d) ", (int) call_trace.missed_cnt);
28497   }
28498   if (prefix != NULL) {
28499     fprintf(stderr, "%s", prefix);
28500   }
28501   for (i = (int) call_trace.size - 1 - skip_cnt; i >= 0; i--) {
28502     fprintf(stderr, " %lx", (unsigned long) call_trace.addresses[i]);
28503     if (max_cnt > 0) {
28504       if (--max_cnt == 0) {
28505         break;
28506       }
28507     }
28508   }
28509   if (suffix != NULL) {
28510     fprintf(stderr, "%s", suffix);
28511   }
28512   fprintf(stderr, "\n");
28513 }
28514 
28515 #endif
28516 
28517 #ifndef IRAM
28518 #define IRAM
28519 #endif
28520 
28521 #ifndef NOINSTR
28522 #define NOINSTR __attribute__((no_instrument_function))
28523 #endif
28524 
28525 #if defined(__cplusplus)
28526 extern "C" {
28527 #endif /* __cplusplus */
28528 IRAM NOINSTR void __cyg_profile_func_enter(void *this_fn, void *call_site);
28529 
28530 IRAM NOINSTR void __cyg_profile_func_exit(void *this_fn, void *call_site);
28531 
28532 #if defined(__cplusplus)
28533 }
28534 #endif /* __cplusplus */
28535 
28536 IRAM void __cyg_profile_func_enter(void *this_fn, void *call_site) {
28537 #if defined(V7_STACK_GUARD_MIN_SIZE)
28538   {
28539     static int profile_enter = 0;
28540     void *fp = __builtin_frame_address(0);
28541 
28542     (void) call_site;
28543 
28544     if (profile_enter || v7_sp_limit == NULL) return;
28545 
28546     profile_enter++;
28547     if (v7_head != NULL && fp < v7_head->sp_lwm) v7_head->sp_lwm = fp;
28548 
28549     if (((int) fp - (int) v7_sp_limit) < V7_STACK_GUARD_MIN_SIZE) {
28550       printf("fun %p sp %p limit %p left %d\n", this_fn, fp, v7_sp_limit,
28551              (int) fp - (int) v7_sp_limit);
28552       abort();
28553     }
28554     profile_enter--;
28555   }
28556 #endif
28557 
28558 #if defined(V7_ENABLE_GC_CHECK)
28559   {
28560     (void) this_fn;
28561     (void) call_site;
28562   }
28563 #endif
28564 
28565 #if defined(V7_ENABLE_STACK_TRACKING)
28566   {
28567     struct v7 *v7;
28568     struct stack_track_ctx *ctx;
28569     void *fp = __builtin_frame_address(1);
28570 
28571     (void) this_fn;
28572     (void) call_site;
28573 
28574     /*
28575      * TODO(dfrank): it actually won't work for multiple instances of v7 running
28576      * in parallel threads. We need to know the exact v7 instance for which
28577      * current function is called, but so far I failed to find a way to do this.
28578      */
28579     for (v7 = v7_head; v7 != NULL; v7 = v7->next_v7) {
28580       for (ctx = v7->stack_track_ctx; ctx != NULL; ctx = ctx->next) {
28581         /* commented because it fails on legal code compiled with -O3 */
28582         /*assert(fp <= ctx->start);*/
28583 
28584         if (fp < ctx->max) {
28585           ctx->max = fp;
28586         }
28587       }
28588     }
28589   }
28590 #endif
28591 
28592 #if defined(V7_ENABLE_CALL_TRACE)
28593   if (call_trace.size < CALL_TRACE_SIZE) {
28594     call_trace.addresses[call_trace.size] = this_fn;
28595     call_trace.size++;
28596   } else {
28597     call_trace.missed_cnt++;
28598   }
28599 #endif
28600 }
28601 
28602 IRAM void __cyg_profile_func_exit(void *this_fn, void *call_site) {
28603 #if defined(V7_STACK_GUARD_MIN_SIZE)
28604   {
28605     (void) this_fn;
28606     (void) call_site;
28607   }
28608 #endif
28609 
28610 #if defined(V7_ENABLE_GC_CHECK)
28611   {
28612     struct v7 *v7;
28613     void *fp = __builtin_frame_address(1);
28614 
28615     (void) this_fn;
28616     (void) call_site;
28617 
28618     for (v7 = v7_head; v7 != NULL; v7 = v7->next_v7) {
28619       v7_val_t **vp;
28620       if (v7->owned_values.buf == NULL) continue;
28621       vp = (v7_val_t **) (v7->owned_values.buf + v7->owned_values.len -
28622                           sizeof(v7_val_t *));
28623 
28624       for (; (char *) vp >= v7->owned_values.buf; vp--) {
28625         /*
28626          * Check if a variable belongs to a dead stack frame.
28627          * Addresses lower than the parent frame belong to the
28628          * stack frame of the function about to return.
28629          * But the heap also usually below the stack and
28630          * we don't know the end of the stack. But this hook
28631          * is called at each function return, so we have
28632          * to check only up to the maximum stack frame size,
28633          * let's arbitrarily but reasonably set that at 8k.
28634          */
28635         if ((void *) *vp <= fp && (void *) *vp > (fp + 8196)) {
28636           fprintf(stderr, "Found owned variable after return\n");
28637           abort();
28638         }
28639       }
28640     }
28641   }
28642 #endif
28643 
28644 #if defined(V7_ENABLE_STACK_TRACKING)
28645   {
28646     (void) this_fn;
28647     (void) call_site;
28648   }
28649 #endif
28650 
28651 #if defined(V7_ENABLE_CALL_TRACE)
28652   if (call_trace.missed_cnt > 0) {
28653     call_trace.missed_cnt--;
28654   } else if (call_trace.size > 0) {
28655     if (call_trace.addresses[call_trace.size - 1] != this_fn) {
28656       abort();
28657     }
28658     call_trace.size--;
28659   } else {
28660     /*
28661      * We may get here if calls to `__cyg_profile_func_exit()` and
28662      * `__cyg_profile_func_enter()` are unbalanced.
28663      *
28664      * TODO(dfrank) understand, why in the beginning of the program execution
28665      * we get here. I was sure this should be impossible.
28666      */
28667     /* abort(); */
28668   }
28669 #endif
28670 }
28671 
28672 #if defined(V7_ENABLE_STACK_TRACKING)
28673 
28674 void v7_stack_track_start(struct v7 *v7, struct stack_track_ctx *ctx) {
28675   /* insert new context at the head of the list */
28676   ctx->next = v7->stack_track_ctx;
28677   v7->stack_track_ctx = ctx;
28678 
28679   /* init both `max` and `start` to the current frame pointer */
28680   ctx->max = ctx->start = __builtin_frame_address(0);
28681 }
28682 
28683 int v7_stack_track_end(struct v7 *v7, struct stack_track_ctx *ctx) {
28684   int diff;
28685 
28686   /* this function can be called only for the head context */
28687   assert(v7->stack_track_ctx == ctx);
28688 
28689   diff = (int) ((char *) ctx->start - (char *) ctx->max);
28690 
28691   /* remove context from the linked list */
28692   v7->stack_track_ctx = ctx->next;
28693 
28694   return (int) diff;
28695 }
28696 
28697 #endif /* V7_ENABLE_STACK_TRACKING */
28698 #endif /* V7_CYG_PROFILE_ON */
28699 #ifdef V7_MODULE_LINES
28700 #line 1 "v7/src/std_object.c"
28701 #endif
28702 /*
28703  * Copyright (c) 2014 Cesanta Software Limited
28704  * All rights reserved
28705  */
28706 
28707 /* Amalgamated: #include "common/str_util.h" */
28708 /* Amalgamated: #include "v7/src/internal.h" */
28709 /* Amalgamated: #include "v7/src/std_object.h" */
28710 /* Amalgamated: #include "v7/src/function.h" */
28711 /* Amalgamated: #include "v7/src/core.h" */
28712 /* Amalgamated: #include "v7/src/conversion.h" */
28713 /* Amalgamated: #include "v7/src/array.h" */
28714 /* Amalgamated: #include "v7/src/object.h" */
28715 /* Amalgamated: #include "v7/src/exceptions.h" */
28716 /* Amalgamated: #include "v7/src/primitive.h" */
28717 /* Amalgamated: #include "v7/src/string.h" */
28718 /* Amalgamated: #include "v7/src/regexp.h" */
28719 /* Amalgamated: #include "v7/src/exec.h" */
28720 
28721 #if V7_ENABLE__Object__getPrototypeOf
28722 WARN_UNUSED_RESULT
28723 V7_PRIVATE enum v7_err Obj_getPrototypeOf(struct v7 *v7, v7_val_t *res) {
28724   enum v7_err rcode = V7_OK;
28725   val_t arg = v7_arg(v7, 0);
28726 
28727   if (!v7_is_object(arg)) {
28728     rcode =
28729         v7_throwf(v7, TYPE_ERROR, "Object.getPrototypeOf called on non-object");
28730     goto clean;
28731   }
28732   *res = v7_get_proto(v7, arg);
28733 
28734 clean:
28735   return rcode;
28736 }
28737 #endif
28738 
28739 #if V7_ENABLE__Object__isPrototypeOf
28740 WARN_UNUSED_RESULT
28741 V7_PRIVATE enum v7_err Obj_isPrototypeOf(struct v7 *v7, v7_val_t *res) {
28742   enum v7_err rcode = V7_OK;
28743   val_t obj = v7_arg(v7, 0);
28744   val_t proto = v7_get_this(v7);
28745 
28746   *res = v7_mk_boolean(v7, is_prototype_of(v7, obj, proto));
28747 
28748   return rcode;
28749 }
28750 #endif
28751 
28752 #if V7_ENABLE__Object__getOwnPropertyNames || V7_ENABLE__Object__keys
28753 /*
28754  * Hack to ensure that the iteration order of the keys array is consistent
28755  * with the iteration order if properties in `for in`
28756  * This will be obsoleted when arrays will have a special object type.
28757  */
28758 static void _Obj_append_reverse(struct v7 *v7, struct v7_property *p, val_t res,
28759                                 int i, v7_prop_attr_t ignore_flags) {
28760   while (p && p->attributes & ignore_flags) p = p->next;
28761   if (p == NULL) return;
28762   if (p->next) _Obj_append_reverse(v7, p->next, res, i + 1, ignore_flags);
28763 
28764   v7_array_set(v7, res, i, p->name);
28765 }
28766 
28767 WARN_UNUSED_RESULT
28768 static enum v7_err _Obj_ownKeys(struct v7 *v7, unsigned int ignore_flags,
28769                                 val_t *res) {
28770   enum v7_err rcode = V7_OK;
28771   val_t obj = v7_arg(v7, 0);
28772 
28773   *res = v7_mk_dense_array(v7);
28774 
28775   if (!v7_is_object(obj)) {
28776     rcode = v7_throwf(v7, TYPE_ERROR, "Object.keys called on non-object");
28777     goto clean;
28778   }
28779 
28780   _Obj_append_reverse(v7, get_object_struct(obj)->properties, *res, 0,
28781                       ignore_flags);
28782 
28783 clean:
28784   return rcode;
28785 }
28786 #endif
28787 
28788 #if V7_ENABLE__Object__hasOwnProperty ||       \
28789     V7_ENABLE__Object__propertyIsEnumerable || \
28790     V7_ENABLE__Object__getOwnPropertyDescriptor
28791 static enum v7_err _Obj_getOwnProperty(struct v7 *v7, val_t obj, val_t name,
28792                                        struct v7_property **res) {
28793   enum v7_err rcode = V7_OK;
28794   char name_buf[512];
28795   size_t name_len;
28796 
28797   rcode = to_string(v7, name, NULL, name_buf, sizeof(name_buf), &name_len);
28798   if (rcode != V7_OK) {
28799     goto clean;
28800   }
28801 
28802   *res = v7_get_own_property(v7, obj, name_buf, name_len);
28803 
28804 clean:
28805   return rcode;
28806 }
28807 #endif
28808 
28809 #if V7_ENABLE__Object__keys
28810 WARN_UNUSED_RESULT
28811 V7_PRIVATE enum v7_err Obj_keys(struct v7 *v7, v7_val_t *res) {
28812   return _Obj_ownKeys(v7, _V7_PROPERTY_HIDDEN | V7_PROPERTY_NON_ENUMERABLE,
28813                       res);
28814 }
28815 #endif
28816 
28817 #if V7_ENABLE__Object__getOwnPropertyNames
28818 WARN_UNUSED_RESULT
28819 V7_PRIVATE enum v7_err Obj_getOwnPropertyNames(struct v7 *v7, v7_val_t *res) {
28820   return _Obj_ownKeys(v7, _V7_PROPERTY_HIDDEN, res);
28821 }
28822 #endif
28823 
28824 #if V7_ENABLE__Object__getOwnPropertyDescriptor
28825 WARN_UNUSED_RESULT
28826 V7_PRIVATE enum v7_err Obj_getOwnPropertyDescriptor(struct v7 *v7,
28827                                                     v7_val_t *res) {
28828   enum v7_err rcode = V7_OK;
28829   struct v7_property *prop;
28830   val_t obj = v7_arg(v7, 0);
28831   val_t name = v7_arg(v7, 1);
28832   val_t desc;
28833 
28834   rcode = _Obj_getOwnProperty(v7, obj, name, &prop);
28835   if (rcode != V7_OK) {
28836     goto clean;
28837   }
28838 
28839   if (prop == NULL) {
28840     goto clean;
28841   }
28842 
28843   desc = v7_mk_object(v7);
28844   v7_set(v7, desc, "value", 5, prop->value);
28845   v7_set(v7, desc, "writable", 8,
28846          v7_mk_boolean(v7, !(prop->attributes & V7_PROPERTY_NON_WRITABLE)));
28847   v7_set(v7, desc, "enumerable", 10,
28848          v7_mk_boolean(v7, !(prop->attributes & (_V7_PROPERTY_HIDDEN |
28849                                                  V7_PROPERTY_NON_ENUMERABLE))));
28850   v7_set(v7, desc, "configurable", 12,
28851          v7_mk_boolean(v7, !(prop->attributes & V7_PROPERTY_NON_CONFIGURABLE)));
28852 
28853   *res = desc;
28854 
28855 clean:
28856   return rcode;
28857 }
28858 #endif
28859 
28860 WARN_UNUSED_RESULT
28861 static enum v7_err o_set_attr(struct v7 *v7, val_t desc, const char *name,
28862                               size_t n, v7_prop_attr_desc_t *pattrs_delta,
28863                               v7_prop_attr_desc_t flag_true,
28864                               v7_prop_attr_desc_t flag_false) {
28865   enum v7_err rcode = V7_OK;
28866 
28867   val_t v = V7_UNDEFINED;
28868   rcode = v7_get_throwing(v7, desc, name, n, &v);
28869   if (rcode != V7_OK) {
28870     goto clean;
28871   }
28872 
28873   if (v7_is_truthy(v7, v)) {
28874     *pattrs_delta |= flag_true;
28875   } else {
28876     *pattrs_delta |= flag_false;
28877   }
28878 
28879 clean:
28880   return rcode;
28881 }
28882 
28883 WARN_UNUSED_RESULT
28884 static enum v7_err _Obj_defineProperty(struct v7 *v7, val_t obj,
28885                                        const char *name, int name_len,
28886                                        val_t desc, val_t *res) {
28887   enum v7_err rcode = V7_OK;
28888   val_t val = V7_UNDEFINED;
28889   v7_prop_attr_desc_t attrs_desc = 0;
28890 
28891   /*
28892    * get provided value, or set `V7_DESC_PRESERVE_VALUE` flag if no value is
28893    * provided at all
28894    */
28895   {
28896     struct v7_property *prop = v7_get_property(v7, desc, "value", 5);
28897     if (prop == NULL) {
28898       /* no value is provided */
28899       attrs_desc |= V7_DESC_PRESERVE_VALUE;
28900     } else {
28901       /* value is provided: use it */
28902       rcode = v7_property_value(v7, desc, prop, &val);
28903       if (rcode != V7_OK) {
28904         goto clean;
28905       }
28906     }
28907   }
28908 
28909   /* Examine given properties, and set appropriate flags for `def_property` */
28910 
28911   rcode = o_set_attr(v7, desc, "enumerable", 10, &attrs_desc,
28912                      V7_DESC_ENUMERABLE(1), V7_DESC_ENUMERABLE(0));
28913   if (rcode != V7_OK) {
28914     goto clean;
28915   }
28916 
28917   rcode = o_set_attr(v7, desc, "writable", 8, &attrs_desc, V7_DESC_WRITABLE(1),
28918                      V7_DESC_WRITABLE(0));
28919   if (rcode != V7_OK) {
28920     goto clean;
28921   }
28922 
28923   rcode = o_set_attr(v7, desc, "configurable", 12, &attrs_desc,
28924                      V7_DESC_CONFIGURABLE(1), V7_DESC_CONFIGURABLE(0));
28925   if (rcode != V7_OK) {
28926     goto clean;
28927   }
28928 
28929   /* TODO(dfrank) : add getter/setter support */
28930 
28931   /* Finally, do the job on defining the property */
28932   rcode = def_property(v7, obj, name, name_len, attrs_desc, val,
28933                        0 /*not assign*/, NULL);
28934   if (rcode != V7_OK) {
28935     goto clean;
28936   }
28937 
28938   *res = obj;
28939   goto clean;
28940 
28941 clean:
28942   return rcode;
28943 }
28944 
28945 WARN_UNUSED_RESULT
28946 V7_PRIVATE enum v7_err Obj_defineProperty(struct v7 *v7, v7_val_t *res) {
28947   enum v7_err rcode = V7_OK;
28948   val_t obj = v7_arg(v7, 0);
28949   val_t name = v7_arg(v7, 1);
28950   val_t desc = v7_arg(v7, 2);
28951   char name_buf[512];
28952   size_t name_len;
28953 
28954   if (!v7_is_object(obj)) {
28955     rcode = v7_throwf(v7, TYPE_ERROR, "object expected");
28956     goto clean;
28957   }
28958 
28959   rcode = to_string(v7, name, NULL, name_buf, sizeof(name_buf), &name_len);
28960   if (rcode != V7_OK) {
28961     goto clean;
28962   }
28963 
28964   rcode = _Obj_defineProperty(v7, obj, name_buf, name_len, desc, res);
28965   goto clean;
28966 
28967 clean:
28968   return rcode;
28969 }
28970 
28971 #if V7_ENABLE__Object__create || V7_ENABLE__Object__defineProperties
28972 WARN_UNUSED_RESULT
28973 static enum v7_err o_define_props(struct v7 *v7, val_t obj, val_t descs,
28974                                   val_t *res) {
28975   enum v7_err rcode = V7_OK;
28976   struct v7_property *p;
28977 
28978   if (!v7_is_object(descs)) {
28979     rcode = v7_throwf(v7, TYPE_ERROR, "object expected");
28980     goto clean;
28981   }
28982 
28983   for (p = get_object_struct(descs)->properties; p; p = p->next) {
28984     size_t n;
28985     const char *s = v7_get_string(v7, &p->name, &n);
28986     if (p->attributes & (_V7_PROPERTY_HIDDEN | V7_PROPERTY_NON_ENUMERABLE)) {
28987       continue;
28988     }
28989     rcode = _Obj_defineProperty(v7, obj, s, n, p->value, res);
28990     if (rcode != V7_OK) {
28991       goto clean;
28992     }
28993   }
28994 
28995 clean:
28996   return rcode;
28997 }
28998 #endif
28999 
29000 #if V7_ENABLE__Object__defineProperties
29001 WARN_UNUSED_RESULT
29002 V7_PRIVATE enum v7_err Obj_defineProperties(struct v7 *v7, v7_val_t *res) {
29003   enum v7_err rcode = V7_OK;
29004   val_t descs = V7_UNDEFINED;
29005 
29006   *res = v7_arg(v7, 0);
29007   descs = v7_arg(v7, 1);
29008   rcode = o_define_props(v7, *res, descs, res);
29009   if (rcode != V7_OK) {
29010     goto clean;
29011   }
29012 
29013 clean:
29014   return rcode;
29015 }
29016 #endif
29017 
29018 #if V7_ENABLE__Object__create
29019 WARN_UNUSED_RESULT
29020 V7_PRIVATE enum v7_err Obj_create(struct v7 *v7, v7_val_t *res) {
29021   enum v7_err rcode = V7_OK;
29022   val_t proto = v7_arg(v7, 0);
29023   val_t descs = v7_arg(v7, 1);
29024   if (!v7_is_null(proto) && !v7_is_object(proto)) {
29025     rcode = v7_throwf(v7, TYPE_ERROR,
29026                       "Object prototype may only be an Object or null");
29027     goto clean;
29028   }
29029   *res = mk_object(v7, proto);
29030   if (v7_is_object(descs)) {
29031     rcode = o_define_props(v7, *res, descs, res);
29032     if (rcode != V7_OK) {
29033       goto clean;
29034     }
29035   }
29036 
29037 clean:
29038   return rcode;
29039 }
29040 #endif
29041 
29042 #if V7_ENABLE__Object__propertyIsEnumerable
29043 WARN_UNUSED_RESULT
29044 V7_PRIVATE enum v7_err Obj_propertyIsEnumerable(struct v7 *v7, v7_val_t *res) {
29045   enum v7_err rcode = V7_OK;
29046   val_t this_obj = v7_get_this(v7);
29047   struct v7_property *prop;
29048   val_t name = v7_arg(v7, 0);
29049 
29050   rcode = _Obj_getOwnProperty(v7, this_obj, name, &prop);
29051   if (rcode != V7_OK) {
29052     goto clean;
29053   }
29054 
29055   if (prop == NULL) {
29056     *res = v7_mk_boolean(v7, 0);
29057   } else {
29058     *res =
29059         v7_mk_boolean(v7, !(prop->attributes & (_V7_PROPERTY_HIDDEN |
29060                                                 V7_PROPERTY_NON_ENUMERABLE)));
29061   }
29062 
29063   goto clean;
29064 
29065 clean:
29066   return rcode;
29067 }
29068 #endif
29069 
29070 #if V7_ENABLE__Object__hasOwnProperty
29071 WARN_UNUSED_RESULT
29072 V7_PRIVATE enum v7_err Obj_hasOwnProperty(struct v7 *v7, v7_val_t *res) {
29073   enum v7_err rcode = V7_OK;
29074   val_t this_obj = v7_get_this(v7);
29075   val_t name = v7_arg(v7, 0);
29076   struct v7_property *ptmp = NULL;
29077 
29078   rcode = _Obj_getOwnProperty(v7, this_obj, name, &ptmp);
29079   if (rcode != V7_OK) {
29080     goto clean;
29081   }
29082 
29083   *res = v7_mk_boolean(v7, ptmp != NULL);
29084   goto clean;
29085 
29086 clean:
29087   return rcode;
29088 }
29089 #endif
29090 
29091 WARN_UNUSED_RESULT
29092 V7_PRIVATE enum v7_err Obj_valueOf(struct v7 *v7, v7_val_t *res) {
29093   enum v7_err rcode = V7_OK;
29094   val_t this_obj = v7_get_this(v7);
29095   struct v7_property *p;
29096 
29097   *res = this_obj;
29098 
29099   if (v7_is_regexp(v7, this_obj)) {
29100     /* res is `this_obj` */
29101     goto clean;
29102   }
29103 
29104   p = v7_get_own_property2(v7, this_obj, "", 0, _V7_PROPERTY_HIDDEN);
29105   if (p != NULL) {
29106     *res = p->value;
29107     goto clean;
29108   }
29109 
29110 clean:
29111   return rcode;
29112 }
29113 
29114 WARN_UNUSED_RESULT
29115 V7_PRIVATE enum v7_err Obj_toString(struct v7 *v7, v7_val_t *res) {
29116   enum v7_err rcode = V7_OK;
29117   val_t ctor, name, this_obj = v7_get_this(v7);
29118   char buf[20];
29119   const char *str = "Object";
29120   size_t name_len = ~0;
29121 
29122   if (v7_is_undefined(this_obj)) {
29123     str = "Undefined";
29124   } else if (v7_is_null(this_obj)) {
29125     str = "Null";
29126   } else if (v7_is_number(this_obj)) {
29127     str = "Number";
29128   } else if (v7_is_boolean(this_obj)) {
29129     str = "Boolean";
29130   } else if (v7_is_string(this_obj)) {
29131     str = "String";
29132   } else if (v7_is_callable(v7, this_obj)) {
29133     str = "Function";
29134   } else {
29135     rcode = v7_get_throwing(v7, this_obj, "constructor", ~0, &ctor);
29136     if (rcode != V7_OK) {
29137       goto clean;
29138     }
29139 
29140     if (!v7_is_undefined(ctor)) {
29141       rcode = v7_get_throwing(v7, ctor, "name", ~0, &name);
29142       if (rcode != V7_OK) {
29143         goto clean;
29144       }
29145 
29146       if (!v7_is_undefined(name)) {
29147         size_t tmp_len;
29148         const char *tmp_str;
29149         tmp_str = v7_get_string(v7, &name, &tmp_len);
29150         /*
29151          * objects constructed with an anonymous constructor are represented as
29152          * Object, ch11/11.1/11.1.1/S11.1.1_A4.2.js
29153          */
29154         if (tmp_len > 0) {
29155           str = tmp_str;
29156           name_len = tmp_len;
29157         }
29158       }
29159     }
29160   }
29161 
29162   if (name_len == (size_t) ~0) {
29163     name_len = strlen(str);
29164   }
29165 
29166   c_snprintf(buf, sizeof(buf), "[object %.*s]", (int) name_len, str);
29167   *res = v7_mk_string(v7, buf, strlen(buf), 1);
29168 
29169 clean:
29170   return rcode;
29171 }
29172 
29173 #if V7_ENABLE__Object__preventExtensions
29174 WARN_UNUSED_RESULT
29175 V7_PRIVATE enum v7_err Obj_preventExtensions(struct v7 *v7, v7_val_t *res) {
29176   enum v7_err rcode = V7_OK;
29177   val_t arg = v7_arg(v7, 0);
29178   if (!v7_is_object(arg)) {
29179     rcode = v7_throwf(v7, TYPE_ERROR, "Object expected");
29180     goto clean;
29181   }
29182   get_object_struct(arg)->attributes |= V7_OBJ_NOT_EXTENSIBLE;
29183   *res = arg;
29184 
29185 clean:
29186   return rcode;
29187 }
29188 #endif
29189 
29190 #if V7_ENABLE__Object__isExtensible
29191 WARN_UNUSED_RESULT
29192 V7_PRIVATE enum v7_err Obj_isExtensible(struct v7 *v7, v7_val_t *res) {
29193   enum v7_err rcode = V7_OK;
29194   val_t arg = v7_arg(v7, 0);
29195 
29196   if (!v7_is_object(arg)) {
29197     rcode = v7_throwf(v7, TYPE_ERROR, "Object expected");
29198     goto clean;
29199   }
29200 
29201   *res = v7_mk_boolean(
29202       v7, !(get_object_struct(arg)->attributes & V7_OBJ_NOT_EXTENSIBLE));
29203 
29204 clean:
29205   return rcode;
29206 }
29207 #endif
29208 
29209 #if V7_ENABLE__Object__isFrozen || V7_ENABLE__Object__isSealed
29210 static enum v7_err is_rigid(struct v7 *v7, v7_val_t *res, int is_frozen) {
29211   enum v7_err rcode = V7_OK;
29212   int ok = 0;
29213   val_t arg = v7_arg(v7, 0);
29214 
29215   if (!v7_is_object(arg)) {
29216     rcode = v7_throwf(v7, TYPE_ERROR, "Object expected");
29217     goto clean;
29218   }
29219 
29220   *res = v7_mk_boolean(v7, 0);
29221 
29222   if (get_object_struct(arg)->attributes & V7_OBJ_NOT_EXTENSIBLE) {
29223     v7_prop_attr_t attrs = 0;
29224     struct prop_iter_ctx ctx;
29225     memset(&ctx, 0, sizeof(ctx));
29226     V7_TRY2(init_prop_iter_ctx(v7, arg, 1, &ctx), clean_iter);
29227     while (1) {
29228       V7_TRY2(next_prop(v7, &ctx, NULL, NULL, &attrs, &ok), clean_iter);
29229       if (!ok) {
29230         break;
29231       }
29232       if (!(attrs & V7_PROPERTY_NON_CONFIGURABLE)) {
29233         goto clean_iter;
29234       }
29235       if (is_frozen) {
29236         if (!(attrs & V7_PROPERTY_SETTER) &&
29237             !(attrs & V7_PROPERTY_NON_WRITABLE)) {
29238           goto clean_iter;
29239         }
29240       }
29241     }
29242 
29243     *res = v7_mk_boolean(v7, 1);
29244 
29245   clean_iter:
29246     v7_destruct_prop_iter_ctx(v7, &ctx);
29247     goto clean;
29248   }
29249 
29250 clean:
29251   return rcode;
29252 }
29253 #endif
29254 
29255 #if V7_ENABLE__Object__isSealed
29256 WARN_UNUSED_RESULT
29257 V7_PRIVATE enum v7_err Obj_isSealed(struct v7 *v7, v7_val_t *res) {
29258   return is_rigid(v7, res, 0 /* is_frozen */);
29259 }
29260 #endif
29261 
29262 #if V7_ENABLE__Object__isFrozen
29263 WARN_UNUSED_RESULT
29264 V7_PRIVATE enum v7_err Obj_isFrozen(struct v7 *v7, v7_val_t *res) {
29265   return is_rigid(v7, res, 1 /* is_frozen */);
29266 }
29267 #endif
29268 
29269 static const char js_function_Object[] =
29270     "function Object(v) {"
29271     "if (typeof v === 'boolean') return new Boolean(v);"
29272     "if (typeof v === 'number') return new Number(v);"
29273     "if (typeof v === 'string') return new String(v);"
29274     "if (typeof v === 'date') return new Date(v);"
29275     "}";
29276 
29277 V7_PRIVATE void init_object(struct v7 *v7) {
29278   enum v7_err rcode = V7_OK;
29279   val_t object, v;
29280   /* TODO(mkm): initialize global object without requiring a parser */
29281   rcode = v7_exec(v7, js_function_Object, &v);
29282   assert(rcode == V7_OK);
29283 #if defined(NDEBUG)
29284   (void) rcode;
29285 #endif
29286 
29287   object = v7_get(v7, v7->vals.global_object, "Object", 6);
29288   v7_set(v7, object, "prototype", 9, v7->vals.object_prototype);
29289   v7_def(v7, v7->vals.object_prototype, "constructor", 11,
29290          V7_DESC_ENUMERABLE(0), object);
29291 
29292   set_method(v7, v7->vals.object_prototype, "toString", Obj_toString, 0);
29293 #if V7_ENABLE__Object__getPrototypeOf
29294   set_cfunc_prop(v7, object, "getPrototypeOf", Obj_getPrototypeOf);
29295 #endif
29296 #if V7_ENABLE__Object__getOwnPropertyDescriptor
29297   set_cfunc_prop(v7, object, "getOwnPropertyDescriptor",
29298                  Obj_getOwnPropertyDescriptor);
29299 #endif
29300 
29301   /* defineProperty is currently required to perform stdlib initialization */
29302   set_method(v7, object, "defineProperty", Obj_defineProperty, 3);
29303 
29304 #if V7_ENABLE__Object__defineProperties
29305   set_cfunc_prop(v7, object, "defineProperties", Obj_defineProperties);
29306 #endif
29307 #if V7_ENABLE__Object__create
29308   set_cfunc_prop(v7, object, "create", Obj_create);
29309 #endif
29310 #if V7_ENABLE__Object__keys
29311   set_cfunc_prop(v7, object, "keys", Obj_keys);
29312 #endif
29313 #if V7_ENABLE__Object__getOwnPropertyNames
29314   set_cfunc_prop(v7, object, "getOwnPropertyNames", Obj_getOwnPropertyNames);
29315 #endif
29316 #if V7_ENABLE__Object__preventExtensions
29317   set_method(v7, object, "preventExtensions", Obj_preventExtensions, 1);
29318 #endif
29319 #if V7_ENABLE__Object__isExtensible
29320   set_method(v7, object, "isExtensible", Obj_isExtensible, 1);
29321 #endif
29322 #if V7_ENABLE__Object__isSealed
29323   set_method(v7, object, "isSealed", Obj_isSealed, 1);
29324 #endif
29325 #if V7_ENABLE__Object__isFrozen
29326   set_method(v7, object, "isFrozen", Obj_isFrozen, 1);
29327 #endif
29328 
29329 #if V7_ENABLE__Object__propertyIsEnumerable
29330   set_cfunc_prop(v7, v7->vals.object_prototype, "propertyIsEnumerable",
29331                  Obj_propertyIsEnumerable);
29332 #endif
29333 #if V7_ENABLE__Object__hasOwnProperty
29334   set_cfunc_prop(v7, v7->vals.object_prototype, "hasOwnProperty",
29335                  Obj_hasOwnProperty);
29336 #endif
29337 #if V7_ENABLE__Object__isPrototypeOf
29338   set_cfunc_prop(v7, v7->vals.object_prototype, "isPrototypeOf",
29339                  Obj_isPrototypeOf);
29340 #endif
29341   set_cfunc_prop(v7, v7->vals.object_prototype, "valueOf", Obj_valueOf);
29342 }
29343 #ifdef V7_MODULE_LINES
29344 #line 1 "v7/src/std_error.c"
29345 #endif
29346 /*
29347  * Copyright (c) 2014 Cesanta Software Limited
29348  * All rights reserved
29349  */
29350 
29351 /* Amalgamated: #include "v7/src/internal.h" */
29352 /* Amalgamated: #include "v7/src/core.h" */
29353 /* Amalgamated: #include "v7/src/function.h" */
29354 /* Amalgamated: #include "v7/src/string.h" */
29355 /* Amalgamated: #include "v7/src/std_error.h" */
29356 /* Amalgamated: #include "v7/src/object.h" */
29357 /* Amalgamated: #include "v7/src/bcode.h" */
29358 /* Amalgamated: #include "v7/src/primitive.h" */
29359 /* Amalgamated: #include "v7/src/util.h" */
29360 
29361 /*
29362  * TODO(dfrank): make the top of v7->call_frame to represent the current
29363  * frame, and thus get rid of the `CUR_LINENO()`
29364  */
29365 #ifndef V7_DISABLE_LINE_NUMBERS
29366 #define CALLFRAME_LINENO(call_frame) ((call_frame)->line_no)
29367 #define CUR_LINENO() (v7->line_no)
29368 #else
29369 #define CALLFRAME_LINENO(call_frame) 0
29370 #define CUR_LINENO() 0
29371 #endif
29372 
29373 WARN_UNUSED_RESULT
29374 V7_PRIVATE enum v7_err Error_ctor(struct v7 *v7, v7_val_t *res);
29375 
29376 #if !defined(V7_DISABLE_FILENAMES) && !defined(V7_DISABLE_LINE_NUMBERS)
29377 static int printf_stack_line(char *p, size_t len, struct bcode *bcode,
29378                              int line_no, const char *leading) {
29379   int ret;
29380   const char *fn = bcode_get_filename(bcode);
29381   if (fn == NULL) {
29382     fn = "<no filename>";
29383   }
29384 
29385   if (bcode->func_name_present) {
29386     /* this is a function's bcode: let's show the function's name as well */
29387     char *funcname;
29388 
29389     /*
29390      * read first name from the bcode ops, which is the function name,
29391      * since `func_name_present` is set
29392      */
29393     bcode_next_name(bcode->ops.p, &funcname, NULL);
29394 
29395     /* Check if it's an anonymous function */
29396     if (funcname[0] == '\0') {
29397       funcname = (char *) "<anonymous>";
29398     }
29399     ret =
29400         snprintf(p, len, "%s    at %s (%s:%d)", leading, funcname, fn, line_no);
29401   } else {
29402     /* it's a file's bcode: show only filename and line number */
29403     ret = snprintf(p, len, "%s    at %s:%d", leading, fn, line_no);
29404   }
29405   return ret;
29406 }
29407 
29408 static int printf_stack_line_cfunc(char *p, size_t len, v7_cfunction_t *cfunc,
29409                                    const char *leading) {
29410   int ret = 0;
29411 
29412 #if !defined(V7_FILENAMES_SUPPRESS_CFUNC_ADDR)
29413   int name_len =
29414       snprintf(NULL, 0, "cfunc_%p", (void *) cfunc) + 1 /*null-term*/;
29415   char *buf = (char *) malloc(name_len);
29416 
29417   snprintf(buf, name_len, "cfunc_%p", (void *) cfunc);
29418 #else
29419   /*
29420    * We need this mode only for ecma test reporting, so that the
29421    * report is not different from one run to another
29422    */
29423   char *buf = (char *) "cfunc";
29424   (void) cfunc;
29425 #endif
29426 
29427   ret = snprintf(p, len, "%s    at %s", leading, buf);
29428 
29429 #if !defined(V7_FILENAMES_SUPPRESS_CFUNC_ADDR)
29430   free(buf);
29431 #endif
29432 
29433   return ret;
29434 }
29435 
29436 static int print_stack_trace(char *p, size_t len,
29437                              struct v7_call_frame_base *call_frame) {
29438   char *p_cur = p;
29439   int total_len = 0;
29440 
29441   assert(call_frame->type_mask == V7_CALL_FRAME_MASK_CFUNC &&
29442          ((struct v7_call_frame_cfunc *) call_frame)->cfunc == Error_ctor);
29443   call_frame = call_frame->prev;
29444 
29445   while (call_frame != NULL) {
29446     int cur_len = 0;
29447     const char *leading = (total_len ? "\n" : "");
29448     size_t line_len = len - (p_cur - p);
29449 
29450     if (call_frame->type_mask & V7_CALL_FRAME_MASK_BCODE) {
29451       struct bcode *bcode = ((struct v7_call_frame_bcode *) call_frame)->bcode;
29452       if (bcode != NULL) {
29453         cur_len = printf_stack_line(p_cur, line_len, bcode,
29454                                     CALLFRAME_LINENO(call_frame), leading);
29455       }
29456     } else if (call_frame->type_mask & V7_CALL_FRAME_MASK_CFUNC) {
29457       cur_len = printf_stack_line_cfunc(
29458           p_cur, line_len, ((struct v7_call_frame_cfunc *) call_frame)->cfunc,
29459           leading);
29460     }
29461 
29462     total_len += cur_len;
29463     if (p_cur != NULL) {
29464       p_cur += cur_len;
29465     }
29466 
29467     call_frame = call_frame->prev;
29468 
29469 #if !(V7_ENABLE__StackTrace)
29470     break;
29471 #endif
29472   }
29473 
29474   return total_len;
29475 }
29476 #endif
29477 
29478 WARN_UNUSED_RESULT
29479 V7_PRIVATE enum v7_err Error_ctor(struct v7 *v7, v7_val_t *res) {
29480   enum v7_err rcode = V7_OK;
29481   val_t this_obj = v7_get_this(v7);
29482   val_t arg0 = v7_arg(v7, 0);
29483 
29484   if (v7_is_object(this_obj) && this_obj != v7->vals.global_object) {
29485     *res = this_obj;
29486   } else {
29487     *res = mk_object(v7, v7->vals.error_prototype);
29488   }
29489   /* TODO(mkm): set non enumerable but provide toString method */
29490   v7_set(v7, *res, "message", 7, arg0);
29491 
29492 #if !defined(V7_DISABLE_FILENAMES) && !defined(V7_DISABLE_LINE_NUMBERS)
29493   /* Save the stack trace */
29494   {
29495     size_t len = 0;
29496     val_t st_v = V7_UNDEFINED;
29497 
29498     v7_own(v7, &st_v);
29499 
29500     len = print_stack_trace(NULL, 0, v7->call_stack);
29501 
29502     if (len > 0) {
29503       /* Now, create a placeholder for string */
29504       st_v = v7_mk_string(v7, NULL, len, 1);
29505       len += 1 /*null-term*/;
29506 
29507       /* And fill it with actual data */
29508       print_stack_trace((char *) v7_get_string(v7, &st_v, NULL), len,
29509                         v7->call_stack);
29510 
29511       v7_set(v7, *res, "stack", ~0, st_v);
29512     }
29513 
29514     v7_disown(v7, &st_v);
29515   }
29516 #endif
29517 
29518   return rcode;
29519 }
29520 
29521 WARN_UNUSED_RESULT
29522 V7_PRIVATE enum v7_err Error_toString(struct v7 *v7, v7_val_t *res) {
29523   enum v7_err rcode = V7_OK;
29524   val_t this_obj = v7_get_this(v7);
29525   val_t prefix, msg = v7_get(v7, this_obj, "message", ~0);
29526 
29527   if (!v7_is_string(msg)) {
29528     *res = v7_mk_string(v7, "Error", ~0, 1);
29529     goto clean;
29530   }
29531 
29532   prefix = v7_mk_string(v7, "Error: ", ~0, 1);
29533   *res = s_concat(v7, prefix, msg);
29534   goto clean;
29535 
29536 clean:
29537   return rcode;
29538 }
29539 
29540 static const char *const error_names[] = {TYPE_ERROR,      SYNTAX_ERROR,
29541                                           REFERENCE_ERROR, INTERNAL_ERROR,
29542                                           RANGE_ERROR,     EVAL_ERROR};
29543 
29544 V7_STATIC_ASSERT(ARRAY_SIZE(error_names) == ERROR_CTOR_MAX,
29545                  error_name_count_mismatch);
29546 
29547 V7_PRIVATE void init_error(struct v7 *v7) {
29548   val_t error;
29549   size_t i;
29550 
29551   error =
29552       mk_cfunction_obj_with_proto(v7, Error_ctor, 1, v7->vals.error_prototype);
29553   v7_def(v7, v7->vals.global_object, "Error", 5, V7_DESC_ENUMERABLE(0), error);
29554   set_method(v7, v7->vals.error_prototype, "toString", Error_toString, 0);
29555 
29556   for (i = 0; i < ARRAY_SIZE(error_names); i++) {
29557     error = mk_cfunction_obj_with_proto(
29558         v7, Error_ctor, 1, mk_object(v7, v7->vals.error_prototype));
29559     v7_def(v7, v7->vals.global_object, error_names[i], strlen(error_names[i]),
29560            V7_DESC_ENUMERABLE(0), error);
29561     v7->vals.error_objects[i] = error;
29562   }
29563 }
29564 #ifdef V7_MODULE_LINES
29565 #line 1 "v7/src/std_number.c"
29566 #endif
29567 /*
29568  * Copyright (c) 2014 Cesanta Software Limited
29569  * All rights reserved
29570  */
29571 
29572 /* Amalgamated: #include "v7/src/internal.h" */
29573 /* Amalgamated: #include "v7/src/std_object.h" */
29574 /* Amalgamated: #include "v7/src/conversion.h" */
29575 /* Amalgamated: #include "v7/src/core.h" */
29576 /* Amalgamated: #include "v7/src/function.h" */
29577 /* Amalgamated: #include "v7/src/object.h" */
29578 /* Amalgamated: #include "v7/src/primitive.h" */
29579 /* Amalgamated: #include "v7/src/string.h" */
29580 /* Amalgamated: #include "v7/src/exceptions.h" */
29581 
29582 #if defined(__cplusplus)
29583 extern "C" {
29584 #endif /* __cplusplus */
29585 
29586 WARN_UNUSED_RESULT
29587 V7_PRIVATE enum v7_err Number_ctor(struct v7 *v7, v7_val_t *res) {
29588   enum v7_err rcode = V7_OK;
29589   val_t this_obj = v7_get_this(v7);
29590   val_t arg0 = v7_argc(v7) == 0 ? v7_mk_number(v7, 0.0) : v7_arg(v7, 0);
29591 
29592   if (v7_is_number(arg0)) {
29593     *res = arg0;
29594   } else {
29595     rcode = to_number_v(v7, arg0, res);
29596     if (rcode != V7_OK) {
29597       goto clean;
29598     }
29599   }
29600 
29601   if (v7_is_generic_object(this_obj) && this_obj != v7->vals.global_object) {
29602     obj_prototype_set(v7, get_object_struct(this_obj),
29603                       get_object_struct(v7->vals.number_prototype));
29604     v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), *res);
29605 
29606     /*
29607      * implicitly returning `this`: `call_cfunction()` in bcode.c will do
29608      * that for us
29609      */
29610   }
29611 
29612 clean:
29613   return rcode;
29614 }
29615 
29616 WARN_UNUSED_RESULT
29617 V7_PRIVATE enum v7_err n_to_str(struct v7 *v7, const char *format, val_t *res) {
29618   enum v7_err rcode = V7_OK;
29619   val_t this_obj = v7_get_this(v7);
29620   val_t arg0 = v7_arg(v7, 0);
29621   int len, digits = 0;
29622   char fmt[10], buf[100];
29623 
29624   rcode = to_number_v(v7, arg0, &arg0);
29625   if (rcode != V7_OK) {
29626     goto clean;
29627   }
29628 
29629   if (v7_get_double(v7, arg0) > 0) {
29630     digits = (int) v7_get_double(v7, arg0);
29631   }
29632 
29633   /*
29634    * NOTE: we don't own `arg0` and `this_obj`, since this function is called
29635    * from cfunctions only, and GC is inhibited during these calls
29636    */
29637 
29638   rcode = obj_value_of(v7, this_obj, &this_obj);
29639   if (rcode != V7_OK) {
29640     goto clean;
29641   }
29642 
29643   snprintf(fmt, sizeof(fmt), format, digits);
29644   len = snprintf(buf, sizeof(buf), fmt, v7_get_double(v7, this_obj));
29645 
29646   *res = v7_mk_string(v7, buf, len, 1);
29647 
29648 clean:
29649   return rcode;
29650 }
29651 
29652 WARN_UNUSED_RESULT
29653 V7_PRIVATE enum v7_err Number_toFixed(struct v7 *v7, v7_val_t *res) {
29654   return n_to_str(v7, "%%.%dlf", res);
29655 }
29656 
29657 WARN_UNUSED_RESULT
29658 V7_PRIVATE enum v7_err Number_toExp(struct v7 *v7, v7_val_t *res) {
29659   return n_to_str(v7, "%%.%de", res);
29660 }
29661 
29662 WARN_UNUSED_RESULT
29663 V7_PRIVATE enum v7_err Number_toPrecision(struct v7 *v7, v7_val_t *res) {
29664   return Number_toExp(v7, res);
29665 }
29666 
29667 WARN_UNUSED_RESULT
29668 V7_PRIVATE enum v7_err Number_valueOf(struct v7 *v7, v7_val_t *res) {
29669   enum v7_err rcode = V7_OK;
29670   val_t this_obj = v7_get_this(v7);
29671 
29672   if (!v7_is_number(this_obj) &&
29673       (v7_is_object(this_obj) &&
29674        v7_get_proto(v7, this_obj) != v7->vals.number_prototype)) {
29675     rcode =
29676         v7_throwf(v7, TYPE_ERROR, "Number.valueOf called on non-number object");
29677     goto clean;
29678   }
29679 
29680   rcode = Obj_valueOf(v7, res);
29681   if (rcode != V7_OK) {
29682     goto clean;
29683   }
29684 
29685 clean:
29686   return rcode;
29687 }
29688 
29689 /*
29690  * Converts a 64 bit signed integer into a string of a given base.
29691  * Requires space for 65 bytes (64 bit + null terminator) in the result buffer
29692  */
29693 static char *cs_itoa(int64_t value, char *result, int base) {
29694   char *ptr = result, *ptr1 = result, tmp_char;
29695   int64_t tmp_value;
29696   int64_t sign = value < 0 ? -1 : 1;
29697   const char *base36 = "0123456789abcdefghijklmnopqrstuvwxyz";
29698 
29699   if (base < 2 || base > 36) {
29700     *result = '\0';
29701     return result;
29702   }
29703 
29704   /* let's think positive */
29705   value = value * sign;
29706   do {
29707     tmp_value = value;
29708     value /= base;
29709     *ptr++ = base36[tmp_value - value * base];
29710   } while (value);
29711 
29712   /* sign */
29713   if (sign < 0) *ptr++ = '-';
29714   *ptr-- = '\0';
29715   while (ptr1 < ptr) {
29716     tmp_char = *ptr;
29717     *ptr-- = *ptr1;
29718     *ptr1++ = tmp_char;
29719   }
29720   return result;
29721 }
29722 
29723 WARN_UNUSED_RESULT
29724 V7_PRIVATE enum v7_err Number_toString(struct v7 *v7, v7_val_t *res) {
29725   enum v7_err rcode = V7_OK;
29726   val_t this_obj = v7_get_this(v7);
29727   val_t radixv = v7_arg(v7, 0);
29728   char buf[65];
29729   double d, radix;
29730 
29731   if (this_obj == v7->vals.number_prototype) {
29732     *res = v7_mk_string(v7, "0", 1, 1);
29733     goto clean;
29734   }
29735 
29736   /* Make sure this function was called on Number instance */
29737   if (!v7_is_number(this_obj) &&
29738       !(v7_is_generic_object(this_obj) &&
29739         is_prototype_of(v7, this_obj, v7->vals.number_prototype))) {
29740     rcode = v7_throwf(v7, TYPE_ERROR,
29741                       "Number.toString called on non-number object");
29742     goto clean;
29743   }
29744 
29745   /* Get number primitive */
29746   rcode = to_number_v(v7, this_obj, &this_obj);
29747   if (rcode != V7_OK) {
29748     goto clean;
29749   }
29750 
29751   /* Get radix if provided, or 10 otherwise */
29752   if (!v7_is_undefined(radixv)) {
29753     rcode = to_number_v(v7, radixv, &radixv);
29754     if (rcode != V7_OK) {
29755       goto clean;
29756     }
29757     radix = v7_get_double(v7, radixv);
29758   } else {
29759     radix = 10.0;
29760   }
29761 
29762   d = v7_get_double(v7, this_obj);
29763   if (!isnan(d) && (int64_t) d == d && radix >= 2) {
29764     cs_itoa(d, buf, radix);
29765     *res = v7_mk_string(v7, buf, strlen(buf), 1);
29766   } else {
29767     rcode = to_string(v7, this_obj, res, NULL, 0, NULL);
29768     if (rcode != V7_OK) {
29769       goto clean;
29770     }
29771   }
29772 
29773 clean:
29774   return rcode;
29775 }
29776 
29777 WARN_UNUSED_RESULT
29778 V7_PRIVATE enum v7_err n_isNaN(struct v7 *v7, v7_val_t *res) {
29779   val_t arg0 = v7_arg(v7, 0);
29780   *res = v7_mk_boolean(v7, !v7_is_number(arg0) || arg0 == V7_TAG_NAN);
29781   return V7_OK;
29782 }
29783 
29784 V7_PRIVATE void init_number(struct v7 *v7) {
29785   v7_prop_attr_desc_t attrs_desc =
29786       (V7_DESC_WRITABLE(0) | V7_DESC_ENUMERABLE(0) | V7_DESC_CONFIGURABLE(0));
29787   val_t num = mk_cfunction_obj_with_proto(v7, Number_ctor, 1,
29788                                           v7->vals.number_prototype);
29789 
29790   v7_def(v7, v7->vals.global_object, "Number", 6, V7_DESC_ENUMERABLE(0), num);
29791 
29792   set_cfunc_prop(v7, v7->vals.number_prototype, "toFixed", Number_toFixed);
29793   set_cfunc_prop(v7, v7->vals.number_prototype, "toPrecision",
29794                  Number_toPrecision);
29795   set_cfunc_prop(v7, v7->vals.number_prototype, "toExponential", Number_toExp);
29796   set_cfunc_prop(v7, v7->vals.number_prototype, "valueOf", Number_valueOf);
29797   set_cfunc_prop(v7, v7->vals.number_prototype, "toString", Number_toString);
29798 
29799   v7_def(v7, num, "MAX_VALUE", 9, attrs_desc,
29800          v7_mk_number(v7, 1.7976931348623157e+308));
29801   v7_def(v7, num, "MIN_VALUE", 9, attrs_desc, v7_mk_number(v7, 5e-324));
29802 #if V7_ENABLE__NUMBER__NEGATIVE_INFINITY
29803   v7_def(v7, num, "NEGATIVE_INFINITY", 17, attrs_desc,
29804          v7_mk_number(v7, -INFINITY));
29805 #endif
29806 #if V7_ENABLE__NUMBER__POSITIVE_INFINITY
29807   v7_def(v7, num, "POSITIVE_INFINITY", 17, attrs_desc,
29808          v7_mk_number(v7, INFINITY));
29809 #endif
29810   v7_def(v7, num, "NaN", 3, attrs_desc, V7_TAG_NAN);
29811 
29812   v7_def(v7, v7->vals.global_object, "NaN", 3, attrs_desc, V7_TAG_NAN);
29813   v7_def(v7, v7->vals.global_object, "isNaN", 5, V7_DESC_ENUMERABLE(0),
29814          v7_mk_cfunction(n_isNaN));
29815 }
29816 
29817 #if defined(__cplusplus)
29818 }
29819 #endif /* __cplusplus */
29820 #ifdef V7_MODULE_LINES
29821 #line 1 "v7/src/std_json.c"
29822 #endif
29823 /*
29824  * Copyright (c) 2014 Cesanta Software Limited
29825  * All rights reserved
29826  */
29827 
29828 /* Amalgamated: #include "v7/src/internal.h" */
29829 /* Amalgamated: #include "v7/src/stdlib.h" */
29830 /* Amalgamated: #include "v7/src/core.h" */
29831 /* Amalgamated: #include "v7/src/object.h" */
29832 /* Amalgamated: #include "v7/src/conversion.h" */
29833 /* Amalgamated: #include "v7/src/string.h" */
29834 /* Amalgamated: #include "v7/src/primitive.h" */
29835 
29836 #if defined(__cplusplus)
29837 extern "C" {
29838 #endif /* __cplusplus */
29839 
29840 #if defined(V7_ALT_JSON_PARSE)
29841 extern enum v7_err v7_alt_json_parse(struct v7 *v7, v7_val_t json_string,
29842                                      v7_val_t *res);
29843 #endif
29844 
29845 WARN_UNUSED_RESULT
29846 V7_PRIVATE enum v7_err Json_stringify(struct v7 *v7, v7_val_t *res) {
29847   val_t arg0 = v7_arg(v7, 0);
29848   char buf[100], *p = v7_to_json(v7, arg0, buf, sizeof(buf));
29849   *res = v7_mk_string(v7, p, strlen(p), 1);
29850 
29851   if (p != buf) free(p);
29852   return V7_OK;
29853 }
29854 
29855 WARN_UNUSED_RESULT
29856 V7_PRIVATE enum v7_err Json_parse(struct v7 *v7, v7_val_t *res) {
29857   v7_val_t arg = v7_arg(v7, 0);
29858   enum v7_err rcode = V7_OK;
29859 #if defined(V7_ALT_JSON_PARSE)
29860   rcode = v7_alt_json_parse(v7, arg, res);
29861 #else
29862   rcode = std_eval(v7, arg, V7_UNDEFINED, 1, res);
29863 #endif
29864   return rcode;
29865 }
29866 
29867 V7_PRIVATE void init_json(struct v7 *v7) {
29868   val_t o = v7_mk_object(v7);
29869   set_method(v7, o, "stringify", Json_stringify, 1);
29870   set_method(v7, o, "parse", Json_parse, 1);
29871   v7_def(v7, v7->vals.global_object, "JSON", 4, V7_DESC_ENUMERABLE(0), o);
29872 }
29873 
29874 #if defined(__cplusplus)
29875 }
29876 #endif /* __cplusplus */
29877 #ifdef V7_MODULE_LINES
29878 #line 1 "v7/src/std_array.c"
29879 #endif
29880 /*
29881  * Copyright (c) 2014 Cesanta Software Limited
29882  * All rights reserved
29883  */
29884 
29885 /* Amalgamated: #include "common/str_util.h" */
29886 /* Amalgamated: #include "v7/src/internal.h" */
29887 /* Amalgamated: #include "v7/src/gc.h" */
29888 /* Amalgamated: #include "v7/src/eval.h" */
29889 /* Amalgamated: #include "v7/src/std_string.h" */
29890 /* Amalgamated: #include "v7/src/conversion.h" */
29891 /* Amalgamated: #include "v7/src/core.h" */
29892 /* Amalgamated: #include "v7/src/function.h" */
29893 /* Amalgamated: #include "v7/src/array.h" */
29894 /* Amalgamated: #include "v7/src/object.h" */
29895 /* Amalgamated: #include "v7/src/exceptions.h" */
29896 
29897 #if defined(__cplusplus)
29898 extern "C" {
29899 #endif /* __cplusplus */
29900 
29901 struct a_sort_data {
29902   val_t sort_func;
29903 };
29904 
29905 WARN_UNUSED_RESULT
29906 V7_PRIVATE enum v7_err Array_ctor(struct v7 *v7, v7_val_t *res) {
29907   enum v7_err rcode = V7_OK;
29908   unsigned long i, len;
29909 
29910   (void) v7;
29911   *res = v7_mk_array(v7);
29912   /*
29913    * The interpreter passes dense array to C functions.
29914    * However dense array implementation is not yet complete
29915    * so we don't want to propagate them at each call to Array()
29916    */
29917   len = v7_argc(v7);
29918   for (i = 0; i < len; i++) {
29919     rcode = v7_array_set_throwing(v7, *res, i, v7_arg(v7, i), NULL);
29920     if (rcode != V7_OK) {
29921       goto clean;
29922     }
29923   }
29924 
29925 clean:
29926   return rcode;
29927 }
29928 
29929 WARN_UNUSED_RESULT
29930 V7_PRIVATE enum v7_err Array_push(struct v7 *v7, v7_val_t *res) {
29931   enum v7_err rcode = V7_OK;
29932   int i, len = v7_argc(v7);
29933 
29934   *res = V7_UNDEFINED;
29935 
29936   for (i = 0; i < len; i++) {
29937     *res = v7_arg(v7, i);
29938     rcode = v7_array_push_throwing(v7, v7_get_this(v7), *res, NULL);
29939     if (rcode != V7_OK) {
29940       goto clean;
29941     }
29942   }
29943 
29944 /*
29945  * TODO(dfrank) : we need to implement `length` as a real property, and here
29946  * we need to set new length and return it (even if the object is not an
29947  * array)
29948  */
29949 
29950 clean:
29951   return rcode;
29952 }
29953 
29954 WARN_UNUSED_RESULT
29955 V7_PRIVATE enum v7_err Array_get_length(struct v7 *v7, v7_val_t *res) {
29956   enum v7_err rcode = V7_OK;
29957   val_t this_obj = v7_get_this(v7);
29958   long len = 0;
29959 
29960   if (is_prototype_of(v7, this_obj, v7->vals.array_prototype)) {
29961     len = v7_array_length(v7, this_obj);
29962   }
29963   *res = v7_mk_number(v7, len);
29964 
29965   return rcode;
29966 }
29967 
29968 WARN_UNUSED_RESULT
29969 V7_PRIVATE enum v7_err Array_set_length(struct v7 *v7, v7_val_t *res) {
29970   enum v7_err rcode = V7_OK;
29971   val_t arg0 = v7_arg(v7, 0);
29972   val_t this_obj = v7_get_this(v7);
29973   long new_len = 0;
29974 
29975   rcode = to_long(v7, v7_arg(v7, 0), -1, &new_len);
29976   if (rcode != V7_OK) {
29977     goto clean;
29978   }
29979 
29980   if (!v7_is_object(this_obj)) {
29981     rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
29982     goto clean;
29983   } else if (new_len < 0 ||
29984              (v7_is_number(arg0) && (isnan(v7_get_double(v7, arg0)) ||
29985                                      isinf(v7_get_double(v7, arg0))))) {
29986     rcode = v7_throwf(v7, RANGE_ERROR, "Invalid array length");
29987     goto clean;
29988   } else {
29989     struct v7_property **p, **next;
29990     long index, max_index = -1;
29991 
29992     /* Remove all items with an index higher than new_len */
29993     for (p = &get_object_struct(this_obj)->properties; *p != NULL; p = next) {
29994       size_t n;
29995       const char *s = v7_get_string(v7, &p[0]->name, &n);
29996       next = &p[0]->next;
29997       index = strtol(s, NULL, 10);
29998       if (index >= new_len) {
29999         v7_destroy_property(p);
30000         *p = *next;
30001         next = p;
30002       } else if (index > max_index) {
30003         max_index = index;
30004       }
30005     }
30006 
30007     /* If we have to expand, insert an item with appropriate index */
30008     if (new_len > 0 && max_index < new_len - 1) {
30009       char buf[40];
30010       c_snprintf(buf, sizeof(buf), "%ld", new_len - 1);
30011       v7_set(v7, this_obj, buf, strlen(buf), V7_UNDEFINED);
30012     }
30013   }
30014 
30015   *res = v7_mk_number(v7, new_len);
30016 
30017 clean:
30018   return rcode;
30019 }
30020 
30021 WARN_UNUSED_RESULT
30022 static enum v7_err a_cmp(struct v7 *v7, void *user_data, const void *pa,
30023                          const void *pb, int *res) {
30024   enum v7_err rcode = V7_OK;
30025   struct a_sort_data *sort_data = (struct a_sort_data *) user_data;
30026   val_t a = *(val_t *) pa, b = *(val_t *) pb, func = sort_data->sort_func;
30027 
30028   if (v7_is_callable(v7, func)) {
30029     int saved_inhibit_gc = v7->inhibit_gc;
30030     val_t vres = V7_UNDEFINED, args = v7_mk_dense_array(v7);
30031     v7_array_push(v7, args, a);
30032     v7_array_push(v7, args, b);
30033     v7->inhibit_gc = 0;
30034     rcode = b_apply(v7, func, V7_UNDEFINED, args, 0, &vres);
30035     if (rcode != V7_OK) {
30036       goto clean;
30037     }
30038     v7->inhibit_gc = saved_inhibit_gc;
30039     *res = (int) -v7_get_double(v7, vres);
30040     goto clean;
30041   } else {
30042     char sa[100], sb[100];
30043 
30044     rcode = to_string(v7, a, NULL, sa, sizeof(sa), NULL);
30045     if (rcode != V7_OK) {
30046       goto clean;
30047     }
30048 
30049     rcode = to_string(v7, b, NULL, sb, sizeof(sb), NULL);
30050     if (rcode != V7_OK) {
30051       goto clean;
30052     }
30053 
30054     sa[sizeof(sa) - 1] = sb[sizeof(sb) - 1] = '\0';
30055     *res = strcmp(sb, sa);
30056     goto clean;
30057   }
30058 
30059 clean:
30060   return rcode;
30061 }
30062 
30063 WARN_UNUSED_RESULT
30064 static enum v7_err a_partition(struct v7 *v7, val_t *a, int l, int r,
30065                                void *user_data, int *res) {
30066   enum v7_err rcode = V7_OK;
30067   val_t t, pivot = a[l];
30068   int i = l, j = r + 1;
30069 
30070   for (;;) {
30071     while (1) {
30072       ++i;
30073 
30074       if (i <= r) {
30075         int tmp = 0;
30076         rcode = a_cmp(v7, user_data, &a[i], &pivot, &tmp);
30077         if (rcode != V7_OK) {
30078           goto clean;
30079         }
30080 
30081         if (tmp > 0) {
30082           break;
30083         }
30084       } else {
30085         break;
30086       }
30087     }
30088     while (1) {
30089       int tmp = 0;
30090       --j;
30091 
30092       rcode = a_cmp(v7, user_data, &a[j], &pivot, &tmp);
30093       if (rcode != V7_OK) {
30094         goto clean;
30095       }
30096 
30097       if (tmp <= 0) {
30098         break;
30099       }
30100     }
30101     if (i >= j) break;
30102     t = a[i];
30103     a[i] = a[j];
30104     a[j] = t;
30105   }
30106   t = a[l];
30107   a[l] = a[j];
30108   a[j] = t;
30109 
30110   *res = j;
30111 clean:
30112   return rcode;
30113 }
30114 
30115 WARN_UNUSED_RESULT
30116 static enum v7_err a_qsort(struct v7 *v7, val_t *a, int l, int r,
30117                            void *user_data) {
30118   enum v7_err rcode = V7_OK;
30119   if (l < r) {
30120     int j = 0;
30121     rcode = a_partition(v7, a, l, r, user_data, &j);
30122     if (rcode != V7_OK) {
30123       goto clean;
30124     }
30125 
30126     rcode = a_qsort(v7, a, l, j - 1, user_data);
30127     if (rcode != V7_OK) {
30128       goto clean;
30129     }
30130 
30131     rcode = a_qsort(v7, a, j + 1, r, user_data);
30132     if (rcode != V7_OK) {
30133       goto clean;
30134     }
30135   }
30136 clean:
30137   return rcode;
30138 }
30139 
30140 WARN_UNUSED_RESULT
30141 static enum v7_err a_sort(struct v7 *v7,
30142                           enum v7_err (*sorting_func)(struct v7 *v7, void *,
30143                                                       const void *,
30144                                                       const void *, int *res),
30145                           v7_val_t *res) {
30146   enum v7_err rcode = V7_OK;
30147   int i = 0, len = 0;
30148   val_t *arr = NULL;
30149   val_t arg0 = v7_arg(v7, 0);
30150 
30151   *res = v7_get_this(v7);
30152   len = v7_array_length(v7, *res);
30153 
30154   if (!v7_is_object(*res)) {
30155     goto clean;
30156   }
30157 
30158   arr = (val_t *) malloc(len * sizeof(arr[0]));
30159 
30160   assert(*res != v7->vals.global_object);
30161 
30162   for (i = 0; i < len; i++) {
30163     arr[i] = v7_array_get(v7, *res, i);
30164   }
30165 
30166   /* TODO(dfrank): sorting_func isn't actually used! something is wrong here */
30167   if (sorting_func != NULL) {
30168     struct a_sort_data sort_data;
30169     sort_data.sort_func = arg0;
30170     rcode = a_qsort(v7, arr, 0, len - 1, &sort_data);
30171     if (rcode != V7_OK) {
30172       goto clean;
30173     }
30174   }
30175 
30176   for (i = 0; i < len; i++) {
30177     v7_array_set(v7, *res, i, arr[len - (i + 1)]);
30178   }
30179 
30180 clean:
30181   if (arr != NULL) {
30182     free(arr);
30183   }
30184   return rcode;
30185 }
30186 
30187 WARN_UNUSED_RESULT
30188 V7_PRIVATE enum v7_err Array_sort(struct v7 *v7, v7_val_t *res) {
30189   return a_sort(v7, a_cmp, res);
30190 }
30191 
30192 WARN_UNUSED_RESULT
30193 V7_PRIVATE enum v7_err Array_reverse(struct v7 *v7, v7_val_t *res) {
30194   return a_sort(v7, NULL, res);
30195 }
30196 
30197 WARN_UNUSED_RESULT
30198 V7_PRIVATE enum v7_err Array_join(struct v7 *v7, v7_val_t *res) {
30199   enum v7_err rcode = V7_OK;
30200   val_t this_obj = v7_get_this(v7);
30201   val_t arg0 = v7_arg(v7, 0);
30202   size_t sep_size = 0;
30203   const char *sep = NULL;
30204 
30205   *res = V7_UNDEFINED;
30206 
30207   /* Get pointer to the separator string */
30208   if (!v7_is_string(arg0)) {
30209     /* If no separator is provided, use comma */
30210     arg0 = v7_mk_string(v7, ",", 1, 1);
30211   }
30212   sep = v7_get_string(v7, &arg0, &sep_size);
30213 
30214   /* Do the actual join */
30215   if (is_prototype_of(v7, this_obj, v7->vals.array_prototype)) {
30216     struct mbuf m;
30217     char buf[100], *p;
30218     long i, n, num_elems = v7_array_length(v7, this_obj);
30219 
30220     mbuf_init(&m, 0);
30221 
30222     for (i = 0; i < num_elems; i++) {
30223       /* Append separator */
30224       if (i > 0) {
30225         mbuf_append(&m, sep, sep_size);
30226       }
30227 
30228       /* Append next item from an array */
30229       p = buf;
30230       {
30231         size_t tmp;
30232         rcode = to_string(v7, v7_array_get(v7, this_obj, i), NULL, buf,
30233                           sizeof(buf), &tmp);
30234         if (rcode != V7_OK) {
30235           goto clean;
30236         }
30237         n = tmp;
30238       }
30239       if (n > (long) sizeof(buf)) {
30240         p = (char *) malloc(n + 1);
30241         rcode = to_string(v7, v7_array_get(v7, this_obj, i), NULL, p, n, NULL);
30242         if (rcode != V7_OK) {
30243           goto clean;
30244         }
30245       }
30246       mbuf_append(&m, p, n);
30247       if (p != buf) {
30248         free(p);
30249       }
30250     }
30251 
30252     /* mbuf contains concatenated string now. Copy it to the result. */
30253     *res = v7_mk_string(v7, m.buf, m.len, 1);
30254     mbuf_free(&m);
30255   }
30256 
30257 clean:
30258   return rcode;
30259 }
30260 
30261 WARN_UNUSED_RESULT
30262 V7_PRIVATE enum v7_err Array_toString(struct v7 *v7, v7_val_t *res) {
30263   return Array_join(v7, res);
30264 }
30265 
30266 WARN_UNUSED_RESULT
30267 static enum v7_err a_splice(struct v7 *v7, int mutate, v7_val_t *res) {
30268   enum v7_err rcode = V7_OK;
30269   val_t this_obj = v7_get_this(v7);
30270   long i, len = v7_array_length(v7, this_obj);
30271   long num_args = v7_argc(v7);
30272   long elems_to_insert = num_args > 2 ? num_args - 2 : 0;
30273   long arg0, arg1;
30274 
30275   if (!v7_is_object(this_obj)) {
30276     rcode = v7_throwf(v7, TYPE_ERROR,
30277                       "Array.splice or Array.slice called on non-object value");
30278     goto clean;
30279   }
30280 
30281   *res = v7_mk_dense_array(v7);
30282 
30283   rcode = to_long(v7, v7_arg(v7, 0), 0, &arg0);
30284   if (rcode != V7_OK) {
30285     goto clean;
30286   }
30287 
30288   rcode = to_long(v7, v7_arg(v7, 1), len, &arg1);
30289   if (rcode != V7_OK) {
30290     goto clean;
30291   }
30292 
30293   /* Bounds check */
30294   if (!mutate && len <= 0) {
30295     goto clean;
30296   }
30297   if (arg0 < 0) arg0 = len + arg0;
30298   if (arg0 < 0) arg0 = 0;
30299   if (arg0 > len) arg0 = len;
30300   if (mutate) {
30301     if (arg1 < 0) arg1 = 0;
30302     arg1 += arg0;
30303   } else if (arg1 < 0) {
30304     arg1 = len + arg1;
30305   }
30306 
30307   /* Create return value - slice */
30308   for (i = arg0; i < arg1 && i < len; i++) {
30309     rcode =
30310         v7_array_push_throwing(v7, *res, v7_array_get(v7, this_obj, i), NULL);
30311     if (rcode != V7_OK) {
30312       goto clean;
30313     }
30314   }
30315 
30316   if (mutate && get_object_struct(this_obj)->attributes & V7_OBJ_DENSE_ARRAY) {
30317     /*
30318      * dense arrays are spliced by memmoving leaving the trailing
30319      * space allocated for future appends.
30320      * TODO(mkm): figure out if trimming is better
30321      */
30322     struct v7_property *p =
30323         v7_get_own_property2(v7, this_obj, "", 0, _V7_PROPERTY_HIDDEN);
30324     struct mbuf *abuf;
30325     if (p == NULL) {
30326       goto clean;
30327     }
30328     abuf = (struct mbuf *) v7_get_ptr(v7, p->value);
30329     if (abuf == NULL) {
30330       goto clean;
30331     }
30332 
30333     memmove(abuf->buf + arg0 * sizeof(val_t), abuf->buf + arg1 * sizeof(val_t),
30334             (len - arg1) * sizeof(val_t));
30335     abuf->len -= (arg1 - arg0) * sizeof(val_t);
30336   } else if (mutate) {
30337     /* If splicing, modify this_obj array: remove spliced sub-array */
30338     struct v7_property **p, **next;
30339     long i;
30340 
30341     for (p = &get_object_struct(this_obj)->properties; *p != NULL; p = next) {
30342       size_t n;
30343       const char *s = v7_get_string(v7, &p[0]->name, &n);
30344       next = &p[0]->next;
30345       i = strtol(s, NULL, 10);
30346       if (i >= arg0 && i < arg1) {
30347         /* Remove items from spliced sub-array */
30348         v7_destroy_property(p);
30349         *p = *next;
30350         next = p;
30351       } else if (i >= arg1) {
30352         /* Modify indices of the elements past sub-array */
30353         char key[20];
30354         size_t n = c_snprintf(key, sizeof(key), "%ld",
30355                               i - (arg1 - arg0) + elems_to_insert);
30356         p[0]->name = v7_mk_string(v7, key, n, 1);
30357       }
30358     }
30359 
30360     /* Insert optional extra elements */
30361     for (i = 2; i < num_args; i++) {
30362       char key[20];
30363       size_t n = c_snprintf(key, sizeof(key), "%ld", arg0 + i - 2);
30364       rcode = set_property(v7, this_obj, key, n, v7_arg(v7, i), NULL);
30365       if (rcode != V7_OK) {
30366         goto clean;
30367       }
30368     }
30369   }
30370 
30371 clean:
30372   return rcode;
30373 }
30374 
30375 WARN_UNUSED_RESULT
30376 V7_PRIVATE enum v7_err Array_slice(struct v7 *v7, v7_val_t *res) {
30377   return a_splice(v7, 0, res);
30378 }
30379 
30380 WARN_UNUSED_RESULT
30381 V7_PRIVATE enum v7_err Array_splice(struct v7 *v7, v7_val_t *res) {
30382   return a_splice(v7, 1, res);
30383 }
30384 
30385 static void a_prep1(struct v7 *v7, val_t t, val_t *a0, val_t *a1) {
30386   *a0 = v7_arg(v7, 0);
30387   *a1 = v7_arg(v7, 1);
30388   if (v7_is_undefined(*a1)) {
30389     *a1 = t;
30390   }
30391 }
30392 
30393 /*
30394  * Call callback function `cb`, passing `this_obj` as `this`, with the
30395  * following arguments:
30396  *
30397  *   cb(v, n, this_obj);
30398  *
30399  */
30400 WARN_UNUSED_RESULT
30401 static enum v7_err a_prep2(struct v7 *v7, val_t cb, val_t v, val_t n,
30402                            val_t this_obj, val_t *res) {
30403   enum v7_err rcode = V7_OK;
30404   int saved_inhibit_gc = v7->inhibit_gc;
30405   val_t args = v7_mk_dense_array(v7);
30406 
30407   *res = v7_mk_dense_array(v7);
30408 
30409   v7_own(v7, &args);
30410 
30411   v7_array_push(v7, args, v);
30412   v7_array_push(v7, args, n);
30413   v7_array_push(v7, args, this_obj);
30414 
30415   v7->inhibit_gc = 0;
30416   rcode = b_apply(v7, cb, this_obj, args, 0, res);
30417   if (rcode != V7_OK) {
30418     goto clean;
30419   }
30420 
30421 clean:
30422   v7->inhibit_gc = saved_inhibit_gc;
30423   v7_disown(v7, &args);
30424 
30425   return rcode;
30426 }
30427 
30428 WARN_UNUSED_RESULT
30429 V7_PRIVATE enum v7_err Array_forEach(struct v7 *v7, v7_val_t *res) {
30430   enum v7_err rcode = V7_OK;
30431   val_t this_obj = v7_get_this(v7);
30432   val_t v = V7_UNDEFINED, cb = v7_arg(v7, 0);
30433   unsigned long len, i;
30434   int has;
30435   /* a_prep2 uninhibits GC when calling cb */
30436   struct gc_tmp_frame vf = new_tmp_frame(v7);
30437 
30438   if (!v7_is_object(this_obj)) {
30439     rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
30440     goto clean;
30441   }
30442 
30443   if (!v7_is_callable(v7, cb)) {
30444     rcode = v7_throwf(v7, TYPE_ERROR, "Function expected");
30445     goto clean;
30446   }
30447 
30448   tmp_stack_push(&vf, &v);
30449 
30450   len = v7_array_length(v7, this_obj);
30451   for (i = 0; i < len; i++) {
30452     v = v7_array_get2(v7, this_obj, i, &has);
30453     if (!has) continue;
30454 
30455     rcode = a_prep2(v7, cb, v, v7_mk_number(v7, i), this_obj, res);
30456     if (rcode != V7_OK) {
30457       goto clean;
30458     }
30459   }
30460 
30461 clean:
30462   tmp_frame_cleanup(&vf);
30463   return rcode;
30464 }
30465 
30466 WARN_UNUSED_RESULT
30467 V7_PRIVATE enum v7_err Array_map(struct v7 *v7, v7_val_t *res) {
30468   enum v7_err rcode = V7_OK;
30469   val_t this_obj = v7_get_this(v7);
30470   val_t arg0, arg1, el, v;
30471   unsigned long len, i;
30472   int has;
30473   /* a_prep2 uninhibits GC when calling cb */
30474   struct gc_tmp_frame vf = new_tmp_frame(v7);
30475 
30476   if (!v7_is_object(this_obj)) {
30477     rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
30478     goto clean;
30479   } else {
30480     a_prep1(v7, this_obj, &arg0, &arg1);
30481     *res = v7_mk_dense_array(v7);
30482     len = v7_array_length(v7, this_obj);
30483 
30484     tmp_stack_push(&vf, &arg0);
30485     tmp_stack_push(&vf, &arg1);
30486     tmp_stack_push(&vf, &v);
30487 
30488     for (i = 0; i < len; i++) {
30489       v = v7_array_get2(v7, this_obj, i, &has);
30490       if (!has) continue;
30491       rcode = a_prep2(v7, arg0, v, v7_mk_number(v7, i), arg1, &el);
30492       if (rcode != V7_OK) {
30493         goto clean;
30494       }
30495 
30496       rcode = v7_array_set_throwing(v7, *res, i, el, NULL);
30497       if (rcode != V7_OK) {
30498         goto clean;
30499       }
30500     }
30501   }
30502 
30503 clean:
30504   tmp_frame_cleanup(&vf);
30505   return rcode;
30506 }
30507 
30508 WARN_UNUSED_RESULT
30509 V7_PRIVATE enum v7_err Array_every(struct v7 *v7, v7_val_t *res) {
30510   enum v7_err rcode = V7_OK;
30511   val_t this_obj = v7_get_this(v7);
30512   val_t arg0, arg1, el, v;
30513   unsigned long i, len;
30514   int has;
30515   /* a_prep2 uninhibits GC when calling cb */
30516   struct gc_tmp_frame vf = new_tmp_frame(v7);
30517 
30518   *res = v7_mk_boolean(v7, 0);
30519 
30520   if (!v7_is_object(this_obj)) {
30521     rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
30522     goto clean;
30523   } else {
30524     a_prep1(v7, this_obj, &arg0, &arg1);
30525 
30526     tmp_stack_push(&vf, &arg0);
30527     tmp_stack_push(&vf, &arg1);
30528     tmp_stack_push(&vf, &v);
30529 
30530     len = v7_array_length(v7, this_obj);
30531     for (i = 0; i < len; i++) {
30532       v = v7_array_get2(v7, this_obj, i, &has);
30533       if (!has) continue;
30534       rcode = a_prep2(v7, arg0, v, v7_mk_number(v7, i), arg1, &el);
30535       if (rcode != V7_OK) {
30536         goto clean;
30537       }
30538       if (!v7_is_truthy(v7, el)) {
30539         *res = v7_mk_boolean(v7, 0);
30540         goto clean;
30541       }
30542     }
30543   }
30544 
30545   *res = v7_mk_boolean(v7, 1);
30546 
30547 clean:
30548   tmp_frame_cleanup(&vf);
30549   return rcode;
30550 }
30551 
30552 WARN_UNUSED_RESULT
30553 V7_PRIVATE enum v7_err Array_some(struct v7 *v7, v7_val_t *res) {
30554   enum v7_err rcode = V7_OK;
30555   val_t this_obj = v7_get_this(v7);
30556   val_t arg0, arg1, el, v;
30557   unsigned long i, len;
30558   int has;
30559   /* a_prep2 uninhibits GC when calling cb */
30560   struct gc_tmp_frame vf = new_tmp_frame(v7);
30561 
30562   *res = v7_mk_boolean(v7, 1);
30563 
30564   if (!v7_is_object(this_obj)) {
30565     rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
30566     goto clean;
30567   } else {
30568     a_prep1(v7, this_obj, &arg0, &arg1);
30569 
30570     tmp_stack_push(&vf, &arg0);
30571     tmp_stack_push(&vf, &arg1);
30572     tmp_stack_push(&vf, &v);
30573 
30574     len = v7_array_length(v7, this_obj);
30575     for (i = 0; i < len; i++) {
30576       v = v7_array_get2(v7, this_obj, i, &has);
30577       if (!has) continue;
30578       rcode = a_prep2(v7, arg0, v, v7_mk_number(v7, i), arg1, &el);
30579       if (rcode != V7_OK) {
30580         goto clean;
30581       }
30582       if (v7_is_truthy(v7, el)) {
30583         *res = v7_mk_boolean(v7, 1);
30584         goto clean;
30585       }
30586     }
30587   }
30588 
30589   *res = v7_mk_boolean(v7, 0);
30590 
30591 clean:
30592   tmp_frame_cleanup(&vf);
30593   return rcode;
30594 }
30595 
30596 WARN_UNUSED_RESULT
30597 V7_PRIVATE enum v7_err Array_filter(struct v7 *v7, v7_val_t *res) {
30598   enum v7_err rcode = V7_OK;
30599   val_t this_obj = v7_get_this(v7);
30600   val_t arg0, arg1, el, v;
30601   unsigned long len, i;
30602   int has;
30603   /* a_prep2 uninhibits GC when calling cb */
30604   struct gc_tmp_frame vf = new_tmp_frame(v7);
30605 
30606   if (!v7_is_object(this_obj)) {
30607     rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
30608     goto clean;
30609   } else {
30610     a_prep1(v7, this_obj, &arg0, &arg1);
30611     *res = v7_mk_dense_array(v7);
30612     len = v7_array_length(v7, this_obj);
30613 
30614     tmp_stack_push(&vf, &arg0);
30615     tmp_stack_push(&vf, &arg1);
30616     tmp_stack_push(&vf, &v);
30617 
30618     for (i = 0; i < len; i++) {
30619       v = v7_array_get2(v7, this_obj, i, &has);
30620       if (!has) continue;
30621       rcode = a_prep2(v7, arg0, v, v7_mk_number(v7, i), arg1, &el);
30622       if (rcode != V7_OK) {
30623         goto clean;
30624       }
30625       if (v7_is_truthy(v7, el)) {
30626         rcode = v7_array_push_throwing(v7, *res, v, NULL);
30627         if (rcode != V7_OK) {
30628           goto clean;
30629         }
30630       }
30631     }
30632   }
30633 
30634 clean:
30635   tmp_frame_cleanup(&vf);
30636   return rcode;
30637 }
30638 
30639 WARN_UNUSED_RESULT
30640 V7_PRIVATE enum v7_err Array_concat(struct v7 *v7, v7_val_t *res) {
30641   enum v7_err rcode = V7_OK;
30642   val_t this_obj = v7_get_this(v7);
30643   size_t i, j, len;
30644   val_t saved_args;
30645 
30646   if (!v7_is_array(v7, this_obj)) {
30647     rcode = v7_throwf(v7, TYPE_ERROR, "Array expected");
30648     goto clean;
30649   }
30650 
30651   len = v7_argc(v7);
30652 
30653   /*
30654    * reuse a_splice but override it's arguments. a_splice
30655    * internally uses a lot of helpers that fetch arguments
30656    * from the v7 context.
30657    * TODO(mkm): we need a better helper call another cfunction
30658    * from a cfunction.
30659    */
30660   saved_args = v7->vals.arguments;
30661   v7->vals.arguments = V7_UNDEFINED;
30662   rcode = a_splice(v7, 1, res);
30663   if (rcode != V7_OK) {
30664     goto clean;
30665   }
30666   v7->vals.arguments = saved_args;
30667 
30668   for (i = 0; i < len; i++) {
30669     val_t a = v7_arg(v7, i);
30670     if (!v7_is_array(v7, a)) {
30671       rcode = v7_array_push_throwing(v7, *res, a, NULL);
30672       if (rcode != V7_OK) {
30673         goto clean;
30674       }
30675     } else {
30676       size_t alen = v7_array_length(v7, a);
30677       for (j = 0; j < alen; j++) {
30678         rcode = v7_array_push_throwing(v7, *res, v7_array_get(v7, a, j), NULL);
30679         if (rcode != V7_OK) {
30680           goto clean;
30681         }
30682       }
30683     }
30684   }
30685 
30686 clean:
30687   return rcode;
30688 }
30689 
30690 WARN_UNUSED_RESULT
30691 V7_PRIVATE enum v7_err Array_isArray(struct v7 *v7, v7_val_t *res) {
30692   val_t arg0 = v7_arg(v7, 0);
30693   *res = v7_mk_boolean(v7, v7_is_array(v7, arg0));
30694   return V7_OK;
30695 }
30696 
30697 V7_PRIVATE void init_array(struct v7 *v7) {
30698   val_t ctor = mk_cfunction_obj(v7, Array_ctor, 1);
30699   val_t length = v7_mk_dense_array(v7);
30700 
30701   v7_set(v7, ctor, "prototype", 9, v7->vals.array_prototype);
30702   set_method(v7, ctor, "isArray", Array_isArray, 1);
30703   v7_set(v7, v7->vals.global_object, "Array", 5, ctor);
30704   v7_def(v7, v7->vals.array_prototype, "constructor", ~0, _V7_DESC_HIDDEN(1),
30705          ctor);
30706   v7_set(v7, ctor, "name", 4, v7_mk_string(v7, "Array", ~0, 1));
30707 
30708   set_method(v7, v7->vals.array_prototype, "concat", Array_concat, 1);
30709   set_method(v7, v7->vals.array_prototype, "every", Array_every, 1);
30710   set_method(v7, v7->vals.array_prototype, "filter", Array_filter, 1);
30711   set_method(v7, v7->vals.array_prototype, "forEach", Array_forEach, 1);
30712   set_method(v7, v7->vals.array_prototype, "join", Array_join, 1);
30713   set_method(v7, v7->vals.array_prototype, "map", Array_map, 1);
30714   set_method(v7, v7->vals.array_prototype, "push", Array_push, 1);
30715   set_method(v7, v7->vals.array_prototype, "reverse", Array_reverse, 0);
30716   set_method(v7, v7->vals.array_prototype, "slice", Array_slice, 2);
30717   set_method(v7, v7->vals.array_prototype, "some", Array_some, 1);
30718   set_method(v7, v7->vals.array_prototype, "sort", Array_sort, 1);
30719   set_method(v7, v7->vals.array_prototype, "splice", Array_splice, 2);
30720   set_method(v7, v7->vals.array_prototype, "toString", Array_toString, 0);
30721 
30722   v7_array_set(v7, length, 0, v7_mk_cfunction(Array_get_length));
30723   v7_array_set(v7, length, 1, v7_mk_cfunction(Array_set_length));
30724   v7_def(v7, v7->vals.array_prototype, "length", 6,
30725          V7_DESC_ENUMERABLE(0) | V7_DESC_GETTER(1) | V7_DESC_SETTER(1), length);
30726 }
30727 
30728 #if defined(__cplusplus)
30729 }
30730 #endif /* __cplusplus */
30731 #ifdef V7_MODULE_LINES
30732 #line 1 "v7/src/std_boolean.c"
30733 #endif
30734 /*
30735  * Copyright (c) 2014 Cesanta Software Limited
30736  * All rights reserved
30737  */
30738 
30739 /* Amalgamated: #include "v7/src/internal.h" */
30740 /* Amalgamated: #include "v7/src/std_object.h" */
30741 /* Amalgamated: #include "v7/src/core.h" */
30742 /* Amalgamated: #include "v7/src/function.h" */
30743 /* Amalgamated: #include "v7/src/object.h" */
30744 /* Amalgamated: #include "v7/src/conversion.h" */
30745 /* Amalgamated: #include "v7/src/primitive.h" */
30746 /* Amalgamated: #include "v7/src/exceptions.h" */
30747 /* Amalgamated: #include "v7/src/string.h" */
30748 
30749 #if defined(__cplusplus)
30750 extern "C" {
30751 #endif /* __cplusplus */
30752 
30753 WARN_UNUSED_RESULT
30754 V7_PRIVATE enum v7_err Boolean_ctor(struct v7 *v7, v7_val_t *res) {
30755   enum v7_err rcode = V7_OK;
30756   val_t this_obj = v7_get_this(v7);
30757 
30758   *res = to_boolean_v(v7, v7_arg(v7, 0));
30759 
30760   if (v7_is_generic_object(this_obj) && this_obj != v7->vals.global_object) {
30761     /* called as "new Boolean(...)" */
30762     obj_prototype_set(v7, get_object_struct(this_obj),
30763                       get_object_struct(v7->vals.boolean_prototype));
30764     v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), *res);
30765 
30766     /*
30767      * implicitly returning `this`: `call_cfunction()` in bcode.c will do
30768      * that for us
30769      */
30770   }
30771 
30772   return rcode;
30773 }
30774 
30775 WARN_UNUSED_RESULT
30776 V7_PRIVATE enum v7_err Boolean_valueOf(struct v7 *v7, v7_val_t *res) {
30777   enum v7_err rcode = V7_OK;
30778   val_t this_obj = v7_get_this(v7);
30779   if (!v7_is_boolean(this_obj) &&
30780       (v7_is_object(this_obj) &&
30781        v7_get_proto(v7, this_obj) != v7->vals.boolean_prototype)) {
30782     rcode = v7_throwf(v7, TYPE_ERROR,
30783                       "Boolean.valueOf called on non-boolean object");
30784     goto clean;
30785   }
30786 
30787   rcode = Obj_valueOf(v7, res);
30788   if (rcode != V7_OK) {
30789     goto clean;
30790   }
30791 
30792 clean:
30793   return rcode;
30794 }
30795 
30796 WARN_UNUSED_RESULT
30797 V7_PRIVATE enum v7_err Boolean_toString(struct v7 *v7, v7_val_t *res) {
30798   enum v7_err rcode = V7_OK;
30799   val_t this_obj = v7_get_this(v7);
30800 
30801   *res = V7_UNDEFINED;
30802 
30803   if (this_obj == v7->vals.boolean_prototype) {
30804     *res = v7_mk_string(v7, "false", 5, 1);
30805     goto clean;
30806   }
30807 
30808   if (!v7_is_boolean(this_obj) &&
30809       !(v7_is_generic_object(this_obj) &&
30810         is_prototype_of(v7, this_obj, v7->vals.boolean_prototype))) {
30811     rcode = v7_throwf(v7, TYPE_ERROR,
30812                       "Boolean.toString called on non-boolean object");
30813     goto clean;
30814   }
30815 
30816   rcode = obj_value_of(v7, this_obj, res);
30817   if (rcode != V7_OK) {
30818     goto clean;
30819   }
30820 
30821   rcode = primitive_to_str(v7, *res, res, NULL, 0, NULL);
30822   if (rcode != V7_OK) {
30823     goto clean;
30824   }
30825 
30826 clean:
30827   return rcode;
30828 }
30829 
30830 V7_PRIVATE void init_boolean(struct v7 *v7) {
30831   val_t ctor = mk_cfunction_obj_with_proto(v7, Boolean_ctor, 1,
30832                                            v7->vals.boolean_prototype);
30833   v7_set(v7, v7->vals.global_object, "Boolean", 7, ctor);
30834 
30835   set_cfunc_prop(v7, v7->vals.boolean_prototype, "valueOf", Boolean_valueOf);
30836   set_cfunc_prop(v7, v7->vals.boolean_prototype, "toString", Boolean_toString);
30837 }
30838 
30839 #if defined(__cplusplus)
30840 }
30841 #endif /* __cplusplus */
30842 #ifdef V7_MODULE_LINES
30843 #line 1 "v7/src/std_math.c"
30844 #endif
30845 /*
30846  * Copyright (c) 2014 Cesanta Software Limited
30847  * All rights reserved
30848  */
30849 
30850 /* Amalgamated: #include "v7/src/internal.h" */
30851 /* Amalgamated: #include "v7/src/core.h" */
30852 /* Amalgamated: #include "v7/src/object.h" */
30853 /* Amalgamated: #include "v7/src/primitive.h" */
30854 
30855 #if V7_ENABLE__Math
30856 
30857 #if defined(__cplusplus)
30858 extern "C" {
30859 #endif /* __cplusplus */
30860 
30861 #ifdef __WATCOM__
30862 int matherr(struct _exception *exc) {
30863   if (exc->type == DOMAIN) {
30864     exc->retval = NAN;
30865     return 0;
30866   }
30867 }
30868 #endif
30869 
30870 #if V7_ENABLE__Math__abs || V7_ENABLE__Math__acos || V7_ENABLE__Math__asin ||  \
30871     V7_ENABLE__Math__atan || V7_ENABLE__Math__ceil || V7_ENABLE__Math__cos ||  \
30872     V7_ENABLE__Math__exp || V7_ENABLE__Math__floor || V7_ENABLE__Math__log ||  \
30873     V7_ENABLE__Math__round || V7_ENABLE__Math__sin || V7_ENABLE__Math__sqrt || \
30874     V7_ENABLE__Math__tan
30875 WARN_UNUSED_RESULT
30876 static enum v7_err m_one_arg(struct v7 *v7, double (*f)(double), val_t *res) {
30877   enum v7_err rcode = V7_OK;
30878   val_t arg0 = v7_arg(v7, 0);
30879   double d0 = v7_get_double(v7, arg0);
30880 #ifdef V7_BROKEN_NAN
30881   if (isnan(d0)) {
30882     *res = V7_TAG_NAN;
30883     goto clean;
30884   }
30885 #endif
30886   *res = v7_mk_number(v7, f(d0));
30887   goto clean;
30888 
30889 clean:
30890   return rcode;
30891 }
30892 #endif /* V7_ENABLE__Math__* */
30893 
30894 #if V7_ENABLE__Math__pow || V7_ENABLE__Math__atan2
30895 WARN_UNUSED_RESULT
30896 static enum v7_err m_two_arg(struct v7 *v7, double (*f)(double, double),
30897                              val_t *res) {
30898   enum v7_err rcode = V7_OK;
30899   val_t arg0 = v7_arg(v7, 0);
30900   val_t arg1 = v7_arg(v7, 1);
30901   double d0 = v7_get_double(v7, arg0);
30902   double d1 = v7_get_double(v7, arg1);
30903 #ifdef V7_BROKEN_NAN
30904   /* pow(NaN,0) == 1, doesn't fix atan2, but who cares */
30905   if (isnan(d1)) {
30906     *res = V7_TAG_NAN;
30907     goto clean;
30908   }
30909 #endif
30910   *res = v7_mk_number(v7, f(d0, d1));
30911   goto clean;
30912 
30913 clean:
30914   return rcode;
30915 }
30916 #endif /* V7_ENABLE__Math__pow || V7_ENABLE__Math__atan2 */
30917 
30918 #define DEFINE_WRAPPER(name, func)                                   \
30919   WARN_UNUSED_RESULT                                                 \
30920   V7_PRIVATE enum v7_err Math_##name(struct v7 *v7, v7_val_t *res) { \
30921     return func(v7, name, res);                                      \
30922   }
30923 
30924 /* Visual studio 2012+ has round() */
30925 #if V7_ENABLE__Math__round && \
30926     ((defined(V7_WINDOWS) && _MSC_VER < 1700) || defined(__WATCOM__))
30927 static double round(double n) {
30928   return n;
30929 }
30930 #endif
30931 
30932 #if V7_ENABLE__Math__abs
30933 DEFINE_WRAPPER(fabs, m_one_arg)
30934 #endif
30935 #if V7_ENABLE__Math__acos
30936 DEFINE_WRAPPER(acos, m_one_arg)
30937 #endif
30938 #if V7_ENABLE__Math__asin
30939 DEFINE_WRAPPER(asin, m_one_arg)
30940 #endif
30941 #if V7_ENABLE__Math__atan
30942 DEFINE_WRAPPER(atan, m_one_arg)
30943 #endif
30944 #if V7_ENABLE__Math__atan2
30945 DEFINE_WRAPPER(atan2, m_two_arg)
30946 #endif
30947 #if V7_ENABLE__Math__ceil
30948 DEFINE_WRAPPER(ceil, m_one_arg)
30949 #endif
30950 #if V7_ENABLE__Math__cos
30951 DEFINE_WRAPPER(cos, m_one_arg)
30952 #endif
30953 #if V7_ENABLE__Math__exp
30954 DEFINE_WRAPPER(exp, m_one_arg)
30955 #endif
30956 #if V7_ENABLE__Math__floor
30957 DEFINE_WRAPPER(floor, m_one_arg)
30958 #endif
30959 #if V7_ENABLE__Math__log
30960 DEFINE_WRAPPER(log, m_one_arg)
30961 #endif
30962 #if V7_ENABLE__Math__pow
30963 DEFINE_WRAPPER(pow, m_two_arg)
30964 #endif
30965 #if V7_ENABLE__Math__round
30966 DEFINE_WRAPPER(round, m_one_arg)
30967 #endif
30968 #if V7_ENABLE__Math__sin
30969 DEFINE_WRAPPER(sin, m_one_arg)
30970 #endif
30971 #if V7_ENABLE__Math__sqrt
30972 DEFINE_WRAPPER(sqrt, m_one_arg)
30973 #endif
30974 #if V7_ENABLE__Math__tan
30975 DEFINE_WRAPPER(tan, m_one_arg)
30976 #endif
30977 
30978 #if V7_ENABLE__Math__random
30979 WARN_UNUSED_RESULT
30980 V7_PRIVATE enum v7_err Math_random(struct v7 *v7, v7_val_t *res) {
30981   (void) v7;
30982   *res = v7_mk_number(v7, (double) rand() / RAND_MAX);
30983   return V7_OK;
30984 }
30985 #endif /* V7_ENABLE__Math__random */
30986 
30987 #if V7_ENABLE__Math__min || V7_ENABLE__Math__max
30988 WARN_UNUSED_RESULT
30989 static enum v7_err min_max(struct v7 *v7, int is_min, val_t *res) {
30990   enum v7_err rcode = V7_OK;
30991   double dres = NAN;
30992   int i, len = v7_argc(v7);
30993 
30994   for (i = 0; i < len; i++) {
30995     double v = v7_get_double(v7, v7_arg(v7, i));
30996     if (isnan(dres) || (is_min && v < dres) || (!is_min && v > dres)) {
30997       dres = v;
30998     }
30999   }
31000 
31001   *res = v7_mk_number(v7, dres);
31002 
31003   return rcode;
31004 }
31005 #endif /* V7_ENABLE__Math__min || V7_ENABLE__Math__max */
31006 
31007 #if V7_ENABLE__Math__min
31008 WARN_UNUSED_RESULT
31009 V7_PRIVATE enum v7_err Math_min(struct v7 *v7, v7_val_t *res) {
31010   return min_max(v7, 1, res);
31011 }
31012 #endif
31013 
31014 #if V7_ENABLE__Math__max
31015 WARN_UNUSED_RESULT
31016 V7_PRIVATE enum v7_err Math_max(struct v7 *v7, v7_val_t *res) {
31017   return min_max(v7, 0, res);
31018 }
31019 #endif
31020 
31021 V7_PRIVATE void init_math(struct v7 *v7) {
31022   val_t math = v7_mk_object(v7);
31023 
31024 #if V7_ENABLE__Math__abs
31025   set_cfunc_prop(v7, math, "abs", Math_fabs);
31026 #endif
31027 #if V7_ENABLE__Math__acos
31028   set_cfunc_prop(v7, math, "acos", Math_acos);
31029 #endif
31030 #if V7_ENABLE__Math__asin
31031   set_cfunc_prop(v7, math, "asin", Math_asin);
31032 #endif
31033 #if V7_ENABLE__Math__atan
31034   set_cfunc_prop(v7, math, "atan", Math_atan);
31035 #endif
31036 #if V7_ENABLE__Math__atan2
31037   set_cfunc_prop(v7, math, "atan2", Math_atan2);
31038 #endif
31039 #if V7_ENABLE__Math__ceil
31040   set_cfunc_prop(v7, math, "ceil", Math_ceil);
31041 #endif
31042 #if V7_ENABLE__Math__cos
31043   set_cfunc_prop(v7, math, "cos", Math_cos);
31044 #endif
31045 #if V7_ENABLE__Math__exp
31046   set_cfunc_prop(v7, math, "exp", Math_exp);
31047 #endif
31048 #if V7_ENABLE__Math__floor
31049   set_cfunc_prop(v7, math, "floor", Math_floor);
31050 #endif
31051 #if V7_ENABLE__Math__log
31052   set_cfunc_prop(v7, math, "log", Math_log);
31053 #endif
31054 #if V7_ENABLE__Math__max
31055   set_cfunc_prop(v7, math, "max", Math_max);
31056 #endif
31057 #if V7_ENABLE__Math__min
31058   set_cfunc_prop(v7, math, "min", Math_min);
31059 #endif
31060 #if V7_ENABLE__Math__pow
31061   set_cfunc_prop(v7, math, "pow", Math_pow);
31062 #endif
31063 #if V7_ENABLE__Math__random
31064   /* Incorporate our pointer into the RNG.
31065    * If srand() has not been called before, this will provide some randomness.
31066    * If it has, it will hopefully not make things worse.
31067    */
31068   srand(rand() ^ ((uintptr_t) v7));
31069   set_cfunc_prop(v7, math, "random", Math_random);
31070 #endif
31071 #if V7_ENABLE__Math__round
31072   set_cfunc_prop(v7, math, "round", Math_round);
31073 #endif
31074 #if V7_ENABLE__Math__sin
31075   set_cfunc_prop(v7, math, "sin", Math_sin);
31076 #endif
31077 #if V7_ENABLE__Math__sqrt
31078   set_cfunc_prop(v7, math, "sqrt", Math_sqrt);
31079 #endif
31080 #if V7_ENABLE__Math__tan
31081   set_cfunc_prop(v7, math, "tan", Math_tan);
31082 #endif
31083 
31084 #if V7_ENABLE__Math__constants
31085   v7_set(v7, math, "E", 1, v7_mk_number(v7, M_E));
31086   v7_set(v7, math, "PI", 2, v7_mk_number(v7, M_PI));
31087   v7_set(v7, math, "LN2", 3, v7_mk_number(v7, M_LN2));
31088   v7_set(v7, math, "LN10", 4, v7_mk_number(v7, M_LN10));
31089   v7_set(v7, math, "LOG2E", 5, v7_mk_number(v7, M_LOG2E));
31090   v7_set(v7, math, "LOG10E", 6, v7_mk_number(v7, M_LOG10E));
31091   v7_set(v7, math, "SQRT1_2", 7, v7_mk_number(v7, M_SQRT1_2));
31092   v7_set(v7, math, "SQRT2", 5, v7_mk_number(v7, M_SQRT2));
31093 #endif
31094 
31095   v7_set(v7, v7->vals.global_object, "Math", 4, math);
31096 }
31097 
31098 #if defined(__cplusplus)
31099 }
31100 #endif /* __cplusplus */
31101 
31102 #endif /* V7_ENABLE__Math */
31103 #ifdef V7_MODULE_LINES
31104 #line 1 "v7/src/std_string.c"
31105 #endif
31106 /*
31107  * Copyright (c) 2014 Cesanta Software Limited
31108  * All rights reserved
31109  */
31110 
31111 /* Amalgamated: #include "common/utf.h" */
31112 /* Amalgamated: #include "v7/src/internal.h" */
31113 /* Amalgamated: #include "v7/src/std_string.h" */
31114 /* Amalgamated: #include "v7/src/core.h" */
31115 /* Amalgamated: #include "v7/src/function.h" */
31116 /* Amalgamated: #include "v7/src/string.h" */
31117 /* Amalgamated: #include "v7/src/slre.h" */
31118 /* Amalgamated: #include "v7/src/std_regex.h" */
31119 /* Amalgamated: #include "v7/src/std_object.h" */
31120 /* Amalgamated: #include "v7/src/eval.h" */
31121 /* Amalgamated: #include "v7/src/conversion.h" */
31122 /* Amalgamated: #include "v7/src/array.h" */
31123 /* Amalgamated: #include "v7/src/object.h" */
31124 /* Amalgamated: #include "v7/src/regexp.h" */
31125 /* Amalgamated: #include "v7/src/exceptions.h" */
31126 
31127 /* Substring implementations: RegExp-based and String-based {{{ */
31128 
31129 /*
31130  * Substring context: currently, used in Str_split() only, but will probably
31131  * be used in Str_replace() and other functions as well.
31132  *
31133  * Needed to provide different implementation for RegExp or String arguments,
31134  * keeping common parts reusable.
31135  */
31136 struct _str_split_ctx {
31137   /* implementation-specific data */
31138   union {
31139 #if V7_ENABLE__RegExp
31140     struct {
31141       struct slre_prog *prog;
31142       struct slre_loot loot;
31143     } regexp;
31144 #endif
31145 
31146     struct {
31147       val_t sep;
31148     } string;
31149   } impl;
31150 
31151   struct v7 *v7;
31152 
31153   /* start and end of previous match (set by `p_exec()`) */
31154   const char *match_start;
31155   const char *match_end;
31156 
31157   /* pointers to implementation functions */
31158 
31159   /*
31160    * Initialize context
31161    */
31162   void (*p_init)(struct _str_split_ctx *ctx, struct v7 *v7, val_t sep);
31163 
31164   /*
31165    * Look for the next match, set `match_start` and `match_end` to appropriate
31166    * values.
31167    *
31168    * Returns 0 if match found, 1 otherwise (in accordance with `slre_exec()`)
31169    */
31170   int (*p_exec)(struct _str_split_ctx *ctx, const char *start, const char *end);
31171 
31172 #if V7_ENABLE__RegExp
31173   /*
31174    * Add captured data to resulting array (for RegExp-based implementation only)
31175    *
31176    * Returns updated `elem` value
31177    */
31178   long (*p_add_caps)(struct _str_split_ctx *ctx, val_t res, long elem,
31179                      long limit);
31180 #endif
31181 };
31182 
31183 #if V7_ENABLE__RegExp
31184 /* RegExp-based implementation of `p_init` in `struct _str_split_ctx` */
31185 static void subs_regexp_init(struct _str_split_ctx *ctx, struct v7 *v7,
31186                              val_t sep) {
31187   ctx->v7 = v7;
31188   ctx->impl.regexp.prog = v7_get_regexp_struct(v7, sep)->compiled_regexp;
31189 }
31190 
31191 /* RegExp-based implementation of `p_exec` in `struct _str_split_ctx` */
31192 static int subs_regexp_exec(struct _str_split_ctx *ctx, const char *start,
31193                             const char *end) {
31194   int ret =
31195       slre_exec(ctx->impl.regexp.prog, 0, start, end, &ctx->impl.regexp.loot);
31196 
31197   ctx->match_start = ctx->impl.regexp.loot.caps[0].start;
31198   ctx->match_end = ctx->impl.regexp.loot.caps[0].end;
31199 
31200   return ret;
31201 }
31202 
31203 /* RegExp-based implementation of `p_add_caps` in `struct _str_split_ctx` */
31204 static long subs_regexp_split_add_caps(struct _str_split_ctx *ctx, val_t res,
31205                                        long elem, long limit) {
31206   int i;
31207   for (i = 1; i < ctx->impl.regexp.loot.num_captures && elem < limit; i++) {
31208     size_t cap_len =
31209         ctx->impl.regexp.loot.caps[i].end - ctx->impl.regexp.loot.caps[i].start;
31210     v7_array_push(
31211         ctx->v7, res,
31212         (ctx->impl.regexp.loot.caps[i].start != NULL)
31213             ? v7_mk_string(ctx->v7, ctx->impl.regexp.loot.caps[i].start,
31214                            cap_len, 1)
31215             : V7_UNDEFINED);
31216     elem++;
31217   }
31218   return elem;
31219 }
31220 #endif
31221 
31222 /* String-based implementation of `p_init` in `struct _str_split_ctx` */
31223 static void subs_string_init(struct _str_split_ctx *ctx, struct v7 *v7,
31224                              val_t sep) {
31225   ctx->v7 = v7;
31226   ctx->impl.string.sep = sep;
31227 }
31228 
31229 /* String-based implementation of `p_exec` in `struct _str_split_ctx` */
31230 static int subs_string_exec(struct _str_split_ctx *ctx, const char *start,
31231                             const char *end) {
31232   int ret = 1;
31233   size_t sep_len;
31234   const char *psep = v7_get_string(ctx->v7, &ctx->impl.string.sep, &sep_len);
31235 
31236   if (sep_len == 0) {
31237     /* separator is an empty string: match empty string */
31238     ctx->match_start = start;
31239     ctx->match_end = start;
31240     ret = 0;
31241   } else {
31242     size_t i;
31243     for (i = 0; start <= (end - sep_len); ++i, start = utfnshift(start, 1)) {
31244       if (memcmp(start, psep, sep_len) == 0) {
31245         ret = 0;
31246         ctx->match_start = start;
31247         ctx->match_end = start + sep_len;
31248         break;
31249       }
31250     }
31251   }
31252 
31253   return ret;
31254 }
31255 
31256 #if V7_ENABLE__RegExp
31257 /* String-based implementation of `p_add_caps` in `struct _str_split_ctx` */
31258 static long subs_string_split_add_caps(struct _str_split_ctx *ctx, val_t res,
31259                                        long elem, long limit) {
31260   /* this is a stub function */
31261   (void) ctx;
31262   (void) res;
31263   (void) limit;
31264   return elem;
31265 }
31266 #endif
31267 
31268 /* }}} */
31269 
31270 WARN_UNUSED_RESULT
31271 V7_PRIVATE enum v7_err String_ctor(struct v7 *v7, v7_val_t *res) {
31272   enum v7_err rcode = V7_OK;
31273   val_t this_obj = v7_get_this(v7);
31274   val_t arg0 = v7_arg(v7, 0);
31275 
31276   *res = arg0;
31277 
31278   if (v7_argc(v7) == 0) {
31279     *res = v7_mk_string(v7, NULL, 0, 1);
31280   } else if (!v7_is_string(arg0)) {
31281     rcode = to_string(v7, arg0, res, NULL, 0, NULL);
31282     if (rcode != V7_OK) {
31283       goto clean;
31284     }
31285   }
31286 
31287   if (v7_is_generic_object(this_obj) && this_obj != v7->vals.global_object) {
31288     obj_prototype_set(v7, get_object_struct(this_obj),
31289                       get_object_struct(v7->vals.string_prototype));
31290     v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), *res);
31291     /*
31292      * implicitly returning `this`: `call_cfunction()` in bcode.c will do
31293      * that for us
31294      */
31295     goto clean;
31296   }
31297 
31298 clean:
31299   return rcode;
31300 }
31301 
31302 WARN_UNUSED_RESULT
31303 V7_PRIVATE enum v7_err Str_fromCharCode(struct v7 *v7, v7_val_t *res) {
31304   enum v7_err rcode = V7_OK;
31305   int i, num_args = v7_argc(v7);
31306 
31307   *res = v7_mk_string(v7, "", 0, 1); /* Empty string */
31308 
31309   for (i = 0; i < num_args; i++) {
31310     char buf[10];
31311     val_t arg = v7_arg(v7, i);
31312     double d = v7_get_double(v7, arg);
31313     Rune r = (Rune)((int32_t)(isnan(d) || isinf(d) ? 0 : d) & 0xffff);
31314     int n = runetochar(buf, &r);
31315     val_t s = v7_mk_string(v7, buf, n, 1);
31316     *res = s_concat(v7, *res, s);
31317   }
31318 
31319   return rcode;
31320 }
31321 
31322 WARN_UNUSED_RESULT
31323 static enum v7_err s_charCodeAt(struct v7 *v7, double *res) {
31324   return v7_char_code_at(v7, v7_get_this(v7), v7_arg(v7, 0), res);
31325 }
31326 
31327 WARN_UNUSED_RESULT
31328 V7_PRIVATE enum v7_err Str_charCodeAt(struct v7 *v7, v7_val_t *res) {
31329   enum v7_err rcode = V7_OK;
31330   double dnum = 0;
31331 
31332   rcode = s_charCodeAt(v7, &dnum);
31333   if (rcode != V7_OK) {
31334     goto clean;
31335   }
31336 
31337   *res = v7_mk_number(v7, dnum);
31338 
31339 clean:
31340   return rcode;
31341 }
31342 
31343 WARN_UNUSED_RESULT
31344 V7_PRIVATE enum v7_err Str_charAt(struct v7 *v7, v7_val_t *res) {
31345   enum v7_err rcode = V7_OK;
31346   double code = 0;
31347   char buf[10] = {0};
31348   int len = 0;
31349 
31350   rcode = s_charCodeAt(v7, &code);
31351   if (rcode != V7_OK) {
31352     goto clean;
31353   }
31354 
31355   if (!isnan(code)) {
31356     Rune r = (Rune) code;
31357     len = runetochar(buf, &r);
31358   }
31359   *res = v7_mk_string(v7, buf, len, 1);
31360 
31361 clean:
31362   return rcode;
31363 }
31364 
31365 WARN_UNUSED_RESULT
31366 V7_PRIVATE enum v7_err Str_concat(struct v7 *v7, v7_val_t *res) {
31367   enum v7_err rcode = V7_OK;
31368   val_t this_obj = v7_get_this(v7);
31369   int i, num_args = v7_argc(v7);
31370 
31371   rcode = to_string(v7, this_obj, res, NULL, 0, NULL);
31372   if (rcode != V7_OK) {
31373     goto clean;
31374   }
31375 
31376   for (i = 0; i < num_args; i++) {
31377     val_t str = V7_UNDEFINED;
31378 
31379     rcode = to_string(v7, v7_arg(v7, i), &str, NULL, 0, NULL);
31380     if (rcode != V7_OK) {
31381       goto clean;
31382     }
31383 
31384     *res = s_concat(v7, *res, str);
31385   }
31386 
31387 clean:
31388   return rcode;
31389 }
31390 
31391 WARN_UNUSED_RESULT
31392 static enum v7_err s_index_of(struct v7 *v7, int last, val_t *res) {
31393   enum v7_err rcode = V7_OK;
31394   val_t this_obj = v7_get_this(v7);
31395   val_t arg0 = v7_arg(v7, 0);
31396   size_t fromIndex = 0;
31397   double dres = -1;
31398 
31399   if (!v7_is_undefined(arg0)) {
31400     const char *p1, *p2, *end;
31401     size_t i, len1, len2, bytecnt1, bytecnt2;
31402     val_t sub = V7_UNDEFINED;
31403 
31404     rcode = to_string(v7, arg0, &sub, NULL, 0, NULL);
31405     if (rcode != V7_OK) {
31406       goto clean;
31407     }
31408 
31409     rcode = to_string(v7, this_obj, &this_obj, NULL, 0, NULL);
31410     if (rcode != V7_OK) {
31411       goto clean;
31412     }
31413 
31414     p1 = v7_get_string(v7, &this_obj, &bytecnt1);
31415     p2 = v7_get_string(v7, &sub, &bytecnt2);
31416 
31417     if (bytecnt2 <= bytecnt1) {
31418       end = p1 + bytecnt1;
31419       len1 = utfnlen(p1, bytecnt1);
31420       len2 = utfnlen(p2, bytecnt2);
31421 
31422       if (v7_argc(v7) > 1) {
31423         /* `fromIndex` was provided. Normalize it */
31424         double d = 0;
31425         {
31426           val_t arg = v7_arg(v7, 1);
31427           rcode = to_number_v(v7, arg, &arg);
31428           if (rcode != V7_OK) {
31429             goto clean;
31430           }
31431           d = v7_get_double(v7, arg);
31432         }
31433         if (isnan(d) || d < 0) {
31434           d = 0.0;
31435         } else if (isinf(d) || d > len1) {
31436           d = len1;
31437         }
31438         fromIndex = d;
31439 
31440         /* adjust pointers accordingly to `fromIndex` */
31441         if (last) {
31442           const char *end_tmp = utfnshift(p1, fromIndex + len2);
31443           end = (end_tmp < end) ? end_tmp : end;
31444         } else {
31445           p1 = utfnshift(p1, fromIndex);
31446         }
31447       }
31448 
31449       /*
31450        * TODO(dfrank): when `last` is set, start from the end and look
31451        * backward. We'll need to improve `utfnshift()` for that, so that it can
31452        * handle negative offsets.
31453        */
31454       for (i = 0; p1 <= (end - bytecnt2); i++, p1 = utfnshift(p1, 1)) {
31455         if (memcmp(p1, p2, bytecnt2) == 0) {
31456           dres = i;
31457           if (!last) break;
31458         }
31459       }
31460     }
31461   }
31462   if (!last && dres >= 0) dres += fromIndex;
31463   *res = v7_mk_number(v7, dres);
31464 
31465 clean:
31466   return rcode;
31467 }
31468 
31469 WARN_UNUSED_RESULT
31470 V7_PRIVATE enum v7_err Str_valueOf(struct v7 *v7, v7_val_t *res) {
31471   enum v7_err rcode = V7_OK;
31472   val_t this_obj = v7_get_this(v7);
31473 
31474   if (!v7_is_string(this_obj) &&
31475       (v7_is_object(this_obj) &&
31476        v7_get_proto(v7, this_obj) != v7->vals.string_prototype)) {
31477     rcode =
31478         v7_throwf(v7, TYPE_ERROR, "String.valueOf called on non-string object");
31479     goto clean;
31480   }
31481 
31482   rcode = Obj_valueOf(v7, res);
31483   goto clean;
31484 
31485 clean:
31486   return rcode;
31487 }
31488 
31489 WARN_UNUSED_RESULT
31490 V7_PRIVATE enum v7_err Str_indexOf(struct v7 *v7, v7_val_t *res) {
31491   return s_index_of(v7, 0, res);
31492 }
31493 
31494 WARN_UNUSED_RESULT
31495 V7_PRIVATE enum v7_err Str_lastIndexOf(struct v7 *v7, v7_val_t *res) {
31496   return s_index_of(v7, 1, res);
31497 }
31498 
31499 #if V7_ENABLE__String__localeCompare
31500 WARN_UNUSED_RESULT
31501 V7_PRIVATE enum v7_err Str_localeCompare(struct v7 *v7, v7_val_t *res) {
31502   enum v7_err rcode = V7_OK;
31503   val_t this_obj = v7_get_this(v7);
31504   val_t arg0 = V7_UNDEFINED;
31505   val_t s = V7_UNDEFINED;
31506 
31507   rcode = to_string(v7, v7_arg(v7, 0), &arg0, NULL, 0, NULL);
31508   if (rcode != V7_OK) {
31509     goto clean;
31510   }
31511 
31512   rcode = to_string(v7, this_obj, &s, NULL, 0, NULL);
31513   if (rcode != V7_OK) {
31514     goto clean;
31515   }
31516 
31517   *res = v7_mk_number(v7, s_cmp(v7, s, arg0));
31518 
31519 clean:
31520   return rcode;
31521 }
31522 #endif
31523 
31524 WARN_UNUSED_RESULT
31525 V7_PRIVATE enum v7_err Str_toString(struct v7 *v7, v7_val_t *res) {
31526   enum v7_err rcode = V7_OK;
31527   val_t this_obj = v7_get_this(v7);
31528 
31529   if (this_obj == v7->vals.string_prototype) {
31530     *res = v7_mk_string(v7, "false", 5, 1);
31531     goto clean;
31532   }
31533 
31534   if (!v7_is_string(this_obj) &&
31535       !(v7_is_generic_object(this_obj) &&
31536         is_prototype_of(v7, this_obj, v7->vals.string_prototype))) {
31537     rcode = v7_throwf(v7, TYPE_ERROR,
31538                       "String.toString called on non-string object");
31539     goto clean;
31540   }
31541 
31542   rcode = obj_value_of(v7, this_obj, &this_obj);
31543   if (rcode != V7_OK) {
31544     goto clean;
31545   }
31546 
31547   rcode = to_string(v7, this_obj, res, NULL, 0, NULL);
31548   if (rcode != V7_OK) {
31549     goto clean;
31550   }
31551 
31552 clean:
31553   return rcode;
31554 }
31555 
31556 #if V7_ENABLE__RegExp
31557 WARN_UNUSED_RESULT
31558 enum v7_err call_regex_ctor(struct v7 *v7, val_t arg, val_t *res) {
31559   /* TODO(mkm): make general helper out of this */
31560   enum v7_err rcode = V7_OK;
31561   val_t saved_args = v7->vals.arguments, args = v7_mk_dense_array(v7);
31562   v7_array_push(v7, args, arg);
31563   v7->vals.arguments = args;
31564 
31565   rcode = Regex_ctor(v7, res);
31566   if (rcode != V7_OK) {
31567     goto clean;
31568   }
31569   v7->vals.arguments = saved_args;
31570 
31571 clean:
31572   return rcode;
31573 }
31574 
31575 WARN_UNUSED_RESULT
31576 V7_PRIVATE enum v7_err Str_match(struct v7 *v7, v7_val_t *res) {
31577   enum v7_err rcode = V7_OK;
31578   val_t this_obj = v7_get_this(v7);
31579   val_t so = V7_UNDEFINED, ro = V7_UNDEFINED;
31580   long previousLastIndex = 0;
31581   int lastMatch = 1, n = 0, flag_g;
31582   struct v7_regexp *rxp;
31583 
31584   *res = V7_NULL;
31585 
31586   rcode = to_string(v7, this_obj, &so, NULL, 0, NULL);
31587   if (rcode != V7_OK) {
31588     goto clean;
31589   }
31590 
31591   if (v7_argc(v7) == 0) {
31592     rcode = v7_mk_regexp(v7, "", 0, "", 0, &ro);
31593     if (rcode != V7_OK) {
31594       goto clean;
31595     }
31596   } else {
31597     rcode = obj_value_of(v7, v7_arg(v7, 0), &ro);
31598     if (rcode != V7_OK) {
31599       goto clean;
31600     }
31601   }
31602 
31603   if (!v7_is_regexp(v7, ro)) {
31604     rcode = call_regex_ctor(v7, ro, &ro);
31605     if (rcode != V7_OK) {
31606       goto clean;
31607     }
31608   }
31609 
31610   rxp = v7_get_regexp_struct(v7, ro);
31611   flag_g = slre_get_flags(rxp->compiled_regexp) & SLRE_FLAG_G;
31612   if (!flag_g) {
31613     rcode = rx_exec(v7, ro, so, 0, res);
31614     goto clean;
31615   }
31616 
31617   rxp->lastIndex = 0;
31618   *res = v7_mk_dense_array(v7);
31619   while (lastMatch) {
31620     val_t result;
31621 
31622     rcode = rx_exec(v7, ro, so, 1, &result);
31623     if (rcode != V7_OK) {
31624       goto clean;
31625     }
31626 
31627     if (v7_is_null(result)) {
31628       lastMatch = 0;
31629     } else {
31630       long thisIndex = rxp->lastIndex;
31631       if (thisIndex == previousLastIndex) {
31632         previousLastIndex = thisIndex + 1;
31633         rxp->lastIndex = previousLastIndex;
31634       } else {
31635         previousLastIndex = thisIndex;
31636       }
31637       rcode =
31638           v7_array_push_throwing(v7, *res, v7_array_get(v7, result, 0), NULL);
31639       if (rcode != V7_OK) {
31640         goto clean;
31641       }
31642       n++;
31643     }
31644   }
31645 
31646   if (n == 0) {
31647     *res = V7_NULL;
31648     goto clean;
31649   }
31650 
31651 clean:
31652   return rcode;
31653 }
31654 
31655 WARN_UNUSED_RESULT
31656 V7_PRIVATE enum v7_err Str_replace(struct v7 *v7, v7_val_t *res) {
31657   enum v7_err rcode = V7_OK;
31658   val_t this_obj = v7_get_this(v7);
31659   const char *s;
31660   size_t s_len;
31661   /*
31662    * Buffer of temporary strings returned by the replacement funciton.  Will be
31663    * allocated below if only the replacement is a function.  We need to store
31664    * each string in a separate `val_t`, because string data of length <= 5 is
31665    * stored right in `val_t`, so if there's more than one replacement,
31666    * each subsequent replacement will overwrite the previous one.
31667    */
31668   val_t *tmp_str_buf = NULL;
31669   val_t out_str_o;
31670   char *old_owned_mbuf_base = v7->owned_strings.buf;
31671   char *old_owned_mbuf_end = v7->owned_strings.buf + v7->owned_strings.len;
31672 
31673   rcode = to_string(v7, this_obj, &this_obj, NULL, 0, NULL);
31674   if (rcode != V7_OK) {
31675     goto clean;
31676   }
31677 
31678   s = v7_get_string(v7, &this_obj, &s_len);
31679 
31680   if (s_len != 0 && v7_argc(v7) > 1) {
31681     const char *const str_end = s + s_len;
31682     char *p = (char *) s;
31683     uint32_t out_sub_num = 0;
31684     val_t ro = V7_UNDEFINED, str_func = V7_UNDEFINED;
31685     struct slre_prog *prog;
31686     struct slre_cap out_sub[V7_RE_MAX_REPL_SUB], *ptok = out_sub;
31687     struct slre_loot loot;
31688     int flag_g;
31689 
31690     rcode = obj_value_of(v7, v7_arg(v7, 0), &ro);
31691     if (rcode != V7_OK) {
31692       goto clean;
31693     }
31694     rcode = obj_value_of(v7, v7_arg(v7, 1), &str_func);
31695     if (rcode != V7_OK) {
31696       goto clean;
31697     }
31698 
31699     if (!v7_is_regexp(v7, ro)) {
31700       rcode = call_regex_ctor(v7, ro, &ro);
31701       if (rcode != V7_OK) {
31702         goto clean;
31703       }
31704     }
31705     prog = v7_get_regexp_struct(v7, ro)->compiled_regexp;
31706     flag_g = slre_get_flags(prog) & SLRE_FLAG_G;
31707 
31708     if (!v7_is_callable(v7, str_func)) {
31709       rcode = to_string(v7, str_func, &str_func, NULL, 0, NULL);
31710       if (rcode != V7_OK) {
31711         goto clean;
31712       }
31713     }
31714 
31715     do {
31716       int i;
31717       if (slre_exec(prog, 0, p, str_end, &loot)) break;
31718       if (p != loot.caps->start) {
31719         ptok->start = p;
31720         ptok->end = loot.caps->start;
31721         ptok++;
31722         out_sub_num++;
31723       }
31724 
31725       if (v7_is_callable(v7, str_func)) { /* replace function */
31726         const char *rez_str;
31727         size_t rez_len;
31728         val_t arr = v7_mk_dense_array(v7);
31729 
31730         for (i = 0; i < loot.num_captures; i++) {
31731           rcode = v7_array_push_throwing(
31732               v7, arr, v7_mk_string(v7, loot.caps[i].start,
31733                                     loot.caps[i].end - loot.caps[i].start, 1),
31734               NULL);
31735           if (rcode != V7_OK) {
31736             goto clean;
31737           }
31738         }
31739         rcode = v7_array_push_throwing(
31740             v7, arr, v7_mk_number(v7, utfnlen(s, loot.caps[0].start - s)),
31741             NULL);
31742         if (rcode != V7_OK) {
31743           goto clean;
31744         }
31745 
31746         rcode = v7_array_push_throwing(v7, arr, this_obj, NULL);
31747         if (rcode != V7_OK) {
31748           goto clean;
31749         }
31750 
31751         {
31752           val_t val = V7_UNDEFINED;
31753 
31754           rcode = b_apply(v7, str_func, this_obj, arr, 0, &val);
31755           if (rcode != V7_OK) {
31756             goto clean;
31757           }
31758 
31759           if (tmp_str_buf == NULL) {
31760             tmp_str_buf = (val_t *) calloc(sizeof(val_t), V7_RE_MAX_REPL_SUB);
31761           }
31762 
31763           rcode = to_string(v7, val, &tmp_str_buf[out_sub_num], NULL, 0, NULL);
31764           if (rcode != V7_OK) {
31765             goto clean;
31766           }
31767         }
31768         rez_str = v7_get_string(v7, &tmp_str_buf[out_sub_num], &rez_len);
31769         if (rez_len) {
31770           ptok->start = rez_str;
31771           ptok->end = rez_str + rez_len;
31772           ptok++;
31773           out_sub_num++;
31774         }
31775       } else { /* replace string */
31776         struct slre_loot newsub;
31777         size_t f_len;
31778         const char *f_str = v7_get_string(v7, &str_func, &f_len);
31779         slre_replace(&loot, s, s_len, f_str, f_len, &newsub);
31780         for (i = 0; i < newsub.num_captures; i++) {
31781           ptok->start = newsub.caps[i].start;
31782           ptok->end = newsub.caps[i].end;
31783           ptok++;
31784           out_sub_num++;
31785         }
31786       }
31787       p = (char *) loot.caps[0].end;
31788     } while (flag_g && p < str_end);
31789     if (p <= str_end) {
31790       ptok->start = p;
31791       ptok->end = str_end;
31792       ptok++;
31793       out_sub_num++;
31794     }
31795     out_str_o = v7_mk_string(v7, NULL, 0, 1);
31796     ptok = out_sub;
31797     do {
31798       size_t ln = ptok->end - ptok->start;
31799       const char *ps = ptok->start;
31800       if (ptok->start >= old_owned_mbuf_base &&
31801           ptok->start < old_owned_mbuf_end) {
31802         ps += v7->owned_strings.buf - old_owned_mbuf_base;
31803       }
31804       out_str_o = s_concat(v7, out_str_o, v7_mk_string(v7, ps, ln, 1));
31805       p += ln;
31806       ptok++;
31807     } while (--out_sub_num);
31808 
31809     *res = out_str_o;
31810     goto clean;
31811   }
31812 
31813   *res = this_obj;
31814 
31815 clean:
31816   if (tmp_str_buf != NULL) {
31817     free(tmp_str_buf);
31818     tmp_str_buf = NULL;
31819   }
31820   return rcode;
31821 }
31822 
31823 WARN_UNUSED_RESULT
31824 V7_PRIVATE enum v7_err Str_search(struct v7 *v7, v7_val_t *res) {
31825   enum v7_err rcode = V7_OK;
31826   val_t this_obj = v7_get_this(v7);
31827   long utf_shift = -1;
31828 
31829   if (v7_argc(v7) > 0) {
31830     size_t s_len;
31831     struct slre_loot sub;
31832     val_t so = V7_UNDEFINED, ro = V7_UNDEFINED;
31833     const char *s;
31834 
31835     rcode = obj_value_of(v7, v7_arg(v7, 0), &ro);
31836     if (rcode != V7_OK) {
31837       goto clean;
31838     }
31839 
31840     if (!v7_is_regexp(v7, ro)) {
31841       rcode = call_regex_ctor(v7, ro, &ro);
31842       if (rcode != V7_OK) {
31843         goto clean;
31844       }
31845     }
31846 
31847     rcode = to_string(v7, this_obj, &so, NULL, 0, NULL);
31848     if (rcode != V7_OK) {
31849       goto clean;
31850     }
31851 
31852     s = v7_get_string(v7, &so, &s_len);
31853 
31854     if (!slre_exec(v7_get_regexp_struct(v7, ro)->compiled_regexp, 0, s,
31855                    s + s_len, &sub))
31856       utf_shift = utfnlen(s, sub.caps[0].start - s); /* calc shift for UTF-8 */
31857   } else {
31858     utf_shift = 0;
31859   }
31860 
31861   *res = v7_mk_number(v7, utf_shift);
31862 
31863 clean:
31864   return rcode;
31865 }
31866 
31867 #endif /* V7_ENABLE__RegExp */
31868 
31869 WARN_UNUSED_RESULT
31870 V7_PRIVATE enum v7_err Str_slice(struct v7 *v7, v7_val_t *res) {
31871   enum v7_err rcode = V7_OK;
31872   val_t this_obj = v7_get_this(v7);
31873   long from = 0, to = 0;
31874   size_t len;
31875   val_t so = V7_UNDEFINED;
31876   const char *begin, *end;
31877   int num_args = v7_argc(v7);
31878 
31879   rcode = to_string(v7, this_obj, &so, NULL, 0, NULL);
31880   if (rcode != V7_OK) {
31881     goto clean;
31882   }
31883 
31884   begin = v7_get_string(v7, &so, &len);
31885 
31886   to = len = utfnlen(begin, len);
31887   if (num_args > 0) {
31888     rcode = to_long(v7, v7_arg(v7, 0), 0, &from);
31889     if (rcode != V7_OK) {
31890       goto clean;
31891     }
31892 
31893     if (from < 0) {
31894       from += len;
31895       if (from < 0) from = 0;
31896     } else if ((size_t) from > len)
31897       from = len;
31898     if (num_args > 1) {
31899       rcode = to_long(v7, v7_arg(v7, 1), 0, &to);
31900       if (rcode != V7_OK) {
31901         goto clean;
31902       }
31903 
31904       if (to < 0) {
31905         to += len;
31906         if (to < 0) to = 0;
31907       } else if ((size_t) to > len)
31908         to = len;
31909     }
31910   }
31911 
31912   if (from > to) to = from;
31913   end = utfnshift(begin, to);
31914   begin = utfnshift(begin, from);
31915 
31916   *res = v7_mk_string(v7, begin, end - begin, 1);
31917 
31918 clean:
31919   return rcode;
31920 }
31921 
31922 WARN_UNUSED_RESULT
31923 static enum v7_err s_transform(struct v7 *v7, val_t obj, Rune (*func)(Rune),
31924                                val_t *res) {
31925   enum v7_err rcode = V7_OK;
31926   val_t s = V7_UNDEFINED;
31927   size_t i, n, len;
31928   const char *p2, *p;
31929 
31930   rcode = to_string(v7, obj, &s, NULL, 0, NULL);
31931   if (rcode != V7_OK) {
31932     goto clean;
31933   }
31934 
31935   p = v7_get_string(v7, &s, &len);
31936 
31937   /* Pass NULL to make sure we're not creating dictionary value */
31938   *res = v7_mk_string(v7, NULL, len, 1);
31939 
31940   {
31941     Rune r;
31942     p2 = v7_get_string(v7, res, &len);
31943     for (i = 0; i < len; i += n) {
31944       n = chartorune(&r, p + i);
31945       r = func(r);
31946       runetochar((char *) p2 + i, &r);
31947     }
31948   }
31949 
31950 clean:
31951   return rcode;
31952 }
31953 
31954 WARN_UNUSED_RESULT
31955 V7_PRIVATE enum v7_err Str_toLowerCase(struct v7 *v7, v7_val_t *res) {
31956   val_t this_obj = v7_get_this(v7);
31957   return s_transform(v7, this_obj, tolowerrune, res);
31958 }
31959 
31960 WARN_UNUSED_RESULT
31961 V7_PRIVATE enum v7_err Str_toUpperCase(struct v7 *v7, v7_val_t *res) {
31962   val_t this_obj = v7_get_this(v7);
31963   return s_transform(v7, this_obj, toupperrune, res);
31964 }
31965 
31966 static int s_isspace(Rune c) {
31967   return isspacerune(c) || isnewline(c);
31968 }
31969 
31970 WARN_UNUSED_RESULT
31971 V7_PRIVATE enum v7_err Str_trim(struct v7 *v7, v7_val_t *res) {
31972   enum v7_err rcode = V7_OK;
31973   val_t this_obj = v7_get_this(v7);
31974   val_t s = V7_UNDEFINED;
31975   size_t i, n, len, start = 0, end, state = 0;
31976   const char *p;
31977   Rune r;
31978 
31979   rcode = to_string(v7, this_obj, &s, NULL, 0, NULL);
31980   if (rcode != V7_OK) {
31981     goto clean;
31982   }
31983   p = v7_get_string(v7, &s, &len);
31984 
31985   end = len;
31986   for (i = 0; i < len; i += n) {
31987     n = chartorune(&r, p + i);
31988     if (!s_isspace(r)) {
31989       if (state++ == 0) start = i;
31990       end = i + n;
31991     }
31992   }
31993 
31994   *res = v7_mk_string(v7, p + start, end - start, 1);
31995 
31996 clean:
31997   return rcode;
31998 }
31999 
32000 WARN_UNUSED_RESULT
32001 V7_PRIVATE enum v7_err Str_length(struct v7 *v7, v7_val_t *res) {
32002   enum v7_err rcode = V7_OK;
32003   val_t this_obj = v7_get_this(v7);
32004   size_t len = 0;
32005   val_t s = V7_UNDEFINED;
32006 
32007   rcode = obj_value_of(v7, this_obj, &s);
32008   if (rcode != V7_OK) {
32009     goto clean;
32010   }
32011 
32012   if (v7_is_string(s)) {
32013     const char *p = v7_get_string(v7, &s, &len);
32014     len = utfnlen(p, len);
32015   }
32016 
32017   *res = v7_mk_number(v7, len);
32018 clean:
32019   return rcode;
32020 }
32021 
32022 WARN_UNUSED_RESULT
32023 V7_PRIVATE enum v7_err Str_at(struct v7 *v7, v7_val_t *res) {
32024   enum v7_err rcode = V7_OK;
32025   val_t this_obj = v7_get_this(v7);
32026   long arg0;
32027   val_t s = V7_UNDEFINED;
32028 
32029   rcode = to_long(v7, v7_arg(v7, 0), -1, &arg0);
32030   if (rcode != V7_OK) {
32031     goto clean;
32032   }
32033 
32034   rcode = obj_value_of(v7, this_obj, &s);
32035   if (rcode != V7_OK) {
32036     goto clean;
32037   }
32038 
32039   if (v7_is_string(s)) {
32040     size_t n;
32041     const unsigned char *p = (unsigned char *) v7_get_string(v7, &s, &n);
32042     if (arg0 >= 0 && (size_t) arg0 < n) {
32043       *res = v7_mk_number(v7, p[arg0]);
32044       goto clean;
32045     }
32046   }
32047 
32048   *res = v7_mk_number(v7, NAN);
32049 
32050 clean:
32051   return rcode;
32052 }
32053 
32054 WARN_UNUSED_RESULT
32055 V7_PRIVATE enum v7_err Str_blen(struct v7 *v7, v7_val_t *res) {
32056   enum v7_err rcode = V7_OK;
32057   val_t this_obj = v7_get_this(v7);
32058   size_t len = 0;
32059   val_t s = V7_UNDEFINED;
32060 
32061   rcode = obj_value_of(v7, this_obj, &s);
32062   if (rcode != V7_OK) {
32063     goto clean;
32064   }
32065 
32066   if (v7_is_string(s)) {
32067     v7_get_string(v7, &s, &len);
32068   }
32069 
32070   *res = v7_mk_number(v7, len);
32071 
32072 clean:
32073   return rcode;
32074 }
32075 
32076 WARN_UNUSED_RESULT
32077 static enum v7_err s_substr(struct v7 *v7, val_t s, long start, long len,
32078                             val_t *res) {
32079   enum v7_err rcode = V7_OK;
32080   size_t n;
32081   const char *p;
32082 
32083   rcode = to_string(v7, s, &s, NULL, 0, NULL);
32084   if (rcode != V7_OK) {
32085     goto clean;
32086   }
32087 
32088   p = v7_get_string(v7, &s, &n);
32089   n = utfnlen(p, n);
32090 
32091   if (start < (long) n && len > 0) {
32092     if (start < 0) start = (long) n + start;
32093     if (start < 0) start = 0;
32094 
32095     if (start > (long) n) start = n;
32096     if (len < 0) len = 0;
32097     if (len > (long) n - start) len = n - start;
32098     p = utfnshift(p, start);
32099   } else {
32100     len = 0;
32101   }
32102 
32103   *res = v7_mk_string(v7, p, len, 1);
32104 
32105 clean:
32106   return rcode;
32107 }
32108 
32109 WARN_UNUSED_RESULT
32110 V7_PRIVATE enum v7_err Str_substr(struct v7 *v7, v7_val_t *res) {
32111   enum v7_err rcode = V7_OK;
32112   val_t this_obj = v7_get_this(v7);
32113   long start, len;
32114 
32115   rcode = to_long(v7, v7_arg(v7, 0), 0, &start);
32116   if (rcode != V7_OK) {
32117     goto clean;
32118   }
32119 
32120   rcode = to_long(v7, v7_arg(v7, 1), LONG_MAX, &len);
32121   if (rcode != V7_OK) {
32122     goto clean;
32123   }
32124 
32125   rcode = s_substr(v7, this_obj, start, len, res);
32126   if (rcode != V7_OK) {
32127     goto clean;
32128   }
32129 
32130 clean:
32131   return rcode;
32132 }
32133 
32134 WARN_UNUSED_RESULT
32135 V7_PRIVATE enum v7_err Str_substring(struct v7 *v7, v7_val_t *res) {
32136   enum v7_err rcode = V7_OK;
32137   val_t this_obj = v7_get_this(v7);
32138   long start, end;
32139 
32140   rcode = to_long(v7, v7_arg(v7, 0), 0, &start);
32141   if (rcode != V7_OK) {
32142     goto clean;
32143   }
32144 
32145   rcode = to_long(v7, v7_arg(v7, 1), LONG_MAX, &end);
32146   if (rcode != V7_OK) {
32147     goto clean;
32148   }
32149 
32150   if (start < 0) start = 0;
32151   if (end < 0) end = 0;
32152   if (start > end) {
32153     long tmp = start;
32154     start = end;
32155     end = tmp;
32156   }
32157 
32158   rcode = s_substr(v7, this_obj, start, end - start, res);
32159   goto clean;
32160 
32161 clean:
32162   return rcode;
32163 }
32164 
32165 WARN_UNUSED_RESULT
32166 V7_PRIVATE enum v7_err Str_split(struct v7 *v7, v7_val_t *res) {
32167   enum v7_err rcode = V7_OK;
32168   val_t this_obj = v7_get_this(v7);
32169   const char *s, *s_end;
32170   size_t s_len;
32171   long num_args = v7_argc(v7);
32172   rcode = to_string(v7, this_obj, &this_obj, NULL, 0, NULL);
32173   if (rcode != V7_OK) {
32174     goto clean;
32175   }
32176   s = v7_get_string(v7, &this_obj, &s_len);
32177   s_end = s + s_len;
32178 
32179   *res = v7_mk_dense_array(v7);
32180 
32181   if (num_args == 0) {
32182     /*
32183      * No arguments were given: resulting array will contain just a single
32184      * element: the source string
32185      */
32186     rcode = v7_array_push_throwing(v7, *res, this_obj, NULL);
32187     if (rcode != V7_OK) {
32188       goto clean;
32189     }
32190   } else {
32191     val_t ro = V7_UNDEFINED;
32192     long elem, limit;
32193     size_t lookup_idx = 0, substr_idx = 0;
32194     struct _str_split_ctx ctx;
32195 
32196     rcode = to_long(v7, v7_arg(v7, 1), LONG_MAX, &limit);
32197     if (rcode != V7_OK) {
32198       goto clean;
32199     }
32200 
32201     rcode = obj_value_of(v7, v7_arg(v7, 0), &ro);
32202     if (rcode != V7_OK) {
32203       goto clean;
32204     }
32205 
32206     /* Initialize substring context depending on the argument type */
32207     if (v7_is_regexp(v7, ro)) {
32208 /* use RegExp implementation */
32209 #if V7_ENABLE__RegExp
32210       ctx.p_init = subs_regexp_init;
32211       ctx.p_exec = subs_regexp_exec;
32212       ctx.p_add_caps = subs_regexp_split_add_caps;
32213 #else
32214       assert(0);
32215 #endif
32216     } else {
32217       /*
32218        * use String implementation: first of all, convert to String (if it's
32219        * not already a String)
32220        */
32221       rcode = to_string(v7, ro, &ro, NULL, 0, NULL);
32222       if (rcode != V7_OK) {
32223         goto clean;
32224       }
32225 
32226       ctx.p_init = subs_string_init;
32227       ctx.p_exec = subs_string_exec;
32228 #if V7_ENABLE__RegExp
32229       ctx.p_add_caps = subs_string_split_add_caps;
32230 #endif
32231     }
32232     /* initialize context */
32233     ctx.p_init(&ctx, v7, ro);
32234 
32235     if (s_len == 0) {
32236       /*
32237        * if `this` is (or converts to) an empty string, resulting array should
32238        * contain empty string if only separator does not match an empty string.
32239        * Otherwise, the array is left empty
32240        */
32241       int matches_empty = !ctx.p_exec(&ctx, s, s);
32242       if (!matches_empty) {
32243         rcode = v7_array_push_throwing(v7, *res, this_obj, NULL);
32244         if (rcode != V7_OK) {
32245           goto clean;
32246         }
32247       }
32248     } else {
32249       size_t last_match_len = 0;
32250 
32251       for (elem = 0; elem < limit && lookup_idx < s_len;) {
32252         size_t substr_len;
32253         /* find next match, and break if there's no match */
32254         if (ctx.p_exec(&ctx, s + lookup_idx, s_end)) break;
32255 
32256         last_match_len = ctx.match_end - ctx.match_start;
32257         substr_len = ctx.match_start - s - substr_idx;
32258 
32259         /* add next substring to the resulting array, if needed */
32260         if (substr_len > 0 || last_match_len > 0) {
32261           rcode = v7_array_push_throwing(
32262               v7, *res, v7_mk_string(v7, s + substr_idx, substr_len, 1), NULL);
32263           if (rcode != V7_OK) {
32264             goto clean;
32265           }
32266           elem++;
32267 
32268 #if V7_ENABLE__RegExp
32269           /* Add captures (for RegExp only) */
32270           elem = ctx.p_add_caps(&ctx, *res, elem, limit);
32271 #endif
32272         }
32273 
32274         /* advance lookup_idx appropriately */
32275         if (last_match_len == 0) {
32276           /* empty match: advance to the next char */
32277           const char *next = utfnshift((s + lookup_idx), 1);
32278           lookup_idx += (next - (s + lookup_idx));
32279         } else {
32280           /* non-empty match: advance to the end of match */
32281           lookup_idx = ctx.match_end - s;
32282         }
32283 
32284         /*
32285          * always remember the end of the match, so that next time we will take
32286          * substring from that position
32287          */
32288         substr_idx = ctx.match_end - s;
32289       }
32290 
32291       /* add the last substring to the resulting array, if needed */
32292       if (elem < limit) {
32293         size_t substr_len = s_len - substr_idx;
32294         if (substr_len > 0 || last_match_len > 0) {
32295           rcode = v7_array_push_throwing(
32296               v7, *res, v7_mk_string(v7, s + substr_idx, substr_len, 1), NULL);
32297           if (rcode != V7_OK) {
32298             goto clean;
32299           }
32300         }
32301       }
32302     }
32303   }
32304 
32305 clean:
32306   return rcode;
32307 }
32308 
32309 V7_PRIVATE void init_string(struct v7 *v7) {
32310   val_t str = mk_cfunction_obj_with_proto(v7, String_ctor, 1,
32311                                           v7->vals.string_prototype);
32312   v7_def(v7, v7->vals.global_object, "String", 6, V7_DESC_ENUMERABLE(0), str);
32313 
32314   set_cfunc_prop(v7, str, "fromCharCode", Str_fromCharCode);
32315   set_cfunc_prop(v7, v7->vals.string_prototype, "charCodeAt", Str_charCodeAt);
32316   set_cfunc_prop(v7, v7->vals.string_prototype, "charAt", Str_charAt);
32317   set_cfunc_prop(v7, v7->vals.string_prototype, "concat", Str_concat);
32318   set_cfunc_prop(v7, v7->vals.string_prototype, "indexOf", Str_indexOf);
32319   set_cfunc_prop(v7, v7->vals.string_prototype, "substr", Str_substr);
32320   set_cfunc_prop(v7, v7->vals.string_prototype, "substring", Str_substring);
32321   set_cfunc_prop(v7, v7->vals.string_prototype, "valueOf", Str_valueOf);
32322   set_cfunc_prop(v7, v7->vals.string_prototype, "lastIndexOf", Str_lastIndexOf);
32323 #if V7_ENABLE__String__localeCompare
32324   set_cfunc_prop(v7, v7->vals.string_prototype, "localeCompare",
32325                  Str_localeCompare);
32326 #endif
32327 #if V7_ENABLE__RegExp
32328   set_cfunc_prop(v7, v7->vals.string_prototype, "match", Str_match);
32329   set_cfunc_prop(v7, v7->vals.string_prototype, "replace", Str_replace);
32330   set_cfunc_prop(v7, v7->vals.string_prototype, "search", Str_search);
32331 #endif
32332   set_cfunc_prop(v7, v7->vals.string_prototype, "split", Str_split);
32333   set_cfunc_prop(v7, v7->vals.string_prototype, "slice", Str_slice);
32334   set_cfunc_prop(v7, v7->vals.string_prototype, "trim", Str_trim);
32335   set_cfunc_prop(v7, v7->vals.string_prototype, "toLowerCase", Str_toLowerCase);
32336 #if V7_ENABLE__String__localeLowerCase
32337   set_cfunc_prop(v7, v7->vals.string_prototype, "toLocaleLowerCase",
32338                  Str_toLowerCase);
32339 #endif
32340   set_cfunc_prop(v7, v7->vals.string_prototype, "toUpperCase", Str_toUpperCase);
32341 #if V7_ENABLE__String__localeUpperCase
32342   set_cfunc_prop(v7, v7->vals.string_prototype, "toLocaleUpperCase",
32343                  Str_toUpperCase);
32344 #endif
32345   set_cfunc_prop(v7, v7->vals.string_prototype, "toString", Str_toString);
32346 
32347   v7_def(v7, v7->vals.string_prototype, "length", 6, V7_DESC_GETTER(1),
32348          v7_mk_cfunction(Str_length));
32349 
32350   /* Non-standard Cesanta extension */
32351   set_cfunc_prop(v7, v7->vals.string_prototype, "at", Str_at);
32352   v7_def(v7, v7->vals.string_prototype, "blen", 4, V7_DESC_GETTER(1),
32353          v7_mk_cfunction(Str_blen));
32354 }
32355 #ifdef V7_MODULE_LINES
32356 #line 1 "v7/src/std_date.c"
32357 #endif
32358 /*
32359  * Copyright (c) 2015 Cesanta Software Limited
32360  * All rights reserved
32361  */
32362 
32363 /* Amalgamated: #include "v7/src/internal.h" */
32364 /* Amalgamated: #include "common/str_util.h" */
32365 /* Amalgamated: #include "v7/src/std_object.h" */
32366 /* Amalgamated: #include "v7/src/core.h" */
32367 /* Amalgamated: #include "v7/src/util.h" */
32368 /* Amalgamated: #include "v7/src/function.h" */
32369 /* Amalgamated: #include "v7/src/object.h" */
32370 /* Amalgamated: #include "v7/src/conversion.h" */
32371 /* Amalgamated: #include "v7/src/exceptions.h" */
32372 /* Amalgamated: #include "v7/src/primitive.h" */
32373 /* Amalgamated: #include "v7/src/string.h" */
32374 
32375 #if V7_ENABLE__Date
32376 
32377 #include <locale.h>
32378 #include <time.h>
32379 
32380 #ifndef _WIN32
32381 extern long timezone;
32382 #include <sys/time.h>
32383 #endif
32384 
32385 #if defined(_MSC_VER)
32386 #define timezone _timezone
32387 #define tzname _tzname
32388 #if _MSC_VER >= 1800
32389 #define tzset _tzset
32390 #endif
32391 #endif
32392 
32393 #if defined(__cplusplus)
32394 extern "C" {
32395 #endif /* __cplusplus */
32396 
32397 typedef double etime_t; /* double is suitable type for ECMA time */
32398 /* inernally we have to use 64-bit integer for some operations */
32399 typedef int64_t etimeint_t;
32400 #define INVALID_TIME NAN
32401 
32402 #define msPerDay 86400000
32403 #define HoursPerDay 24
32404 #define MinutesPerHour 60
32405 #define SecondsPerMinute 60
32406 #define SecondsPerHour 3600
32407 #define msPerSecond 1000
32408 #define msPerMinute 60000
32409 #define msPerHour 3600000
32410 #define MonthsInYear 12
32411 
32412 /* ECMA alternative to struct tm */
32413 struct timeparts {
32414   int year;  /* can be negative, up to +-282000 */
32415   int month; /* 0-11 */
32416   int day;   /* 1-31 */
32417   int hour;  /* 0-23 */
32418   int min;   /* 0-59 */
32419   int sec;   /* 0-59 */
32420   int msec;
32421   int dayofweek; /* 0-6 */
32422 };
32423 
32424 static etimeint_t g_gmtoffms; /* timezone offset, ms, no DST */
32425 static const char *g_tzname;  /* current timezone name */
32426 
32427 /* Leap year formula copied from ECMA 5.1 standart as is */
32428 static int ecma_DaysInYear(int y) {
32429   if (y % 4 != 0) {
32430     return 365;
32431   } else if (y % 4 == 0 && y % 100 != 0) {
32432     return 366;
32433   } else if (y % 100 == 0 && y % 400 != 0) {
32434     return 365;
32435   } else if (y % 400 == 0) {
32436     return 366;
32437   } else {
32438     return 365;
32439   }
32440 }
32441 
32442 static etimeint_t ecma_DayFromYear(etimeint_t y) {
32443   return 365 * (y - 1970) + floor((y - 1969) / 4) - floor((y - 1901) / 100) +
32444          floor((y - 1601) / 400);
32445 }
32446 
32447 static etimeint_t ecma_TimeFromYear(etimeint_t y) {
32448   return msPerDay * ecma_DayFromYear(y);
32449 }
32450 
32451 static int ecma_IsLeapYear(int year) {
32452   return ecma_DaysInYear(year) == 366;
32453 }
32454 
32455 static int *ecma_getfirstdays(int isleap) {
32456   static int sdays[2][MonthsInYear + 1] = {
32457       {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
32458       {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
32459 
32460   return sdays[isleap];
32461 }
32462 
32463 static int ecma_DaylightSavingTA(etime_t t) {
32464   time_t time = t / 1000;
32465   /*
32466    * Win32 doesn't have locatime_r
32467    * nixes don't have localtime_s
32468    * as result using localtime
32469    */
32470   struct tm *tm = localtime(&time);
32471   if (tm == NULL) {
32472     /* doesn't work on windows for times before epoch */
32473     return 0;
32474   }
32475   if (tm->tm_isdst > 0) {
32476     return msPerHour;
32477   } else {
32478     return 0;
32479   }
32480 }
32481 
32482 static int ecma_LocalTZA(void) {
32483   return (int) -g_gmtoffms;
32484 }
32485 
32486 static etimeint_t ecma_UTC(etime_t t) {
32487   return t - ecma_LocalTZA() - ecma_DaylightSavingTA(t - ecma_LocalTZA());
32488 }
32489 
32490 #if V7_ENABLE__Date__toString || V7_ENABLE__Date__toLocaleString || \
32491     V7_ENABLE__Date__toJSON || V7_ENABLE__Date__getters ||          \
32492     V7_ENABLE__Date__setters
32493 static int ecma_YearFromTime_s(etime_t t) {
32494   int first = floor((t / msPerDay) / 366) + 1970,
32495       last = floor((t / msPerDay) / 365) + 1970, middle = 0;
32496 
32497   if (last < first) {
32498     int temp = first;
32499     first = last;
32500     last = temp;
32501   }
32502 
32503   while (last > first) {
32504     middle = (last + first) / 2;
32505     if (ecma_TimeFromYear(middle) > t) {
32506       last = middle - 1;
32507     } else {
32508       if (ecma_TimeFromYear(middle) <= t) {
32509         if (ecma_TimeFromYear(middle + 1) > t) {
32510           first = middle;
32511           break;
32512         }
32513         first = middle + 1;
32514       }
32515     }
32516   }
32517 
32518   return first;
32519 }
32520 
32521 static etimeint_t ecma_Day(etime_t t) {
32522   return floor(t / msPerDay);
32523 }
32524 
32525 static int ecma_DayWithinYear(etime_t t, int year) {
32526   return (int) (ecma_Day(t) - ecma_DayFromYear(year));
32527 }
32528 
32529 static int ecma_MonthFromTime(etime_t t, int year) {
32530   int *days, i;
32531   etimeint_t dwy = ecma_DayWithinYear(t, year);
32532 
32533   days = ecma_getfirstdays(ecma_IsLeapYear(year));
32534 
32535   for (i = 0; i < MonthsInYear; i++) {
32536     if (dwy >= days[i] && dwy < days[i + 1]) {
32537       return i;
32538     }
32539   }
32540 
32541   return -1;
32542 }
32543 
32544 static int ecma_DateFromTime(etime_t t, int year) {
32545   int *days, mft = ecma_MonthFromTime(t, year),
32546              dwy = ecma_DayWithinYear(t, year);
32547 
32548   if (mft > 11) {
32549     return -1;
32550   }
32551 
32552   days = ecma_getfirstdays(ecma_IsLeapYear(year));
32553 
32554   return dwy - days[mft] + 1;
32555 }
32556 
32557 #define DEF_EXTRACT_TIMEPART(funcname, c1, c2) \
32558   static int ecma_##funcname(etime_t t) {      \
32559     int ret = (etimeint_t) floor(t / c1) % c2; \
32560     if (ret < 0) {                             \
32561       ret += c2;                               \
32562     }                                          \
32563     return ret;                                \
32564   }
32565 
32566 DEF_EXTRACT_TIMEPART(HourFromTime, msPerHour, HoursPerDay)
32567 DEF_EXTRACT_TIMEPART(MinFromTime, msPerMinute, MinutesPerHour)
32568 DEF_EXTRACT_TIMEPART(SecFromTime, msPerSecond, SecondsPerMinute)
32569 DEF_EXTRACT_TIMEPART(msFromTime, 1, msPerSecond)
32570 
32571 static int ecma_WeekDay(etime_t t) {
32572   int ret = (ecma_Day(t) + 4) % 7;
32573   if (ret < 0) {
32574     ret += 7;
32575   }
32576 
32577   return ret;
32578 }
32579 
32580 static void d_gmtime(const etime_t *t, struct timeparts *tp) {
32581   tp->year = ecma_YearFromTime_s(*t);
32582   tp->month = ecma_MonthFromTime(*t, tp->year);
32583   tp->day = ecma_DateFromTime(*t, tp->year);
32584   tp->hour = ecma_HourFromTime(*t);
32585   tp->min = ecma_MinFromTime(*t);
32586   tp->sec = ecma_SecFromTime(*t);
32587   tp->msec = ecma_msFromTime(*t);
32588   tp->dayofweek = ecma_WeekDay(*t);
32589 }
32590 #endif /* V7_ENABLE__Date__toString || V7_ENABLE__Date__toLocaleString || \
32591           V7_ENABLE__Date__getters || V7_ENABLE__Date__setters */
32592 
32593 #if V7_ENABLE__Date__toString || V7_ENABLE__Date__toLocaleString || \
32594     V7_ENABLE__Date__getters || V7_ENABLE__Date__setters
32595 static etimeint_t ecma_LocalTime(etime_t t) {
32596   return t + ecma_LocalTZA() + ecma_DaylightSavingTA(t);
32597 }
32598 
32599 static void d_localtime(const etime_t *time, struct timeparts *tp) {
32600   etime_t local_time = ecma_LocalTime(*time);
32601   d_gmtime(&local_time, tp);
32602 }
32603 #endif
32604 
32605 static etimeint_t ecma_MakeTime(etimeint_t hour, etimeint_t min, etimeint_t sec,
32606                                 etimeint_t ms) {
32607   return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) *
32608              msPerSecond +
32609          ms;
32610 }
32611 
32612 static etimeint_t ecma_MakeDay(int year, int month, int date) {
32613   int *days;
32614   etimeint_t yday, mday;
32615 
32616   year += floor(month / 12);
32617   month = month % 12;
32618   yday = floor(ecma_TimeFromYear(year) / msPerDay);
32619   days = ecma_getfirstdays(ecma_IsLeapYear(year));
32620   mday = days[month];
32621 
32622   return yday + mday + date - 1;
32623 }
32624 
32625 static etimeint_t ecma_MakeDate(etimeint_t day, etimeint_t time) {
32626   return (day * msPerDay + time);
32627 }
32628 
32629 static void d_gettime(etime_t *t) {
32630 #ifndef _WIN32
32631   struct timeval tv;
32632   gettimeofday(&tv, NULL);
32633   *t = (etime_t) tv.tv_sec * 1000 + (etime_t) tv.tv_usec / 1000;
32634 #else
32635   /* TODO(mkm): use native windows API in order to get ms granularity */
32636   *t = time(NULL) * 1000.0;
32637 #endif
32638 }
32639 
32640 static etime_t d_mktime_impl(const struct timeparts *tp) {
32641   return ecma_MakeDate(ecma_MakeDay(tp->year, tp->month, tp->day),
32642                        ecma_MakeTime(tp->hour, tp->min, tp->sec, tp->msec));
32643 }
32644 
32645 #if V7_ENABLE__Date__setters
32646 static etime_t d_lmktime(const struct timeparts *tp) {
32647   return ecma_UTC(d_mktime_impl(tp));
32648 }
32649 #endif
32650 
32651 static etime_t d_gmktime(const struct timeparts *tp) {
32652   return d_mktime_impl(tp);
32653 }
32654 
32655 typedef etime_t (*fmaketime_t)(const struct timeparts *);
32656 typedef void (*fbreaktime_t)(const etime_t *, struct timeparts *);
32657 
32658 #if V7_ENABLE__Date__toString || V7_ENABLE__Date__toLocaleString || \
32659     V7_ENABLE__Date__toJSON
32660 static val_t d_trytogetobjforstring(struct v7 *v7, val_t obj) {
32661   enum v7_err rcode = V7_OK;
32662   val_t ret = V7_UNDEFINED;
32663 
32664   rcode = obj_value_of(v7, obj, &ret);
32665   if (rcode != V7_OK) {
32666     goto clean;
32667   }
32668 
32669   if (ret == V7_TAG_NAN) {
32670     rcode = v7_throwf(v7, TYPE_ERROR, "Date is invalid (for string)");
32671     goto clean;
32672   }
32673 
32674 clean:
32675   (void) rcode;
32676   return ret;
32677 }
32678 #endif
32679 
32680 #if V7_ENABLE__Date__parse || V7_ENABLE__Date__UTC
32681 static int d_iscalledasfunction(struct v7 *v7, val_t this_obj) {
32682   /* TODO(alashkin): verify this statement */
32683   return is_prototype_of(v7, this_obj, v7->vals.date_prototype);
32684 }
32685 #endif
32686 
32687 static const char *mon_name[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
32688                                  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
32689 
32690 int d_getnumbyname(const char **arr, int arr_size, const char *str) {
32691   int i;
32692   for (i = 0; i < arr_size; i++) {
32693     if (strncmp(arr[i], str, 3) == 0) {
32694       return i + 1;
32695     }
32696   }
32697 
32698   return -1;
32699 }
32700 
32701 int date_parse(const char *str, int *a1, int *a2, int *a3, char sep,
32702                char *rest) {
32703   char frmDate[] = " %d/%d/%d%[^\0]";
32704   frmDate[3] = frmDate[6] = sep;
32705   return sscanf(str, frmDate, a1, a2, a3, rest);
32706 }
32707 
32708 #define NO_TZ 0x7FFFFFFF
32709 
32710 /*
32711  * not very smart but simple, and working according
32712  * to ECMA5.1 StringToDate function
32713  */
32714 static int d_parsedatestr(const char *jstr, size_t len, struct timeparts *tp,
32715                           int *tz) {
32716   char gmt[4];
32717   char buf1[100] = {0}, buf2[100] = {0};
32718   int res = 0;
32719   char str[101];
32720   memcpy(str, jstr, len);
32721   str[len] = '\0';
32722   memset(tp, 0, sizeof(*tp));
32723   *tz = NO_TZ;
32724 
32725   /* trying toISOSrting() format */
32726   {
32727     const char *frmISOString = " %d-%02d-%02dT%02d:%02d:%02d.%03dZ";
32728     res = sscanf(str, frmISOString, &tp->year, &tp->month, &tp->day, &tp->hour,
32729                  &tp->min, &tp->sec, &tp->msec);
32730     if (res == 7) {
32731       *tz = 0;
32732       return 1;
32733     }
32734   }
32735 
32736   /* trying toString()/toUTCString()/toDateFormat() formats */
32737   {
32738     char month[4];
32739     int dowlen;
32740     const char *frmString = " %*s%n %03s %02d %d %02d:%02d:%02d %03s%d";
32741     res = sscanf(str, frmString, &dowlen, month, &tp->day, &tp->year, &tp->hour,
32742                  &tp->min, &tp->sec, gmt, tz);
32743     if ((res == 3 || (res >= 6 && res <= 8)) && dowlen == 3) {
32744       if ((tp->month = d_getnumbyname(mon_name, ARRAY_SIZE(mon_name), month)) !=
32745           -1) {
32746         if (res == 7 && strncmp(gmt, "GMT", 3) == 0) {
32747           *tz = 0;
32748         }
32749         return 1;
32750       }
32751     }
32752   }
32753 
32754   /* trying the rest */
32755 
32756   /* trying date */
32757 
32758   if (!(date_parse(str, &tp->month, &tp->day, &tp->year, '/', buf1) >= 3 ||
32759         date_parse(str, &tp->day, &tp->month, &tp->year, '.', buf1) >= 3 ||
32760         date_parse(str, &tp->year, &tp->month, &tp->day, '-', buf1) >= 3)) {
32761     return 0;
32762   }
32763 
32764   /*  there is date, trying time; from here return 0 only on errors */
32765 
32766   /* trying HH:mm */
32767   {
32768     const char *frmMMhh = " %d:%d%[^\0]";
32769     res = sscanf(buf1, frmMMhh, &tp->hour, &tp->min, buf2);
32770     /* can't get time, but have some symbols, assuming error */
32771     if (res < 2) {
32772       return (strlen(buf2) == 0);
32773     }
32774   }
32775 
32776   /* trying seconds */
32777   {
32778     const char *frmss = ":%d%[^\0]";
32779     memset(buf1, 0, sizeof(buf1));
32780     res = sscanf(buf2, frmss, &tp->sec, buf1);
32781   }
32782 
32783   /* even if we don't get seconds we gonna try to get tz */
32784   {
32785     char *rest = res ? buf1 : buf2;
32786     char *buf = res ? buf2 : buf1;
32787     const char *frmtz = " %03s%d%[^\0]";
32788 
32789     res = sscanf(rest, frmtz, gmt, tz, buf);
32790     if (res == 1 && strncmp(gmt, "GMT", 3) == 0) {
32791       *tz = 0;
32792     }
32793   }
32794 
32795   /* return OK if we are at the end of string */
32796   return res <= 2;
32797 }
32798 
32799 static int d_timeFromString(etime_t *time, const char *str, size_t str_len) {
32800   struct timeparts tp;
32801   int tz;
32802 
32803   *time = INVALID_TIME;
32804 
32805   if (str_len > 100) {
32806     /* too long for valid date string */
32807     return 0;
32808   }
32809 
32810   if (d_parsedatestr(str, str_len, &tp, &tz)) {
32811     /* check results */
32812     int valid = 0;
32813 
32814     tp.month--;
32815     valid = tp.day >= 1 && tp.day <= 31;
32816     valid &= tp.month >= 0 && tp.month <= 11;
32817     valid &= tp.hour >= 0 && tp.hour <= 23;
32818     valid &= tp.min >= 0 && tp.min <= 59;
32819     valid &= tp.sec >= 0 && tp.sec <= 59;
32820 
32821     if (tz != NO_TZ && tz > 12) {
32822       tz /= 100;
32823     }
32824 
32825     valid &= (abs(tz) <= 12 || tz == NO_TZ);
32826 
32827     if (valid) {
32828       *time = d_gmktime(&tp);
32829 
32830       if (tz != NO_TZ) {
32831         /* timezone specified, use it */
32832         *time -= (tz * msPerHour);
32833       } else if (tz != 0) {
32834         /* assuming local timezone and moving back to UTC */
32835         *time = ecma_UTC(*time);
32836       }
32837     }
32838   }
32839 
32840   return !isnan(*time);
32841 }
32842 
32843 /* notice: holding month in calendar format (1-12, not 0-11) */
32844 struct dtimepartsarr {
32845   etime_t args[7];
32846 };
32847 
32848 enum detimepartsarr {
32849   tpyear = 0,
32850   tpmonth,
32851   tpdate,
32852   tphours,
32853   tpminutes,
32854   tpseconds,
32855   tpmsec,
32856   tpmax
32857 };
32858 
32859 static etime_t d_changepartoftime(const etime_t *current,
32860                                   struct dtimepartsarr *a,
32861                                   fbreaktime_t breaktimefunc,
32862                                   fmaketime_t maketimefunc) {
32863   /*
32864    * 0 = year, 1 = month , 2 = date , 3 = hours,
32865    * 4 = minutes, 5 = seconds, 6 = ms
32866    */
32867   struct timeparts tp;
32868   unsigned long i;
32869   int *tp_arr[7];
32870   /*
32871    * C89 doesn't allow initialization
32872    * like x = {&tp.year, &tp.month, .... }
32873    */
32874   tp_arr[0] = &tp.year;
32875   tp_arr[1] = &tp.month;
32876   tp_arr[2] = &tp.day;
32877   tp_arr[3] = &tp.hour;
32878   tp_arr[4] = &tp.min;
32879   tp_arr[5] = &tp.sec;
32880   tp_arr[6] = &tp.msec;
32881 
32882   memset(&tp, 0, sizeof(tp));
32883 
32884   if (breaktimefunc != NULL) {
32885     breaktimefunc(current, &tp);
32886   }
32887 
32888   for (i = 0; i < ARRAY_SIZE(tp_arr); i++) {
32889     if (!isnan(a->args[i]) && !isinf(a->args[i])) {
32890       *tp_arr[i] = (int) a->args[i];
32891     }
32892   }
32893 
32894   return maketimefunc(&tp);
32895 }
32896 
32897 #if V7_ENABLE__Date__setters || V7_ENABLE__Date__UTC
32898 static etime_t d_time_number_from_arr(struct v7 *v7, int start_pos,
32899                                       fbreaktime_t breaktimefunc,
32900                                       fmaketime_t maketimefunc) {
32901   enum v7_err rcode = V7_OK;
32902   val_t this_obj = v7_get_this(v7);
32903   etime_t ret_time = INVALID_TIME;
32904   long cargs;
32905 
32906   val_t objtime = V7_UNDEFINED;
32907   rcode = obj_value_of(v7, this_obj, &objtime);
32908   if (rcode != V7_OK) {
32909     goto clean;
32910   }
32911 
32912   if ((cargs = v7_argc(v7)) >= 1 && objtime != V7_TAG_NAN) {
32913     int i;
32914     etime_t new_part = INVALID_TIME;
32915     struct dtimepartsarr a;
32916     for (i = 0; i < 7; i++) {
32917       a.args[i] = INVALID_TIME;
32918     }
32919 
32920     for (i = 0; i < cargs && (i + start_pos < tpmax); i++) {
32921       {
32922         val_t arg = v7_arg(v7, i);
32923         rcode = to_number_v(v7, arg, &arg);
32924         if (rcode != V7_OK) {
32925           goto clean;
32926         }
32927         new_part = v7_get_double(v7, arg);
32928       }
32929 
32930       if (isnan(new_part)) {
32931         break;
32932       }
32933 
32934       a.args[i + start_pos] = new_part;
32935     }
32936 
32937     if (!isnan(new_part)) {
32938       etime_t current_time = v7_get_double(v7, objtime);
32939       ret_time =
32940           d_changepartoftime(&current_time, &a, breaktimefunc, maketimefunc);
32941     }
32942   }
32943 
32944 clean:
32945   (void) rcode;
32946   return ret_time;
32947 }
32948 #endif /* V7_ENABLE__Date__setters */
32949 
32950 #if V7_ENABLE__Date__toString
32951 static int d_tptostr(const struct timeparts *tp, char *buf, int addtz);
32952 #endif
32953 
32954 /* constructor */
32955 WARN_UNUSED_RESULT
32956 V7_PRIVATE enum v7_err Date_ctor(struct v7 *v7, v7_val_t *res) {
32957   enum v7_err rcode = V7_OK;
32958   val_t this_obj = v7_get_this(v7);
32959   etime_t ret_time = INVALID_TIME;
32960   if (v7_is_generic_object(this_obj) && this_obj != v7->vals.global_object) {
32961     long cargs = v7_argc(v7);
32962     if (cargs <= 0) {
32963       /* no parameters - return current date & time */
32964       d_gettime(&ret_time);
32965     } else if (cargs == 1) {
32966       /* one parameter */
32967       val_t arg = v7_arg(v7, 0);
32968       if (v7_is_string(arg)) { /* it could be string */
32969         size_t str_size;
32970         const char *str = v7_get_string(v7, &arg, &str_size);
32971         d_timeFromString(&ret_time, str, str_size);
32972       }
32973       if (isnan(ret_time)) {
32974         /*
32975          * if cannot be parsed or
32976          * not string at all - trying to convert to number
32977          */
32978         ret_time = 0;
32979         rcode = to_number_v(v7, arg, &arg);
32980         if (rcode != V7_OK) {
32981           goto clean;
32982         }
32983         ret_time = v7_get_double(v7, arg);
32984         if (rcode != V7_OK) {
32985           goto clean;
32986         }
32987       }
32988     } else {
32989       /* 2+ paramaters - should be parts of a date */
32990       struct dtimepartsarr a;
32991       int i;
32992 
32993       memset(&a, 0, sizeof(a));
32994 
32995       for (i = 0; i < cargs; i++) {
32996         val_t arg = v7_arg(v7, i);
32997         rcode = to_number_v(v7, arg, &arg);
32998         if (rcode != V7_OK) {
32999           goto clean;
33000         }
33001         a.args[i] = v7_get_double(v7, arg);
33002         if (isnan(a.args[i])) {
33003           break;
33004         }
33005       }
33006 
33007       if (i >= cargs) {
33008         /*
33009          * If date is supplied then let
33010          * dt be ToNumber(date); else let dt be 1.
33011          */
33012         if (a.args[tpdate] == 0) {
33013           a.args[tpdate] = 1;
33014         }
33015 
33016         if (a.args[tpyear] >= 0 && a.args[tpyear] <= 99) {
33017           /*
33018            * If y is not NaN and 0 <= ToInteger(y) <= 99,
33019            * then let yr be 1900+ToInteger(y); otherwise, let yr be y.
33020            */
33021           a.args[tpyear] += 1900;
33022         }
33023 
33024         ret_time = ecma_UTC(d_changepartoftime(0, &a, 0, d_gmktime));
33025       }
33026     }
33027 
33028     obj_prototype_set(v7, get_object_struct(this_obj),
33029                       get_object_struct(v7->vals.date_prototype));
33030 
33031     v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), v7_mk_number(v7, ret_time));
33032     /*
33033      * implicitly returning `this`: `call_cfunction()` in bcode.c will do
33034      * that for us
33035      */
33036     goto clean;
33037   } else {
33038     /*
33039      * according to 15.9.2.1 we should ignore all
33040      * parameters in case of function-call
33041      */
33042     char buf[50];
33043     int len;
33044 
33045 #if V7_ENABLE__Date__toString
33046     struct timeparts tp;
33047     d_gettime(&ret_time);
33048     d_localtime(&ret_time, &tp);
33049     len = d_tptostr(&tp, buf, 1);
33050 #else
33051     len = 0;
33052 #endif /* V7_ENABLE__Date__toString */
33053 
33054     *res = v7_mk_string(v7, buf, len, 1);
33055     goto clean;
33056   }
33057 
33058 clean:
33059   return rcode;
33060 }
33061 
33062 #if V7_ENABLE__Date__toString || V7_ENABLE__Date__toJSON
33063 static int d_timetoISOstr(const etime_t *time, char *buf, size_t buf_size) {
33064   /* ISO format: "+XXYYYY-MM-DDTHH:mm:ss.sssZ"; */
33065   struct timeparts tp;
33066   char use_ext = 0;
33067   const char *ey_frm = "%06d-%02d-%02dT%02d:%02d:%02d.%03dZ";
33068   const char *simpl_frm = "%d-%02d-%02dT%02d:%02d:%02d.%03dZ";
33069 
33070   d_gmtime(time, &tp);
33071 
33072   if (abs(tp.year) > 9999 || tp.year < 0) {
33073     *buf = (tp.year > 0) ? '+' : '-';
33074     use_ext = 1;
33075   }
33076 
33077   return c_snprintf(buf + use_ext, buf_size - use_ext,
33078                     use_ext ? ey_frm : simpl_frm, abs(tp.year), tp.month + 1,
33079                     tp.day, tp.hour, tp.min, tp.sec, tp.msec) +
33080          use_ext;
33081 }
33082 
33083 WARN_UNUSED_RESULT
33084 V7_PRIVATE enum v7_err Date_toISOString(struct v7 *v7, v7_val_t *res) {
33085   enum v7_err rcode = V7_OK;
33086   val_t this_obj = v7_get_this(v7);
33087   char buf[30];
33088   etime_t time;
33089   int len;
33090 
33091   if (val_type(v7, this_obj) != V7_TYPE_DATE_OBJECT) {
33092     rcode = v7_throwf(v7, TYPE_ERROR, "This is not a Date object");
33093     goto clean;
33094   }
33095 
33096   time = v7_get_double(v7, d_trytogetobjforstring(v7, this_obj));
33097   len = d_timetoISOstr(&time, buf, sizeof(buf));
33098   if (len > (int) (sizeof(buf) - 1 /*null-term*/)) {
33099     len = (int) (sizeof(buf) - 1 /*null-term*/);
33100   }
33101 
33102   *res = v7_mk_string(v7, buf, len, 1);
33103 
33104 clean:
33105   return rcode;
33106 }
33107 #endif /* V7_ENABLE__Date__toString || V7_ENABLE__Date__toJSON */
33108 
33109 #if V7_ENABLE__Date__toString
33110 typedef int (*ftostring_t)(const struct timeparts *, char *, int);
33111 
33112 WARN_UNUSED_RESULT
33113 static enum v7_err d_tostring(struct v7 *v7, val_t obj,
33114                               fbreaktime_t breaktimefunc,
33115                               ftostring_t tostringfunc, int addtz,
33116                               v7_val_t *res) {
33117   enum v7_err rcode = V7_OK;
33118   struct timeparts tp;
33119   int len;
33120   char buf[100];
33121   etime_t time;
33122 
33123   time = v7_get_double(v7, d_trytogetobjforstring(v7, obj));
33124 
33125   breaktimefunc(&time, &tp);
33126   len = tostringfunc(&tp, buf, addtz);
33127 
33128   *res = v7_mk_string(v7, buf, len, 1);
33129   return rcode;
33130 }
33131 
33132 /* using macros to avoid copy-paste technic */
33133 #define DEF_TOSTR(funcname, breaktimefunc, tostrfunc, addtz)               \
33134   WARN_UNUSED_RESULT                                                       \
33135   V7_PRIVATE enum v7_err Date_to##funcname(struct v7 *v7, v7_val_t *res) { \
33136     val_t this_obj = v7_get_this(v7);                                      \
33137     return d_tostring(v7, this_obj, breaktimefunc, tostrfunc, addtz, res); \
33138   }
33139 
33140 /* non-locale function should always return in english and 24h-format */
33141 static const char *wday_name[] = {"Sun", "Mon", "Tue", "Wed",
33142                                   "Thu", "Fri", "Sat"};
33143 
33144 static int d_tptodatestr(const struct timeparts *tp, char *buf, int addtz) {
33145   (void) addtz;
33146 
33147   return sprintf(buf, "%s %s %02d %d", wday_name[tp->dayofweek],
33148                  mon_name[tp->month], tp->day, tp->year);
33149 }
33150 
33151 DEF_TOSTR(DateString, d_localtime, d_tptodatestr, 1)
33152 
33153 static const char *d_gettzname(void) {
33154   return g_tzname;
33155 }
33156 
33157 static int d_tptotimestr(const struct timeparts *tp, char *buf, int addtz) {
33158   int len;
33159 
33160   len = sprintf(buf, "%02d:%02d:%02d GMT", tp->hour, tp->min, tp->sec);
33161 
33162   if (addtz && g_gmtoffms != 0) {
33163     len = sprintf(buf + len, "%c%02d00 (%s)", g_gmtoffms > 0 ? '-' : '+',
33164                   abs((int) g_gmtoffms / msPerHour), d_gettzname());
33165   }
33166 
33167   return (int) strlen(buf);
33168 }
33169 
33170 DEF_TOSTR(TimeString, d_localtime, d_tptotimestr, 1)
33171 
33172 static int d_tptostr(const struct timeparts *tp, char *buf, int addtz) {
33173   int len = d_tptodatestr(tp, buf, addtz);
33174   *(buf + len) = ' ';
33175   return d_tptotimestr(tp, buf + len + 1, addtz) + len + 1;
33176 }
33177 
33178 DEF_TOSTR(String, d_localtime, d_tptostr, 1)
33179 DEF_TOSTR(UTCString, d_gmtime, d_tptostr, 0)
33180 #endif /* V7_ENABLE__Date__toString */
33181 
33182 #if V7_ENABLE__Date__toLocaleString
33183 struct d_locale {
33184   char locale[50];
33185 };
33186 
33187 static void d_getcurrentlocale(struct d_locale *loc) {
33188   strcpy(loc->locale, setlocale(LC_TIME, 0));
33189 }
33190 
33191 static void d_setlocale(const struct d_locale *loc) {
33192   setlocale(LC_TIME, loc ? loc->locale : "");
33193 }
33194 
33195 /* TODO(alashkin): check portability */
33196 WARN_UNUSED_RESULT
33197 static enum v7_err d_tolocalestr(struct v7 *v7, val_t obj, const char *frm,
33198                                  v7_val_t *res) {
33199   enum v7_err rcode = V7_OK;
33200   char buf[250];
33201   size_t len;
33202   struct tm t;
33203   etime_t time;
33204   struct d_locale prev_locale;
33205   struct timeparts tp;
33206 
33207   time = v7_get_double(v7, d_trytogetobjforstring(v7, obj));
33208 
33209   d_getcurrentlocale(&prev_locale);
33210   d_setlocale(0);
33211   d_localtime(&time, &tp);
33212 
33213   memset(&t, 0, sizeof(t));
33214   t.tm_year = tp.year - 1900;
33215   t.tm_mon = tp.month;
33216   t.tm_mday = tp.day;
33217   t.tm_hour = tp.hour;
33218   t.tm_min = tp.min;
33219   t.tm_sec = tp.sec;
33220   t.tm_wday = tp.dayofweek;
33221 
33222   len = strftime(buf, sizeof(buf), frm, &t);
33223 
33224   d_setlocale(&prev_locale);
33225 
33226   *res = v7_mk_string(v7, buf, len, 1);
33227   return rcode;
33228 }
33229 
33230 #define DEF_TOLOCALESTR(funcname, frm)                                     \
33231   WARN_UNUSED_RESULT                                                       \
33232   V7_PRIVATE enum v7_err Date_to##funcname(struct v7 *v7, v7_val_t *res) { \
33233     val_t this_obj = v7_get_this(v7);                                      \
33234     return d_tolocalestr(v7, this_obj, frm, res);                          \
33235   }
33236 
33237 DEF_TOLOCALESTR(LocaleString, "%c")
33238 DEF_TOLOCALESTR(LocaleDateString, "%x")
33239 DEF_TOLOCALESTR(LocaleTimeString, "%X")
33240 #endif /* V7_ENABLE__Date__toLocaleString */
33241 
33242 WARN_UNUSED_RESULT
33243 V7_PRIVATE enum v7_err Date_valueOf(struct v7 *v7, v7_val_t *res) {
33244   enum v7_err rcode = V7_OK;
33245   val_t this_obj = v7_get_this(v7);
33246   if (!v7_is_generic_object(this_obj) ||
33247       (v7_is_generic_object(this_obj) &&
33248        v7_get_proto(v7, this_obj) != v7->vals.date_prototype)) {
33249     rcode = v7_throwf(v7, TYPE_ERROR, "Date.valueOf called on non-Date object");
33250     goto clean;
33251   }
33252 
33253   rcode = Obj_valueOf(v7, res);
33254   if (rcode != V7_OK) {
33255     goto clean;
33256   }
33257 
33258 clean:
33259   return rcode;
33260 }
33261 
33262 #if V7_ENABLE__Date__getters
33263 static struct timeparts *d_getTimePart(struct v7 *v7, val_t val,
33264                                        struct timeparts *tp,
33265                                        fbreaktime_t breaktimefunc) {
33266   etime_t time;
33267   time = v7_get_double(v7, val);
33268   breaktimefunc(&time, tp);
33269   return tp;
33270 }
33271 
33272 #define DEF_GET_TP_FUNC(funcName, tpmember, breaktimefunc)                   \
33273   WARN_UNUSED_RESULT                                                         \
33274   V7_PRIVATE enum v7_err Date_get##funcName(struct v7 *v7, v7_val_t *res) {  \
33275     enum v7_err rcode = V7_OK;                                               \
33276     val_t v = V7_UNDEFINED;                                                  \
33277     struct timeparts tp;                                                     \
33278     val_t this_obj = v7_get_this(v7);                                        \
33279                                                                              \
33280     rcode = obj_value_of(v7, this_obj, &v);                                  \
33281     if (rcode != V7_OK) {                                                    \
33282       goto clean;                                                            \
33283     }                                                                        \
33284     *res = v7_mk_number(                                                     \
33285         v7, v == V7_TAG_NAN ? NAN : d_getTimePart(v7, v, &tp, breaktimefunc) \
33286                                         ->tpmember);                         \
33287   clean:                                                                     \
33288     return rcode;                                                            \
33289   }
33290 
33291 #define DEF_GET_TP(funcName, tpmember)               \
33292   DEF_GET_TP_FUNC(UTC##funcName, tpmember, d_gmtime) \
33293   DEF_GET_TP_FUNC(funcName, tpmember, d_localtime)
33294 
33295 DEF_GET_TP(Date, day)
33296 DEF_GET_TP(FullYear, year)
33297 DEF_GET_TP(Month, month)
33298 DEF_GET_TP(Hours, hour)
33299 DEF_GET_TP(Minutes, min)
33300 DEF_GET_TP(Seconds, sec)
33301 DEF_GET_TP(Milliseconds, msec)
33302 DEF_GET_TP(Day, dayofweek)
33303 
33304 WARN_UNUSED_RESULT
33305 V7_PRIVATE enum v7_err Date_getTime(struct v7 *v7, v7_val_t *res) {
33306   return Date_valueOf(v7, res);
33307 }
33308 
33309 WARN_UNUSED_RESULT
33310 V7_PRIVATE enum v7_err Date_getTimezoneOffset(struct v7 *v7, v7_val_t *res) {
33311   (void) v7;
33312   *res = v7_mk_number(v7, g_gmtoffms / msPerMinute);
33313   return V7_OK;
33314 }
33315 #endif /* V7_ENABLE__Date__getters */
33316 
33317 #if V7_ENABLE__Date__setters
33318 WARN_UNUSED_RESULT
33319 static enum v7_err d_setTimePart(struct v7 *v7, int start_pos,
33320                                  fbreaktime_t breaktimefunc,
33321                                  fmaketime_t maketimefunc, v7_val_t *res) {
33322   enum v7_err rcode = V7_OK;
33323   val_t this_obj = v7_get_this(v7);
33324   etime_t ret_time =
33325       d_time_number_from_arr(v7, start_pos, breaktimefunc, maketimefunc);
33326 
33327   *res = v7_mk_number(v7, ret_time);
33328   v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), *res);
33329 
33330   return rcode;
33331 }
33332 
33333 #define DEF_SET_TP(name, start_pos)                                        \
33334   WARN_UNUSED_RESULT                                                       \
33335   V7_PRIVATE enum v7_err Date_setUTC##name(struct v7 *v7, v7_val_t *res) { \
33336     return d_setTimePart(v7, start_pos, d_gmtime, d_gmktime, res);         \
33337   }                                                                        \
33338   WARN_UNUSED_RESULT                                                       \
33339   V7_PRIVATE enum v7_err Date_set##name(struct v7 *v7, v7_val_t *res) {    \
33340     return d_setTimePart(v7, start_pos, d_localtime, d_lmktime, res);      \
33341   }
33342 
33343 DEF_SET_TP(Milliseconds, tpmsec)
33344 DEF_SET_TP(Seconds, tpseconds)
33345 DEF_SET_TP(Minutes, tpminutes)
33346 DEF_SET_TP(Hours, tphours)
33347 DEF_SET_TP(Date, tpdate)
33348 DEF_SET_TP(Month, tpmonth)
33349 DEF_SET_TP(FullYear, tpyear)
33350 
33351 WARN_UNUSED_RESULT
33352 V7_PRIVATE enum v7_err Date_setTime(struct v7 *v7, v7_val_t *res) {
33353   enum v7_err rcode = V7_OK;
33354   val_t this_obj = v7_get_this(v7);
33355 
33356   if (v7_argc(v7) >= 1) {
33357     rcode = to_number_v(v7, v7_arg(v7, 0), res);
33358     if (rcode != V7_OK) {
33359       goto clean;
33360     }
33361   }
33362 
33363   v7_def(v7, this_obj, "", 0, _V7_DESC_HIDDEN(1), *res);
33364 
33365 clean:
33366   return rcode;
33367 }
33368 #endif /* V7_ENABLE__Date__setters */
33369 
33370 #if V7_ENABLE__Date__toJSON
33371 WARN_UNUSED_RESULT
33372 V7_PRIVATE enum v7_err Date_toJSON(struct v7 *v7, v7_val_t *res) {
33373   return Date_toISOString(v7, res);
33374 }
33375 #endif /* V7_ENABLE__Date__toJSON */
33376 
33377 #if V7_ENABLE__Date__now
33378 WARN_UNUSED_RESULT
33379 V7_PRIVATE enum v7_err Date_now(struct v7 *v7, v7_val_t *res) {
33380   etime_t ret_time;
33381   (void) v7;
33382 
33383   d_gettime(&ret_time);
33384 
33385   *res = v7_mk_number(v7, ret_time);
33386   return V7_OK;
33387 }
33388 #endif /* V7_ENABLE__Date__now */
33389 
33390 #if V7_ENABLE__Date__parse
33391 WARN_UNUSED_RESULT
33392 V7_PRIVATE enum v7_err Date_parse(struct v7 *v7, v7_val_t *res) {
33393   enum v7_err rcode = V7_OK;
33394   val_t this_obj = v7_get_this(v7);
33395   etime_t ret_time = INVALID_TIME;
33396 
33397   if (!d_iscalledasfunction(v7, this_obj)) {
33398     rcode = v7_throwf(v7, TYPE_ERROR, "Date.parse() called on object");
33399     goto clean;
33400   }
33401 
33402   if (v7_argc(v7) >= 1) {
33403     val_t arg0 = v7_arg(v7, 0);
33404     if (v7_is_string(arg0)) {
33405       size_t size;
33406       const char *time_str = v7_get_string(v7, &arg0, &size);
33407 
33408       d_timeFromString(&ret_time, time_str, size);
33409     }
33410   }
33411 
33412   *res = v7_mk_number(v7, ret_time);
33413 
33414 clean:
33415   return rcode;
33416 }
33417 #endif /* V7_ENABLE__Date__parse */
33418 
33419 #if V7_ENABLE__Date__UTC
33420 WARN_UNUSED_RESULT
33421 V7_PRIVATE enum v7_err Date_UTC(struct v7 *v7, v7_val_t *res) {
33422   enum v7_err rcode = V7_OK;
33423   val_t this_obj = v7_get_this(v7);
33424   etime_t ret_time;
33425 
33426   if (!d_iscalledasfunction(v7, this_obj)) {
33427     rcode = v7_throwf(v7, TYPE_ERROR, "Date.now() called on object");
33428     goto clean;
33429   }
33430 
33431   ret_time = d_time_number_from_arr(v7, tpyear, 0, d_gmktime);
33432   *res = v7_mk_number(v7, ret_time);
33433 
33434 clean:
33435   return rcode;
33436 }
33437 #endif /* V7_ENABLE__Date__UTC */
33438 
33439 /****** Initialization *******/
33440 
33441 /*
33442  * We should clear V7_PROPERTY_ENUMERABLE for all Date props
33443  * TODO(mkm): check other objects
33444 */
33445 static int d_set_cfunc_prop(struct v7 *v7, val_t o, const char *name,
33446                             v7_cfunction_t *f) {
33447   return v7_def(v7, o, name, strlen(name), V7_DESC_ENUMERABLE(0),
33448                 v7_mk_cfunction(f));
33449 }
33450 
33451 #define DECLARE_GET(func)                                       \
33452   d_set_cfunc_prop(v7, v7->vals.date_prototype, "getUTC" #func, \
33453                    Date_getUTC##func);                          \
33454   d_set_cfunc_prop(v7, v7->vals.date_prototype, "get" #func, Date_get##func);
33455 
33456 #define DECLARE_SET(func)                                       \
33457   d_set_cfunc_prop(v7, v7->vals.date_prototype, "setUTC" #func, \
33458                    Date_setUTC##func);                          \
33459   d_set_cfunc_prop(v7, v7->vals.date_prototype, "set" #func, Date_set##func);
33460 
33461 V7_PRIVATE void init_date(struct v7 *v7) {
33462   val_t date =
33463       mk_cfunction_obj_with_proto(v7, Date_ctor, 7, v7->vals.date_prototype);
33464   v7_def(v7, v7->vals.global_object, "Date", 4, V7_DESC_ENUMERABLE(0), date);
33465   d_set_cfunc_prop(v7, v7->vals.date_prototype, "valueOf", Date_valueOf);
33466 
33467 #if V7_ENABLE__Date__getters
33468   DECLARE_GET(Date);
33469   DECLARE_GET(FullYear);
33470   DECLARE_GET(Month);
33471   DECLARE_GET(Hours);
33472   DECLARE_GET(Minutes);
33473   DECLARE_GET(Seconds);
33474   DECLARE_GET(Milliseconds);
33475   DECLARE_GET(Day);
33476   d_set_cfunc_prop(v7, v7->vals.date_prototype, "getTime", Date_getTime);
33477 #endif
33478 
33479 #if V7_ENABLE__Date__setters
33480   DECLARE_SET(Date);
33481   DECLARE_SET(FullYear);
33482   DECLARE_SET(Month);
33483   DECLARE_SET(Hours);
33484   DECLARE_SET(Minutes);
33485   DECLARE_SET(Seconds);
33486   DECLARE_SET(Milliseconds);
33487   d_set_cfunc_prop(v7, v7->vals.date_prototype, "setTime", Date_setTime);
33488   d_set_cfunc_prop(v7, v7->vals.date_prototype, "getTimezoneOffset",
33489                    Date_getTimezoneOffset);
33490 #endif
33491 
33492 #if V7_ENABLE__Date__now
33493   d_set_cfunc_prop(v7, date, "now", Date_now);
33494 #endif
33495 #if V7_ENABLE__Date__parse
33496   d_set_cfunc_prop(v7, date, "parse", Date_parse);
33497 #endif
33498 #if V7_ENABLE__Date__UTC
33499   d_set_cfunc_prop(v7, date, "UTC", Date_UTC);
33500 #endif
33501 
33502 #if V7_ENABLE__Date__toString
33503   d_set_cfunc_prop(v7, v7->vals.date_prototype, "toString", Date_toString);
33504   d_set_cfunc_prop(v7, v7->vals.date_prototype, "toISOString",
33505                    Date_toISOString);
33506   d_set_cfunc_prop(v7, v7->vals.date_prototype, "toUTCString",
33507                    Date_toUTCString);
33508   d_set_cfunc_prop(v7, v7->vals.date_prototype, "toDateString",
33509                    Date_toDateString);
33510   d_set_cfunc_prop(v7, v7->vals.date_prototype, "toTimeString",
33511                    Date_toTimeString);
33512 #endif
33513 #if V7_ENABLE__Date__toLocaleString
33514   d_set_cfunc_prop(v7, v7->vals.date_prototype, "toLocaleString",
33515                    Date_toLocaleString);
33516   d_set_cfunc_prop(v7, v7->vals.date_prototype, "toLocaleDateString",
33517                    Date_toLocaleDateString);
33518   d_set_cfunc_prop(v7, v7->vals.date_prototype, "toLocaleTimeString",
33519                    Date_toLocaleTimeString);
33520 #endif
33521 #if V7_ENABLE__Date__toJSON
33522   d_set_cfunc_prop(v7, v7->vals.date_prototype, "toJSON", Date_toJSON);
33523 #endif
33524 
33525   /*
33526    * GTM offset without DST
33527    * TODO(alashkin): check this
33528    * Could be changed to tm::tm_gmtoff,
33529    * but tm_gmtoff includes DST, so
33530    * side effects are possible
33531    */
33532   tzset();
33533   g_gmtoffms = timezone * msPerSecond;
33534   /*
33535    * tzname could be changed by localtime_r call,
33536    * so we have to store pointer
33537    * TODO(alashkin): need restart on tz change???
33538    */
33539   g_tzname = tzname[0];
33540 }
33541 
33542 #if defined(__cplusplus)
33543 }
33544 #endif /* __cplusplus */
33545 
33546 #endif /* V7_ENABLE__Date */
33547 #ifdef V7_MODULE_LINES
33548 #line 1 "v7/src/std_function.c"
33549 #endif
33550 /*
33551  * Copyright (c) 2014 Cesanta Software Limited
33552  * All rights reserved
33553  */
33554 
33555 /* Amalgamated: #include "common/str_util.h" */
33556 /* Amalgamated: #include "v7/src/internal.h" */
33557 /* Amalgamated: #include "v7/src/core.h" */
33558 /* Amalgamated: #include "v7/src/function.h" */
33559 /* Amalgamated: #include "v7/src/bcode.h" */
33560 /* Amalgamated: #include "v7/src/eval.h" */
33561 /* Amalgamated: #include "v7/src/conversion.h" */
33562 /* Amalgamated: #include "v7/src/object.h" */
33563 /* Amalgamated: #include "v7/src/exec.h" */
33564 /* Amalgamated: #include "v7/src/exceptions.h" */
33565 
33566 #if defined(__cplusplus)
33567 extern "C" {
33568 #endif /* __cplusplus */
33569 
33570 WARN_UNUSED_RESULT
33571 V7_PRIVATE enum v7_err Function_ctor(struct v7 *v7, v7_val_t *res) {
33572   enum v7_err rcode = V7_OK;
33573   long i, num_args = v7_argc(v7);
33574   size_t size;
33575   const char *s;
33576   struct mbuf m;
33577 
33578   mbuf_init(&m, 0);
33579 
33580   if (num_args <= 0) {
33581     goto clean;
33582   }
33583 
33584   mbuf_append(&m, "(function(", 10);
33585 
33586   for (i = 0; i < num_args - 1; i++) {
33587     rcode = obj_value_of(v7, v7_arg(v7, i), res);
33588     if (rcode != V7_OK) {
33589       goto clean;
33590     }
33591     if (v7_is_string(*res)) {
33592       if (i > 0) mbuf_append(&m, ",", 1);
33593       s = v7_get_string(v7, res, &size);
33594       mbuf_append(&m, s, size);
33595     }
33596   }
33597   mbuf_append(&m, "){", 2);
33598   rcode = obj_value_of(v7, v7_arg(v7, num_args - 1), res);
33599   if (rcode != V7_OK) {
33600     goto clean;
33601   }
33602   if (v7_is_string(*res)) {
33603     s = v7_get_string(v7, res, &size);
33604     mbuf_append(&m, s, size);
33605   }
33606   mbuf_append(&m, "})\0", 3);
33607 
33608   rcode = v7_exec(v7, m.buf, res);
33609   if (rcode != V7_OK) {
33610     rcode = v7_throwf(v7, SYNTAX_ERROR, "Invalid function body");
33611     goto clean;
33612   }
33613 
33614 clean:
33615   mbuf_free(&m);
33616   return rcode;
33617 }
33618 
33619 WARN_UNUSED_RESULT
33620 V7_PRIVATE enum v7_err Function_length(struct v7 *v7, v7_val_t *res) {
33621   enum v7_err rcode = V7_OK;
33622   v7_val_t this_obj = v7_get_this(v7);
33623   struct v7_js_function *func;
33624 
33625   rcode = obj_value_of(v7, this_obj, &this_obj);
33626   if (rcode != V7_OK) {
33627     goto clean;
33628   }
33629   if (!is_js_function(this_obj)) {
33630     *res = v7_mk_number(v7, 0);
33631     goto clean;
33632   }
33633 
33634   func = get_js_function_struct(this_obj);
33635 
33636   *res = v7_mk_number(v7, func->bcode->args_cnt);
33637 
33638 clean:
33639   return rcode;
33640 }
33641 
33642 WARN_UNUSED_RESULT
33643 V7_PRIVATE enum v7_err Function_name(struct v7 *v7, v7_val_t *res) {
33644   enum v7_err rcode = V7_OK;
33645   v7_val_t this_obj = v7_get_this(v7);
33646   struct v7_js_function *func;
33647 
33648   rcode = obj_value_of(v7, this_obj, &this_obj);
33649   if (rcode != V7_OK) {
33650     goto clean;
33651   }
33652   if (!is_js_function(this_obj)) {
33653     goto clean;
33654   }
33655 
33656   func = get_js_function_struct(this_obj);
33657 
33658   assert(func->bcode != NULL);
33659 
33660   assert(func->bcode->names_cnt >= 1);
33661   bcode_next_name_v(v7, func->bcode, func->bcode->ops.p, res);
33662 
33663 clean:
33664   return rcode;
33665 }
33666 
33667 WARN_UNUSED_RESULT
33668 V7_PRIVATE enum v7_err Function_apply(struct v7 *v7, v7_val_t *res) {
33669   enum v7_err rcode = V7_OK;
33670   val_t this_obj = v7_get_this(v7);
33671   val_t this_arg = v7_arg(v7, 0);
33672   val_t func_args = v7_arg(v7, 1);
33673 
33674   rcode = obj_value_of(v7, this_obj, &this_obj);
33675   if (rcode != V7_OK) {
33676     goto clean;
33677   }
33678 
33679   if (is_js_function(this_obj)) {
33680     /*
33681      * `Function_apply` is a cfunction, so, GC is inhibited before calling it.
33682      * But the given function to call is a JS function, so we should enable GC;
33683      * otherwise, it will be inhibited during the whole execution of the given
33684      * JS function
33685      */
33686     v7_set_gc_enabled(v7, 1);
33687   }
33688 
33689   rcode = b_apply(v7, this_obj, this_arg, func_args, 0, res);
33690   if (rcode != V7_OK) {
33691     goto clean;
33692   }
33693 
33694 clean:
33695   return rcode;
33696 }
33697 
33698 WARN_UNUSED_RESULT
33699 V7_PRIVATE enum v7_err Function_toString(struct v7 *v7, v7_val_t *res) {
33700   enum v7_err rcode = V7_OK;
33701   char *ops;
33702   char *name;
33703   size_t name_len;
33704   char buf[50];
33705   char *b = buf;
33706   struct v7_js_function *func = get_js_function_struct(v7_get_this(v7));
33707   int i;
33708 
33709   b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "[function");
33710 
33711   assert(func->bcode != NULL);
33712   ops = func->bcode->ops.p;
33713 
33714   /* first entry in name list */
33715   ops = bcode_next_name(ops, &name, &name_len);
33716 
33717   if (name_len > 0) {
33718     b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), " %.*s", (int) name_len,
33719                     name);
33720   }
33721   b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "(");
33722   for (i = 0; i < func->bcode->args_cnt; i++) {
33723     ops = bcode_next_name(ops, &name, &name_len);
33724 
33725     b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "%.*s", (int) name_len,
33726                     name);
33727     if (i < func->bcode->args_cnt - 1) {
33728       b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), ",");
33729     }
33730   }
33731   b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), ")");
33732 
33733   {
33734     uint8_t loc_cnt =
33735         func->bcode->names_cnt - func->bcode->args_cnt - 1 /*func name*/;
33736 
33737     if (loc_cnt > 0) {
33738       b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "{var ");
33739       for (i = 0; i < loc_cnt; ++i) {
33740         ops = bcode_next_name(ops, &name, &name_len);
33741 
33742         b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "%.*s",
33743                         (int) name_len, name);
33744         if (i < (loc_cnt - 1)) {
33745           b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), ",");
33746         }
33747       }
33748 
33749       b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "}");
33750     }
33751   }
33752 
33753   b += c_snprintf(b, BUF_LEFT(sizeof(buf), b - buf), "]");
33754 
33755   *res = v7_mk_string(v7, buf, strlen(buf), 1);
33756 
33757   return rcode;
33758 }
33759 
33760 V7_PRIVATE void init_function(struct v7 *v7) {
33761   val_t ctor = mk_cfunction_obj(v7, Function_ctor, 1);
33762 
33763   v7_set(v7, ctor, "prototype", 9, v7->vals.function_prototype);
33764   v7_set(v7, v7->vals.global_object, "Function", 8, ctor);
33765   set_method(v7, v7->vals.function_prototype, "apply", Function_apply, 1);
33766   set_method(v7, v7->vals.function_prototype, "toString", Function_toString, 0);
33767   v7_def(v7, v7->vals.function_prototype, "length", 6,
33768          (V7_DESC_ENUMERABLE(0) | V7_DESC_GETTER(1)),
33769          v7_mk_cfunction(Function_length));
33770   v7_def(v7, v7->vals.function_prototype, "name", 4,
33771          (V7_DESC_ENUMERABLE(0) | V7_DESC_GETTER(1)),
33772          v7_mk_cfunction(Function_name));
33773 }
33774 
33775 #if defined(__cplusplus)
33776 }
33777 #endif /* __cplusplus */
33778 #ifdef V7_MODULE_LINES
33779 #line 1 "v7/src/std_regex.c"
33780 #endif
33781 /*
33782  * Copyright (c) 2014 Cesanta Software Limited
33783  * All rights reserved
33784  */
33785 
33786 /* Amalgamated: #include "common/utf.h" */
33787 /* Amalgamated: #include "common/str_util.h" */
33788 /* Amalgamated: #include "v7/src/internal.h" */
33789 /* Amalgamated: #include "v7/src/std_regex.h" */
33790 /* Amalgamated: #include "v7/src/std_string.h" */
33791 /* Amalgamated: #include "v7/src/slre.h" */
33792 /* Amalgamated: #include "v7/src/core.h" */
33793 /* Amalgamated: #include "v7/src/function.h" */
33794 /* Amalgamated: #include "v7/src/conversion.h" */
33795 /* Amalgamated: #include "v7/src/array.h" */
33796 /* Amalgamated: #include "v7/src/object.h" */
33797 /* Amalgamated: #include "v7/src/regexp.h" */
33798 /* Amalgamated: #include "v7/src/exceptions.h" */
33799 /* Amalgamated: #include "v7/src/string.h" */
33800 /* Amalgamated: #include "v7/src/primitive.h" */
33801 
33802 #if V7_ENABLE__RegExp
33803 
33804 WARN_UNUSED_RESULT
33805 V7_PRIVATE enum v7_err Regex_ctor(struct v7 *v7, v7_val_t *res) {
33806   enum v7_err rcode = V7_OK;
33807   long argnum = v7_argc(v7);
33808 
33809   if (argnum > 0) {
33810     val_t arg = v7_arg(v7, 0);
33811     val_t ro, fl;
33812     size_t re_len, flags_len = 0;
33813     const char *re, *flags = NULL;
33814 
33815     if (v7_is_regexp(v7, arg)) {
33816       if (argnum > 1) {
33817         /* ch15/15.10/15.10.3/S15.10.3.1_A2_T1.js */
33818         rcode = v7_throwf(v7, TYPE_ERROR, "invalid flags");
33819         goto clean;
33820       }
33821       *res = arg;
33822       goto clean;
33823     }
33824     rcode = to_string(v7, arg, &ro, NULL, 0, NULL);
33825     if (rcode != V7_OK) {
33826       goto clean;
33827     }
33828 
33829     if (argnum > 1) {
33830       rcode = to_string(v7, v7_arg(v7, 1), &fl, NULL, 0, NULL);
33831       if (rcode != V7_OK) {
33832         goto clean;
33833       }
33834 
33835       flags = v7_get_string(v7, &fl, &flags_len);
33836     }
33837     re = v7_get_string(v7, &ro, &re_len);
33838     rcode = v7_mk_regexp(v7, re, re_len, flags, flags_len, res);
33839     if (rcode != V7_OK) {
33840       goto clean;
33841     }
33842 
33843   } else {
33844     rcode = v7_mk_regexp(v7, "(?:)", 4, NULL, 0, res);
33845     if (rcode != V7_OK) {
33846       goto clean;
33847     }
33848   }
33849 
33850 clean:
33851   return rcode;
33852 }
33853 
33854 WARN_UNUSED_RESULT
33855 V7_PRIVATE enum v7_err Regex_global(struct v7 *v7, v7_val_t *res) {
33856   enum v7_err rcode = V7_OK;
33857   int flags = 0;
33858   val_t this_obj = v7_get_this(v7);
33859   val_t r = V7_UNDEFINED;
33860   rcode = obj_value_of(v7, this_obj, &r);
33861   if (rcode != V7_OK) {
33862     goto clean;
33863   }
33864 
33865   if (v7_is_regexp(v7, r)) {
33866     flags = slre_get_flags(v7_get_regexp_struct(v7, r)->compiled_regexp);
33867   }
33868 
33869   *res = v7_mk_boolean(v7, flags & SLRE_FLAG_G);
33870 
33871 clean:
33872   return rcode;
33873 }
33874 
33875 WARN_UNUSED_RESULT
33876 V7_PRIVATE enum v7_err Regex_ignoreCase(struct v7 *v7, v7_val_t *res) {
33877   enum v7_err rcode = V7_OK;
33878   int flags = 0;
33879   val_t this_obj = v7_get_this(v7);
33880   val_t r = V7_UNDEFINED;
33881   rcode = obj_value_of(v7, this_obj, &r);
33882   if (rcode != V7_OK) {
33883     goto clean;
33884   }
33885 
33886   if (v7_is_regexp(v7, r)) {
33887     flags = slre_get_flags(v7_get_regexp_struct(v7, r)->compiled_regexp);
33888   }
33889 
33890   *res = v7_mk_boolean(v7, flags & SLRE_FLAG_I);
33891 
33892 clean:
33893   return rcode;
33894 }
33895 
33896 WARN_UNUSED_RESULT
33897 V7_PRIVATE enum v7_err Regex_multiline(struct v7 *v7, v7_val_t *res) {
33898   enum v7_err rcode = V7_OK;
33899   int flags = 0;
33900   val_t this_obj = v7_get_this(v7);
33901   val_t r = V7_UNDEFINED;
33902   rcode = obj_value_of(v7, this_obj, &r);
33903   if (rcode != V7_OK) {
33904     goto clean;
33905   }
33906 
33907   if (v7_is_regexp(v7, r)) {
33908     flags = slre_get_flags(v7_get_regexp_struct(v7, r)->compiled_regexp);
33909   }
33910 
33911   *res = v7_mk_boolean(v7, flags & SLRE_FLAG_M);
33912 
33913 clean:
33914   return rcode;
33915 }
33916 
33917 WARN_UNUSED_RESULT
33918 V7_PRIVATE enum v7_err Regex_source(struct v7 *v7, v7_val_t *res) {
33919   enum v7_err rcode = V7_OK;
33920   val_t this_obj = v7_get_this(v7);
33921   val_t r = V7_UNDEFINED;
33922   const char *buf = 0;
33923   size_t len = 0;
33924 
33925   rcode = obj_value_of(v7, this_obj, &r);
33926   if (rcode != V7_OK) {
33927     goto clean;
33928   }
33929 
33930   if (v7_is_regexp(v7, r)) {
33931     buf = v7_get_string(v7, &v7_get_regexp_struct(v7, r)->regexp_string, &len);
33932   }
33933 
33934   *res = v7_mk_string(v7, buf, len, 1);
33935 
33936 clean:
33937   return rcode;
33938 }
33939 
33940 WARN_UNUSED_RESULT
33941 V7_PRIVATE enum v7_err Regex_get_lastIndex(struct v7 *v7, v7_val_t *res) {
33942   enum v7_err rcode = V7_OK;
33943   long lastIndex = 0;
33944   val_t this_obj = v7_get_this(v7);
33945 
33946   if (v7_is_regexp(v7, this_obj)) {
33947     lastIndex = v7_get_regexp_struct(v7, this_obj)->lastIndex;
33948   }
33949 
33950   *res = v7_mk_number(v7, lastIndex);
33951 
33952   return rcode;
33953 }
33954 
33955 WARN_UNUSED_RESULT
33956 V7_PRIVATE enum v7_err Regex_set_lastIndex(struct v7 *v7, v7_val_t *res) {
33957   enum v7_err rcode = V7_OK;
33958   long lastIndex = 0;
33959   val_t this_obj = v7_get_this(v7);
33960 
33961   if (v7_is_regexp(v7, this_obj)) {
33962     rcode = to_long(v7, v7_arg(v7, 0), 0, &lastIndex);
33963     if (rcode != V7_OK) {
33964       goto clean;
33965     }
33966     v7_get_regexp_struct(v7, this_obj)->lastIndex = lastIndex;
33967   }
33968 
33969   *res = v7_mk_number(v7, lastIndex);
33970 
33971 clean:
33972   return rcode;
33973 }
33974 
33975 WARN_UNUSED_RESULT
33976 V7_PRIVATE enum v7_err rx_exec(struct v7 *v7, val_t rx, val_t vstr, int lind,
33977                                val_t *res) {
33978   enum v7_err rcode = V7_OK;
33979   if (v7_is_regexp(v7, rx)) {
33980     val_t s = V7_UNDEFINED;
33981     size_t len;
33982     struct slre_loot sub;
33983     struct slre_cap *ptok = sub.caps;
33984     const char *str = NULL;
33985     const char *end = NULL;
33986     const char *begin = NULL;
33987     struct v7_regexp *rp = v7_get_regexp_struct(v7, rx);
33988     int flag_g = slre_get_flags(rp->compiled_regexp) & SLRE_FLAG_G;
33989 
33990     rcode = to_string(v7, vstr, &s, NULL, 0, NULL);
33991     if (rcode != V7_OK) {
33992       goto clean;
33993     }
33994     str = v7_get_string(v7, &s, &len);
33995     end = str + len;
33996     begin = str;
33997 
33998     if (rp->lastIndex < 0) rp->lastIndex = 0;
33999     if (flag_g || lind) begin = utfnshift(str, rp->lastIndex);
34000 
34001     if (!slre_exec(rp->compiled_regexp, 0, begin, end, &sub)) {
34002       int i;
34003       val_t arr = v7_mk_array(v7);
34004       char *old_mbuf_base = v7->owned_strings.buf;
34005       ptrdiff_t rel = 0; /* creating strings might relocate the mbuf */
34006 
34007       for (i = 0; i < sub.num_captures; i++, ptok++) {
34008         rel = v7->owned_strings.buf - old_mbuf_base;
34009         v7_array_push(v7, arr, v7_mk_string(v7, ptok->start + rel,
34010                                             ptok->end - ptok->start, 1));
34011       }
34012       if (flag_g) rp->lastIndex = utfnlen(str, sub.caps->end + rel - str);
34013       v7_def(v7, arr, "index", 5, V7_DESC_WRITABLE(0),
34014              v7_mk_number(v7, utfnlen(str + rel, sub.caps->start - str)));
34015       *res = arr;
34016       goto clean;
34017     } else {
34018       rp->lastIndex = 0;
34019     }
34020   }
34021 
34022   *res = V7_NULL;
34023 
34024 clean:
34025   return rcode;
34026 }
34027 
34028 WARN_UNUSED_RESULT
34029 V7_PRIVATE enum v7_err Regex_exec(struct v7 *v7, v7_val_t *res) {
34030   enum v7_err rcode = V7_OK;
34031   val_t this_obj = v7_get_this(v7);
34032 
34033   if (v7_argc(v7) > 0) {
34034     rcode = rx_exec(v7, this_obj, v7_arg(v7, 0), 0, res);
34035     if (rcode != V7_OK) {
34036       goto clean;
34037     }
34038   } else {
34039     *res = V7_NULL;
34040   }
34041 
34042 clean:
34043   return rcode;
34044 }
34045 
34046 WARN_UNUSED_RESULT
34047 V7_PRIVATE enum v7_err Regex_test(struct v7 *v7, v7_val_t *res) {
34048   enum v7_err rcode = V7_OK;
34049   val_t tmp = V7_UNDEFINED;
34050 
34051   rcode = Regex_exec(v7, &tmp);
34052   if (rcode != V7_OK) {
34053     goto clean;
34054   }
34055 
34056   *res = v7_mk_boolean(v7, !v7_is_null(tmp));
34057 
34058 clean:
34059   return rcode;
34060 }
34061 
34062 WARN_UNUSED_RESULT
34063 V7_PRIVATE enum v7_err Regex_flags(struct v7 *v7, v7_val_t *res) {
34064   enum v7_err rcode = V7_OK;
34065   char buf[3] = {0};
34066   val_t this_obj = v7_get_this(v7);
34067   struct v7_regexp *rp = v7_get_regexp_struct(v7, this_obj);
34068   size_t n = get_regexp_flags_str(v7, rp, buf);
34069   *res = v7_mk_string(v7, buf, n, 1);
34070 
34071   return rcode;
34072 }
34073 
34074 WARN_UNUSED_RESULT
34075 V7_PRIVATE enum v7_err Regex_toString(struct v7 *v7, v7_val_t *res) {
34076   enum v7_err rcode = V7_OK;
34077   size_t n1, n2 = 0;
34078   char s2[3] = {0};
34079   char buf[50];
34080   val_t this_obj = v7_get_this(v7);
34081   struct v7_regexp *rp;
34082   const char *s1;
34083 
34084   rcode = obj_value_of(v7, this_obj, &this_obj);
34085   if (rcode != V7_OK) {
34086     goto clean;
34087   }
34088 
34089   if (!v7_is_regexp(v7, this_obj)) {
34090     rcode = v7_throwf(v7, TYPE_ERROR, "Not a regexp");
34091     goto clean;
34092   }
34093 
34094   rp = v7_get_regexp_struct(v7, this_obj);
34095   s1 = v7_get_string(v7, &rp->regexp_string, &n1);
34096   n2 = get_regexp_flags_str(v7, rp, s2);
34097 
34098   c_snprintf(buf, sizeof(buf), "/%.*s/%.*s", (int) n1, s1, (int) n2, s2);
34099 
34100   *res = v7_mk_string(v7, buf, strlen(buf), 1);
34101 
34102 clean:
34103   return rcode;
34104 }
34105 
34106 V7_PRIVATE void init_regex(struct v7 *v7) {
34107   val_t ctor =
34108       mk_cfunction_obj_with_proto(v7, Regex_ctor, 1, v7->vals.regexp_prototype);
34109   val_t lastIndex = v7_mk_dense_array(v7);
34110 
34111   v7_def(v7, v7->vals.global_object, "RegExp", 6, V7_DESC_ENUMERABLE(0), ctor);
34112 
34113   set_cfunc_prop(v7, v7->vals.regexp_prototype, "exec", Regex_exec);
34114   set_cfunc_prop(v7, v7->vals.regexp_prototype, "test", Regex_test);
34115   set_method(v7, v7->vals.regexp_prototype, "toString", Regex_toString, 0);
34116 
34117   v7_def(v7, v7->vals.regexp_prototype, "global", 6, V7_DESC_GETTER(1),
34118          v7_mk_cfunction(Regex_global));
34119   v7_def(v7, v7->vals.regexp_prototype, "ignoreCase", 10, V7_DESC_GETTER(1),
34120          v7_mk_cfunction(Regex_ignoreCase));
34121   v7_def(v7, v7->vals.regexp_prototype, "multiline", 9, V7_DESC_GETTER(1),
34122          v7_mk_cfunction(Regex_multiline));
34123   v7_def(v7, v7->vals.regexp_prototype, "source", 6, V7_DESC_GETTER(1),
34124          v7_mk_cfunction(Regex_source));
34125   v7_def(v7, v7->vals.regexp_prototype, "flags", 5, V7_DESC_GETTER(1),
34126          v7_mk_cfunction(Regex_flags));
34127 
34128   v7_array_set(v7, lastIndex, 0, v7_mk_cfunction(Regex_get_lastIndex));
34129   v7_array_set(v7, lastIndex, 1, v7_mk_cfunction(Regex_set_lastIndex));
34130   v7_def(v7, v7->vals.regexp_prototype, "lastIndex", 9,
34131          (V7_DESC_GETTER(1) | V7_DESC_SETTER(1)), lastIndex);
34132 }
34133 
34134 #endif /* V7_ENABLE__RegExp */
34135 #ifdef V7_MODULE_LINES
34136 #line 1 "v7/src/std_proxy.c"
34137 #endif
34138 /*
34139  * Copyright (c) 2014 Cesanta Software Limited
34140  * All rights reserved
34141  */
34142 
34143 /* Amalgamated: #include "v7/src/internal.h" */
34144 /* Amalgamated: #include "v7/src/std_object.h" */
34145 /* Amalgamated: #include "v7/src/std_proxy.h" */
34146 /* Amalgamated: #include "v7/src/conversion.h" */
34147 /* Amalgamated: #include "v7/src/core.h" */
34148 /* Amalgamated: #include "v7/src/function.h" */
34149 /* Amalgamated: #include "v7/src/object.h" */
34150 /* Amalgamated: #include "v7/src/primitive.h" */
34151 /* Amalgamated: #include "v7/src/string.h" */
34152 /* Amalgamated: #include "v7/src/exceptions.h" */
34153 
34154 #if defined(__cplusplus)
34155 extern "C" {
34156 #endif /* __cplusplus */
34157 
34158 #if V7_ENABLE__Proxy
34159 
34160 WARN_UNUSED_RESULT
34161 V7_PRIVATE enum v7_err Proxy_ctor(struct v7 *v7, v7_val_t *res) {
34162   enum v7_err rcode = V7_OK;
34163   val_t this_obj = v7_get_this(v7);
34164   val_t target_v = v7_arg(v7, 0);
34165   val_t handler_v = v7_arg(v7, 1);
34166   struct v7_object *t = NULL;
34167   v7_prop_attr_desc_t attrs_desc =
34168       (V7_DESC_WRITABLE(0) | V7_DESC_ENUMERABLE(0) | V7_DESC_CONFIGURABLE(0));
34169 
34170   if (this_obj == v7_get_global(v7) || !v7_is_object(this_obj)) {
34171     rcode = v7_throwf(v7, TYPE_ERROR, "Wrong 'this' object for Proxy ctor");
34172     goto clean;
34173   }
34174 
34175   if (!v7_is_object(target_v) || !v7_is_object(handler_v)) {
34176     rcode =
34177         v7_throwf(v7, TYPE_ERROR,
34178                   "Cannot create proxy with a non-object as target or handler");
34179     goto clean;
34180   }
34181 
34182   t = get_object_struct(this_obj);
34183   t->attributes |= V7_OBJ_PROXY;
34184 
34185   v7_def(v7, this_obj, _V7_PROXY_TARGET_NAME, ~0, attrs_desc, target_v);
34186   v7_def(v7, this_obj, _V7_PROXY_HANDLER_NAME, ~0, attrs_desc, handler_v);
34187 
34188   (void) res;
34189 
34190 clean:
34191   return rcode;
34192 }
34193 
34194 V7_PRIVATE void init_proxy(struct v7 *v7) {
34195   /*v7_prop_attr_desc_t attrs_desc =*/
34196   /*(V7_DESC_WRITABLE(0) | V7_DESC_ENUMERABLE(0) | V7_DESC_CONFIGURABLE(0));*/
34197   val_t proxy =
34198       mk_cfunction_obj_with_proto(v7, Proxy_ctor, 1, v7->vals.proxy_prototype);
34199 
34200   v7_def(v7, v7->vals.global_object, "Proxy", ~0, V7_DESC_ENUMERABLE(0), proxy);
34201 }
34202 
34203 V7_PRIVATE int is_special_proxy_name(const char *name, size_t name_len) {
34204   int ret = 0;
34205   if (name_len == (size_t) ~0) {
34206     name_len = strlen(name);
34207   }
34208   if (name_len == 5 && (memcmp(name, _V7_PROXY_TARGET_NAME, name_len) == 0 ||
34209                         memcmp(name, _V7_PROXY_HANDLER_NAME, name_len) == 0)) {
34210     ret = 1;
34211   }
34212   return ret;
34213 }
34214 
34215 #endif /* V7_ENABLE__Proxy */
34216 
34217 #if defined(__cplusplus)
34218 }
34219 #endif /* __cplusplus */
34220 #ifdef V7_MODULE_LINES
34221 #line 1 "v7/src/main.c"
34222 #endif
34223 /*
34224  * Copyright (c) 2014 Cesanta Software Limited
34225  * All rights reserved
34226  */
34227 
34228 /* Amalgamated: #include "v7/src/internal.h" */
34229 /* Amalgamated: #include "v7/src/gc.h" */
34230 /* Amalgamated: #include "v7/src/freeze.h" */
34231 /* Amalgamated: #include "v7/src/main.h" */
34232 /* Amalgamated: #include "v7/src/primitive.h" */
34233 /* Amalgamated: #include "v7/src/exec.h" */
34234 /* Amalgamated: #include "v7/src/util.h" */
34235 /* Amalgamated: #include "v7/src/conversion.h" */
34236 /* Amalgamated: #include "common/platform.h" */
34237 /* Amalgamated: #include "common/cs_file.h" */
34238 
34239 #if defined(_MSC_VER) && _MSC_VER >= 1800
34240 #define fileno _fileno
34241 #endif
34242 
34243 #ifdef V7_EXE
34244 #define V7_MAIN
34245 #endif
34246 
34247 #ifdef V7_MAIN
34248 
34249 #include <sys/stat.h>
34250 
34251 static void show_usage(char *argv[]) {
34252   fprintf(stderr, "V7 version %s (c) Cesanta Software, built on %s\n",
34253           V7_VERSION, __DATE__);
34254   fprintf(stderr, "Usage: %s [OPTIONS] js_file ...\n", argv[0]);
34255   fprintf(stderr, "%s\n", "OPTIONS:");
34256   fprintf(stderr, "%s\n", "  -e <expr>            execute expression");
34257   fprintf(stderr, "%s\n", "  -t                   dump generated text AST");
34258   fprintf(stderr, "%s\n", "  -b                   dump generated binary AST");
34259   fprintf(stderr, "%s\n", "  -c                   dump compiled binary bcode");
34260   fprintf(stderr, "%s\n", "  -mm                  dump memory stats");
34261   fprintf(stderr, "%s\n", "  -vo <n>              object arena size");
34262   fprintf(stderr, "%s\n", "  -vf <n>              function arena size");
34263   fprintf(stderr, "%s\n", "  -vp <n>              property arena size");
34264 #ifdef V7_FREEZE
34265   fprintf(stderr, "%s\n", "  -freeze filename     dump JS heap into a file");
34266 #endif
34267   exit(EXIT_FAILURE);
34268 }
34269 
34270 #if V7_ENABLE__Memory__stats
34271 static void dump_mm_arena_stats(const char *msg, struct gc_arena *a) {
34272   printf("%s: total allocations %lu, total garbage %lu, max %" SIZE_T_FMT
34273          ", alive %lu\n",
34274          msg, a->allocations, a->garbage, gc_arena_size(a), a->alive);
34275   printf(
34276       "%s: (bytes: total allocations %lu, total garbage %lu, max %" SIZE_T_FMT
34277       ", alive %lu)\n",
34278       msg, a->allocations * a->cell_size, a->garbage * a->cell_size,
34279       gc_arena_size(a) * a->cell_size, a->alive * a->cell_size);
34280 }
34281 
34282 static void dump_mm_stats(struct v7 *v7) {
34283   dump_mm_arena_stats("object: ", &v7->generic_object_arena);
34284   dump_mm_arena_stats("function: ", &v7->function_arena);
34285   dump_mm_arena_stats("property: ", &v7->property_arena);
34286   printf("string arena len: %" SIZE_T_FMT "\n", v7->owned_strings.len);
34287   printf("Total heap size: %" SIZE_T_FMT "\n",
34288          v7->owned_strings.len +
34289              gc_arena_size(&v7->generic_object_arena) *
34290                  v7->generic_object_arena.cell_size +
34291              gc_arena_size(&v7->function_arena) * v7->function_arena.cell_size +
34292              gc_arena_size(&v7->property_arena) * v7->property_arena.cell_size);
34293 }
34294 #endif
34295 
34296 int v7_main(int argc, char *argv[], void (*pre_freeze_init)(struct v7 *),
34297             void (*pre_init)(struct v7 *), void (*post_init)(struct v7 *)) {
34298   int exit_rcode = EXIT_SUCCESS;
34299   struct v7 *v7;
34300   struct v7_create_opts opts;
34301   int as_json = 0;
34302   int i, j, show_ast = 0, binary_ast = 0, dump_bcode = 0, dump_stats = 0;
34303   val_t res;
34304   int nexprs = 0;
34305   const char *exprs[16];
34306 
34307   memset(&opts, 0, sizeof(opts));
34308 
34309   (void) show_ast;
34310   (void) binary_ast;
34311   (void) dump_bcode;
34312 
34313   /* Execute inline code */
34314   for (i = 1; i < argc && argv[i][0] == '-'; i++) {
34315     if (strcmp(argv[i], "-e") == 0 && i + 1 < argc) {
34316       exprs[nexprs++] = argv[i + 1];
34317       i++;
34318     } else if (strcmp(argv[i], "-t") == 0) {
34319       show_ast = 1;
34320     } else if (strcmp(argv[i], "-b") == 0) {
34321       show_ast = 1;
34322       binary_ast = 1;
34323     } else if (strcmp(argv[i], "-c") == 0) {
34324       binary_ast = 1;
34325       dump_bcode = 1;
34326     } else if (strcmp(argv[i], "-h") == 0) {
34327       show_usage(argv);
34328     } else if (strcmp(argv[i], "-j") == 0) {
34329       as_json = 1;
34330 #if V7_ENABLE__Memory__stats
34331     } else if (strcmp(argv[i], "-mm") == 0) {
34332       dump_stats = 1;
34333 #endif
34334     } else if (strcmp(argv[i], "-vo") == 0 && i + 1 < argc) {
34335       opts.object_arena_size = atoi(argv[i + 1]);
34336       i++;
34337     } else if (strcmp(argv[i], "-vf") == 0 && i + 1 < argc) {
34338       opts.function_arena_size = atoi(argv[i + 1]);
34339       i++;
34340     } else if (strcmp(argv[i], "-vp") == 0 && i + 1 < argc) {
34341       opts.property_arena_size = atoi(argv[i + 1]);
34342       i++;
34343     }
34344 #ifdef V7_FREEZE
34345     else if (strcmp(argv[i], "-freeze") == 0 && i + 1 < argc) {
34346       opts.freeze_file = argv[i + 1];
34347       i++;
34348     }
34349 #endif
34350   }
34351 
34352 #ifndef V7_ALLOW_ARGLESS_MAIN
34353   if (argc == 1) {
34354     show_usage(argv);
34355   }
34356 #endif
34357 
34358   v7 = v7_create_opt(opts);
34359   res = V7_UNDEFINED;
34360 
34361   if (pre_freeze_init != NULL) {
34362     pre_freeze_init(v7);
34363   }
34364 
34365 #ifdef V7_FREEZE
34366   /*
34367    * Skip pre_init if freezing, but still execute cmdline expressions.
34368    * This makes it easier to add custom code when freezing from cmdline.
34369    */
34370   if (opts.freeze_file == NULL) {
34371 #endif
34372 
34373     if (pre_init != NULL) {
34374       pre_init(v7);
34375     }
34376 
34377 #ifdef V7_FREEZE
34378   }
34379 #endif
34380 
34381 #if V7_ENABLE__Memory__stats > 0 && !defined(V7_DISABLE_GC)
34382   if (dump_stats) {
34383     printf("Memory stats during init:\n");
34384     dump_mm_stats(v7);
34385     v7_gc(v7, 0);
34386     printf("Memory stats before run:\n");
34387     dump_mm_stats(v7);
34388   }
34389 #else
34390   (void) dump_stats;
34391 #endif
34392 
34393   /* Execute inline expressions */
34394   for (j = 0; j < nexprs; j++) {
34395     enum v7_err (*exec)(struct v7 *, const char *, v7_val_t *);
34396     exec = v7_exec;
34397 
34398     if (show_ast || dump_bcode) {
34399 #if !defined(V7_NO_COMPILER)
34400       if (v7_compile(exprs[j], binary_ast, dump_bcode, stdout) != V7_OK) {
34401         exit_rcode = EXIT_FAILURE;
34402         fprintf(stderr, "%s\n", "parse error");
34403       }
34404 #else  /* V7_NO_COMPILER */
34405       exit_rcode = EXIT_FAILURE;
34406       fprintf(stderr, "%s\n", "Parsing is disabled by V7_NO_COMPILER");
34407 #endif /* V7_NO_COMPILER */
34408     } else if (exec(v7, exprs[j], &res) != V7_OK) {
34409       v7_print_error(stderr, v7, exprs[j], res);
34410       exit_rcode = EXIT_FAILURE;
34411       res = V7_UNDEFINED;
34412     }
34413   }
34414 
34415   /* Execute files */
34416   for (; i < argc; i++) {
34417     if (show_ast || dump_bcode) {
34418 #if !defined(V7_NO_COMPILER)
34419       size_t size;
34420       char *source_code;
34421       if ((source_code = cs_read_file(argv[i], &size)) == NULL) {
34422         exit_rcode = EXIT_FAILURE;
34423         fprintf(stderr, "Cannot read [%s]\n", argv[i]);
34424       } else {
34425         if (_v7_compile(source_code, size, binary_ast, dump_bcode, stdout) !=
34426             V7_OK) {
34427           fprintf(stderr, "error: %s\n", v7->error_msg);
34428           exit_rcode = EXIT_FAILURE;
34429           exit(exit_rcode);
34430         }
34431         free(source_code);
34432       }
34433 #else  /* V7_NO_COMPILER */
34434       exit_rcode = EXIT_FAILURE;
34435       fprintf(stderr, "%s\n", "Parsing is disabled by V7_NO_COMPILER");
34436 #endif /* V7_NO_COMPILER */
34437     } else if (v7_exec_file(v7, argv[i], &res) != V7_OK) {
34438       v7_print_error(stderr, v7, argv[i], res);
34439       res = V7_UNDEFINED;
34440     }
34441   }
34442 
34443 #ifdef V7_FREEZE
34444   if (opts.freeze_file != NULL) {
34445     freeze(v7, opts.freeze_file);
34446     exit(0);
34447   }
34448 #endif
34449 
34450   if (!(show_ast || dump_bcode)) {
34451     char buf[2000];
34452     char *s = v7_stringify(v7, res, buf, sizeof(buf),
34453                            as_json ? V7_STRINGIFY_JSON : V7_STRINGIFY_DEBUG);
34454     printf("%s\n", s);
34455     if (s != buf) {
34456       free(s);
34457     }
34458   }
34459 
34460   if (post_init != NULL) {
34461     post_init(v7);
34462   }
34463 
34464 #if V7_ENABLE__Memory__stats
34465   if (dump_stats) {
34466     printf("Memory stats after run:\n");
34467     dump_mm_stats(v7);
34468   }
34469 #else
34470   (void) dump_stats;
34471 #endif
34472 
34473   v7_destroy(v7);
34474   return exit_rcode;
34475 }
34476 #endif
34477 
34478 #ifdef V7_EXE
34479 int main(int argc, char *argv[]) {
34480   return v7_main(argc, argv, NULL, NULL, NULL);
34481 }
34482 #endif
34483 #endif /* V7_EXPORT_INTERNAL_HEADERS */