Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: DISCO-F469NI_javascript_blinker
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(¤t_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 */
Generated on Thu Jul 14 2022 12:18:29 by
1.7.2