├── CMakeLists.txt ├── main.cpp ├── quickjs ├── CMakeLists.txt ├── VERSION ├── cutils.c ├── cutils.h ├── libbf.c ├── libbf.h ├── libregexp-opcode.h ├── libregexp.c ├── libregexp.h ├── libunicode-table.h ├── libunicode.c ├── libunicode.h ├── list.h ├── quickjs-atom.h ├── quickjs-libc.c ├── quickjs-libc.h ├── quickjs-opcode.h ├── quickjs.c └── quickjs.h └── quickjspp.hpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(quickjspp) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | #set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) 6 | 7 | #if(GNU) 8 | # add_compile_options(-Wall -Wno-unused-parameter) 9 | # endif() 10 | 11 | add_subdirectory(quickjs) 12 | add_executable(quickjspp main.cpp) 13 | target_link_libraries(quickjspp quickjs ) 14 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "quickjspp.hpp" 2 | 3 | 4 | #include 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | int32_t f(int32_t x) 13 | { 14 | return x * x; 15 | }; 16 | 17 | class test 18 | { 19 | int x; 20 | public: 21 | inline static JSClassID QJSClassId; 22 | 23 | 24 | test(int32_t x) : x{x} 25 | { printf("ctor %d!\n", x); } 26 | 27 | test(const test&) = delete; 28 | 29 | ~test() 30 | { printf("dtor!\n"); } 31 | 32 | void f() 33 | { printf("f(%p): x=%d\n", this, x); } 34 | 35 | static void g() 36 | { printf("g()\n"); } 37 | }; 38 | 39 | 40 | int32_t f2(int32_t x, std::shared_ptr ptr) 41 | { 42 | std::cout << ptr.get() << std::endl; 43 | return x * x; 44 | }; 45 | 46 | 47 | int main(int argc, char ** argv) 48 | { 49 | JSRuntime * rt; 50 | JSContext * ctx; 51 | using namespace qjs; 52 | 53 | Runtime runtime; 54 | rt = runtime.rt; 55 | 56 | Context context(runtime); 57 | ctx = context.ctx; 58 | 59 | auto obj = context.newObject(); 60 | obj["test"] = 54; 61 | obj["test2"] = 56; 62 | obj["g"] = detail::fwrapper<&test::g>{"g"}; 63 | obj["fun2"] = detail::fwrapper<&f2>{"f2"}; 64 | obj["f"] = detail::fwrapper<&test::f>{"f"}; 65 | 66 | 67 | context.registerClass("test_class", std::move(obj)); 68 | 69 | 70 | context.addModule("test") 71 | .add("sqr", detail::fwrapper<&f>{"sqr"}) 72 | .add("sqr2", detail::fwrapper<&f>{}) 73 | .add("p", detail::fwrapper<&f2>{"p"}) 74 | .add("obj", obj) 75 | .add("Test", detail::ctor_wrapper{"Test"}); 76 | 77 | 78 | 79 | /* loader for ES6 modules */ 80 | JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); 81 | js_std_add_helpers(ctx, argc, argv); 82 | 83 | /* system modules */ 84 | js_init_module_std(ctx, "std"); 85 | js_init_module_os(ctx, "os"); 86 | 87 | /* make 'std' and 'os' visible to non module code */ 88 | const char * str = "import * as std from 'std';\n" 89 | "import * as os from 'os';\n" 90 | "import * as test from 'test';\n" 91 | "std.global.std = std;\n" 92 | "std.global.test = test;\n" 93 | "std.global.os = os;\n"; 94 | context.eval(str, "", JS_EVAL_TYPE_MODULE); 95 | const char * filename = argv[1]; 96 | 97 | context.evalFile(filename, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_SHEBANG); 98 | 99 | js_std_loop(ctx); 100 | 101 | js_std_free_handlers(rt); 102 | 103 | return 0; 104 | 105 | } 106 | -------------------------------------------------------------------------------- /quickjs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(quickjs LANGUAGES C) 2 | 3 | 4 | file(STRINGS VERSION version) 5 | 6 | set(quickjs_src quickjs.c libunicode.c libregexp.c cutils.c quickjs-libc.c) 7 | set(quickjs_def CONFIG_VERSION="${version}" _GNU_SOURCE) 8 | 9 | option(QUICKJS_BIGNUM "Compile BigNum support" ON) 10 | 11 | if(QUICKJS_BIGNUM) 12 | list(APPEND quickjs_src libbf.c) 13 | list(APPEND quickjs_def CONFIG_BIGNUM) 14 | endif() 15 | 16 | add_library(quickjs ${quickjs_src}) 17 | target_compile_definitions(quickjs PRIVATE ${quickjs_def} ) 18 | 19 | 20 | if(UNIX) 21 | target_link_libraries(quickjs ${CMAKE_DL_LIBS} m ) 22 | endif() 23 | -------------------------------------------------------------------------------- /quickjs/VERSION: -------------------------------------------------------------------------------- 1 | 2019-07-09 2 | -------------------------------------------------------------------------------- /quickjs/cutils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * C utilities 3 | * 4 | * Copyright (c) 2017 Fabrice Bellard 5 | * Copyright (c) 2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "cutils.h" 31 | 32 | void pstrcpy(char *buf, int buf_size, const char *str) 33 | { 34 | int c; 35 | char *q = buf; 36 | 37 | if (buf_size <= 0) 38 | return; 39 | 40 | for(;;) { 41 | c = *str++; 42 | if (c == 0 || q >= buf + buf_size - 1) 43 | break; 44 | *q++ = c; 45 | } 46 | *q = '\0'; 47 | } 48 | 49 | /* strcat and truncate. */ 50 | char *pstrcat(char *buf, int buf_size, const char *s) 51 | { 52 | int len; 53 | len = strlen(buf); 54 | if (len < buf_size) 55 | pstrcpy(buf + len, buf_size - len, s); 56 | return buf; 57 | } 58 | 59 | int strstart(const char *str, const char *val, const char **ptr) 60 | { 61 | const char *p, *q; 62 | p = str; 63 | q = val; 64 | while (*q != '\0') { 65 | if (*p != *q) 66 | return 0; 67 | p++; 68 | q++; 69 | } 70 | if (ptr) 71 | *ptr = p; 72 | return 1; 73 | } 74 | 75 | int has_suffix(const char *str, const char *suffix) 76 | { 77 | size_t len = strlen(str); 78 | size_t slen = strlen(suffix); 79 | return (len >= slen && !memcmp(str + len - slen, suffix, slen)); 80 | } 81 | 82 | /* Dynamic buffer package */ 83 | 84 | static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size) 85 | { 86 | return realloc(ptr, size); 87 | } 88 | 89 | void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func) 90 | { 91 | memset(s, 0, sizeof(*s)); 92 | if (!realloc_func) 93 | realloc_func = dbuf_default_realloc; 94 | s->opaque = opaque; 95 | s->realloc_func = realloc_func; 96 | } 97 | 98 | void dbuf_init(DynBuf *s) 99 | { 100 | dbuf_init2(s, NULL, NULL); 101 | } 102 | 103 | /* return < 0 if error */ 104 | int dbuf_realloc(DynBuf *s, size_t new_size) 105 | { 106 | size_t size; 107 | uint8_t *new_buf; 108 | if (new_size > s->allocated_size) { 109 | if (s->error) 110 | return -1; 111 | size = s->allocated_size * 3 / 2; 112 | if (size > new_size) 113 | new_size = size; 114 | new_buf = s->realloc_func(s->opaque, s->buf, new_size); 115 | if (!new_buf) { 116 | s->error = TRUE; 117 | return -1; 118 | } 119 | s->buf = new_buf; 120 | s->allocated_size = new_size; 121 | } 122 | return 0; 123 | } 124 | 125 | int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len) 126 | { 127 | size_t end; 128 | end = offset + len; 129 | if (dbuf_realloc(s, end)) 130 | return -1; 131 | memcpy(s->buf + offset, data, len); 132 | if (end > s->size) 133 | s->size = end; 134 | return 0; 135 | } 136 | 137 | int dbuf_put(DynBuf *s, const uint8_t *data, size_t len) 138 | { 139 | if (unlikely((s->size + len) > s->allocated_size)) { 140 | if (dbuf_realloc(s, s->size + len)) 141 | return -1; 142 | } 143 | memcpy(s->buf + s->size, data, len); 144 | s->size += len; 145 | return 0; 146 | } 147 | 148 | int dbuf_put_self(DynBuf *s, size_t offset, size_t len) 149 | { 150 | if (unlikely((s->size + len) > s->allocated_size)) { 151 | if (dbuf_realloc(s, s->size + len)) 152 | return -1; 153 | } 154 | memcpy(s->buf + s->size, s->buf + offset, len); 155 | s->size += len; 156 | return 0; 157 | } 158 | 159 | int dbuf_putc(DynBuf *s, uint8_t c) 160 | { 161 | return dbuf_put(s, &c, 1); 162 | } 163 | 164 | int dbuf_putstr(DynBuf *s, const char *str) 165 | { 166 | return dbuf_put(s, (const uint8_t *)str, strlen(str)); 167 | } 168 | 169 | int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, 170 | const char *fmt, ...) 171 | { 172 | va_list ap; 173 | char buf[128]; 174 | int len; 175 | 176 | va_start(ap, fmt); 177 | len = vsnprintf(buf, sizeof(buf), fmt, ap); 178 | va_end(ap); 179 | if (len < sizeof(buf)) { 180 | /* fast case */ 181 | return dbuf_put(s, (uint8_t *)buf, len); 182 | } else { 183 | if (dbuf_realloc(s, s->size + len + 1)) 184 | return -1; 185 | va_start(ap, fmt); 186 | vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size, 187 | fmt, ap); 188 | va_end(ap); 189 | s->size += len; 190 | } 191 | return 0; 192 | } 193 | 194 | void dbuf_free(DynBuf *s) 195 | { 196 | /* we test s->buf as a fail safe to avoid crashing if dbuf_free() 197 | is called twice */ 198 | if (s->buf) { 199 | s->realloc_func(s->opaque, s->buf, 0); 200 | } 201 | memset(s, 0, sizeof(*s)); 202 | } 203 | 204 | /* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes 205 | are output. */ 206 | int unicode_to_utf8(uint8_t *buf, unsigned int c) 207 | { 208 | uint8_t *q = buf; 209 | 210 | if (c < 0x80) { 211 | *q++ = c; 212 | } else { 213 | if (c < 0x800) { 214 | *q++ = (c >> 6) | 0xc0; 215 | } else { 216 | if (c < 0x10000) { 217 | *q++ = (c >> 12) | 0xe0; 218 | } else { 219 | if (c < 0x00200000) { 220 | *q++ = (c >> 18) | 0xf0; 221 | } else { 222 | if (c < 0x04000000) { 223 | *q++ = (c >> 24) | 0xf8; 224 | } else if (c < 0x80000000) { 225 | *q++ = (c >> 30) | 0xfc; 226 | *q++ = ((c >> 24) & 0x3f) | 0x80; 227 | } else { 228 | return 0; 229 | } 230 | *q++ = ((c >> 18) & 0x3f) | 0x80; 231 | } 232 | *q++ = ((c >> 12) & 0x3f) | 0x80; 233 | } 234 | *q++ = ((c >> 6) & 0x3f) | 0x80; 235 | } 236 | *q++ = (c & 0x3f) | 0x80; 237 | } 238 | return q - buf; 239 | } 240 | 241 | static const unsigned int utf8_min_code[5] = { 242 | 0x80, 0x800, 0x10000, 0x00200000, 0x04000000, 243 | }; 244 | 245 | static const unsigned char utf8_first_code_mask[5] = { 246 | 0x1f, 0xf, 0x7, 0x3, 0x1, 247 | }; 248 | 249 | /* return -1 if error. *pp is not updated in this case. max_len must 250 | be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */ 251 | int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp) 252 | { 253 | int l, c, b, i; 254 | 255 | c = *p++; 256 | if (c < 0x80) { 257 | *pp = p; 258 | return c; 259 | } 260 | switch(c) { 261 | case 0xc0 ... 0xdf: 262 | l = 1; 263 | break; 264 | case 0xe0 ... 0xef: 265 | l = 2; 266 | break; 267 | case 0xf0 ... 0xf7: 268 | l = 3; 269 | break; 270 | case 0xf8 ... 0xfb: 271 | l = 4; 272 | break; 273 | case 0xfc ... 0xfd: 274 | l = 5; 275 | break; 276 | default: 277 | return -1; 278 | } 279 | /* check that we have enough characters */ 280 | if (l > (max_len - 1)) 281 | return -1; 282 | c &= utf8_first_code_mask[l - 1]; 283 | for(i = 0; i < l; i++) { 284 | b = *p++; 285 | if (b < 0x80 || b >= 0xc0) 286 | return -1; 287 | c = (c << 6) | (b & 0x3f); 288 | } 289 | if (c < utf8_min_code[l - 1]) 290 | return -1; 291 | *pp = p; 292 | return c; 293 | } 294 | 295 | #if 0 296 | 297 | #if defined(EMSCRIPTEN) || defined(__ANDROID__) 298 | 299 | static void *rqsort_arg; 300 | static int (*rqsort_cmp)(const void *, const void *, void *); 301 | 302 | static int rqsort_cmp2(const void *p1, const void *p2) 303 | { 304 | return rqsort_cmp(p1, p2, rqsort_arg); 305 | } 306 | 307 | /* not reentrant, but not needed with emscripten */ 308 | void rqsort(void *base, size_t nmemb, size_t size, 309 | int (*cmp)(const void *, const void *, void *), 310 | void *arg) 311 | { 312 | rqsort_arg = arg; 313 | rqsort_cmp = cmp; 314 | qsort(base, nmemb, size, rqsort_cmp2); 315 | } 316 | 317 | #endif 318 | 319 | #else 320 | 321 | typedef void (*exchange_f)(void *a, void *b, size_t size); 322 | typedef int (*cmp_f)(const void *, const void *, void *opaque); 323 | 324 | static void exchange_bytes(void *a, void *b, size_t size) { 325 | uint8_t *ap = (uint8_t *)a; 326 | uint8_t *bp = (uint8_t *)b; 327 | 328 | while (size-- != 0) { 329 | uint8_t t = *ap; 330 | *ap++ = *bp; 331 | *bp++ = t; 332 | } 333 | } 334 | 335 | static void exchange_one_byte(void *a, void *b, size_t size) { 336 | uint8_t *ap = (uint8_t *)a; 337 | uint8_t *bp = (uint8_t *)b; 338 | uint8_t t = *ap; 339 | *ap = *bp; 340 | *bp = t; 341 | } 342 | 343 | static void exchange_int16s(void *a, void *b, size_t size) { 344 | uint16_t *ap = (uint16_t *)a; 345 | uint16_t *bp = (uint16_t *)b; 346 | 347 | for (size /= sizeof(uint16_t); size-- != 0;) { 348 | uint16_t t = *ap; 349 | *ap++ = *bp; 350 | *bp++ = t; 351 | } 352 | } 353 | 354 | static void exchange_one_int16(void *a, void *b, size_t size) { 355 | uint16_t *ap = (uint16_t *)a; 356 | uint16_t *bp = (uint16_t *)b; 357 | uint16_t t = *ap; 358 | *ap = *bp; 359 | *bp = t; 360 | } 361 | 362 | static void exchange_int32s(void *a, void *b, size_t size) { 363 | uint32_t *ap = (uint32_t *)a; 364 | uint32_t *bp = (uint32_t *)b; 365 | 366 | for (size /= sizeof(uint32_t); size-- != 0;) { 367 | uint32_t t = *ap; 368 | *ap++ = *bp; 369 | *bp++ = t; 370 | } 371 | } 372 | 373 | static void exchange_one_int32(void *a, void *b, size_t size) { 374 | uint32_t *ap = (uint32_t *)a; 375 | uint32_t *bp = (uint32_t *)b; 376 | uint32_t t = *ap; 377 | *ap = *bp; 378 | *bp = t; 379 | } 380 | 381 | static void exchange_int64s(void *a, void *b, size_t size) { 382 | uint64_t *ap = (uint64_t *)a; 383 | uint64_t *bp = (uint64_t *)b; 384 | 385 | for (size /= sizeof(uint64_t); size-- != 0;) { 386 | uint64_t t = *ap; 387 | *ap++ = *bp; 388 | *bp++ = t; 389 | } 390 | } 391 | 392 | static void exchange_one_int64(void *a, void *b, size_t size) { 393 | uint64_t *ap = (uint64_t *)a; 394 | uint64_t *bp = (uint64_t *)b; 395 | uint64_t t = *ap; 396 | *ap = *bp; 397 | *bp = t; 398 | } 399 | 400 | static void exchange_int128s(void *a, void *b, size_t size) { 401 | uint64_t *ap = (uint64_t *)a; 402 | uint64_t *bp = (uint64_t *)b; 403 | 404 | for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) { 405 | uint64_t t = ap[0]; 406 | uint64_t u = ap[1]; 407 | ap[0] = bp[0]; 408 | ap[1] = bp[1]; 409 | bp[0] = t; 410 | bp[1] = u; 411 | } 412 | } 413 | 414 | static void exchange_one_int128(void *a, void *b, size_t size) { 415 | uint64_t *ap = (uint64_t *)a; 416 | uint64_t *bp = (uint64_t *)b; 417 | uint64_t t = ap[0]; 418 | uint64_t u = ap[1]; 419 | ap[0] = bp[0]; 420 | ap[1] = bp[1]; 421 | bp[0] = t; 422 | bp[1] = u; 423 | } 424 | 425 | static inline exchange_f exchange_func(const void *base, size_t size) { 426 | switch (((uintptr_t)base | (uintptr_t)size) & 15) { 427 | case 0: 428 | if (size == sizeof(uint64_t) * 2) 429 | return exchange_one_int128; 430 | else 431 | return exchange_int128s; 432 | case 8: 433 | if (size == sizeof(uint64_t)) 434 | return exchange_one_int64; 435 | else 436 | return exchange_int64s; 437 | case 4: 438 | case 12: 439 | if (size == sizeof(uint32_t)) 440 | return exchange_one_int32; 441 | else 442 | return exchange_int32s; 443 | case 2: 444 | case 6: 445 | case 10: 446 | case 14: 447 | if (size == sizeof(uint16_t)) 448 | return exchange_one_int16; 449 | else 450 | return exchange_int16s; 451 | default: 452 | if (size == 1) 453 | return exchange_one_byte; 454 | else 455 | return exchange_bytes; 456 | } 457 | } 458 | 459 | static void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) 460 | { 461 | uint8_t *basep = (uint8_t *)base; 462 | size_t i, n, c, r; 463 | exchange_f swap = exchange_func(base, size); 464 | 465 | if (nmemb > 1) { 466 | i = (nmemb / 2) * size; 467 | n = nmemb * size; 468 | 469 | while (i > 0) { 470 | i -= size; 471 | for (r = i; (c = r * 2 + size) < n; r = c) { 472 | if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0) 473 | c += size; 474 | if (cmp(basep + r, basep + c, opaque) > 0) 475 | break; 476 | swap(basep + r, basep + c, size); 477 | } 478 | } 479 | for (i = n - size; i > 0; i -= size) { 480 | swap(basep, basep + i, size); 481 | 482 | for (r = 0; (c = r * 2 + size) < i; r = c) { 483 | if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0) 484 | c += size; 485 | if (cmp(basep + r, basep + c, opaque) > 0) 486 | break; 487 | swap(basep + r, basep + c, size); 488 | } 489 | } 490 | } 491 | } 492 | 493 | static inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque) 494 | { 495 | return cmp(a, b, opaque) < 0 ? 496 | (cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) : 497 | (cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c )); 498 | } 499 | 500 | /* pointer based version with local stack and insertion sort threshhold */ 501 | void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque) 502 | { 503 | struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack; 504 | uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m; 505 | size_t m4, i, lt, gt, span, span2; 506 | int c, depth; 507 | exchange_f swap = exchange_func(base, size); 508 | exchange_f swap_block = exchange_func(base, size | 128); 509 | 510 | if (nmemb < 2 || size <= 0) 511 | return; 512 | 513 | sp->base = (uint8_t *)base; 514 | sp->count = nmemb; 515 | sp->depth = 0; 516 | sp++; 517 | 518 | while (sp > stack) { 519 | sp--; 520 | ptr = sp->base; 521 | nmemb = sp->count; 522 | depth = sp->depth; 523 | 524 | while (nmemb > 6) { 525 | if (++depth > 50) { 526 | /* depth check to ensure worst case logarithmic time */ 527 | heapsortx(ptr, nmemb, size, cmp, opaque); 528 | nmemb = 0; 529 | break; 530 | } 531 | /* select median of 3 from 1/4, 1/2, 3/4 positions */ 532 | /* should use median of 5 or 9? */ 533 | m4 = (nmemb >> 2) * size; 534 | m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque); 535 | swap(ptr, m, size); /* move the pivot to the start or the array */ 536 | i = lt = 1; 537 | pi = plt = ptr + size; 538 | gt = nmemb; 539 | pj = pgt = top = ptr + nmemb * size; 540 | for (;;) { 541 | while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) { 542 | if (c == 0) { 543 | swap(plt, pi, size); 544 | lt++; 545 | plt += size; 546 | } 547 | i++; 548 | pi += size; 549 | } 550 | while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) { 551 | if (c == 0) { 552 | gt--; 553 | pgt -= size; 554 | swap(pgt, pj, size); 555 | } 556 | } 557 | if (pi >= pj) 558 | break; 559 | swap(pi, pj, size); 560 | i++; 561 | pi += size; 562 | } 563 | /* array has 4 parts: 564 | * from 0 to lt excluded: elements identical to pivot 565 | * from lt to pi excluded: elements smaller than pivot 566 | * from pi to gt excluded: elements greater than pivot 567 | * from gt to n excluded: elements identical to pivot 568 | */ 569 | /* move elements identical to pivot in the middle of the array: */ 570 | /* swap values in ranges [0..lt[ and [i-lt..i[ 571 | swapping the smallest span between lt and i-lt is sufficient 572 | */ 573 | span = plt - ptr; 574 | span2 = pi - plt; 575 | plt = pi - span; 576 | lt = i - lt; 577 | if (span > span2) 578 | span = span2; 579 | swap_block(ptr, pi - span, span); 580 | /* swap values in ranges [gt..top[ and [i..top-(top-gt)[ 581 | swapping the smallest span between top-gt and gt-i is sufficient 582 | */ 583 | span = top - pgt; 584 | span2 = pgt - pi; 585 | pgt = top - span2; 586 | gt = nmemb - (gt - i); 587 | if (span > span2) 588 | span = span2; 589 | swap_block(pi, top - span, span); 590 | 591 | /* now array has 3 parts: 592 | * from 0 to lt excluded: elements smaller than pivot 593 | * from lt to gt excluded: elements identical to pivot 594 | * from gt to n excluded: elements greater than pivot 595 | */ 596 | /* stack the larger segment and keep processing the smaller one 597 | to minimize stack use for pathological distributions */ 598 | if (lt > nmemb - gt) { 599 | sp->base = ptr; 600 | sp->count = lt; 601 | sp->depth = depth; 602 | sp++; 603 | ptr = pgt; 604 | nmemb -= gt; 605 | } else { 606 | sp->base = pgt; 607 | sp->count = nmemb - gt; 608 | sp->depth = depth; 609 | sp++; 610 | nmemb = lt; 611 | } 612 | } 613 | /* Use insertion sort for small fragments */ 614 | for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) { 615 | for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size) 616 | swap(pj, pj - size, size); 617 | } 618 | } 619 | } 620 | 621 | #endif 622 | -------------------------------------------------------------------------------- /quickjs/cutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * C utilities 3 | * 4 | * Copyright (c) 2017 Fabrice Bellard 5 | * Copyright (c) 2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | #ifndef CUTILS_H 26 | #define CUTILS_H 27 | 28 | #include 29 | #include 30 | 31 | /* set if CPU is big endian */ 32 | #undef WORDS_BIGENDIAN 33 | 34 | #define likely(x) __builtin_expect(!!(x), 1) 35 | #define unlikely(x) __builtin_expect(!!(x), 0) 36 | #define force_inline inline __attribute__((always_inline)) 37 | #define no_inline __attribute__((noinline)) 38 | 39 | #define xglue(x, y) x ## y 40 | #define glue(x, y) xglue(x, y) 41 | #define stringify(s) tostring(s) 42 | #define tostring(s) #s 43 | 44 | #ifndef offsetof 45 | #define offsetof(type, field) ((size_t) &((type *)0)->field) 46 | #endif 47 | #ifndef countof 48 | #define countof(x) (sizeof(x) / sizeof((x)[0])) 49 | #endif 50 | 51 | typedef int BOOL; 52 | 53 | #ifndef FALSE 54 | enum { 55 | FALSE = 0, 56 | TRUE = 1, 57 | }; 58 | #endif 59 | 60 | void pstrcpy(char *buf, int buf_size, const char *str); 61 | char *pstrcat(char *buf, int buf_size, const char *s); 62 | int strstart(const char *str, const char *val, const char **ptr); 63 | int has_suffix(const char *str, const char *suffix); 64 | 65 | static inline int max_int(int a, int b) 66 | { 67 | if (a > b) 68 | return a; 69 | else 70 | return b; 71 | } 72 | 73 | static inline int min_int(int a, int b) 74 | { 75 | if (a < b) 76 | return a; 77 | else 78 | return b; 79 | } 80 | 81 | static inline uint32_t max_uint32(uint32_t a, uint32_t b) 82 | { 83 | if (a > b) 84 | return a; 85 | else 86 | return b; 87 | } 88 | 89 | static inline uint32_t min_uint32(uint32_t a, uint32_t b) 90 | { 91 | if (a < b) 92 | return a; 93 | else 94 | return b; 95 | } 96 | 97 | static inline int64_t max_int64(int64_t a, int64_t b) 98 | { 99 | if (a > b) 100 | return a; 101 | else 102 | return b; 103 | } 104 | 105 | static inline int64_t min_int64(int64_t a, int64_t b) 106 | { 107 | if (a < b) 108 | return a; 109 | else 110 | return b; 111 | } 112 | 113 | /* WARNING: undefined if a = 0 */ 114 | static inline int clz32(unsigned int a) 115 | { 116 | return __builtin_clz(a); 117 | } 118 | 119 | /* WARNING: undefined if a = 0 */ 120 | static inline int clz64(uint64_t a) 121 | { 122 | return __builtin_clzll(a); 123 | } 124 | 125 | /* WARNING: undefined if a = 0 */ 126 | static inline int ctz32(unsigned int a) 127 | { 128 | return __builtin_ctz(a); 129 | } 130 | 131 | /* WARNING: undefined if a = 0 */ 132 | static inline int ctz64(uint64_t a) 133 | { 134 | return __builtin_ctzll(a); 135 | } 136 | 137 | struct __attribute__((packed)) packed_u64 { 138 | uint64_t v; 139 | }; 140 | 141 | struct __attribute__((packed)) packed_u32 { 142 | uint32_t v; 143 | }; 144 | 145 | struct __attribute__((packed)) packed_u16 { 146 | uint16_t v; 147 | }; 148 | 149 | static inline uint64_t get_u64(const uint8_t *tab) 150 | { 151 | return ((const struct packed_u64 *)tab)->v; 152 | } 153 | 154 | static inline int64_t get_i64(const uint8_t *tab) 155 | { 156 | return (int64_t)((const struct packed_u64 *)tab)->v; 157 | } 158 | 159 | static inline void put_u64(uint8_t *tab, uint64_t val) 160 | { 161 | ((struct packed_u64 *)tab)->v = val; 162 | } 163 | 164 | static inline uint32_t get_u32(const uint8_t *tab) 165 | { 166 | return ((const struct packed_u32 *)tab)->v; 167 | } 168 | 169 | static inline int32_t get_i32(const uint8_t *tab) 170 | { 171 | return (int32_t)((const struct packed_u32 *)tab)->v; 172 | } 173 | 174 | static inline void put_u32(uint8_t *tab, uint32_t val) 175 | { 176 | ((struct packed_u32 *)tab)->v = val; 177 | } 178 | 179 | static inline uint32_t get_u16(const uint8_t *tab) 180 | { 181 | return ((const struct packed_u16 *)tab)->v; 182 | } 183 | 184 | static inline int32_t get_i16(const uint8_t *tab) 185 | { 186 | return (int16_t)((const struct packed_u16 *)tab)->v; 187 | } 188 | 189 | static inline void put_u16(uint8_t *tab, uint16_t val) 190 | { 191 | ((struct packed_u16 *)tab)->v = val; 192 | } 193 | 194 | static inline uint32_t get_u8(const uint8_t *tab) 195 | { 196 | return *tab; 197 | } 198 | 199 | static inline int32_t get_i8(const uint8_t *tab) 200 | { 201 | return (int8_t)*tab; 202 | } 203 | 204 | static inline void put_u8(uint8_t *tab, uint8_t val) 205 | { 206 | *tab = val; 207 | } 208 | 209 | static inline uint16_t bswap16(uint16_t x) 210 | { 211 | return (x >> 8) | (x << 8); 212 | } 213 | 214 | static inline uint32_t bswap32(uint32_t v) 215 | { 216 | return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) | 217 | ((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24); 218 | } 219 | 220 | static inline uint64_t bswap64(uint64_t v) 221 | { 222 | return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) | 223 | ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) | 224 | ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) | 225 | ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) | 226 | ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) | 227 | ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) | 228 | ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) | 229 | ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8)); 230 | } 231 | 232 | /* XXX: should take an extra argument to pass slack information to the caller */ 233 | typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size); 234 | 235 | typedef struct DynBuf { 236 | uint8_t *buf; 237 | size_t size; 238 | size_t allocated_size; 239 | BOOL error; /* true if a memory allocation error occurred */ 240 | DynBufReallocFunc *realloc_func; 241 | void *opaque; /* for realloc_func */ 242 | } DynBuf; 243 | 244 | void dbuf_init(DynBuf *s); 245 | void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func); 246 | int dbuf_realloc(DynBuf *s, size_t new_size); 247 | int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len); 248 | int dbuf_put(DynBuf *s, const uint8_t *data, size_t len); 249 | int dbuf_put_self(DynBuf *s, size_t offset, size_t len); 250 | int dbuf_putc(DynBuf *s, uint8_t c); 251 | int dbuf_putstr(DynBuf *s, const char *str); 252 | static inline int dbuf_put_u16(DynBuf *s, uint16_t val) 253 | { 254 | return dbuf_put(s, (uint8_t *)&val, 2); 255 | } 256 | static inline int dbuf_put_u32(DynBuf *s, uint32_t val) 257 | { 258 | return dbuf_put(s, (uint8_t *)&val, 4); 259 | } 260 | static inline int dbuf_put_u64(DynBuf *s, uint64_t val) 261 | { 262 | return dbuf_put(s, (uint8_t *)&val, 8); 263 | } 264 | int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, 265 | const char *fmt, ...); 266 | void dbuf_free(DynBuf *s); 267 | static inline BOOL dbuf_error(DynBuf *s) { 268 | return s->error; 269 | } 270 | 271 | #define UTF8_CHAR_LEN_MAX 6 272 | 273 | int unicode_to_utf8(uint8_t *buf, unsigned int c); 274 | int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp); 275 | 276 | static inline int from_hex(int c) 277 | { 278 | if (c >= '0' && c <= '9') 279 | return c - '0'; 280 | else if (c >= 'A' && c <= 'F') 281 | return c - 'A' + 10; 282 | else if (c >= 'a' && c <= 'f') 283 | return c - 'a' + 10; 284 | else 285 | return -1; 286 | } 287 | 288 | void rqsort(void *base, size_t nmemb, size_t size, 289 | int (*cmp)(const void *, const void *, void *), 290 | void *arg); 291 | 292 | #endif /* CUTILS_H */ 293 | -------------------------------------------------------------------------------- /quickjs/libbf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Tiny arbitrary precision floating point library 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIBBF_H 25 | #define LIBBF_H 26 | 27 | #include 28 | #include 29 | 30 | #if defined(__x86_64__) 31 | #define LIMB_LOG2_BITS 6 32 | #else 33 | #define LIMB_LOG2_BITS 5 34 | #endif 35 | 36 | #define LIMB_BITS (1 << LIMB_LOG2_BITS) 37 | 38 | #if LIMB_BITS == 64 39 | typedef __int128 int128_t; 40 | typedef unsigned __int128 uint128_t; 41 | typedef int64_t slimb_t; 42 | typedef uint64_t limb_t; 43 | typedef uint128_t dlimb_t; 44 | #define EXP_MIN INT64_MIN 45 | #define EXP_MAX INT64_MAX 46 | 47 | #else 48 | 49 | typedef int32_t slimb_t; 50 | typedef uint32_t limb_t; 51 | typedef uint64_t dlimb_t; 52 | #define EXP_MIN INT32_MIN 53 | #define EXP_MAX INT32_MAX 54 | 55 | #endif 56 | 57 | /* in bits */ 58 | #define BF_EXP_BITS_MIN 3 59 | #define BF_EXP_BITS_MAX (LIMB_BITS - 2) 60 | #define BF_PREC_MIN 2 61 | #define BF_PREC_MAX (((limb_t)1 << BF_EXP_BITS_MAX) - 2) 62 | #define BF_PREC_INF (BF_PREC_MAX + 1) /* infinite precision */ 63 | 64 | #if LIMB_BITS == 64 65 | #define BF_CHKSUM_MOD (UINT64_C(975620677) * UINT64_C(9795002197)) 66 | #else 67 | #define BF_CHKSUM_MOD 975620677U 68 | #endif 69 | 70 | #define BF_EXP_ZERO EXP_MIN 71 | #define BF_EXP_INF (EXP_MAX - 1) 72 | #define BF_EXP_NAN EXP_MAX 73 | 74 | /* +/-zero is represented with expn = BF_EXP_ZERO and len = 0, 75 | +/-infinity is represented with expn = BF_EXP_INF and len = 0, 76 | NaN is represented with expn = BF_EXP_NAN and len = 0 (sign is ignored) 77 | */ 78 | typedef struct { 79 | struct bf_context_t *ctx; 80 | int sign; 81 | slimb_t expn; 82 | limb_t len; 83 | limb_t *tab; 84 | } bf_t; 85 | 86 | typedef enum { 87 | BF_RNDN, /* round to nearest, ties to even */ 88 | BF_RNDZ, /* round to zero */ 89 | BF_RNDD, /* round to -inf */ 90 | BF_RNDU, /* round to +inf */ 91 | BF_RNDNA, /* round to nearest, ties away from zero */ 92 | BF_RNDNU, /* round to nearest, ties to +inf */ 93 | BF_RNDF, /* faithful rounding (nondeterministic, either RNDD or RNDU, 94 | inexact flag is always set) */ 95 | } bf_rnd_t; 96 | 97 | /* allow subnormal numbers (only available if the number of exponent 98 | bits is < BF_EXP_BITS_MAX and prec != BF_PREC_INF) */ 99 | #define BF_FLAG_SUBNORMAL (1 << 3) 100 | 101 | #define BF_RND_MASK 0x7 102 | #define BF_EXP_BITS_SHIFT 4 103 | #define BF_EXP_BITS_MASK 0x3f 104 | 105 | /* contains the rounding mode and number of exponents bits */ 106 | typedef uint32_t bf_flags_t; 107 | 108 | typedef void *bf_realloc_func_t(void *opaque, void *ptr, size_t size); 109 | 110 | typedef struct { 111 | bf_t val; 112 | limb_t prec; 113 | } BFConstCache; 114 | 115 | typedef struct bf_context_t { 116 | void *realloc_opaque; 117 | bf_realloc_func_t *realloc_func; 118 | BFConstCache log2_cache; 119 | BFConstCache pi_cache; 120 | struct BFNTTState *ntt_state; 121 | } bf_context_t; 122 | 123 | static inline int bf_get_exp_bits(bf_flags_t flags) 124 | { 125 | return BF_EXP_BITS_MAX - ((flags >> BF_EXP_BITS_SHIFT) & BF_EXP_BITS_MASK); 126 | } 127 | 128 | static inline bf_flags_t bf_set_exp_bits(int n) 129 | { 130 | return (BF_EXP_BITS_MAX - n) << BF_EXP_BITS_SHIFT; 131 | } 132 | 133 | /* returned status */ 134 | #define BF_ST_INVALID_OP (1 << 0) 135 | #define BF_ST_DIVIDE_ZERO (1 << 1) 136 | #define BF_ST_OVERFLOW (1 << 2) 137 | #define BF_ST_UNDERFLOW (1 << 3) 138 | #define BF_ST_INEXACT (1 << 4) 139 | /* not used yet, indicate that a memory allocation error occured. NaN 140 | is returned */ 141 | #define BF_ST_MEM_ERROR (1 << 5) 142 | 143 | #define BF_RADIX_MAX 36 /* maximum radix for bf_atof() and bf_ftoa() */ 144 | 145 | static inline slimb_t bf_max(slimb_t a, slimb_t b) 146 | { 147 | if (a > b) 148 | return a; 149 | else 150 | return b; 151 | } 152 | 153 | static inline slimb_t bf_min(slimb_t a, slimb_t b) 154 | { 155 | if (a < b) 156 | return a; 157 | else 158 | return b; 159 | } 160 | 161 | void bf_context_init(bf_context_t *s, bf_realloc_func_t *realloc_func, 162 | void *realloc_opaque); 163 | void bf_context_end(bf_context_t *s); 164 | /* free memory allocated for the bf cache data */ 165 | void bf_clear_cache(bf_context_t *s); 166 | 167 | static inline void *bf_realloc(bf_context_t *s, void *ptr, size_t size) 168 | { 169 | return s->realloc_func(s->realloc_opaque, ptr, size); 170 | } 171 | 172 | void bf_init(bf_context_t *s, bf_t *r); 173 | 174 | static inline void bf_delete(bf_t *r) 175 | { 176 | bf_context_t *s = r->ctx; 177 | /* we accept to delete a zeroed bf_t structure */ 178 | if (s) { 179 | bf_realloc(s, r->tab, 0); 180 | } 181 | } 182 | 183 | static inline void bf_neg(bf_t *r) 184 | { 185 | r->sign ^= 1; 186 | } 187 | 188 | static inline int bf_is_finite(const bf_t *a) 189 | { 190 | return (a->expn < BF_EXP_INF); 191 | } 192 | 193 | static inline int bf_is_nan(const bf_t *a) 194 | { 195 | return (a->expn == BF_EXP_NAN); 196 | } 197 | 198 | static inline int bf_is_zero(const bf_t *a) 199 | { 200 | return (a->expn == BF_EXP_ZERO); 201 | } 202 | 203 | void bf_set_ui(bf_t *r, uint64_t a); 204 | void bf_set_si(bf_t *r, int64_t a); 205 | void bf_set_nan(bf_t *r); 206 | void bf_set_zero(bf_t *r, int is_neg); 207 | void bf_set_inf(bf_t *r, int is_neg); 208 | void bf_set(bf_t *r, const bf_t *a); 209 | void bf_move(bf_t *r, bf_t *a); 210 | int bf_get_float64(const bf_t *a, double *pres, bf_rnd_t rnd_mode); 211 | void bf_set_float64(bf_t *a, double d); 212 | 213 | int bf_cmpu(const bf_t *a, const bf_t *b); 214 | int bf_cmp_full(const bf_t *a, const bf_t *b); 215 | int bf_cmp_eq(const bf_t *a, const bf_t *b); 216 | int bf_cmp_le(const bf_t *a, const bf_t *b); 217 | int bf_cmp_lt(const bf_t *a, const bf_t *b); 218 | int bf_add(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); 219 | int bf_sub(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); 220 | int bf_add_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, bf_flags_t flags); 221 | int bf_mul(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); 222 | int bf_mul_ui(bf_t *r, const bf_t *a, uint64_t b1, limb_t prec, bf_flags_t flags); 223 | int bf_mul_si(bf_t *r, const bf_t *a, int64_t b1, limb_t prec, 224 | bf_flags_t flags); 225 | int bf_mul_2exp(bf_t *r, slimb_t e, limb_t prec, bf_flags_t flags); 226 | int bf_div(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, bf_flags_t flags); 227 | #define BF_DIVREM_EUCLIDIAN BF_RNDF 228 | int bf_divrem(bf_t *q, bf_t *r, const bf_t *a, const bf_t *b, 229 | limb_t prec, bf_flags_t flags, int rnd_mode); 230 | int bf_fmod(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, 231 | bf_flags_t flags); 232 | int bf_remainder(bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, 233 | bf_flags_t flags); 234 | int bf_remquo(slimb_t *pq, bf_t *r, const bf_t *a, const bf_t *b, limb_t prec, 235 | bf_flags_t flags); 236 | int bf_pow_ui(bf_t *r, const bf_t *a, limb_t b, limb_t prec, 237 | bf_flags_t flags); 238 | int bf_pow_ui_ui(bf_t *r, limb_t a1, limb_t b, limb_t prec, bf_flags_t flags); 239 | int bf_rint(bf_t *r, limb_t prec, bf_flags_t flags); 240 | int bf_round(bf_t *r, limb_t prec, bf_flags_t flags); 241 | int bf_sqrtrem(bf_t *r, bf_t *rem1, const bf_t *a); 242 | int bf_sqrt(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 243 | slimb_t bf_get_exp_min(const bf_t *a); 244 | void bf_logic_or(bf_t *r, const bf_t *a, const bf_t *b); 245 | void bf_logic_xor(bf_t *r, const bf_t *a, const bf_t *b); 246 | void bf_logic_and(bf_t *r, const bf_t *a, const bf_t *b); 247 | 248 | /* additional flags for bf_atof */ 249 | /* do not accept hex radix prefix (0x or 0X) if radix = 0 or radix = 16 */ 250 | #define BF_ATOF_NO_HEX (1 << 16) 251 | /* accept binary (0b or 0B) or octal (0o or 0O) radix prefix if radix = 0 */ 252 | #define BF_ATOF_BIN_OCT (1 << 17) 253 | /* Only accept integers (no decimal point, no exponent, no infinity nor NaN */ 254 | #define BF_ATOF_INT_ONLY (1 << 18) 255 | /* Do not accept radix prefix after sign */ 256 | #define BF_ATOF_NO_PREFIX_AFTER_SIGN (1 << 19) 257 | /* Do not parse NaN and parse case sensitive 'Infinity' */ 258 | #define BF_ATOF_JS_QUIRKS (1 << 20) 259 | /* Do not round integers to the indicated precision */ 260 | #define BF_ATOF_INT_PREC_INF (1 << 21) 261 | /* Support legacy octal syntax for well formed numbers */ 262 | #define BF_ATOF_LEGACY_OCTAL (1 << 22) 263 | /* accept _ between digits as a digit separator */ 264 | #define BF_ATOF_UNDERSCORE_SEP (1 << 23) 265 | /* if a 'n' suffix is present, force integer parsing (XXX: remove) */ 266 | #define BF_ATOF_INT_N_SUFFIX (1 << 24) 267 | /* if set return NaN if empty number string (instead of 0) */ 268 | #define BF_ATOF_NAN_IF_EMPTY (1 << 25) 269 | /* only accept decimal floating point if radix = 0 */ 270 | #define BF_ATOF_ONLY_DEC_FLOAT (1 << 26) 271 | 272 | /* one more return flag: indicate that the parsed number is an integer 273 | (only set when the flags BF_ATOF_INT_PREC_INF or 274 | BF_ATOF_INT_N_SUFFIX are used) */ 275 | #define BF_ATOF_ST_INTEGER (1 << 5) 276 | 277 | int bf_atof(bf_t *a, const char *str, const char **pnext, int radix, 278 | limb_t prec, bf_flags_t flags); 279 | /* this version accepts prec = BF_PREC_INF and returns the radix 280 | exponent */ 281 | int bf_atof2(bf_t *r, slimb_t *pexponent, 282 | const char *str, const char **pnext, int radix, 283 | limb_t prec, bf_flags_t flags); 284 | int bf_mul_pow_radix(bf_t *r, const bf_t *T, limb_t radix, 285 | slimb_t expn, limb_t prec, bf_flags_t flags); 286 | 287 | #define BF_FTOA_FORMAT_MASK (3 << 16) 288 | /* fixed format: prec significant digits rounded with (flags & 289 | BF_RND_MASK). Exponential notation is used if too many zeros are 290 | needed. */ 291 | #define BF_FTOA_FORMAT_FIXED (0 << 16) 292 | /* fractional format: prec digits after the decimal point rounded with 293 | (flags & BF_RND_MASK) */ 294 | #define BF_FTOA_FORMAT_FRAC (1 << 16) 295 | /* free format: use as many digits as necessary so that bf_atof() 296 | return the same number when using precision 'prec', rounding to 297 | nearest and the subnormal+exponent configuration of 'flags'. The 298 | result is meaningful only if 'a' is already rounded to the wanted 299 | precision. 300 | 301 | Infinite precision (BF_PREC_INF) is supported when the radix is a 302 | power of two. */ 303 | #define BF_FTOA_FORMAT_FREE (2 << 16) 304 | /* same as BF_FTOA_FORMAT_FREE but uses the minimum number of digits 305 | (takes more computation time). */ 306 | #define BF_FTOA_FORMAT_FREE_MIN (3 << 16) 307 | 308 | /* force exponential notation for fixed or free format */ 309 | #define BF_FTOA_FORCE_EXP (1 << 20) 310 | /* add 0x prefix for base 16, 0o prefix for base 8 or 0b prefix for 311 | base 2 if non zero value */ 312 | #define BF_FTOA_ADD_PREFIX (1 << 21) 313 | #define BF_FTOA_JS_QUIRKS (1 << 22) 314 | 315 | size_t bf_ftoa(char **pbuf, const bf_t *a, int radix, limb_t prec, 316 | bf_flags_t flags); 317 | 318 | /* modulo 2^n instead of saturation. NaN and infinity return 0 */ 319 | #define BF_GET_INT_MOD (1 << 0) 320 | int bf_get_int32(int *pres, const bf_t *a, int flags); 321 | int bf_get_int64(int64_t *pres, const bf_t *a, int flags); 322 | 323 | /* the following functions are exported for testing only. */ 324 | void bf_print_str(const char *str, const bf_t *a); 325 | void bf_resize(bf_t *r, limb_t len); 326 | int bf_get_fft_size(int *pdpl, int *pnb_mods, limb_t len); 327 | void bf_recip(bf_t *r, const bf_t *a, limb_t prec); 328 | void bf_rsqrt(bf_t *a, const bf_t *x, limb_t prec); 329 | int bf_normalize_and_round(bf_t *r, limb_t prec1, bf_flags_t flags); 330 | int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k); 331 | slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv, 332 | int is_ceil1); 333 | 334 | /* transcendental functions */ 335 | int bf_const_log2(bf_t *T, limb_t prec, bf_flags_t flags); 336 | int bf_const_pi(bf_t *T, limb_t prec, bf_flags_t flags); 337 | int bf_exp(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 338 | int bf_log(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 339 | #define BF_POW_JS_QUICKS (1 << 16) 340 | int bf_pow(bf_t *r, const bf_t *x, const bf_t *y, limb_t prec, bf_flags_t flags); 341 | int bf_cos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 342 | int bf_sin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 343 | int bf_tan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 344 | int bf_atan(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 345 | int bf_atan2(bf_t *r, const bf_t *y, const bf_t *x, 346 | limb_t prec, bf_flags_t flags); 347 | int bf_asin(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 348 | int bf_acos(bf_t *r, const bf_t *a, limb_t prec, bf_flags_t flags); 349 | 350 | #endif /* LIBBF_H */ 351 | -------------------------------------------------------------------------------- /quickjs/libregexp-opcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Regular Expression Engine 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifdef DEF 26 | 27 | DEF(invalid, 1) /* never used */ 28 | DEF(char, 3) 29 | DEF(char32, 5) 30 | DEF(dot, 1) 31 | DEF(any, 1) /* same as dot but match any character including line terminator */ 32 | DEF(line_start, 1) 33 | DEF(line_end, 1) 34 | DEF(goto, 5) 35 | DEF(split_goto_first, 5) 36 | DEF(split_next_first, 5) 37 | DEF(match, 1) 38 | DEF(save_start, 2) /* save start position */ 39 | DEF(save_end, 2) /* save end position, must come after saved_start */ 40 | DEF(save_reset, 3) /* reset save positions */ 41 | DEF(loop, 5) /* decrement the top the stack and goto if != 0 */ 42 | DEF(push_i32, 5) /* push integer on the stack */ 43 | DEF(drop, 1) 44 | DEF(word_boundary, 1) 45 | DEF(not_word_boundary, 1) 46 | DEF(back_reference, 2) 47 | DEF(backward_back_reference, 2) /* must come after back_reference */ 48 | DEF(range, 3) /* variable length */ 49 | DEF(range32, 3) /* variable length */ 50 | DEF(lookahead, 5) 51 | DEF(negative_lookahead, 5) 52 | DEF(push_char_pos, 1) /* push the character position on the stack */ 53 | DEF(bne_char_pos, 5) /* pop one stack element and jump if equal to the character 54 | position */ 55 | DEF(prev, 1) /* go to the previous char */ 56 | DEF(simple_greedy_quant, 17) 57 | 58 | #endif /* DEF */ 59 | -------------------------------------------------------------------------------- /quickjs/libregexp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Regular Expression Engine 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIBREGEXP_H 25 | #define LIBREGEXP_H 26 | 27 | #include 28 | 29 | #include "libunicode.h" 30 | 31 | #define LRE_BOOL int /* for documentation purposes */ 32 | 33 | #define LRE_FLAG_GLOBAL (1 << 0) 34 | #define LRE_FLAG_IGNORECASE (1 << 1) 35 | #define LRE_FLAG_MULTILINE (1 << 2) 36 | #define LRE_FLAG_DOTALL (1 << 3) 37 | #define LRE_FLAG_UTF16 (1 << 4) 38 | #define LRE_FLAG_STICKY (1 << 5) 39 | 40 | #define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */ 41 | 42 | uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, 43 | const char *buf, size_t buf_len, int re_flags, 44 | void *opaque); 45 | int lre_get_capture_count(const uint8_t *bc_buf); 46 | int lre_get_flags(const uint8_t *bc_buf); 47 | int lre_exec(uint8_t **capture, 48 | const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen, 49 | int cbuf_type, void *opaque); 50 | 51 | int lre_parse_escape(const uint8_t **pp, int allow_utf16); 52 | LRE_BOOL lre_is_space(int c); 53 | 54 | /* must be provided by the user */ 55 | LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size); 56 | void *lre_realloc(void *opaque, void *ptr, size_t size); 57 | 58 | /* JS identifier test */ 59 | extern uint32_t const lre_id_start_table_ascii[4]; 60 | extern uint32_t const lre_id_continue_table_ascii[4]; 61 | 62 | static inline int lre_js_is_ident_first(int c) 63 | { 64 | if ((uint32_t)c < 128) { 65 | return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1; 66 | } else { 67 | #ifdef CONFIG_ALL_UNICODE 68 | return lre_is_id_start(c); 69 | #else 70 | return !lre_is_space(c); 71 | #endif 72 | } 73 | } 74 | 75 | static inline int lre_js_is_ident_next(int c) 76 | { 77 | if ((uint32_t)c < 128) { 78 | return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1; 79 | } else { 80 | /* ZWNJ and ZWJ are accepted in identifiers */ 81 | #ifdef CONFIG_ALL_UNICODE 82 | return lre_is_id_continue(c) || c == 0x200C || c == 0x200D; 83 | #else 84 | return !lre_is_space(c) || c == 0x200C || c == 0x200D; 85 | #endif 86 | } 87 | } 88 | 89 | #undef LRE_BOOL 90 | 91 | #endif /* LIBREGEXP_H */ 92 | -------------------------------------------------------------------------------- /quickjs/libunicode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Unicode utilities 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "cutils.h" 31 | #include "libunicode.h" 32 | #include "libunicode-table.h" 33 | 34 | enum { 35 | RUN_TYPE_U, 36 | RUN_TYPE_L, 37 | RUN_TYPE_UF, 38 | RUN_TYPE_LF, 39 | RUN_TYPE_UL, 40 | RUN_TYPE_LSU, 41 | RUN_TYPE_U2L_399_EXT2, 42 | RUN_TYPE_UF_D20, 43 | RUN_TYPE_UF_D1_EXT, 44 | RUN_TYPE_U_EXT, 45 | RUN_TYPE_LF_EXT, 46 | RUN_TYPE_U_EXT2, 47 | RUN_TYPE_L_EXT2, 48 | RUN_TYPE_U_EXT3, 49 | }; 50 | 51 | /* conv_type: 52 | 0 = to upper 53 | 1 = to lower 54 | 2 = case folding (= to lower with modifications) 55 | */ 56 | int lre_case_conv(uint32_t *res, uint32_t c, int conv_type) 57 | { 58 | if (c < 128) { 59 | if (conv_type) { 60 | if (c >= 'A' && c <= 'Z') { 61 | c = c - 'A' + 'a'; 62 | } 63 | } else { 64 | if (c >= 'a' && c <= 'z') { 65 | c = c - 'a' + 'A'; 66 | } 67 | } 68 | } else { 69 | uint32_t v, code, data, type, len, a, is_lower; 70 | int idx, idx_min, idx_max; 71 | 72 | is_lower = (conv_type != 0); 73 | idx_min = 0; 74 | idx_max = countof(case_conv_table1) - 1; 75 | while (idx_min <= idx_max) { 76 | idx = (unsigned)(idx_max + idx_min) / 2; 77 | v = case_conv_table1[idx]; 78 | code = v >> (32 - 17); 79 | len = (v >> (32 - 17 - 7)) & 0x7f; 80 | if (c < code) { 81 | idx_max = idx - 1; 82 | } else if (c >= code + len) { 83 | idx_min = idx + 1; 84 | } else { 85 | type = (v >> (32 - 17 - 7 - 4)) & 0xf; 86 | data = ((v & 0xf) << 8) | case_conv_table2[idx]; 87 | switch(type) { 88 | case RUN_TYPE_U: 89 | case RUN_TYPE_L: 90 | case RUN_TYPE_UF: 91 | case RUN_TYPE_LF: 92 | if (conv_type == (type & 1) || 93 | (type >= RUN_TYPE_UF && conv_type == 2)) { 94 | c = c - code + (case_conv_table1[data] >> (32 - 17)); 95 | } 96 | break; 97 | case RUN_TYPE_UL: 98 | a = c - code; 99 | if ((a & 1) != (1 - is_lower)) 100 | break; 101 | c = (a ^ 1) + code; 102 | break; 103 | case RUN_TYPE_LSU: 104 | a = c - code; 105 | if (a == 1) { 106 | c += 2 * is_lower - 1; 107 | } else if (a == (1 - is_lower) * 2) { 108 | c += (2 * is_lower - 1) * 2; 109 | } 110 | break; 111 | case RUN_TYPE_U2L_399_EXT2: 112 | if (!is_lower) { 113 | res[0] = c - code + case_conv_ext[data >> 6]; 114 | res[1] = 0x399; 115 | return 2; 116 | } else { 117 | c = c - code + case_conv_ext[data & 0x3f]; 118 | } 119 | break; 120 | case RUN_TYPE_UF_D20: 121 | if (conv_type == 1) 122 | break; 123 | c = data + (conv_type == 2) * 0x20; 124 | break; 125 | case RUN_TYPE_UF_D1_EXT: 126 | if (conv_type == 1) 127 | break; 128 | c = case_conv_ext[data] + (conv_type == 2); 129 | break; 130 | case RUN_TYPE_U_EXT: 131 | case RUN_TYPE_LF_EXT: 132 | if (is_lower != (type - RUN_TYPE_U_EXT)) 133 | break; 134 | c = case_conv_ext[data]; 135 | break; 136 | case RUN_TYPE_U_EXT2: 137 | case RUN_TYPE_L_EXT2: 138 | if (conv_type != (type - RUN_TYPE_U_EXT2)) 139 | break; 140 | res[0] = c - code + case_conv_ext[data >> 6]; 141 | res[1] = case_conv_ext[data & 0x3f]; 142 | return 2; 143 | default: 144 | case RUN_TYPE_U_EXT3: 145 | if (conv_type != 0) 146 | break; 147 | res[0] = case_conv_ext[data >> 8]; 148 | res[1] = case_conv_ext[(data >> 4) & 0xf]; 149 | res[2] = case_conv_ext[data & 0xf]; 150 | return 3; 151 | } 152 | break; 153 | } 154 | } 155 | } 156 | res[0] = c; 157 | return 1; 158 | } 159 | 160 | static uint32_t get_le24(const uint8_t *ptr) 161 | { 162 | #if defined(__x86__) || defined(__x86_64__) 163 | return *(uint16_t *)ptr | (ptr[2] << 16); 164 | #else 165 | return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16); 166 | #endif 167 | } 168 | 169 | #define UNICODE_INDEX_BLOCK_LEN 32 170 | 171 | /* return -1 if not in table, otherwise the offset in the block */ 172 | static int get_index_pos(uint32_t *pcode, uint32_t c, 173 | const uint8_t *index_table, int index_table_len) 174 | { 175 | uint32_t code, v; 176 | int idx_min, idx_max, idx; 177 | 178 | idx_min = 0; 179 | v = get_le24(index_table); 180 | code = v & ((1 << 21) - 1); 181 | if (c < code) { 182 | *pcode = 0; 183 | return 0; 184 | } 185 | idx_max = index_table_len - 1; 186 | code = get_le24(index_table + idx_max * 3); 187 | if (c >= code) 188 | return -1; 189 | /* invariant: tab[idx_min] <= c < tab2[idx_max] */ 190 | while ((idx_max - idx_min) > 1) { 191 | idx = (idx_max + idx_min) / 2; 192 | v = get_le24(index_table + idx * 3); 193 | code = v & ((1 << 21) - 1); 194 | if (c < code) { 195 | idx_max = idx; 196 | } else { 197 | idx_min = idx; 198 | } 199 | } 200 | v = get_le24(index_table + idx_min * 3); 201 | *pcode = v & ((1 << 21) - 1); 202 | return (idx_min + 1) * UNICODE_INDEX_BLOCK_LEN + (v >> 21); 203 | } 204 | 205 | static BOOL lre_is_in_table(uint32_t c, const uint8_t *table, 206 | const uint8_t *index_table, int index_table_len) 207 | { 208 | uint32_t code, b, bit; 209 | int pos; 210 | const uint8_t *p; 211 | 212 | pos = get_index_pos(&code, c, index_table, index_table_len); 213 | if (pos < 0) 214 | return FALSE; /* outside the table */ 215 | p = table + pos; 216 | bit = 0; 217 | for(;;) { 218 | b = *p++; 219 | if (b < 64) { 220 | code += (b >> 3) + 1; 221 | if (c < code) 222 | return bit; 223 | bit ^= 1; 224 | code += (b & 7) + 1; 225 | } else if (b >= 0x80) { 226 | code += b - 0x80 + 1; 227 | } else if (b < 0x60) { 228 | code += (((b - 0x40) << 8) | p[0]) + 1; 229 | p++; 230 | } else { 231 | code += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1; 232 | p += 2; 233 | } 234 | if (c < code) 235 | return bit; 236 | bit ^= 1; 237 | } 238 | } 239 | 240 | BOOL lre_is_cased(uint32_t c) 241 | { 242 | uint32_t v, code, len; 243 | int idx, idx_min, idx_max; 244 | 245 | idx_min = 0; 246 | idx_max = countof(case_conv_table1) - 1; 247 | while (idx_min <= idx_max) { 248 | idx = (unsigned)(idx_max + idx_min) / 2; 249 | v = case_conv_table1[idx]; 250 | code = v >> (32 - 17); 251 | len = (v >> (32 - 17 - 7)) & 0x7f; 252 | if (c < code) { 253 | idx_max = idx - 1; 254 | } else if (c >= code + len) { 255 | idx_min = idx + 1; 256 | } else { 257 | return TRUE; 258 | } 259 | } 260 | return lre_is_in_table(c, unicode_prop_Cased1_table, 261 | unicode_prop_Cased1_index, 262 | sizeof(unicode_prop_Cased1_index) / 3); 263 | } 264 | 265 | BOOL lre_is_case_ignorable(uint32_t c) 266 | { 267 | return lre_is_in_table(c, unicode_prop_Case_Ignorable_table, 268 | unicode_prop_Case_Ignorable_index, 269 | sizeof(unicode_prop_Case_Ignorable_index) / 3); 270 | } 271 | 272 | /* character range */ 273 | 274 | static __attribute__((unused)) void cr_dump(CharRange *cr) 275 | { 276 | int i; 277 | for(i = 0; i < cr->len; i++) 278 | printf("%d: 0x%04x\n", i, cr->points[i]); 279 | } 280 | 281 | static void *cr_default_realloc(void *opaque, void *ptr, size_t size) 282 | { 283 | return realloc(ptr, size); 284 | } 285 | 286 | void cr_init(CharRange *cr, void *mem_opaque, DynBufReallocFunc *realloc_func) 287 | { 288 | cr->len = cr->size = 0; 289 | cr->points = NULL; 290 | cr->mem_opaque = mem_opaque; 291 | cr->realloc_func = realloc_func ? realloc_func : cr_default_realloc; 292 | } 293 | 294 | void cr_free(CharRange *cr) 295 | { 296 | cr->realloc_func(cr->mem_opaque, cr->points, 0); 297 | } 298 | 299 | int cr_realloc(CharRange *cr, int size) 300 | { 301 | int new_size; 302 | uint32_t *new_buf; 303 | 304 | if (size > cr->size) { 305 | new_size = max_int(size, cr->size * 3 / 2); 306 | new_buf = cr->realloc_func(cr->mem_opaque, cr->points, 307 | new_size * sizeof(cr->points[0])); 308 | if (!new_buf) 309 | return -1; 310 | cr->points = new_buf; 311 | cr->size = new_size; 312 | } 313 | return 0; 314 | } 315 | 316 | int cr_copy(CharRange *cr, const CharRange *cr1) 317 | { 318 | if (cr_realloc(cr, cr1->len)) 319 | return -1; 320 | memcpy(cr->points, cr1->points, sizeof(cr->points[0]) * cr1->len); 321 | cr->len = cr1->len; 322 | return 0; 323 | } 324 | 325 | /* merge consecutive intervals and remove empty intervals */ 326 | static void cr_compress(CharRange *cr) 327 | { 328 | int i, j, k, len; 329 | uint32_t *pt; 330 | 331 | pt = cr->points; 332 | len = cr->len; 333 | i = 0; 334 | j = 0; 335 | k = 0; 336 | while ((i + 1) < len) { 337 | if (pt[i] == pt[i + 1]) { 338 | /* empty interval */ 339 | i += 2; 340 | } else { 341 | j = i; 342 | while ((j + 3) < len && pt[j + 1] == pt[j + 2]) 343 | j += 2; 344 | /* just copy */ 345 | pt[k] = pt[i]; 346 | pt[k + 1] = pt[j + 1]; 347 | k += 2; 348 | i = j + 2; 349 | } 350 | } 351 | cr->len = k; 352 | } 353 | 354 | /* union or intersection */ 355 | int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, 356 | const uint32_t *b_pt, int b_len, int op) 357 | { 358 | int a_idx, b_idx, is_in; 359 | uint32_t v; 360 | 361 | a_idx = 0; 362 | b_idx = 0; 363 | for(;;) { 364 | /* get one more point from a or b in increasing order */ 365 | if (a_idx < a_len && b_idx < b_len) { 366 | if (a_pt[a_idx] < b_pt[b_idx]) { 367 | goto a_add; 368 | } else if (a_pt[a_idx] == b_pt[b_idx]) { 369 | v = a_pt[a_idx]; 370 | a_idx++; 371 | b_idx++; 372 | } else { 373 | goto b_add; 374 | } 375 | } else if (a_idx < a_len) { 376 | a_add: 377 | v = a_pt[a_idx++]; 378 | } else if (b_idx < b_len) { 379 | b_add: 380 | v = b_pt[b_idx++]; 381 | } else { 382 | break; 383 | } 384 | /* add the point if the in/out status changes */ 385 | switch(op) { 386 | case CR_OP_UNION: 387 | is_in = (a_idx & 1) | (b_idx & 1); 388 | break; 389 | case CR_OP_INTER: 390 | is_in = (a_idx & 1) & (b_idx & 1); 391 | break; 392 | case CR_OP_XOR: 393 | is_in = (a_idx & 1) ^ (b_idx & 1); 394 | break; 395 | default: 396 | abort(); 397 | } 398 | if (is_in != (cr->len & 1)) { 399 | if (cr_add_point(cr, v)) 400 | return -1; 401 | } 402 | } 403 | cr_compress(cr); 404 | return 0; 405 | } 406 | 407 | int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len) 408 | { 409 | CharRange a = *cr; 410 | int ret; 411 | cr->len = 0; 412 | cr->size = 0; 413 | cr->points = NULL; 414 | ret = cr_op(cr, a.points, a.len, b_pt, b_len, CR_OP_UNION); 415 | cr_free(&a); 416 | return ret; 417 | } 418 | 419 | int cr_invert(CharRange *cr) 420 | { 421 | int len; 422 | len = cr->len; 423 | if (cr_realloc(cr, len + 2)) 424 | return -1; 425 | memmove(cr->points + 1, cr->points, len * sizeof(cr->points[0])); 426 | cr->points[0] = 0; 427 | cr->points[len + 1] = UINT32_MAX; 428 | cr->len = len + 2; 429 | cr_compress(cr); 430 | return 0; 431 | } 432 | 433 | #ifdef CONFIG_ALL_UNICODE 434 | 435 | BOOL lre_is_id_start(uint32_t c) 436 | { 437 | return lre_is_in_table(c, unicode_prop_ID_Start_table, 438 | unicode_prop_ID_Start_index, 439 | sizeof(unicode_prop_ID_Start_index) / 3); 440 | } 441 | 442 | BOOL lre_is_id_continue(uint32_t c) 443 | { 444 | return lre_is_id_start(c) || 445 | lre_is_in_table(c, unicode_prop_ID_Continue1_table, 446 | unicode_prop_ID_Continue1_index, 447 | sizeof(unicode_prop_ID_Continue1_index) / 3); 448 | } 449 | 450 | #define UNICODE_DECOMP_LEN_MAX 18 451 | 452 | typedef enum { 453 | DECOMP_TYPE_C1, /* 16 bit char */ 454 | DECOMP_TYPE_L1, /* 16 bit char table */ 455 | DECOMP_TYPE_L2, 456 | DECOMP_TYPE_L3, 457 | DECOMP_TYPE_L4, 458 | DECOMP_TYPE_L5, /* XXX: not used */ 459 | DECOMP_TYPE_L6, /* XXX: could remove */ 460 | DECOMP_TYPE_L7, /* XXX: could remove */ 461 | DECOMP_TYPE_LL1, /* 18 bit char table */ 462 | DECOMP_TYPE_LL2, 463 | DECOMP_TYPE_S1, /* 8 bit char table */ 464 | DECOMP_TYPE_S2, 465 | DECOMP_TYPE_S3, 466 | DECOMP_TYPE_S4, 467 | DECOMP_TYPE_S5, 468 | DECOMP_TYPE_I1, /* increment 16 bit char value */ 469 | DECOMP_TYPE_I2_0, 470 | DECOMP_TYPE_I2_1, 471 | DECOMP_TYPE_I3_1, 472 | DECOMP_TYPE_I3_2, 473 | DECOMP_TYPE_I4_1, 474 | DECOMP_TYPE_I4_2, 475 | DECOMP_TYPE_B1, /* 16 bit base + 8 bit offset */ 476 | DECOMP_TYPE_B2, 477 | DECOMP_TYPE_B3, 478 | DECOMP_TYPE_B4, 479 | DECOMP_TYPE_B5, 480 | DECOMP_TYPE_B6, 481 | DECOMP_TYPE_B7, 482 | DECOMP_TYPE_B8, 483 | DECOMP_TYPE_B18, 484 | DECOMP_TYPE_LS2, 485 | DECOMP_TYPE_PAT3, 486 | DECOMP_TYPE_S2_UL, 487 | DECOMP_TYPE_LS2_UL, 488 | } DecompTypeEnum; 489 | 490 | static uint32_t unicode_get_short_code(uint32_t c) 491 | { 492 | static const uint16_t unicode_short_table[2] = { 0x2044, 0x2215 }; 493 | 494 | if (c < 0x80) 495 | return c; 496 | else if (c < 0x80 + 0x50) 497 | return c - 0x80 + 0x300; 498 | else 499 | return unicode_short_table[c - 0x80 - 0x50]; 500 | } 501 | 502 | static uint32_t unicode_get_lower_simple(uint32_t c) 503 | { 504 | if (c < 0x100 || (c >= 0x410 && c <= 0x42f)) 505 | c += 0x20; 506 | else 507 | c++; 508 | return c; 509 | } 510 | 511 | static uint16_t unicode_get16(const uint8_t *p) 512 | { 513 | return p[0] | (p[1] << 8); 514 | } 515 | 516 | static int unicode_decomp_entry(uint32_t *res, uint32_t c, 517 | int idx, uint32_t code, uint32_t len, 518 | uint32_t type) 519 | { 520 | uint32_t c1; 521 | int l, i, p; 522 | const uint8_t *d; 523 | 524 | if (type == DECOMP_TYPE_C1) { 525 | res[0] = unicode_decomp_table2[idx]; 526 | return 1; 527 | } else { 528 | d = unicode_decomp_data + unicode_decomp_table2[idx]; 529 | switch(type) { 530 | case DECOMP_TYPE_L1 ... DECOMP_TYPE_L7: 531 | l = type - DECOMP_TYPE_L1 + 1; 532 | d += (c - code) * l * 2; 533 | for(i = 0; i < l; i++) { 534 | if ((res[i] = unicode_get16(d + 2 * i)) == 0) 535 | return 0; 536 | } 537 | return l; 538 | case DECOMP_TYPE_LL1 ... DECOMP_TYPE_LL2: 539 | { 540 | uint32_t k, p; 541 | l = type - DECOMP_TYPE_LL1 + 1; 542 | k = (c - code) * l; 543 | p = len * l * 2; 544 | for(i = 0; i < l; i++) { 545 | c1 = unicode_get16(d + 2 * k) | 546 | (((d[p + (k / 4)] >> ((k % 4) * 2)) & 3) << 16); 547 | if (!c1) 548 | return 0; 549 | res[i] = c1; 550 | k++; 551 | } 552 | } 553 | return l; 554 | case DECOMP_TYPE_S1 ... DECOMP_TYPE_S5: 555 | l = type - DECOMP_TYPE_S1 + 1; 556 | d += (c - code) * l; 557 | for(i = 0; i < l; i++) { 558 | if ((res[i] = unicode_get_short_code(d[i])) == 0) 559 | return 0; 560 | } 561 | return l; 562 | case DECOMP_TYPE_I1: 563 | l = 1; 564 | p = 0; 565 | goto decomp_type_i; 566 | case DECOMP_TYPE_I2_0: 567 | case DECOMP_TYPE_I2_1: 568 | case DECOMP_TYPE_I3_1: 569 | case DECOMP_TYPE_I3_2: 570 | case DECOMP_TYPE_I4_1: 571 | case DECOMP_TYPE_I4_2: 572 | l = 2 + ((type - DECOMP_TYPE_I2_0) >> 1); 573 | p = ((type - DECOMP_TYPE_I2_0) & 1) + (l > 2); 574 | decomp_type_i: 575 | for(i = 0; i < l; i++) { 576 | c1 = unicode_get16(d + 2 * i); 577 | if (i == p) 578 | c1 += c - code; 579 | res[i] = c1; 580 | } 581 | return l; 582 | case DECOMP_TYPE_B18: 583 | l = 18; 584 | goto decomp_type_b; 585 | case DECOMP_TYPE_B1 ... DECOMP_TYPE_B8: 586 | l = type - DECOMP_TYPE_B1 + 1; 587 | decomp_type_b: 588 | { 589 | uint32_t c_min; 590 | c_min = unicode_get16(d); 591 | d += 2 + (c - code) * l; 592 | for(i = 0; i < l; i++) { 593 | c1 = d[i]; 594 | if (c1 == 0xff) 595 | c1 = 0x20; 596 | else 597 | c1 += c_min; 598 | res[i] = c1; 599 | } 600 | } 601 | return l; 602 | case DECOMP_TYPE_LS2: 603 | d += (c - code) * 3; 604 | if (!(res[0] = unicode_get16(d))) 605 | return 0; 606 | res[1] = unicode_get_short_code(d[2]); 607 | return 2; 608 | case DECOMP_TYPE_PAT3: 609 | res[0] = unicode_get16(d); 610 | res[2] = unicode_get16(d + 2); 611 | d += 4 + (c - code) * 2; 612 | res[1] = unicode_get16(d); 613 | return 3; 614 | case DECOMP_TYPE_S2_UL: 615 | case DECOMP_TYPE_LS2_UL: 616 | c1 = c - code; 617 | if (type == DECOMP_TYPE_S2_UL) { 618 | d += c1 & ~1; 619 | c = unicode_get_short_code(*d); 620 | d++; 621 | } else { 622 | d += (c1 >> 1) * 3; 623 | c = unicode_get16(d); 624 | d += 2; 625 | } 626 | if (c1 & 1) 627 | c = unicode_get_lower_simple(c); 628 | res[0] = c; 629 | res[1] = unicode_get_short_code(*d); 630 | return 2; 631 | } 632 | } 633 | return 0; 634 | } 635 | 636 | 637 | /* return the length of the decomposition (length <= 638 | UNICODE_DECOMP_LEN_MAX) or 0 if no decomposition */ 639 | static int unicode_decomp_char(uint32_t *res, uint32_t c, BOOL is_compat1) 640 | { 641 | uint32_t v, type, is_compat, code, len; 642 | int idx_min, idx_max, idx; 643 | 644 | idx_min = 0; 645 | idx_max = countof(unicode_decomp_table1) - 1; 646 | while (idx_min <= idx_max) { 647 | idx = (idx_max + idx_min) / 2; 648 | v = unicode_decomp_table1[idx]; 649 | code = v >> (32 - 18); 650 | len = (v >> (32 - 18 - 7)) & 0x7f; 651 | // printf("idx=%d code=%05x len=%d\n", idx, code, len); 652 | if (c < code) { 653 | idx_max = idx - 1; 654 | } else if (c >= code + len) { 655 | idx_min = idx + 1; 656 | } else { 657 | is_compat = v & 1; 658 | if (is_compat1 < is_compat) 659 | break; 660 | type = (v >> (32 - 18 - 7 - 6)) & 0x3f; 661 | return unicode_decomp_entry(res, c, idx, code, len, type); 662 | } 663 | } 664 | return 0; 665 | } 666 | 667 | /* return 0 if no pair found */ 668 | static int unicode_compose_pair(uint32_t c0, uint32_t c1) 669 | { 670 | uint32_t code, len, type, v, idx1, d_idx, d_offset, ch; 671 | int idx_min, idx_max, idx, d; 672 | uint32_t pair[2]; 673 | 674 | idx_min = 0; 675 | idx_max = countof(unicode_comp_table) - 1; 676 | while (idx_min <= idx_max) { 677 | idx = (idx_max + idx_min) / 2; 678 | idx1 = unicode_comp_table[idx]; 679 | 680 | /* idx1 represent an entry of the decomposition table */ 681 | d_idx = idx1 >> 6; 682 | d_offset = idx1 & 0x3f; 683 | v = unicode_decomp_table1[d_idx]; 684 | code = v >> (32 - 18); 685 | len = (v >> (32 - 18 - 7)) & 0x7f; 686 | type = (v >> (32 - 18 - 7 - 6)) & 0x3f; 687 | ch = code + d_offset; 688 | unicode_decomp_entry(pair, ch, d_idx, code, len, type); 689 | d = c0 - pair[0]; 690 | if (d == 0) 691 | d = c1 - pair[1]; 692 | if (d < 0) { 693 | idx_max = idx - 1; 694 | } else if (d > 0) { 695 | idx_min = idx + 1; 696 | } else { 697 | return ch; 698 | } 699 | } 700 | return 0; 701 | } 702 | 703 | /* return the combining class of character c (between 0 and 255) */ 704 | static int unicode_get_cc(uint32_t c) 705 | { 706 | uint32_t code, n, type, cc, c1, b; 707 | int pos; 708 | const uint8_t *p; 709 | 710 | pos = get_index_pos(&code, c, 711 | unicode_cc_index, sizeof(unicode_cc_index) / 3); 712 | if (pos < 0) 713 | return 0; 714 | p = unicode_cc_table + pos; 715 | for(;;) { 716 | b = *p++; 717 | type = b >> 6; 718 | n = b & 0x3f; 719 | if (n < 48) { 720 | } else if (n < 56) { 721 | n = (n - 48) << 8; 722 | n |= *p++; 723 | n += 48; 724 | } else { 725 | n = (n - 56) << 8; 726 | n |= *p++ << 8; 727 | n |= *p++; 728 | n += 48 + (1 << 11); 729 | } 730 | if (type <= 1) 731 | p++; 732 | c1 = code + n + 1; 733 | if (c < c1) { 734 | switch(type) { 735 | case 0: 736 | cc = p[-1]; 737 | break; 738 | case 1: 739 | cc = p[-1] + c - code; 740 | break; 741 | case 2: 742 | cc = 0; 743 | break; 744 | default: 745 | case 3: 746 | cc = 230; 747 | break; 748 | } 749 | return cc; 750 | } 751 | code = c1; 752 | } 753 | } 754 | 755 | static void sort_cc(int *buf, int len) 756 | { 757 | int i, j, k, cc, cc1, start, ch1; 758 | 759 | for(i = 0; i < len; i++) { 760 | cc = unicode_get_cc(buf[i]); 761 | if (cc != 0) { 762 | start = i; 763 | j = i + 1; 764 | while (j < len) { 765 | ch1 = buf[j]; 766 | cc1 = unicode_get_cc(ch1); 767 | if (cc1 == 0) 768 | break; 769 | k = j - 1; 770 | while (k >= start) { 771 | if (unicode_get_cc(buf[k]) <= cc1) 772 | break; 773 | buf[k + 1] = buf[k]; 774 | k--; 775 | } 776 | buf[k + 1] = ch1; 777 | j++; 778 | } 779 | #if 0 780 | printf("cc:"); 781 | for(k = start; k < j; k++) { 782 | printf(" %3d", unicode_get_cc(buf[k])); 783 | } 784 | printf("\n"); 785 | #endif 786 | i = j; 787 | } 788 | } 789 | } 790 | 791 | static void to_nfd_rec(DynBuf *dbuf, 792 | const int *src, int src_len, int is_compat) 793 | { 794 | uint32_t c, v; 795 | int i, l; 796 | uint32_t res[UNICODE_DECOMP_LEN_MAX]; 797 | 798 | for(i = 0; i < src_len; i++) { 799 | c = src[i]; 800 | if (c >= 0xac00 && c < 0xd7a4) { 801 | /* Hangul decomposition */ 802 | c -= 0xac00; 803 | dbuf_put_u32(dbuf, 0x1100 + c / 588); 804 | dbuf_put_u32(dbuf, 0x1161 + (c % 588) / 28); 805 | v = c % 28; 806 | if (v != 0) 807 | dbuf_put_u32(dbuf, 0x11a7 + v); 808 | } else { 809 | l = unicode_decomp_char(res, c, is_compat); 810 | if (l) { 811 | to_nfd_rec(dbuf, (int *)res, l, is_compat); 812 | } else { 813 | dbuf_put_u32(dbuf, c); 814 | } 815 | } 816 | } 817 | } 818 | 819 | /* return 0 if not found */ 820 | static int compose_pair(uint32_t c0, uint32_t c1) 821 | { 822 | /* Hangul composition */ 823 | if (c0 >= 0x1100 && c0 < 0x1100 + 19 && 824 | c1 >= 0x1161 && c1 < 0x1161 + 21) { 825 | return 0xac00 + (c0 - 0x1100) * 588 + (c1 - 0x1161) * 28; 826 | } else if (c0 >= 0xac00 && c0 < 0xac00 + 11172 && 827 | (c0 - 0xac00) % 28 == 0 && 828 | c1 >= 0x11a7 && c1 < 0x11a7 + 28) { 829 | return c0 + c1 - 0x11a7; 830 | } else { 831 | return unicode_compose_pair(c0, c1); 832 | } 833 | } 834 | 835 | int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, 836 | UnicodeNormalizationEnum n_type, 837 | void *opaque, DynBufReallocFunc *realloc_func) 838 | { 839 | int *buf, buf_len, i, p, starter_pos, cc, last_cc, out_len; 840 | BOOL is_compat; 841 | DynBuf dbuf_s, *dbuf = &dbuf_s; 842 | 843 | is_compat = n_type >> 1; 844 | 845 | dbuf_init2(dbuf, opaque, realloc_func); 846 | if (dbuf_realloc(dbuf, sizeof(int) * src_len)) 847 | goto fail; 848 | 849 | /* common case: latin1 is unaffected by NFC */ 850 | if (n_type == UNICODE_NFC) { 851 | for(i = 0; i < src_len; i++) { 852 | if (src[i] >= 0x100) 853 | goto not_latin1; 854 | } 855 | buf = (int *)dbuf->buf; 856 | memcpy(buf, src, src_len * sizeof(int)); 857 | *pdst = (uint32_t *)buf; 858 | return src_len; 859 | not_latin1: ; 860 | } 861 | 862 | to_nfd_rec(dbuf, (const int *)src, src_len, is_compat); 863 | if (dbuf_error(dbuf)) { 864 | fail: 865 | *pdst = NULL; 866 | return -1; 867 | } 868 | buf = (int *)dbuf->buf; 869 | buf_len = dbuf->size / sizeof(int); 870 | 871 | sort_cc(buf, buf_len); 872 | 873 | if (buf_len <= 1 || (n_type & 1) != 0) { 874 | /* NFD / NFKD */ 875 | *pdst = (uint32_t *)buf; 876 | return buf_len; 877 | } 878 | 879 | i = 1; 880 | out_len = 1; 881 | while (i < buf_len) { 882 | /* find the starter character and test if it is blocked from 883 | the character at 'i' */ 884 | last_cc = unicode_get_cc(buf[i]); 885 | starter_pos = out_len - 1; 886 | while (starter_pos >= 0) { 887 | cc = unicode_get_cc(buf[starter_pos]); 888 | if (cc == 0) 889 | break; 890 | if (cc >= last_cc) 891 | goto next; 892 | last_cc = 256; 893 | starter_pos--; 894 | } 895 | if (starter_pos >= 0 && 896 | (p = compose_pair(buf[starter_pos], buf[i])) != 0) { 897 | buf[starter_pos] = p; 898 | i++; 899 | } else { 900 | next: 901 | buf[out_len++] = buf[i++]; 902 | } 903 | } 904 | *pdst = (uint32_t *)buf; 905 | return out_len; 906 | } 907 | 908 | /* char ranges for various unicode properties */ 909 | 910 | static int unicode_find_name(const char *name_table, const char *name) 911 | { 912 | const char *p, *r; 913 | int pos; 914 | size_t name_len, len; 915 | 916 | p = name_table; 917 | pos = 0; 918 | name_len = strlen(name); 919 | while (*p) { 920 | for(;;) { 921 | r = strchr(p, ','); 922 | if (!r) 923 | len = strlen(p); 924 | else 925 | len = r - p; 926 | if (len == name_len && !memcmp(p, name, name_len)) 927 | return pos; 928 | p += len + 1; 929 | if (!r) 930 | break; 931 | } 932 | pos++; 933 | } 934 | return -1; 935 | } 936 | 937 | /* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 938 | if not found */ 939 | int unicode_script(CharRange *cr, 940 | const char *script_name, BOOL is_ext) 941 | { 942 | int script_idx; 943 | const uint8_t *p, *p_end; 944 | uint32_t c, c1, b, n, v, v_len, i, type; 945 | CharRange cr1_s, *cr1; 946 | CharRange cr2_s, *cr2 = &cr2_s; 947 | BOOL is_common; 948 | 949 | script_idx = unicode_find_name(unicode_script_name_table, script_name); 950 | if (script_idx < 0) 951 | return -2; 952 | /* Note: we remove the "Unknown" Script */ 953 | script_idx += UNICODE_SCRIPT_Unknown + 1; 954 | 955 | is_common = (script_idx == UNICODE_SCRIPT_Common || 956 | script_idx == UNICODE_SCRIPT_Inherited); 957 | if (is_ext) { 958 | cr1 = &cr1_s; 959 | cr_init(cr1, cr->mem_opaque, cr->realloc_func); 960 | cr_init(cr2, cr->mem_opaque, cr->realloc_func); 961 | } else { 962 | cr1 = cr; 963 | } 964 | 965 | p = unicode_script_table; 966 | p_end = unicode_script_table + countof(unicode_script_table); 967 | c = 0; 968 | while (p < p_end) { 969 | b = *p++; 970 | type = b >> 7; 971 | n = b & 0x7f; 972 | if (n < 96) { 973 | } else if (n < 112) { 974 | n = (n - 96) << 8; 975 | n |= *p++; 976 | n += 96; 977 | } else { 978 | n = (n - 112) << 16; 979 | n |= *p++ << 8; 980 | n |= *p++; 981 | n += 96 + (1 << 12); 982 | } 983 | if (type == 0) 984 | v = 0; 985 | else 986 | v = *p++; 987 | c1 = c + n + 1; 988 | if (v == script_idx) { 989 | if (cr_add_interval(cr1, c, c1)) 990 | goto fail; 991 | } 992 | c = c1; 993 | } 994 | 995 | if (is_ext) { 996 | /* add the script extensions */ 997 | p = unicode_script_ext_table; 998 | p_end = unicode_script_ext_table + countof(unicode_script_ext_table); 999 | c = 0; 1000 | while (p < p_end) { 1001 | b = *p++; 1002 | if (b < 128) { 1003 | n = b; 1004 | } else if (b < 128 + 64) { 1005 | n = (b - 128) << 8; 1006 | n |= *p++; 1007 | n += 128; 1008 | } else { 1009 | n = (b - 128 - 64) << 16; 1010 | n |= *p++ << 8; 1011 | n |= *p++; 1012 | n += 128 + (1 << 14); 1013 | } 1014 | c1 = c + n + 1; 1015 | v_len = *p++; 1016 | if (is_common) { 1017 | if (v_len != 0) { 1018 | if (cr_add_interval(cr2, c, c1)) 1019 | goto fail; 1020 | } 1021 | } else { 1022 | for(i = 0; i < v_len; i++) { 1023 | if (p[i] == script_idx) { 1024 | if (cr_add_interval(cr2, c, c1)) 1025 | goto fail; 1026 | break; 1027 | } 1028 | } 1029 | } 1030 | p += v_len; 1031 | c = c1; 1032 | } 1033 | if (is_common) { 1034 | /* remove all the characters with script extensions */ 1035 | if (cr_invert(cr2)) 1036 | goto fail; 1037 | if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len, 1038 | CR_OP_INTER)) 1039 | goto fail; 1040 | } else { 1041 | if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len, 1042 | CR_OP_UNION)) 1043 | goto fail; 1044 | } 1045 | cr_free(cr1); 1046 | cr_free(cr2); 1047 | } 1048 | return 0; 1049 | fail: 1050 | if (is_ext) { 1051 | cr_free(cr1); 1052 | cr_free(cr2); 1053 | } 1054 | goto fail; 1055 | } 1056 | 1057 | #define M(id) (1U << UNICODE_GC_ ## id) 1058 | 1059 | static int unicode_general_category1(CharRange *cr, uint32_t gc_mask) 1060 | { 1061 | const uint8_t *p, *p_end; 1062 | uint32_t c, c0, b, n, v; 1063 | 1064 | p = unicode_gc_table; 1065 | p_end = unicode_gc_table + countof(unicode_gc_table); 1066 | c = 0; 1067 | while (p < p_end) { 1068 | b = *p++; 1069 | n = b >> 5; 1070 | v = b & 0x1f; 1071 | if (n == 7) { 1072 | n = *p++; 1073 | if (n < 128) { 1074 | n += 7; 1075 | } else if (n < 128 + 64) { 1076 | n = (n - 128) << 8; 1077 | n |= *p++; 1078 | n += 7 + 128; 1079 | } else { 1080 | n = (n - 128 - 64) << 16; 1081 | n |= *p++ << 8; 1082 | n |= *p++; 1083 | n += 7 + 128 + (1 << 14); 1084 | } 1085 | } 1086 | c0 = c; 1087 | c += n + 1; 1088 | if (v == 31) { 1089 | /* run of Lu / Ll */ 1090 | b = gc_mask & (M(Lu) | M(Ll)); 1091 | if (b != 0) { 1092 | if (b == (M(Lu) | M(Ll))) { 1093 | goto add_range; 1094 | } else { 1095 | c0 += ((gc_mask & M(Ll)) != 0); 1096 | for(; c0 < c; c0 += 2) { 1097 | if (cr_add_interval(cr, c0, c0 + 1)) 1098 | return -1; 1099 | } 1100 | } 1101 | } 1102 | } else if ((gc_mask >> v) & 1) { 1103 | add_range: 1104 | if (cr_add_interval(cr, c0, c)) 1105 | return -1; 1106 | } 1107 | } 1108 | return 0; 1109 | } 1110 | 1111 | static int unicode_prop1(CharRange *cr, int prop_idx) 1112 | { 1113 | const uint8_t *p, *p_end; 1114 | uint32_t c, c0, b, bit; 1115 | 1116 | p = unicode_prop_table[prop_idx]; 1117 | p_end = p + unicode_prop_len_table[prop_idx]; 1118 | c = 0; 1119 | bit = 0; 1120 | while (p < p_end) { 1121 | c0 = c; 1122 | b = *p++; 1123 | if (b < 64) { 1124 | c += (b >> 3) + 1; 1125 | if (bit) { 1126 | if (cr_add_interval(cr, c0, c)) 1127 | return -1; 1128 | } 1129 | bit ^= 1; 1130 | c0 = c; 1131 | c += (b & 7) + 1; 1132 | } else if (b >= 0x80) { 1133 | c += b - 0x80 + 1; 1134 | } else if (b < 0x60) { 1135 | c += (((b - 0x40) << 8) | p[0]) + 1; 1136 | p++; 1137 | } else { 1138 | c += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1; 1139 | p += 2; 1140 | } 1141 | if (bit) { 1142 | if (cr_add_interval(cr, c0, c)) 1143 | return -1; 1144 | } 1145 | bit ^= 1; 1146 | } 1147 | return 0; 1148 | } 1149 | 1150 | #define CASE_U (1 << 0) 1151 | #define CASE_L (1 << 1) 1152 | #define CASE_F (1 << 2) 1153 | 1154 | /* use the case conversion table to generate range of characters. 1155 | CASE_U: set char if modified by uppercasing, 1156 | CASE_L: set char if modified by lowercasing, 1157 | CASE_F: set char if modified by case folding, 1158 | */ 1159 | static int unicode_case1(CharRange *cr, int case_mask) 1160 | { 1161 | #define MR(x) (1 << RUN_TYPE_ ## x) 1162 | const uint32_t tab_run_mask[3] = { 1163 | MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) | 1164 | MR(UF_D1_EXT) | MR(U_EXT) | MR(U_EXT2) | MR(U_EXT3), 1165 | 1166 | MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(L_EXT2), 1167 | 1168 | MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT), 1169 | }; 1170 | #undef MR 1171 | uint32_t mask, v, code, type, len, i, idx; 1172 | 1173 | if (case_mask == 0) 1174 | return 0; 1175 | mask = 0; 1176 | for(i = 0; i < 3; i++) { 1177 | if ((case_mask >> i) & 1) 1178 | mask |= tab_run_mask[i]; 1179 | } 1180 | for(idx = 0; idx < countof(case_conv_table1); idx++) { 1181 | v = case_conv_table1[idx]; 1182 | type = (v >> (32 - 17 - 7 - 4)) & 0xf; 1183 | code = v >> (32 - 17); 1184 | len = (v >> (32 - 17 - 7)) & 0x7f; 1185 | if ((mask >> type) & 1) { 1186 | // printf("%d: type=%d %04x %04x\n", idx, type, code, code + len - 1); 1187 | switch(type) { 1188 | case RUN_TYPE_UL: 1189 | if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F))) 1190 | goto def_case; 1191 | code += ((case_mask & CASE_U) != 0); 1192 | for(i = 0; i < len; i += 2) { 1193 | if (cr_add_interval(cr, code + i, code + i + 1)) 1194 | return -1; 1195 | } 1196 | break; 1197 | case RUN_TYPE_LSU: 1198 | if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F))) 1199 | goto def_case; 1200 | if (!(case_mask & CASE_U)) { 1201 | if (cr_add_interval(cr, code, code + 1)) 1202 | return -1; 1203 | } 1204 | if (cr_add_interval(cr, code + 1, code + 2)) 1205 | return -1; 1206 | if (case_mask & CASE_U) { 1207 | if (cr_add_interval(cr, code + 2, code + 3)) 1208 | return -1; 1209 | } 1210 | break; 1211 | default: 1212 | def_case: 1213 | if (cr_add_interval(cr, code, code + len)) 1214 | return -1; 1215 | break; 1216 | } 1217 | } 1218 | } 1219 | return 0; 1220 | } 1221 | 1222 | typedef enum { 1223 | POP_GC, 1224 | POP_PROP, 1225 | POP_CASE, 1226 | POP_UNION, 1227 | POP_INTER, 1228 | POP_XOR, 1229 | POP_INVERT, 1230 | POP_END, 1231 | } PropOPEnum; 1232 | 1233 | #define POP_STACK_LEN_MAX 4 1234 | 1235 | static int unicode_prop_ops(CharRange *cr, ...) 1236 | { 1237 | va_list ap; 1238 | CharRange stack[POP_STACK_LEN_MAX]; 1239 | int stack_len, op, ret, i; 1240 | uint32_t a; 1241 | 1242 | va_start(ap, cr); 1243 | stack_len = 0; 1244 | for(;;) { 1245 | op = va_arg(ap, int); 1246 | switch(op) { 1247 | case POP_GC: 1248 | assert(stack_len < POP_STACK_LEN_MAX); 1249 | a = va_arg(ap, int); 1250 | cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); 1251 | if (unicode_general_category1(&stack[stack_len - 1], a)) 1252 | goto fail; 1253 | break; 1254 | case POP_PROP: 1255 | assert(stack_len < POP_STACK_LEN_MAX); 1256 | a = va_arg(ap, int); 1257 | cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); 1258 | if (unicode_prop1(&stack[stack_len - 1], a)) 1259 | goto fail; 1260 | break; 1261 | case POP_CASE: 1262 | assert(stack_len < POP_STACK_LEN_MAX); 1263 | a = va_arg(ap, int); 1264 | cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func); 1265 | if (unicode_case1(&stack[stack_len - 1], a)) 1266 | goto fail; 1267 | break; 1268 | case POP_UNION: 1269 | case POP_INTER: 1270 | case POP_XOR: 1271 | { 1272 | CharRange *cr1, *cr2, *cr3; 1273 | assert(stack_len >= 2); 1274 | assert(stack_len < POP_STACK_LEN_MAX); 1275 | cr1 = &stack[stack_len - 2]; 1276 | cr2 = &stack[stack_len - 1]; 1277 | cr3 = &stack[stack_len++]; 1278 | cr_init(cr3, cr->mem_opaque, cr->realloc_func); 1279 | if (cr_op(cr3, cr1->points, cr1->len, 1280 | cr2->points, cr2->len, op - POP_UNION + CR_OP_UNION)) 1281 | goto fail; 1282 | cr_free(cr1); 1283 | cr_free(cr2); 1284 | *cr1 = *cr3; 1285 | stack_len -= 2; 1286 | } 1287 | break; 1288 | case POP_INVERT: 1289 | assert(stack_len >= 1); 1290 | if (cr_invert(&stack[stack_len - 1])) 1291 | goto fail; 1292 | break; 1293 | case POP_END: 1294 | goto done; 1295 | default: 1296 | abort(); 1297 | } 1298 | } 1299 | done: 1300 | assert(stack_len == 1); 1301 | ret = cr_copy(cr, &stack[0]); 1302 | cr_free(&stack[0]); 1303 | return ret; 1304 | fail: 1305 | for(i = 0; i < stack_len; i++) 1306 | cr_free(&stack[i]); 1307 | return -1; 1308 | } 1309 | 1310 | static const uint32_t unicode_gc_mask_table[] = { 1311 | M(Lu) | M(Ll) | M(Lt), /* LC */ 1312 | M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo), /* L */ 1313 | M(Mn) | M(Mc) | M(Me), /* M */ 1314 | M(Nd) | M(Nl) | M(No), /* N */ 1315 | M(Sm) | M(Sc) | M(Sk) | M(So), /* S */ 1316 | M(Pc) | M(Pd) | M(Ps) | M(Pe) | M(Pi) | M(Pf) | M(Po), /* P */ 1317 | M(Zs) | M(Zl) | M(Zp), /* Z */ 1318 | M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn), /* C */ 1319 | }; 1320 | 1321 | /* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 1322 | if not found */ 1323 | int unicode_general_category(CharRange *cr, const char *gc_name) 1324 | { 1325 | int gc_idx; 1326 | uint32_t gc_mask; 1327 | 1328 | gc_idx = unicode_find_name(unicode_gc_name_table, gc_name); 1329 | if (gc_idx < 0) 1330 | return -2; 1331 | if (gc_idx <= UNICODE_GC_Co) { 1332 | gc_mask = (uint64_t)1 << gc_idx; 1333 | } else { 1334 | gc_mask = unicode_gc_mask_table[gc_idx - UNICODE_GC_LC]; 1335 | } 1336 | return unicode_general_category1(cr, gc_mask); 1337 | } 1338 | 1339 | 1340 | /* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2 1341 | if not found */ 1342 | int unicode_prop(CharRange *cr, const char *prop_name) 1343 | { 1344 | int prop_idx, ret; 1345 | 1346 | prop_idx = unicode_find_name(unicode_prop_name_table, prop_name); 1347 | if (prop_idx < 0) 1348 | return -2; 1349 | prop_idx += UNICODE_PROP_ASCII_Hex_Digit; 1350 | 1351 | ret = 0; 1352 | switch(prop_idx) { 1353 | case UNICODE_PROP_ASCII: 1354 | if (cr_add_interval(cr, 0x00, 0x7f + 1)) 1355 | return -1; 1356 | break; 1357 | case UNICODE_PROP_Any: 1358 | if (cr_add_interval(cr, 0x00000, 0x10ffff + 1)) 1359 | return -1; 1360 | break; 1361 | case UNICODE_PROP_Assigned: 1362 | ret = unicode_prop_ops(cr, 1363 | POP_GC, M(Cn), 1364 | POP_INVERT, 1365 | POP_END); 1366 | break; 1367 | case UNICODE_PROP_Math: 1368 | ret = unicode_prop_ops(cr, 1369 | POP_GC, M(Sm), 1370 | POP_PROP, UNICODE_PROP_Other_Math, 1371 | POP_UNION, 1372 | POP_END); 1373 | break; 1374 | case UNICODE_PROP_Lowercase: 1375 | ret = unicode_prop_ops(cr, 1376 | POP_GC, M(Ll), 1377 | POP_PROP, UNICODE_PROP_Other_Lowercase, 1378 | POP_UNION, 1379 | POP_END); 1380 | break; 1381 | case UNICODE_PROP_Uppercase: 1382 | ret = unicode_prop_ops(cr, 1383 | POP_GC, M(Lu), 1384 | POP_PROP, UNICODE_PROP_Other_Uppercase, 1385 | POP_UNION, 1386 | POP_END); 1387 | break; 1388 | case UNICODE_PROP_Cased: 1389 | ret = unicode_prop_ops(cr, 1390 | POP_GC, M(Lu) | M(Ll) | M(Lt), 1391 | POP_PROP, UNICODE_PROP_Other_Uppercase, 1392 | POP_UNION, 1393 | POP_PROP, UNICODE_PROP_Other_Lowercase, 1394 | POP_UNION, 1395 | POP_END); 1396 | break; 1397 | case UNICODE_PROP_Alphabetic: 1398 | ret = unicode_prop_ops(cr, 1399 | POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), 1400 | POP_PROP, UNICODE_PROP_Other_Uppercase, 1401 | POP_UNION, 1402 | POP_PROP, UNICODE_PROP_Other_Lowercase, 1403 | POP_UNION, 1404 | POP_PROP, UNICODE_PROP_Other_Alphabetic, 1405 | POP_UNION, 1406 | POP_END); 1407 | break; 1408 | case UNICODE_PROP_Grapheme_Base: 1409 | ret = unicode_prop_ops(cr, 1410 | POP_GC, M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn) | M(Zl) | M(Zp) | M(Me) | M(Mn), 1411 | POP_PROP, UNICODE_PROP_Other_Grapheme_Extend, 1412 | POP_UNION, 1413 | POP_INVERT, 1414 | POP_END); 1415 | break; 1416 | case UNICODE_PROP_Grapheme_Extend: 1417 | ret = unicode_prop_ops(cr, 1418 | POP_GC, M(Me) | M(Mn), 1419 | POP_PROP, UNICODE_PROP_Other_Grapheme_Extend, 1420 | POP_UNION, 1421 | POP_END); 1422 | break; 1423 | case UNICODE_PROP_XID_Start: 1424 | ret = unicode_prop_ops(cr, 1425 | POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), 1426 | POP_PROP, UNICODE_PROP_Other_ID_Start, 1427 | POP_UNION, 1428 | POP_PROP, UNICODE_PROP_Pattern_Syntax, 1429 | POP_PROP, UNICODE_PROP_Pattern_White_Space, 1430 | POP_UNION, 1431 | POP_PROP, UNICODE_PROP_XID_Start1, 1432 | POP_UNION, 1433 | POP_INVERT, 1434 | POP_INTER, 1435 | POP_END); 1436 | break; 1437 | case UNICODE_PROP_XID_Continue: 1438 | ret = unicode_prop_ops(cr, 1439 | POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) | 1440 | M(Mn) | M(Mc) | M(Nd) | M(Pc), 1441 | POP_PROP, UNICODE_PROP_Other_ID_Start, 1442 | POP_UNION, 1443 | POP_PROP, UNICODE_PROP_Other_ID_Continue, 1444 | POP_UNION, 1445 | POP_PROP, UNICODE_PROP_Pattern_Syntax, 1446 | POP_PROP, UNICODE_PROP_Pattern_White_Space, 1447 | POP_UNION, 1448 | POP_PROP, UNICODE_PROP_XID_Continue1, 1449 | POP_UNION, 1450 | POP_INVERT, 1451 | POP_INTER, 1452 | POP_END); 1453 | break; 1454 | case UNICODE_PROP_Changes_When_Uppercased: 1455 | ret = unicode_case1(cr, CASE_U); 1456 | break; 1457 | case UNICODE_PROP_Changes_When_Lowercased: 1458 | ret = unicode_case1(cr, CASE_L); 1459 | break; 1460 | case UNICODE_PROP_Changes_When_Casemapped: 1461 | ret = unicode_case1(cr, CASE_U | CASE_L | CASE_F); 1462 | break; 1463 | case UNICODE_PROP_Changes_When_Titlecased: 1464 | ret = unicode_prop_ops(cr, 1465 | POP_CASE, CASE_U, 1466 | POP_PROP, UNICODE_PROP_Changes_When_Titlecased1, 1467 | POP_XOR, 1468 | POP_END); 1469 | break; 1470 | case UNICODE_PROP_Changes_When_Casefolded: 1471 | ret = unicode_prop_ops(cr, 1472 | POP_CASE, CASE_F, 1473 | POP_PROP, UNICODE_PROP_Changes_When_Casefolded1, 1474 | POP_XOR, 1475 | POP_END); 1476 | break; 1477 | case UNICODE_PROP_Changes_When_NFKC_Casefolded: 1478 | ret = unicode_prop_ops(cr, 1479 | POP_CASE, CASE_F, 1480 | POP_PROP, UNICODE_PROP_Changes_When_NFKC_Casefolded1, 1481 | POP_XOR, 1482 | POP_END); 1483 | break; 1484 | #if 0 1485 | case UNICODE_PROP_ID_Start: 1486 | ret = unicode_prop_ops(cr, 1487 | POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl), 1488 | POP_PROP, UNICODE_PROP_Other_ID_Start, 1489 | POP_UNION, 1490 | POP_PROP, UNICODE_PROP_Pattern_Syntax, 1491 | POP_PROP, UNICODE_PROP_Pattern_White_Space, 1492 | POP_UNION, 1493 | POP_INVERT, 1494 | POP_INTER, 1495 | POP_END); 1496 | break; 1497 | case UNICODE_PROP_ID_Continue: 1498 | ret = unicode_prop_ops(cr, 1499 | POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) | 1500 | M(Mn) | M(Mc) | M(Nd) | M(Pc), 1501 | POP_PROP, UNICODE_PROP_Other_ID_Start, 1502 | POP_UNION, 1503 | POP_PROP, UNICODE_PROP_Other_ID_Continue, 1504 | POP_UNION, 1505 | POP_PROP, UNICODE_PROP_Pattern_Syntax, 1506 | POP_PROP, UNICODE_PROP_Pattern_White_Space, 1507 | POP_UNION, 1508 | POP_INVERT, 1509 | POP_INTER, 1510 | POP_END); 1511 | break; 1512 | case UNICODE_PROP_Case_Ignorable: 1513 | ret = unicode_prop_ops(cr, 1514 | POP_GC, M(Mn) | M(Cf) | M(Lm) | M(Sk), 1515 | POP_PROP, UNICODE_PROP_Case_Ignorable1, 1516 | POP_XOR, 1517 | POP_END); 1518 | break; 1519 | #else 1520 | /* we use the existing tables */ 1521 | case UNICODE_PROP_ID_Continue: 1522 | ret = unicode_prop_ops(cr, 1523 | POP_PROP, UNICODE_PROP_ID_Start, 1524 | POP_PROP, UNICODE_PROP_ID_Continue1, 1525 | POP_XOR, 1526 | POP_END); 1527 | break; 1528 | #endif 1529 | default: 1530 | if (prop_idx >= countof(unicode_prop_table)) 1531 | return -2; 1532 | ret = unicode_prop1(cr, prop_idx); 1533 | break; 1534 | } 1535 | return ret; 1536 | } 1537 | 1538 | #endif /* CONFIG_ALL_UNICODE */ 1539 | -------------------------------------------------------------------------------- /quickjs/libunicode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Unicode utilities 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIBUNICODE_H 25 | #define LIBUNICODE_H 26 | 27 | #include 28 | 29 | #define LRE_BOOL int /* for documentation purposes */ 30 | 31 | /* define it to include all the unicode tables (40KB larger) */ 32 | #define CONFIG_ALL_UNICODE 33 | 34 | #define LRE_CC_RES_LEN_MAX 3 35 | 36 | typedef enum { 37 | UNICODE_NFC, 38 | UNICODE_NFD, 39 | UNICODE_NFKC, 40 | UNICODE_NFKD, 41 | } UnicodeNormalizationEnum; 42 | 43 | int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); 44 | LRE_BOOL lre_is_cased(uint32_t c); 45 | LRE_BOOL lre_is_case_ignorable(uint32_t c); 46 | 47 | /* char ranges */ 48 | 49 | typedef struct { 50 | int len; /* in points, always even */ 51 | int size; 52 | uint32_t *points; /* points sorted by increasing value */ 53 | void *mem_opaque; 54 | void *(*realloc_func)(void *opaque, void *ptr, size_t size); 55 | } CharRange; 56 | 57 | typedef enum { 58 | CR_OP_UNION, 59 | CR_OP_INTER, 60 | CR_OP_XOR, 61 | } CharRangeOpEnum; 62 | 63 | void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); 64 | void cr_free(CharRange *cr); 65 | int cr_realloc(CharRange *cr, int size); 66 | int cr_copy(CharRange *cr, const CharRange *cr1); 67 | 68 | static inline int cr_add_point(CharRange *cr, uint32_t v) 69 | { 70 | if (cr->len >= cr->size) { 71 | if (cr_realloc(cr, cr->len + 1)) 72 | return -1; 73 | } 74 | cr->points[cr->len++] = v; 75 | return 0; 76 | } 77 | 78 | static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2) 79 | { 80 | if ((cr->len + 2) > cr->size) { 81 | if (cr_realloc(cr, cr->len + 2)) 82 | return -1; 83 | } 84 | cr->points[cr->len++] = c1; 85 | cr->points[cr->len++] = c2; 86 | return 0; 87 | } 88 | 89 | int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len); 90 | 91 | static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2) 92 | { 93 | uint32_t b_pt[2]; 94 | b_pt[0] = c1; 95 | b_pt[1] = c2 + 1; 96 | return cr_union1(cr, b_pt, 2); 97 | } 98 | 99 | int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, 100 | const uint32_t *b_pt, int b_len, int op); 101 | 102 | int cr_invert(CharRange *cr); 103 | 104 | #ifdef CONFIG_ALL_UNICODE 105 | 106 | LRE_BOOL lre_is_id_start(uint32_t c); 107 | LRE_BOOL lre_is_id_continue(uint32_t c); 108 | 109 | int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, 110 | UnicodeNormalizationEnum n_type, 111 | void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); 112 | 113 | /* Unicode character range functions */ 114 | 115 | int unicode_script(CharRange *cr, 116 | const char *script_name, LRE_BOOL is_ext); 117 | int unicode_general_category(CharRange *cr, const char *gc_name); 118 | int unicode_prop(CharRange *cr, const char *prop_name); 119 | 120 | #endif /* CONFIG_ALL_UNICODE */ 121 | 122 | #undef LRE_BOOL 123 | 124 | #endif /* LIBUNICODE_H */ 125 | -------------------------------------------------------------------------------- /quickjs/list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Linux klist like system 3 | * 4 | * Copyright (c) 2016-2017 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIST_H 25 | #define LIST_H 26 | 27 | #ifndef NULL 28 | #include 29 | #endif 30 | 31 | struct list_head { 32 | struct list_head *prev; 33 | struct list_head *next; 34 | }; 35 | 36 | #define LIST_HEAD_INIT(el) { &(el), &(el) } 37 | 38 | /* return the pointer of type 'type *' containing 'el' as field 'member' */ 39 | #define list_entry(el, type, member) \ 40 | ((type *)((uint8_t *)(el) - offsetof(type, member))) 41 | 42 | static inline void init_list_head(struct list_head *head) 43 | { 44 | head->prev = head; 45 | head->next = head; 46 | } 47 | 48 | /* insert 'el' between 'prev' and 'next' */ 49 | static inline void __list_add(struct list_head *el, 50 | struct list_head *prev, struct list_head *next) 51 | { 52 | prev->next = el; 53 | el->prev = prev; 54 | el->next = next; 55 | next->prev = el; 56 | } 57 | 58 | /* add 'el' at the head of the list 'head' (= after element head) */ 59 | static inline void list_add(struct list_head *el, struct list_head *head) 60 | { 61 | __list_add(el, head, head->next); 62 | } 63 | 64 | /* add 'el' at the end of the list 'head' (= before element head) */ 65 | static inline void list_add_tail(struct list_head *el, struct list_head *head) 66 | { 67 | __list_add(el, head->prev, head); 68 | } 69 | 70 | static inline void list_del(struct list_head *el) 71 | { 72 | struct list_head *prev, *next; 73 | prev = el->prev; 74 | next = el->next; 75 | prev->next = next; 76 | next->prev = prev; 77 | el->prev = NULL; /* fail safe */ 78 | el->next = NULL; /* fail safe */ 79 | } 80 | 81 | static inline int list_empty(struct list_head *el) 82 | { 83 | return el->next == el; 84 | } 85 | 86 | #define list_for_each(el, head) \ 87 | for(el = (head)->next; el != (head); el = el->next) 88 | 89 | #define list_for_each_safe(el, el1, head) \ 90 | for(el = (head)->next, el1 = el->next; el != (head); \ 91 | el = el1, el1 = el->next) 92 | 93 | #define list_for_each_prev(el, head) \ 94 | for(el = (head)->prev; el != (head); el = el->prev) 95 | 96 | #define list_for_each_prev_safe(el, el1, head) \ 97 | for(el = (head)->prev, el1 = el->prev; el != (head); \ 98 | el = el1, el1 = el->prev) 99 | 100 | #endif /* LIST_H */ 101 | -------------------------------------------------------------------------------- /quickjs/quickjs-atom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS atom definitions 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * Copyright (c) 2017-2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | #ifdef DEF 27 | 28 | /* Note: first atoms are considered as keywords in the parser */ 29 | DEF(null, "null") /* must be first */ 30 | DEF(false, "false") 31 | DEF(true, "true") 32 | DEF(if, "if") 33 | DEF(else, "else") 34 | DEF(return, "return") 35 | DEF(var, "var") 36 | DEF(this, "this") 37 | DEF(delete, "delete") 38 | DEF(void, "void") 39 | DEF(typeof, "typeof") 40 | DEF(new, "new") 41 | DEF(in, "in") 42 | DEF(instanceof, "instanceof") 43 | DEF(do, "do") 44 | DEF(while, "while") 45 | DEF(for, "for") 46 | DEF(break, "break") 47 | DEF(continue, "continue") 48 | DEF(switch, "switch") 49 | DEF(case, "case") 50 | DEF(default, "default") 51 | DEF(throw, "throw") 52 | DEF(try, "try") 53 | DEF(catch, "catch") 54 | DEF(finally, "finally") 55 | DEF(function, "function") 56 | DEF(debugger, "debugger") 57 | DEF(with, "with") 58 | /* FutureReservedWord */ 59 | DEF(class, "class") 60 | DEF(const, "const") 61 | DEF(enum, "enum") 62 | DEF(export, "export") 63 | DEF(extends, "extends") 64 | DEF(import, "import") 65 | DEF(super, "super") 66 | /* FutureReservedWords when parsing strict mode code */ 67 | DEF(implements, "implements") 68 | DEF(interface, "interface") 69 | DEF(let, "let") 70 | DEF(package, "package") 71 | DEF(private, "private") 72 | DEF(protected, "protected") 73 | DEF(public, "public") 74 | DEF(static, "static") 75 | DEF(yield, "yield") 76 | DEF(await, "await") 77 | 78 | /* empty string */ 79 | DEF(empty_string, "") 80 | /* identifiers */ 81 | DEF(length, "length") 82 | DEF(fileName, "fileName") 83 | DEF(lineNumber, "lineNumber") 84 | DEF(message, "message") 85 | DEF(stack, "stack") 86 | DEF(name, "name") 87 | DEF(toString, "toString") 88 | DEF(toLocaleString, "toLocaleString") 89 | DEF(valueOf, "valueOf") 90 | DEF(eval, "eval") 91 | DEF(prototype, "prototype") 92 | DEF(constructor, "constructor") 93 | DEF(configurable, "configurable") 94 | DEF(writable, "writable") 95 | DEF(enumerable, "enumerable") 96 | DEF(value, "value") 97 | DEF(get, "get") 98 | DEF(set, "set") 99 | DEF(of, "of") 100 | DEF(__proto__, "__proto__") 101 | DEF(undefined, "undefined") 102 | DEF(number, "number") 103 | DEF(boolean, "boolean") 104 | DEF(string, "string") 105 | DEF(object, "object") 106 | DEF(symbol, "symbol") 107 | DEF(integer, "integer") 108 | DEF(unknown, "unknown") 109 | DEF(arguments, "arguments") 110 | DEF(callee, "callee") 111 | DEF(caller, "caller") 112 | DEF(_eval_, "") 113 | DEF(_ret_, "") 114 | DEF(_var_, "") 115 | DEF(_with_, "") 116 | DEF(lastIndex, "lastIndex") 117 | DEF(target, "target") 118 | DEF(index, "index") 119 | DEF(input, "input") 120 | DEF(defineProperties, "defineProperties") 121 | DEF(apply, "apply") 122 | DEF(join, "join") 123 | DEF(concat, "concat") 124 | DEF(split, "split") 125 | DEF(construct, "construct") 126 | DEF(getPrototypeOf, "getPrototypeOf") 127 | DEF(setPrototypeOf, "setPrototypeOf") 128 | DEF(isExtensible, "isExtensible") 129 | DEF(preventExtensions, "preventExtensions") 130 | DEF(has, "has") 131 | DEF(deleteProperty, "deleteProperty") 132 | DEF(defineProperty, "defineProperty") 133 | DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor") 134 | DEF(ownKeys, "ownKeys") 135 | DEF(add, "add") 136 | DEF(done, "done") 137 | DEF(next, "next") 138 | DEF(values, "values") 139 | DEF(source, "source") 140 | DEF(flags, "flags") 141 | DEF(global, "global") 142 | DEF(unicode, "unicode") 143 | DEF(raw, "raw") 144 | DEF(new_target, "new.target") 145 | DEF(this_active_func, "this.active_func") 146 | DEF(home_object, "") 147 | DEF(as, "as") 148 | DEF(from, "from") 149 | DEF(_default_, "*default*") 150 | DEF(_star_, "*") 151 | DEF(Module, "Module") 152 | DEF(then, "then") 153 | DEF(resolve, "resolve") 154 | DEF(reject, "reject") 155 | DEF(promise, "promise") 156 | DEF(proxy, "proxy") 157 | DEF(revoke, "revoke") 158 | DEF(async, "async") 159 | DEF(exec, "exec") 160 | DEF(groups, "groups") 161 | #ifdef CONFIG_BIGNUM 162 | DEF(bigint, "bigint") 163 | DEF(bigfloat, "bigfloat") 164 | #endif 165 | #ifdef CONFIG_ATOMICS 166 | DEF(not_equal, "not-equal") 167 | DEF(timed_out, "timed-out") 168 | DEF(ok, "ok") 169 | #endif 170 | DEF(toJSON, "toJSON") 171 | /* class names */ 172 | DEF(Object, "Object") 173 | DEF(Array, "Array") 174 | DEF(Error, "Error") 175 | DEF(Number, "Number") 176 | DEF(String, "String") 177 | DEF(Boolean, "Boolean") 178 | DEF(Symbol, "Symbol") 179 | DEF(Arguments, "Arguments") 180 | DEF(Math, "Math") 181 | DEF(JSON, "JSON") 182 | DEF(Date, "Date") 183 | DEF(Function, "Function") 184 | DEF(GeneratorFunction, "GeneratorFunction") 185 | DEF(ForInIterator, "ForInIterator") 186 | DEF(RegExp, "RegExp") 187 | DEF(ArrayBuffer, "ArrayBuffer") 188 | DEF(SharedArrayBuffer, "SharedArrayBuffer") 189 | /* must keep same order as class IDs for typed arrays */ 190 | DEF(Uint8ClampedArray, "Uint8ClampedArray") 191 | DEF(Int8Array, "Int8Array") 192 | DEF(Uint8Array, "Uint8Array") 193 | DEF(Int16Array, "Int16Array") 194 | DEF(Uint16Array, "Uint16Array") 195 | DEF(Int32Array, "Int32Array") 196 | DEF(Uint32Array, "Uint32Array") 197 | #ifdef CONFIG_BIGNUM 198 | DEF(BigInt64Array, "BigInt64Array") 199 | DEF(BigUint64Array, "BigUint64Array") 200 | #endif 201 | DEF(Float32Array, "Float32Array") 202 | DEF(Float64Array, "Float64Array") 203 | DEF(DataView, "DataView") 204 | #ifdef CONFIG_BIGNUM 205 | DEF(BigInt, "BigInt") 206 | DEF(BigFloat, "BigFloat") 207 | DEF(BigFloatEnv, "BigFloatEnv") 208 | #endif 209 | DEF(Map, "Map") 210 | DEF(Set, "Set") /* Map + 1 */ 211 | DEF(WeakMap, "WeakMap") /* Map + 2 */ 212 | DEF(WeakSet, "WeakSet") /* Map + 3 */ 213 | DEF(Map_Iterator, "Map Iterator") 214 | DEF(Set_Iterator, "Set Iterator") 215 | DEF(Array_Iterator, "Array Iterator") 216 | DEF(String_Iterator, "String Iterator") 217 | DEF(Generator, "Generator") 218 | DEF(Proxy, "Proxy") 219 | DEF(Promise, "Promise") 220 | DEF(PromiseResolveFunction, "PromiseResolveFunction") 221 | DEF(PromiseRejectFunction, "PromiseRejectFunction") 222 | DEF(AsyncFunction, "AsyncFunction") 223 | DEF(AsyncFunctionResolve, "AsyncFunctionResolve") 224 | DEF(AsyncFunctionReject, "AsyncFunctionReject") 225 | DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction") 226 | DEF(AsyncGenerator, "AsyncGenerator") 227 | DEF(EvalError, "EvalError") 228 | DEF(RangeError, "RangeError") 229 | DEF(ReferenceError, "ReferenceError") 230 | DEF(SyntaxError, "SyntaxError") 231 | DEF(TypeError, "TypeError") 232 | DEF(URIError, "URIError") 233 | DEF(InternalError, "InternalError") 234 | 235 | /* symbols */ 236 | DEF(Symbol_toPrimitive, "Symbol.toPrimitive") 237 | DEF(Symbol_iterator, "Symbol.iterator") 238 | DEF(Symbol_match, "Symbol.match") 239 | DEF(Symbol_replace, "Symbol.replace") 240 | DEF(Symbol_search, "Symbol.search") 241 | DEF(Symbol_split, "Symbol.split") 242 | DEF(Symbol_toStringTag, "Symbol.toStringTag") 243 | DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable") 244 | DEF(Symbol_hasInstance, "Symbol.hasInstance") 245 | DEF(Symbol_species, "Symbol.species") 246 | DEF(Symbol_unscopables, "Symbol.unscopables") 247 | DEF(Symbol_asyncIterator, "Symbol.asyncIterator") 248 | #ifdef CONFIG_BIGNUM 249 | DEF(Symbol_operatorOrder, "Symbol.operatorOrder") 250 | DEF(Symbol_operatorAdd, "Symbol.operatorAdd") 251 | DEF(Symbol_operatorSub, "Symbol.operatorSub") 252 | DEF(Symbol_operatorMul, "Symbol.operatorMul") 253 | DEF(Symbol_operatorDiv, "Symbol.operatorDiv") 254 | DEF(Symbol_operatorMod, "Symbol.operatorMod") 255 | DEF(Symbol_operatorPow, "Symbol.operatorPow") 256 | DEF(Symbol_operatorShl, "Symbol.operatorShl") 257 | DEF(Symbol_operatorShr, "Symbol.operatorShr") 258 | DEF(Symbol_operatorAnd, "Symbol.operatorAnd") 259 | DEF(Symbol_operatorOr, "Symbol.operatorOr") 260 | DEF(Symbol_operatorXor, "Symbol.operatorXor") 261 | DEF(Symbol_operatorCmpLT, "Symbol.operatorCmpLT") 262 | DEF(Symbol_operatorCmpLE, "Symbol.operatorCmpLE") 263 | DEF(Symbol_operatorCmpEQ, "Symbol.operatorCmpEQ") 264 | DEF(Symbol_operatorPlus, "Symbol.operatorPlus") 265 | DEF(Symbol_operatorNeg, "Symbol.operatorNeg") 266 | DEF(Symbol_operatorNot, "Symbol.operatorNot") 267 | DEF(Symbol_operatorInc, "Symbol.operatorInc") 268 | DEF(Symbol_operatorDec, "Symbol.operatorDec") 269 | DEF(Symbol_operatorMathDiv, "Symbol.operatorMathDiv") 270 | DEF(Symbol_operatorMathMod, "Symbol.operatorMathMod") 271 | DEF(Symbol_operatorMathPow, "Symbol.operatorMathPow") 272 | #endif 273 | 274 | #endif /* DEF */ 275 | -------------------------------------------------------------------------------- /quickjs/quickjs-libc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS C library 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef QUICKJS_LIBC_H 25 | #define QUICKJS_LIBC_H 26 | 27 | #include 28 | #include 29 | 30 | #include "quickjs.h" 31 | 32 | JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); 33 | JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); 34 | void js_std_add_helpers(JSContext *ctx, int argc, char **argv); 35 | void js_std_loop(JSContext *ctx); 36 | void js_std_free_handlers(JSRuntime *rt); 37 | void js_std_dump_error(JSContext *ctx); 38 | uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename); 39 | JSModuleDef *js_module_loader(JSContext *ctx, 40 | const char *module_name, void *opaque); 41 | void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, 42 | int flags); 43 | 44 | #endif /* QUICKJS_LIBC_H */ 45 | -------------------------------------------------------------------------------- /quickjs/quickjs-opcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS opcode definitions 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * Copyright (c) 2017-2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | #ifdef FMT 27 | FMT(none) 28 | FMT(none_int) 29 | FMT(none_loc) 30 | FMT(none_arg) 31 | FMT(none_var_ref) 32 | FMT(u8) 33 | FMT(i8) 34 | FMT(loc8) 35 | FMT(const8) 36 | FMT(label8) 37 | FMT(u16) 38 | FMT(i16) 39 | FMT(label16) 40 | FMT(npop) 41 | FMT(npopx) 42 | FMT(loc) 43 | FMT(arg) 44 | FMT(var_ref) 45 | FMT(u32) 46 | FMT(i32) 47 | FMT(const) 48 | FMT(label) 49 | FMT(atom) 50 | FMT(atom_u8) 51 | FMT(atom_u16) 52 | FMT(atom_label_u8) 53 | FMT(atom_label_u16) 54 | FMT(label_u16) 55 | #undef FMT 56 | #endif /* FMT */ 57 | 58 | #ifdef DEF 59 | 60 | #ifndef def 61 | #define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f) 62 | #endif 63 | 64 | def(invalid, 1, 0, 0, none) /* never emitted */ 65 | 66 | /* push values */ 67 | DEF( push_i32, 5, 0, 1, i32) 68 | DEF( push_const, 5, 0, 1, const) 69 | DEF( fclosure, 5, 0, 1, const) /* must follow push_const */ 70 | DEF(push_atom_value, 5, 0, 1, atom) 71 | DEF( undefined, 1, 0, 1, none) 72 | DEF( null, 1, 0, 1, none) 73 | DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */ 74 | DEF( push_false, 1, 0, 1, none) 75 | DEF( push_true, 1, 0, 1, none) 76 | DEF( object, 1, 0, 1, none) 77 | DEF( var_object, 1, 0, 1, none) 78 | DEF( this_func, 1, 0, 1, none) /* only used at the start of a function */ 79 | DEF( arguments, 2, 0, 1, none) /* only used at the start of a function */ 80 | DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */ 81 | DEF( new_target, 1, 0, 1, none) /* only used at the start of a function */ 82 | DEF( home_object, 1, 0, 1, none) /* only used at the start of a function */ 83 | 84 | DEF( drop, 1, 1, 0, none) /* a -> */ 85 | DEF( nip, 1, 2, 1, none) /* a b -> b */ 86 | DEF( nip1, 1, 3, 2, none) /* a b c -> b c */ 87 | DEF( dup, 1, 1, 2, none) /* a -> a a */ 88 | DEF( dup1, 1, 2, 3, none) /* a b -> a a b */ 89 | DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */ 90 | DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */ 91 | DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */ 92 | DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */ 93 | DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */ 94 | DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */ 95 | DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */ 96 | DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */ 97 | DEF( swap, 1, 2, 2, none) /* a b -> b a */ 98 | DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */ 99 | DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */ 100 | DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */ 101 | DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */ 102 | DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */ 103 | 104 | DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */ 105 | DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */ 106 | DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */ 107 | DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */ 108 | DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */ 109 | DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */ 110 | DEF( apply, 3, 3, 1, u16) 111 | DEF( return, 1, 1, 0, none) 112 | DEF( return_undef, 1, 0, 0, none) 113 | DEF(check_ctor_return, 1, 1, 2, none) 114 | DEF( check_ctor, 1, 0, 0, none) 115 | DEF( return_async, 1, 1, 0, none) 116 | DEF( throw, 1, 1, 0, none) 117 | DEF( throw_var, 6, 0, 0, atom_u8) 118 | DEF( eval, 3, 1, 1, u16) 119 | DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a 120 | bytecode string */ 121 | DEF( get_super_ctor, 1, 1, 1, none) 122 | DEF( get_super, 1, 1, 1, none) 123 | 124 | DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */ 125 | DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */ 126 | DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */ 127 | DEF( put_var, 5, 1, 0, atom) /* must come after get_var */ 128 | DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */ 129 | DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */ 130 | 131 | DEF( get_ref_value, 1, 2, 3, none) 132 | DEF( put_ref_value, 1, 3, 0, none) 133 | 134 | DEF( define_var, 6, 0, 0, atom_u8) 135 | DEF(check_define_var, 6, 0, 0, atom_u8) 136 | DEF( define_func, 6, 1, 0, atom_u8) 137 | DEF( get_field, 5, 1, 1, atom) 138 | DEF( get_field2, 5, 1, 2, atom) 139 | DEF( put_field, 5, 2, 0, atom) 140 | DEF( get_array_el, 1, 2, 1, none) 141 | DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */ 142 | DEF( put_array_el, 1, 3, 0, none) 143 | DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */ 144 | DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */ 145 | DEF( define_field, 5, 2, 1, atom) 146 | DEF( set_name, 5, 1, 1, atom) 147 | DEF(set_name_computed, 1, 2, 2, none) 148 | DEF( set_proto, 1, 2, 1, none) 149 | DEF(define_array_el, 1, 3, 2, none) 150 | DEF( append, 1, 3, 2, none) /* append enumerated object, update length */ 151 | DEF(copy_data_properties, 2, 3, 3, u8) 152 | DEF( define_method, 6, 2, 1, atom_u8) 153 | DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */ 154 | DEF( define_class, 2, 2, 2, u8) 155 | 156 | DEF( get_loc, 3, 0, 1, loc) 157 | DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */ 158 | DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */ 159 | DEF( get_arg, 3, 0, 1, arg) 160 | DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */ 161 | DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */ 162 | DEF( get_var_ref, 3, 0, 1, var_ref) 163 | DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */ 164 | DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */ 165 | DEF(set_loc_uninitialized, 3, 0, 0, loc) 166 | def(set_arg_valid_upto, 3, 0, 0, arg) /* emitted in phase 1, removed in phase 2 */ 167 | DEF( get_loc_check, 3, 0, 1, loc) 168 | DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */ 169 | DEF( put_loc_check_init, 3, 1, 0, loc) 170 | DEF(get_var_ref_check, 3, 0, 1, var_ref) 171 | DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */ 172 | DEF(put_var_ref_check_init, 3, 1, 0, var_ref) 173 | DEF( close_loc, 3, 0, 0, loc) 174 | def(close_var_object, 1, 0, 0, none) /* emitted in phase 1, removed in phase 2 */ 175 | def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ 176 | def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */ 177 | 178 | DEF( if_false, 5, 1, 0, label) 179 | DEF( if_true, 5, 1, 0, label) /* must come after if_false */ 180 | DEF( goto, 5, 0, 0, label) /* must come after if_true */ 181 | def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */ 182 | DEF( catch, 5, 0, 1, label) 183 | DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */ 184 | DEF( ret, 1, 1, 0, none) /* used to return from the finally block */ 185 | 186 | def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 187 | def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 188 | def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */ 189 | def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */ 190 | def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */ 191 | def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ 192 | def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ 193 | 194 | DEF( to_object, 1, 1, 1, none) 195 | //DEF( to_string, 1, 1, 1, none) 196 | DEF( to_propkey, 1, 1, 1, none) 197 | DEF( to_propkey2, 1, 2, 2, none) 198 | 199 | DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 200 | DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */ 201 | DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 202 | DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 203 | DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */ 204 | DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8) 205 | 206 | DEF( make_loc_ref, 7, 0, 2, atom_u16) 207 | DEF( make_arg_ref, 7, 0, 2, atom_u16) 208 | DEF(make_var_ref_ref, 7, 0, 2, atom_u16) 209 | DEF( make_var_ref, 5, 0, 2, atom) 210 | 211 | def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */ 212 | 213 | DEF( for_in_start, 1, 1, 1, none) 214 | DEF( for_of_start, 1, 1, 3, none) 215 | DEF(for_await_of_start, 1, 1, 3, none) 216 | DEF( for_in_next, 1, 1, 3, none) 217 | DEF( for_of_next, 2, 3, 5, u8) 218 | DEF(for_await_of_next, 1, 3, 4, none) 219 | DEF(iterator_get_value_done, 1, 1, 2, none) 220 | DEF( iterator_close, 1, 3, 0, none) 221 | DEF(iterator_close_return, 1, 4, 4, none) 222 | DEF(async_iterator_close, 1, 3, 2, none) 223 | DEF(async_iterator_next, 1, 4, 4, none) 224 | DEF(async_iterator_get, 2, 4, 5, u8) 225 | DEF( initial_yield, 1, 0, 0, none) 226 | DEF( yield, 1, 1, 2, none) 227 | DEF( yield_star, 1, 2, 2, none) 228 | DEF(async_yield_star, 1, 1, 2, none) 229 | DEF( await, 1, 1, 1, none) 230 | 231 | /* arithmetic/logic operations */ 232 | DEF( neg, 1, 1, 1, none) 233 | DEF( plus, 1, 1, 1, none) 234 | DEF( dec, 1, 1, 1, none) 235 | DEF( inc, 1, 1, 1, none) 236 | DEF( post_dec, 1, 1, 2, none) 237 | DEF( post_inc, 1, 1, 2, none) 238 | DEF( dec_loc, 2, 0, 0, loc8) 239 | DEF( inc_loc, 2, 0, 0, loc8) 240 | DEF( add_loc, 2, 1, 0, loc8) 241 | DEF( not, 1, 1, 1, none) 242 | DEF( lnot, 1, 1, 1, none) 243 | DEF( typeof, 1, 1, 1, none) 244 | DEF( delete, 1, 2, 1, none) 245 | DEF( delete_var, 5, 0, 1, atom) 246 | 247 | DEF( mul, 1, 2, 1, none) 248 | DEF( div, 1, 2, 1, none) 249 | DEF( mod, 1, 2, 1, none) 250 | DEF( add, 1, 2, 1, none) 251 | DEF( sub, 1, 2, 1, none) 252 | DEF( pow, 1, 2, 1, none) 253 | DEF( shl, 1, 2, 1, none) 254 | DEF( sar, 1, 2, 1, none) 255 | DEF( shr, 1, 2, 1, none) 256 | DEF( lt, 1, 2, 1, none) 257 | DEF( lte, 1, 2, 1, none) 258 | DEF( gt, 1, 2, 1, none) 259 | DEF( gte, 1, 2, 1, none) 260 | DEF( instanceof, 1, 2, 1, none) 261 | DEF( in, 1, 2, 1, none) 262 | DEF( eq, 1, 2, 1, none) 263 | DEF( neq, 1, 2, 1, none) 264 | DEF( strict_eq, 1, 2, 1, none) 265 | DEF( strict_neq, 1, 2, 1, none) 266 | DEF( and, 1, 2, 1, none) 267 | DEF( xor, 1, 2, 1, none) 268 | DEF( or, 1, 2, 1, none) 269 | #ifdef CONFIG_BIGNUM 270 | DEF( mul_pow10, 1, 2, 1, none) 271 | DEF( math_div, 1, 2, 1, none) 272 | DEF( math_mod, 1, 2, 1, none) 273 | DEF( math_pow, 1, 2, 1, none) 274 | #endif 275 | 276 | #if SHORT_OPCODES 277 | DEF( push_minus1, 1, 0, 1, none_int) 278 | DEF( push_0, 1, 0, 1, none_int) 279 | DEF( push_1, 1, 0, 1, none_int) 280 | DEF( push_2, 1, 0, 1, none_int) 281 | DEF( push_3, 1, 0, 1, none_int) 282 | DEF( push_4, 1, 0, 1, none_int) 283 | DEF( push_5, 1, 0, 1, none_int) 284 | DEF( push_6, 1, 0, 1, none_int) 285 | DEF( push_7, 1, 0, 1, none_int) 286 | DEF( push_i8, 2, 0, 1, i8) 287 | DEF( push_i16, 3, 0, 1, i16) 288 | DEF( push_const8, 2, 0, 1, const8) 289 | DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */ 290 | DEF(push_empty_string, 1, 0, 1, none) 291 | 292 | DEF( get_loc8, 2, 0, 1, loc8) 293 | DEF( put_loc8, 2, 1, 0, loc8) 294 | DEF( set_loc8, 2, 1, 1, loc8) 295 | 296 | DEF( get_loc0, 1, 0, 1, none_loc) 297 | DEF( get_loc1, 1, 0, 1, none_loc) 298 | DEF( get_loc2, 1, 0, 1, none_loc) 299 | DEF( get_loc3, 1, 0, 1, none_loc) 300 | DEF( put_loc0, 1, 1, 0, none_loc) 301 | DEF( put_loc1, 1, 1, 0, none_loc) 302 | DEF( put_loc2, 1, 1, 0, none_loc) 303 | DEF( put_loc3, 1, 1, 0, none_loc) 304 | DEF( set_loc0, 1, 1, 1, none_loc) 305 | DEF( set_loc1, 1, 1, 1, none_loc) 306 | DEF( set_loc2, 1, 1, 1, none_loc) 307 | DEF( set_loc3, 1, 1, 1, none_loc) 308 | DEF( get_arg0, 1, 0, 1, none_arg) 309 | DEF( get_arg1, 1, 0, 1, none_arg) 310 | DEF( get_arg2, 1, 0, 1, none_arg) 311 | DEF( get_arg3, 1, 0, 1, none_arg) 312 | DEF( put_arg0, 1, 1, 0, none_arg) 313 | DEF( put_arg1, 1, 1, 0, none_arg) 314 | DEF( put_arg2, 1, 1, 0, none_arg) 315 | DEF( put_arg3, 1, 1, 0, none_arg) 316 | DEF( set_arg0, 1, 1, 1, none_arg) 317 | DEF( set_arg1, 1, 1, 1, none_arg) 318 | DEF( set_arg2, 1, 1, 1, none_arg) 319 | DEF( set_arg3, 1, 1, 1, none_arg) 320 | DEF( get_var_ref0, 1, 0, 1, none_var_ref) 321 | DEF( get_var_ref1, 1, 0, 1, none_var_ref) 322 | DEF( get_var_ref2, 1, 0, 1, none_var_ref) 323 | DEF( get_var_ref3, 1, 0, 1, none_var_ref) 324 | DEF( put_var_ref0, 1, 1, 0, none_var_ref) 325 | DEF( put_var_ref1, 1, 1, 0, none_var_ref) 326 | DEF( put_var_ref2, 1, 1, 0, none_var_ref) 327 | DEF( put_var_ref3, 1, 1, 0, none_var_ref) 328 | DEF( set_var_ref0, 1, 1, 1, none_var_ref) 329 | DEF( set_var_ref1, 1, 1, 1, none_var_ref) 330 | DEF( set_var_ref2, 1, 1, 1, none_var_ref) 331 | DEF( set_var_ref3, 1, 1, 1, none_var_ref) 332 | 333 | DEF( get_length, 1, 1, 1, none) 334 | 335 | DEF( if_false8, 2, 1, 0, label8) 336 | DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */ 337 | DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */ 338 | DEF( goto16, 3, 0, 0, label16) 339 | 340 | DEF( call0, 1, 1, 1, npopx) 341 | DEF( call1, 1, 1, 1, npopx) 342 | DEF( call2, 1, 1, 1, npopx) 343 | DEF( call3, 1, 1, 1, npopx) 344 | 345 | DEF( is_undefined, 1, 1, 1, none) 346 | DEF( is_null, 1, 1, 1, none) 347 | DEF( is_function, 1, 1, 1, none) 348 | #endif 349 | 350 | DEF( nop, 1, 0, 0, none) /* temporary use during code generation */ 351 | 352 | #undef DEF 353 | #undef def 354 | #endif /* DEF */ 355 | -------------------------------------------------------------------------------- /quickjs/quickjs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS Javascript Engine 3 | * 4 | * Copyright (c) 2017-2019 Fabrice Bellard 5 | * Copyright (c) 2017-2019 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | #ifndef QUICKJS_H 26 | #define QUICKJS_H 27 | 28 | #include 29 | #include 30 | 31 | #if defined(__GNUC__) || defined(__clang__) 32 | #define js_likely(x) __builtin_expect(!!(x), 1) 33 | #define js_unlikely(x) __builtin_expect(!!(x), 0) 34 | #define js_force_inline inline __attribute__((always_inline)) 35 | #define __js_printf_like(f, a) __attribute__((format(printf, f, a))) 36 | #else 37 | #define js_likely(x) (x) 38 | #define js_unlikely(x) (x) 39 | #define js_force_inline inline 40 | #define __js_printf_like(a, b) 41 | #endif 42 | 43 | #define JS_BOOL int 44 | 45 | typedef struct JSRuntime JSRuntime; 46 | typedef struct JSContext JSContext; 47 | typedef struct JSObject JSObject; 48 | typedef struct JSClass JSClass; 49 | typedef uint32_t JSClassID; 50 | typedef uint32_t JSAtom; 51 | 52 | #if defined(__x86_64__) || defined(__aarch64__) 53 | #define JS_PTR64 54 | #define JS_PTR64_DEF(a) a 55 | #else 56 | #define JS_PTR64_DEF(a) 57 | #endif 58 | 59 | #ifndef JS_PTR64 60 | #define JS_NAN_BOXING 61 | #endif 62 | 63 | enum { 64 | /* all tags with a reference count are negative */ 65 | JS_TAG_FIRST = -10, /* first negative tag */ 66 | JS_TAG_BIG_INT = -10, 67 | JS_TAG_BIG_FLOAT = -9, 68 | JS_TAG_SYMBOL = -8, 69 | JS_TAG_STRING = -7, 70 | JS_TAG_SHAPE = -6, /* used internally during GC */ 71 | JS_TAG_ASYNC_FUNCTION = -5, /* used internally during GC */ 72 | JS_TAG_VAR_REF = -4, /* used internally during GC */ 73 | JS_TAG_MODULE = -3, /* used internally */ 74 | JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */ 75 | JS_TAG_OBJECT = -1, 76 | 77 | JS_TAG_INT = 0, 78 | JS_TAG_BOOL = 1, 79 | JS_TAG_NULL = 2, 80 | JS_TAG_UNDEFINED = 3, 81 | JS_TAG_UNINITIALIZED = 4, 82 | JS_TAG_CATCH_OFFSET = 5, 83 | JS_TAG_EXCEPTION = 6, 84 | JS_TAG_FLOAT64 = 7, 85 | /* any larger tag is FLOAT64 if JS_NAN_BOXING */ 86 | }; 87 | 88 | typedef struct JSRefCountHeader { 89 | int ref_count; 90 | } JSRefCountHeader; 91 | 92 | #define JS_FLOAT64_NAN NAN 93 | 94 | #ifdef CONFIG_CHECK_JSVALUE 95 | /* JSValue consistency : it is not possible to run the code in this 96 | mode, but it is useful to detect simple reference counting 97 | errors. It would be interesting to modify a static C analyzer to 98 | handle specific annotations (clang has such annotations but only 99 | for objective C) */ 100 | typedef struct __JSValue *JSValue; 101 | typedef const struct __JSValue *JSValueConst; 102 | 103 | #define JS_VALUE_GET_TAG(v) (int)((uintptr_t)(v) & 0xf) 104 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 105 | #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) 106 | #define JS_VALUE_GET_INT(v) (int)((intptr_t)(v) >> 4) 107 | #define JS_VALUE_GET_BOOL(v) JS_VALUE_GET_INT(v) 108 | #define JS_VALUE_GET_FLOAT64(v) (double)JS_VALUE_GET_INT(v) 109 | #define JS_VALUE_GET_PTR(v) (void *)((intptr_t)(v) & ~0xf) 110 | 111 | #define JS_MKVAL(tag, val) (JSValue)(intptr_t)(((val) << 4) | (tag)) 112 | #define JS_MKPTR(tag, p) (JSValue)((intptr_t)(p) | (tag)) 113 | 114 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) 115 | 116 | #define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 1) 117 | 118 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 119 | { 120 | return JS_MKVAL(JS_TAG_FLOAT64, (int)d); 121 | } 122 | 123 | #elif defined(JS_NAN_BOXING) 124 | 125 | typedef uint64_t JSValue; 126 | 127 | #define JSValueConst JSValue 128 | 129 | #define JS_VALUE_GET_TAG(v) (int)((v) >> 32) 130 | #define JS_VALUE_GET_INT(v) (int)(v) 131 | #define JS_VALUE_GET_BOOL(v) (int)(v) 132 | #define JS_VALUE_GET_PTR(v) (void *)(intptr_t)(v) 133 | 134 | #define JS_MKVAL(tag, val) (((uint64_t)(tag) << 32) | (uint32_t)(val)) 135 | #define JS_MKPTR(tag, ptr) (((uint64_t)(tag) << 32) | (uintptr_t)(ptr)) 136 | 137 | #define JS_FLOAT64_TAG_ADDEND (0x7ff80000 - JS_TAG_FIRST + 1) /* quiet NaN encoding */ 138 | 139 | static inline double JS_VALUE_GET_FLOAT64(JSValue v) 140 | { 141 | union { 142 | JSValue v; 143 | double d; 144 | } u; 145 | u.v = v; 146 | u.v += (uint64_t)JS_FLOAT64_TAG_ADDEND << 32; 147 | return u.d; 148 | } 149 | 150 | #define JS_NAN (0x7ff8000000000000 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32)) 151 | 152 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 153 | { 154 | union { 155 | double d; 156 | uint64_t u64; 157 | } u; 158 | JSValue v; 159 | u.d = d; 160 | /* normalize NaN */ 161 | if (js_unlikely((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000)) 162 | v = JS_NAN; 163 | else 164 | v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32); 165 | return v; 166 | } 167 | 168 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)((tag) - JS_TAG_FIRST) >= (JS_TAG_FLOAT64 - JS_TAG_FIRST)) 169 | 170 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 171 | static inline int JS_VALUE_GET_NORM_TAG(JSValue v) 172 | { 173 | uint32_t tag; 174 | tag = JS_VALUE_GET_TAG(v); 175 | if (JS_TAG_IS_FLOAT64(tag)) 176 | return JS_TAG_FLOAT64; 177 | else 178 | return tag; 179 | } 180 | 181 | #else /* !JS_NAN_BOXING */ 182 | 183 | typedef union JSValueUnion { 184 | int32_t int32; 185 | double float64; 186 | void *ptr; 187 | } JSValueUnion; 188 | 189 | typedef struct JSValue { 190 | JSValueUnion u; 191 | int64_t tag; 192 | } JSValue; 193 | 194 | #define JSValueConst JSValue 195 | 196 | #define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag) 197 | /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ 198 | #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) 199 | #define JS_VALUE_GET_INT(v) ((v).u.int32) 200 | #define JS_VALUE_GET_BOOL(v) ((v).u.int32) 201 | #define JS_VALUE_GET_FLOAT64(v) ((v).u.float64) 202 | #define JS_VALUE_GET_PTR(v) ((v).u.ptr) 203 | 204 | #ifdef __cplusplus 205 | #define JS_MKVAL(tag, val) JSValue{ JSValueUnion{.int32 = val}, tag } 206 | #define JS_MKPTR(tag, p) JSValue{ JSValueUnion{.ptr = p}, tag } 207 | #else 208 | #define JS_MKVAL(tag, val) (JSValue){ .u.int32 = val, tag } 209 | #define JS_MKPTR(tag, p) (JSValue){ .u.ptr = p, tag } 210 | #endif 211 | 212 | #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) 213 | 214 | #define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 } 215 | 216 | static inline JSValue __JS_NewFloat64(JSContext *ctx, double d) 217 | { 218 | JSValue v; 219 | v.tag = JS_TAG_FLOAT64; 220 | v.u.float64 = d; 221 | return v; 222 | } 223 | 224 | #endif /* !JS_NAN_BOXING */ 225 | 226 | #define JS_VALUE_IS_BOTH_INT(v1, v2) ((JS_VALUE_GET_TAG(v1) | JS_VALUE_GET_TAG(v2)) == 0) 227 | #define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2))) 228 | 229 | #define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v)) 230 | #define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v)) 231 | #define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST) 232 | 233 | /* special values */ 234 | #define JS_NULL JS_MKVAL(JS_TAG_NULL, 0) 235 | #define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0) 236 | #define JS_FALSE JS_MKVAL(JS_TAG_BOOL, 0) 237 | #define JS_TRUE JS_MKVAL(JS_TAG_BOOL, 1) 238 | #define JS_EXCEPTION JS_MKVAL(JS_TAG_EXCEPTION, 0) 239 | #define JS_UNINITIALIZED JS_MKVAL(JS_TAG_UNINITIALIZED, 0) 240 | 241 | /* flags for object properties */ 242 | #define JS_PROP_CONFIGURABLE (1 << 0) 243 | #define JS_PROP_WRITABLE (1 << 1) 244 | #define JS_PROP_ENUMERABLE (1 << 2) 245 | #define JS_PROP_C_W_E (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_ENUMERABLE) 246 | #define JS_PROP_LENGTH (1 << 3) /* used internally in Arrays */ 247 | #define JS_PROP_TMASK (3 << 4) /* mask for NORMAL, GETSET, VARREF, AUTOINIT */ 248 | #define JS_PROP_NORMAL (0 << 4) 249 | #define JS_PROP_GETSET (1 << 4) 250 | #define JS_PROP_VARREF (2 << 4) /* used internally */ 251 | #define JS_PROP_AUTOINIT (3 << 4) /* used internally */ 252 | 253 | /* flags for JS_DefineProperty */ 254 | #define JS_PROP_HAS_SHIFT 8 255 | #define JS_PROP_HAS_CONFIGURABLE (1 << 8) 256 | #define JS_PROP_HAS_WRITABLE (1 << 9) 257 | #define JS_PROP_HAS_ENUMERABLE (1 << 10) 258 | #define JS_PROP_HAS_GET (1 << 11) 259 | #define JS_PROP_HAS_SET (1 << 12) 260 | #define JS_PROP_HAS_VALUE (1 << 13) 261 | 262 | /* throw an exception if false would be returned 263 | (JS_DefineProperty/JS_SetProperty) */ 264 | #define JS_PROP_THROW (1 << 14) 265 | /* throw an exception if false would be returned in strict mode 266 | (JS_SetProperty) */ 267 | #define JS_PROP_THROW_STRICT (1 << 15) 268 | 269 | #define JS_PROP_NO_ADD (1 << 16) /* internal use */ 270 | #define JS_PROP_NO_EXOTIC (1 << 17) /* internal use */ 271 | 272 | #define JS_DEFAULT_STACK_SIZE (256 * 1024) 273 | 274 | /* JS_Eval() flags */ 275 | #define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */ 276 | #define JS_EVAL_TYPE_MODULE (1 << 0) /* module code */ 277 | #define JS_EVAL_TYPE_DIRECT (2 << 0) /* direct call (internal use) */ 278 | #define JS_EVAL_TYPE_INDIRECT (3 << 0) /* indirect call (internal use) */ 279 | #define JS_EVAL_TYPE_MASK (3 << 0) 280 | 281 | #define JS_EVAL_FLAG_SHEBANG (1 << 2) /* skip first line beginning with '#!' */ 282 | #define JS_EVAL_FLAG_STRICT (1 << 3) /* force 'strict' mode */ 283 | #define JS_EVAL_FLAG_STRIP (1 << 4) /* force 'strip' mode */ 284 | #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) /* internal use */ 285 | 286 | typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); 287 | typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); 288 | typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); 289 | 290 | typedef struct JSMallocState { 291 | size_t malloc_count; 292 | size_t malloc_size; 293 | size_t malloc_limit; 294 | void *opaque; /* user opaque */ 295 | } JSMallocState; 296 | 297 | typedef struct JSMallocFunctions { 298 | void *(*js_malloc)(JSMallocState *s, size_t size); 299 | void (*js_free)(JSMallocState *s, void *ptr); 300 | void *(*js_realloc)(JSMallocState *s, void *ptr, size_t size); 301 | size_t (*js_malloc_usable_size)(const void *ptr); 302 | } JSMallocFunctions; 303 | 304 | JSRuntime *JS_NewRuntime(void); 305 | /* info lifetime must exceed that of rt */ 306 | void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); 307 | void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); 308 | void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); 309 | JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque); 310 | void JS_FreeRuntime(JSRuntime *rt); 311 | typedef void JS_MarkFunc(JSRuntime *rt, JSValueConst val); 312 | void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); 313 | void JS_RunGC(JSRuntime *rt); 314 | JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); 315 | JS_BOOL JS_IsInGCSweep(JSRuntime *rt); 316 | 317 | JSContext *JS_NewContext(JSRuntime *rt); 318 | void JS_FreeContext(JSContext *s); 319 | void *JS_GetContextOpaque(JSContext *ctx); 320 | void JS_SetContextOpaque(JSContext *ctx, void *opaque); 321 | JSRuntime *JS_GetRuntime(JSContext *ctx); 322 | void JS_SetMaxStackSize(JSContext *ctx, size_t stack_size); 323 | void JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj); 324 | JSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id); 325 | 326 | /* the following functions are used to select the intrinsic object to 327 | save memory */ 328 | JSContext *JS_NewContextRaw(JSRuntime *rt); 329 | void JS_AddIntrinsicBaseObjects(JSContext *ctx); 330 | void JS_AddIntrinsicDate(JSContext *ctx); 331 | void JS_AddIntrinsicEval(JSContext *ctx); 332 | void JS_AddIntrinsicStringNormalize(JSContext *ctx); 333 | void JS_AddIntrinsicRegExpCompiler(JSContext *ctx); 334 | void JS_AddIntrinsicRegExp(JSContext *ctx); 335 | void JS_AddIntrinsicJSON(JSContext *ctx); 336 | void JS_AddIntrinsicProxy(JSContext *ctx); 337 | void JS_AddIntrinsicMapSet(JSContext *ctx); 338 | void JS_AddIntrinsicTypedArrays(JSContext *ctx); 339 | void JS_AddIntrinsicPromise(JSContext *ctx); 340 | JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, 341 | int argc, JSValueConst *argv); 342 | 343 | void *js_malloc_rt(JSRuntime *rt, size_t size); 344 | void js_free_rt(JSRuntime *rt, void *ptr); 345 | void *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size); 346 | size_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr); 347 | void *js_mallocz_rt(JSRuntime *rt, size_t size); 348 | 349 | void *js_malloc(JSContext *ctx, size_t size); 350 | void js_free(JSContext *ctx, void *ptr); 351 | void *js_realloc(JSContext *ctx, void *ptr, size_t size); 352 | size_t js_malloc_usable_size(JSContext *ctx, const void *ptr); 353 | void *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack); 354 | void *js_mallocz(JSContext *ctx, size_t size); 355 | char *js_strdup(JSContext *ctx, const char *str); 356 | char *js_strndup(JSContext *ctx, const char *s, size_t n); 357 | 358 | typedef struct JSMemoryUsage { 359 | int64_t malloc_size, malloc_limit, memory_used_size; 360 | int64_t malloc_count; 361 | int64_t memory_used_count; 362 | int64_t atom_count, atom_size; 363 | int64_t str_count, str_size; 364 | int64_t obj_count, obj_size; 365 | int64_t prop_count, prop_size; 366 | int64_t shape_count, shape_size; 367 | int64_t js_func_count, js_func_size, js_func_code_size; 368 | int64_t js_func_pc2line_count, js_func_pc2line_size; 369 | int64_t c_func_count, array_count; 370 | int64_t fast_array_count, fast_array_elements; 371 | int64_t binary_object_count, binary_object_size; 372 | } JSMemoryUsage; 373 | 374 | void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s); 375 | void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); 376 | 377 | /* atom support */ 378 | JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, int len); 379 | JSAtom JS_NewAtom(JSContext *ctx, const char *str); 380 | JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n); 381 | JSAtom JS_DupAtom(JSContext *ctx, JSAtom v); 382 | void JS_FreeAtom(JSContext *ctx, JSAtom v); 383 | void JS_FreeAtomRT(JSRuntime *rt, JSAtom v); 384 | JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom); 385 | JSValue JS_AtomToString(JSContext *ctx, JSAtom atom); 386 | const char *JS_AtomToCString(JSContext *ctx, JSAtom atom); 387 | 388 | /* object class support */ 389 | 390 | typedef struct JSPropertyEnum { 391 | JS_BOOL is_enumerable; 392 | JSAtom atom; 393 | } JSPropertyEnum; 394 | 395 | typedef struct JSPropertyDescriptor { 396 | int flags; 397 | JSValue value; 398 | JSValue getter; 399 | JSValue setter; 400 | } JSPropertyDescriptor; 401 | 402 | typedef struct JSClassExoticMethods { 403 | /* Return -1 if exception (can only happen in case of Proxy object), 404 | FALSE if the property does not exists, TRUE if it exists. If 1 is 405 | returned, the property descriptor 'desc' is filled if != NULL. */ 406 | int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc, 407 | JSValueConst obj, JSAtom prop); 408 | /* '*ptab' should hold the '*plen' property keys. Return 0 if OK, 409 | -1 if exception. The 'is_enumerable' field is ignored. 410 | */ 411 | int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab, 412 | uint32_t *plen, 413 | JSValueConst obj); 414 | /* return < 0 if exception, or TRUE/FALSE */ 415 | int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop); 416 | /* return < 0 if exception or TRUE/FALSE */ 417 | int (*define_own_property)(JSContext *ctx, JSValueConst this_obj, 418 | JSAtom prop, JSValueConst val, 419 | JSValueConst getter, JSValueConst setter, 420 | int flags); 421 | /* The following methods can be emulated with the previous ones, 422 | so they are usually not needed */ 423 | /* return < 0 if exception or TRUE/FALSE */ 424 | int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom); 425 | JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, 426 | JSValueConst receiver); 427 | /* return < 0 if exception or TRUE/FALSE */ 428 | int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, 429 | JSValueConst value, JSValueConst receiver, int flags); 430 | } JSClassExoticMethods; 431 | 432 | typedef void JSClassFinalizer(JSRuntime *rt, JSValue val); 433 | typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val, 434 | JS_MarkFunc *mark_func); 435 | typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj, 436 | JSValueConst this_val, int argc, JSValueConst *argv); 437 | 438 | typedef struct JSClassDef { 439 | const char *class_name; 440 | JSClassFinalizer *finalizer; 441 | JSClassGCMark *gc_mark; 442 | JSClassCall *call; 443 | /* XXX: suppress this indirection ? It is here only to save memory 444 | because only a few classes need these methods */ 445 | JSClassExoticMethods *exotic; 446 | } JSClassDef; 447 | 448 | JSClassID JS_NewClassID(JSClassID *pclass_id); 449 | int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def); 450 | int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id); 451 | 452 | /* value handling */ 453 | 454 | static js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val) 455 | { 456 | return JS_MKVAL(JS_TAG_BOOL, val); 457 | } 458 | 459 | static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val) 460 | { 461 | return JS_MKVAL(JS_TAG_INT, val); 462 | } 463 | 464 | static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val) 465 | { 466 | return JS_MKVAL(JS_TAG_CATCH_OFFSET, val); 467 | } 468 | 469 | JSValue JS_NewInt64(JSContext *ctx, int64_t v); 470 | 471 | static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d) 472 | { 473 | JSValue v; 474 | int32_t val; 475 | union { 476 | double d; 477 | uint64_t u; 478 | } u, t; 479 | u.d = d; 480 | val = (int32_t)d; 481 | t.d = val; 482 | /* -0 cannot be represented as integer, so we compare the bit 483 | representation */ 484 | if (u.u == t.u) { 485 | v = JS_MKVAL(JS_TAG_INT, val); 486 | } else { 487 | v = __JS_NewFloat64(ctx, d); 488 | } 489 | return v; 490 | } 491 | 492 | JS_BOOL JS_IsNumber(JSValueConst v); 493 | 494 | static inline JS_BOOL JS_IsInteger(JSValueConst v) 495 | { 496 | int tag = JS_VALUE_GET_TAG(v); 497 | return tag == JS_TAG_INT || tag == JS_TAG_BIG_INT; 498 | } 499 | 500 | static inline JS_BOOL JS_IsBigFloat(JSValueConst v) 501 | { 502 | int tag = JS_VALUE_GET_TAG(v); 503 | return tag == JS_TAG_BIG_FLOAT; 504 | } 505 | 506 | static inline JS_BOOL JS_IsBool(JSValueConst v) 507 | { 508 | return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL; 509 | } 510 | 511 | static inline JS_BOOL JS_IsNull(JSValueConst v) 512 | { 513 | return JS_VALUE_GET_TAG(v) == JS_TAG_NULL; 514 | } 515 | 516 | static inline JS_BOOL JS_IsUndefined(JSValueConst v) 517 | { 518 | return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED; 519 | } 520 | 521 | static inline JS_BOOL JS_IsException(JSValueConst v) 522 | { 523 | return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION); 524 | } 525 | 526 | static inline JS_BOOL JS_IsUninitialized(JSValueConst v) 527 | { 528 | return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED); 529 | } 530 | 531 | static inline JS_BOOL JS_IsString(JSValueConst v) 532 | { 533 | return JS_VALUE_GET_TAG(v) == JS_TAG_STRING; 534 | } 535 | 536 | static inline JS_BOOL JS_IsSymbol(JSValueConst v) 537 | { 538 | return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL; 539 | } 540 | 541 | static inline JS_BOOL JS_IsObject(JSValueConst v) 542 | { 543 | return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT; 544 | } 545 | 546 | JSValue JS_Throw(JSContext *ctx, JSValue obj); 547 | JSValue JS_GetException(JSContext *ctx); 548 | JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val); 549 | void JS_EnableIsErrorProperty(JSContext *ctx, JS_BOOL enable); 550 | void JS_ResetUncatchableError(JSContext *ctx); 551 | JSValue JS_NewError(JSContext *ctx); 552 | JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...); 553 | JSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...); 554 | JSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...); 555 | JSValue __js_printf_like(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...); 556 | JSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...); 557 | JSValue JS_ThrowOutOfMemory(JSContext *ctx); 558 | 559 | void __JS_FreeValue(JSContext *ctx, JSValue v); 560 | static inline void JS_FreeValue(JSContext *ctx, JSValue v) 561 | { 562 | if (JS_VALUE_HAS_REF_COUNT(v)) { 563 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 564 | if (--p->ref_count <= 0) { 565 | __JS_FreeValue(ctx, v); 566 | } 567 | } 568 | } 569 | void __JS_FreeValueRT(JSRuntime *rt, JSValue v); 570 | static inline void JS_FreeValueRT(JSRuntime *rt, JSValue v) 571 | { 572 | if (JS_VALUE_HAS_REF_COUNT(v)) { 573 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 574 | if (--p->ref_count <= 0) { 575 | __JS_FreeValueRT(rt, v); 576 | } 577 | } 578 | } 579 | 580 | static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v) 581 | { 582 | if (JS_VALUE_HAS_REF_COUNT(v)) { 583 | JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); 584 | p->ref_count++; 585 | } 586 | return (JSValue)v; 587 | } 588 | 589 | int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */ 590 | int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val); 591 | static int inline JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val) 592 | { 593 | return JS_ToInt32(ctx, (int32_t*)pres, val); 594 | } 595 | int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val); 596 | int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val); 597 | int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val); 598 | 599 | JSValue JS_NewStringLen(JSContext *ctx, const char *str1, int len1); 600 | JSValue JS_NewString(JSContext *ctx, const char *str); 601 | JSValue JS_NewAtomString(JSContext *ctx, const char *str); 602 | JSValue JS_ToString(JSContext *ctx, JSValueConst val); 603 | JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val); 604 | const char *JS_ToCStringLen(JSContext *ctx, int *plen, JSValueConst val1, JS_BOOL cesu8); 605 | static inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1) 606 | { 607 | return JS_ToCStringLen(ctx, NULL, val1, 0); 608 | } 609 | void JS_FreeCString(JSContext *ctx, const char *ptr); 610 | 611 | JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto, JSClassID class_id); 612 | JSValue JS_NewObjectClass(JSContext *ctx, int class_id); 613 | JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto); 614 | JSValue JS_NewObject(JSContext *ctx); 615 | 616 | JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val); 617 | JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val); 618 | 619 | JSValue JS_NewArray(JSContext *ctx); 620 | int JS_IsArray(JSContext *ctx, JSValueConst val); 621 | 622 | JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, 623 | JSAtom prop, JSValueConst receiver, 624 | JS_BOOL throw_ref_error); 625 | static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj, 626 | JSAtom prop) 627 | { 628 | return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0); 629 | } 630 | JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj, 631 | const char *prop); 632 | JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj, 633 | uint32_t idx); 634 | 635 | int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, 636 | JSAtom prop, JSValue val, 637 | int flags); 638 | static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj, 639 | JSAtom prop, JSValue val) 640 | { 641 | return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW); 642 | } 643 | int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj, 644 | uint32_t idx, JSValue val); 645 | int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, 646 | int64_t idx, JSValue val); 647 | int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, 648 | const char *prop, JSValue val); 649 | int JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop); 650 | int JS_IsExtensible(JSContext *ctx, JSValueConst obj); 651 | int JS_PreventExtensions(JSContext *ctx, JSValueConst obj); 652 | int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags); 653 | int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val); 654 | JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val); 655 | 656 | JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, 657 | const char *filename); 658 | JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, 659 | int argc, JSValueConst *argv); 660 | JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, 661 | int argc, JSValueConst *argv); 662 | JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, 663 | int argc, JSValueConst *argv); 664 | JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, 665 | JSValueConst new_target, 666 | int argc, JSValueConst *argv); 667 | JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, 668 | const char *filename, int eval_flags); 669 | #define JS_EVAL_BINARY_LOAD_ONLY (1 << 0) /* only load the module */ 670 | JSValue JS_EvalBinary(JSContext *ctx, 671 | const uint8_t *buf, size_t buf_len, int flags); 672 | JSValue JS_GetGlobalObject(JSContext *ctx); 673 | int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj); 674 | int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, 675 | JSAtom prop, JSValueConst val, 676 | JSValueConst getter, JSValueConst setter, int flags); 677 | int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, 678 | JSAtom prop, JSValue val, int flags); 679 | int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, 680 | uint32_t idx, JSValue val, int flags); 681 | int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, 682 | const char *prop, JSValue val, int flags); 683 | int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, 684 | JSAtom prop, JSValue getter, JSValue setter, 685 | int flags); 686 | void JS_SetOpaque(JSValue obj, void *opaque); 687 | void *JS_GetOpaque(JSValueConst obj, JSClassID class_id); 688 | void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id); 689 | 690 | typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr); 691 | JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, 692 | JSFreeArrayBufferDataFunc *free_func, void *opaque, 693 | JS_BOOL is_shared); 694 | JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len); 695 | void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj); 696 | uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj); 697 | 698 | /* return != 0 if the JS code needs to be interrupted */ 699 | typedef int JSInterruptHandler(JSRuntime *rt, void *opaque); 700 | void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque); 701 | /* if can_block is TRUE, Atomics.wait() can be used */ 702 | void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block); 703 | 704 | typedef struct JSModuleDef JSModuleDef; 705 | 706 | /* return the module specifier (allocated with js_malloc()) or NULL if 707 | exception */ 708 | typedef char *JSModuleNormalizeFunc(JSContext *ctx, 709 | const char *module_base_name, 710 | const char *module_name, void *opaque); 711 | typedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx, 712 | const char *module_name, void *opaque); 713 | 714 | /* module_normalize = NULL is allowed and invokes the default module 715 | filename normalizer */ 716 | void JS_SetModuleLoaderFunc(JSRuntime *rt, 717 | JSModuleNormalizeFunc *module_normalize, 718 | JSModuleLoaderFunc *module_loader, void *opaque); 719 | 720 | /* JS Job support */ 721 | 722 | typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValueConst *argv); 723 | int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValueConst *argv); 724 | 725 | JS_BOOL JS_IsJobPending(JSRuntime *rt); 726 | int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx); 727 | 728 | /* Object Writer/Reader (currently only used to handle precompiled code) */ 729 | #define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */ 730 | #define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */ 731 | uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, 732 | int flags); 733 | #define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */ 734 | #define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */ 735 | JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, 736 | int flags); 737 | JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj, JSValueConst this_obj); 738 | 739 | /* C function definition */ 740 | typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ 741 | JS_CFUNC_generic, 742 | JS_CFUNC_generic_magic, 743 | JS_CFUNC_constructor, 744 | JS_CFUNC_constructor_magic, 745 | JS_CFUNC_constructor_or_func, 746 | JS_CFUNC_constructor_or_func_magic, 747 | JS_CFUNC_f_f, 748 | JS_CFUNC_f_f_f, 749 | JS_CFUNC_getter, 750 | JS_CFUNC_setter, 751 | JS_CFUNC_getter_magic, 752 | JS_CFUNC_setter_magic, 753 | JS_CFUNC_iterator_next, 754 | } JSCFunctionEnum; 755 | 756 | typedef union JSCFunctionType { 757 | JSCFunction *generic; 758 | JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); 759 | JSCFunction *constructor; 760 | JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic); 761 | JSCFunction *constructor_or_func; 762 | double (*f_f)(double); 763 | double (*f_f_f)(double, double); 764 | JSValue (*getter)(JSContext *ctx, JSValueConst this_val); 765 | JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val); 766 | JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic); 767 | JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic); 768 | JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val, 769 | int argc, JSValueConst *argv, int *pdone, int magic); 770 | } JSCFunctionType; 771 | 772 | JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, 773 | const char *name, 774 | int length, JSCFunctionEnum cproto, int magic); 775 | JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, 776 | int length, int magic, int data_len, 777 | JSValueConst *data); 778 | 779 | static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name, 780 | int length) 781 | { 782 | return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0); 783 | } 784 | 785 | static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func, 786 | const char *name, 787 | int length, JSCFunctionEnum cproto, int magic) 788 | { 789 | return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic); 790 | } 791 | 792 | /* C property definition */ 793 | 794 | typedef struct JSCFunctionListEntry { 795 | const char *name; 796 | uint8_t prop_flags; 797 | uint8_t def_type; 798 | int16_t magic; 799 | union { 800 | struct { 801 | uint8_t length; /* XXX: should move outside union */ 802 | uint8_t cproto; /* XXX: should move outside union */ 803 | JSCFunctionType cfunc; 804 | } func; 805 | struct { 806 | JSCFunctionType get; 807 | JSCFunctionType set; 808 | } getset; 809 | struct { 810 | const char *name; 811 | int base; 812 | } alias; 813 | struct { 814 | const struct JSCFunctionListEntry *tab; 815 | int len; 816 | } prop_list; 817 | const char *str; 818 | int32_t i32; 819 | int64_t i64; 820 | double f64; 821 | } u; 822 | } JSCFunctionListEntry; 823 | 824 | #define JS_DEF_CFUNC 0 825 | #define JS_DEF_CGETSET 1 826 | #define JS_DEF_CGETSET_MAGIC 2 827 | #define JS_DEF_PROP_STRING 3 828 | #define JS_DEF_PROP_INT32 4 829 | #define JS_DEF_PROP_INT64 5 830 | #define JS_DEF_PROP_DOUBLE 6 831 | #define JS_DEF_PROP_UNDEFINED 7 832 | #define JS_DEF_OBJECT 8 833 | #define JS_DEF_ALIAS 9 834 | 835 | #define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u.func = { length, JS_CFUNC_generic, { .generic = func1 } } } 836 | #define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u.func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } 837 | #define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u.func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } 838 | #define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u.func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } 839 | #define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u.getset.get.getter = fgetter, .u.getset.set.setter = fsetter } 840 | #define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u.getset.get.getter_magic = fgetter, .u.getset.set.setter_magic = fsetter } 841 | #define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u.str = cstr } 842 | #define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u.i32 = val } 843 | #define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u.i64 = val } 844 | #define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u.f64 = val } 845 | #define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u.i32 = 0 } 846 | #define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u.prop_list = { tab, len } } 847 | #define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u.alias = { from, -1 } } 848 | #define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u.alias = { from, base } } 849 | 850 | void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj, 851 | const JSCFunctionListEntry *tab, 852 | int len); 853 | 854 | /* C module definition */ 855 | 856 | typedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m); 857 | 858 | JSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str, 859 | JSModuleInitFunc *func); 860 | /* can only be called before the module is instantiated */ 861 | int JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str); 862 | int JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m, 863 | const JSCFunctionListEntry *tab, int len); 864 | /* can only be called after the module is instantiated */ 865 | int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, 866 | JSValue val); 867 | int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, 868 | const JSCFunctionListEntry *tab, int len); 869 | 870 | #undef js_unlikely 871 | #undef js_force_inline 872 | 873 | #endif /* QUICKJS_H */ 874 | -------------------------------------------------------------------------------- /quickjspp.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern "C" { 4 | #include "quickjs/quickjs.h" 5 | #include "quickjs/quickjs-libc.h" 6 | } 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace qjs { 16 | 17 | namespace detail { 18 | class exception {}; 19 | 20 | template 21 | struct js_traits 22 | { 23 | //static R unwrap(JSContext * ctx, JSValue v); 24 | //static JSValue wrap(JSContext * ctx, R value) 25 | }; 26 | 27 | // identity 28 | template <> 29 | struct js_traits 30 | { 31 | static JSValue unwrap(JSContext * ctx, JSValue v) noexcept 32 | { 33 | return v; 34 | } 35 | 36 | static JSValue wrap(JSContext * ctx, JSValue v) noexcept 37 | { 38 | return v; 39 | } 40 | }; 41 | 42 | template <> 43 | struct js_traits 44 | { 45 | static int32_t unwrap(JSContext * ctx, JSValue v) 46 | { 47 | int32_t r; 48 | if(JS_ToInt32(ctx, &r, v)) 49 | throw exception{}; 50 | return r; 51 | } 52 | 53 | static JSValue wrap(JSContext * ctx, int32_t i) noexcept 54 | { 55 | return JS_NewInt32(ctx, i); 56 | } 57 | }; 58 | 59 | /* 60 | template 61 | std::tuple to_tuple_impl(JSContext * ctx, JSValue * argv) 62 | { 63 | if constexpr (sizeof...(Args) == 0) 64 | return std::make_tuple(js_traits>::unwrap(ctx, *argv)); 65 | else // todo:rewrite 66 | return std::tuple_cat(std::make_tuple(js_traits>::unwrap(ctx, *argv)), 67 | to_tuple_impl(ctx, argv + 1)); 68 | } 69 | */ 70 | template 71 | Tuple unwrap_args_impl(JSContext * ctx, JSValue * argv, std::index_sequence) 72 | { 73 | return Tuple{js_traits>>::unwrap(ctx, argv[I])...}; 74 | } 75 | 76 | template 77 | std::tuple unwrap_args(JSContext * ctx, JSValue * argv) 78 | { 79 | return unwrap_args_impl>(ctx, argv, std::make_index_sequence()); 80 | } 81 | 82 | // free function 83 | 84 | template 85 | struct fwrapper 86 | { 87 | const char * name = nullptr; 88 | }; 89 | 90 | template 91 | struct js_traits> 92 | { 93 | static JSValue wrap(JSContext * ctx, fwrapper fw) 94 | { 95 | return JS_NewCFunction(ctx, [](JSContext * ctx, JSValue this_value, int argc, 96 | JSValue * argv) noexcept -> JSValue { 97 | //if(argc < sizeof...(Args)) 98 | //return JS_EXCEPTION; 99 | try 100 | { 101 | if constexpr (std::is_same_v) 102 | { 103 | std::apply(F, detail::unwrap_args(ctx, argv)); 104 | return JS_UNDEFINED; 105 | } else 106 | return js_traits::wrap(ctx, 107 | std::apply(F, detail::unwrap_args(ctx, argv)) 108 | ); 109 | } catch(detail::exception) // todo: inspect exception 110 | { 111 | return JS_EXCEPTION; 112 | } 113 | }, fw.name, sizeof...(Args)); 114 | 115 | } 116 | }; 117 | 118 | // class member function 119 | 120 | template 121 | struct js_traits> 122 | { 123 | static JSValue wrap(JSContext * ctx, fwrapper fw) 124 | { 125 | return JS_NewCFunction(ctx, [](JSContext * ctx, JSValue this_value, int argc, 126 | JSValue * argv) noexcept -> JSValue { 127 | //if(argc < sizeof...(Args)) 128 | //return JS_EXCEPTION; 129 | try 130 | { 131 | const auto& this_sp = js_traits>::unwrap(ctx, this_value); 132 | 133 | if constexpr (std::is_same_v) 134 | { 135 | std::apply(F, std::tuple_cat(std::make_tuple(this_sp.get()), 136 | detail::unwrap_args(ctx, argv))); 137 | return JS_UNDEFINED; 138 | } else 139 | return js_traits::wrap(ctx, 140 | std::apply(F, std::tuple_cat(std::make_tuple(this_sp.get()), 141 | detail::unwrap_args(ctx, 142 | argv))) 143 | ); 144 | } catch(detail::exception) 145 | { 146 | return JS_EXCEPTION; 147 | } 148 | }, fw.name, sizeof...(Args)); 149 | 150 | } 151 | }; 152 | 153 | 154 | // class constructor 155 | 156 | template 157 | struct ctor_wrapper 158 | { 159 | const char * name = nullptr; 160 | }; 161 | 162 | template 163 | struct js_traits> 164 | { 165 | static JSValue wrap(JSContext * ctx, ctor_wrapper cw) 166 | { 167 | return JS_NewCFunction2(ctx, [](JSContext * ctx, JSValue this_value, int argc, 168 | JSValue * argv) noexcept -> JSValue { 169 | try 170 | { 171 | 172 | return js_traits>::wrap(ctx, 173 | std::apply(std::make_shared, 174 | detail::unwrap_args(ctx, argv)) 175 | ); 176 | } catch(detail::exception) 177 | { 178 | return JS_EXCEPTION; 179 | } 180 | }, cw.name, sizeof...(Args), JS_CFUNC_constructor, 0); 181 | 182 | } 183 | }; 184 | 185 | 186 | // SP class 187 | 188 | template 189 | struct js_traits> 190 | { 191 | inline static JSClassID QJSClassId; 192 | 193 | static void register_class(JSContext * ctx, const char * name, JSValue proto) 194 | { 195 | JSClassDef def{ 196 | name, 197 | // destructor 198 | [](JSRuntime * rt, JSValue obj) noexcept { 199 | auto pptr = reinterpret_cast *>(JS_GetOpaque(obj, QJSClassId)); 200 | if(!pptr) 201 | { 202 | assert(false && "bad destructor"); 203 | } 204 | delete pptr; 205 | } 206 | }; 207 | if(QJSClassId == 0) 208 | { 209 | int e = JS_NewClass(JS_GetRuntime(ctx), JS_NewClassID(&QJSClassId), &def); 210 | if(e < 0) 211 | throw exception{}; 212 | } 213 | JS_SetClassProto(ctx, QJSClassId, proto); 214 | } 215 | 216 | static JSValue wrap(JSContext * ctx, std::shared_ptr ptr) 217 | { 218 | if(QJSClassId == 0) // not registered 219 | throw exception{}; 220 | auto pptr = new std::shared_ptr(std::move(ptr)); 221 | auto jsobj = JS_NewObjectClass(ctx, QJSClassId); 222 | JS_SetOpaque(jsobj, pptr); 223 | return jsobj; 224 | } 225 | 226 | static const std::shared_ptr& unwrap(JSContext * ctx, JSValue v) 227 | { 228 | auto ptr = reinterpret_cast *>(JS_GetOpaque2(ctx, v, QJSClassId)); 229 | if(!ptr) 230 | throw exception{}; 231 | return *ptr; 232 | } 233 | }; 234 | 235 | // properties 236 | 237 | template 238 | struct js_property_traits 239 | { 240 | // static void set_property(JSContext * ctx, JSValue this_obj, R key, JSValue value) 241 | // static JSValue get_property(JSContext * ctx, JSValue this_obj, R key) 242 | }; 243 | 244 | template <> 245 | struct js_property_traits 246 | { 247 | static void set_property(JSContext * ctx, JSValue this_obj, const char * name, JSValue value) 248 | { 249 | int err = JS_SetPropertyStr(ctx, this_obj, name, value); 250 | if(err < 0) 251 | throw exception{}; 252 | } 253 | 254 | static JSValue get_property(JSContext * ctx, JSValue this_obj, const char * name) noexcept 255 | { 256 | return JS_GetPropertyStr(ctx, this_obj, name); 257 | } 258 | 259 | }; 260 | 261 | template 262 | struct property_proxy 263 | { 264 | JSContext * ctx; 265 | JSValue this_obj; 266 | Key key; 267 | 268 | operator JSValue() const 269 | { 270 | return js_property_traits::get_property(ctx, this_obj, key); 271 | } 272 | 273 | template 274 | property_proxy& operator =(Value value) 275 | { 276 | js_property_traits::set_property(ctx, this_obj, key, 277 | js_traits::wrap(ctx, std::move(value))); 278 | return *this; 279 | } 280 | }; 281 | 282 | } 283 | 284 | class Value 285 | { 286 | public: 287 | JSValue v; 288 | JSContext * ctx = nullptr; 289 | 290 | public: 291 | template 292 | Value(JSContext * ctx, T val) : ctx(ctx) 293 | { 294 | v = detail::js_traits::wrap(ctx, val); 295 | } 296 | 297 | Value(const Value& rhs) 298 | { 299 | ctx = rhs.ctx; 300 | v = JS_DupValue(ctx, rhs.v); 301 | } 302 | 303 | Value(Value&& rhs) 304 | { 305 | std::swap(ctx, rhs.ctx); 306 | v = rhs.v; 307 | } 308 | 309 | ~Value() 310 | { 311 | if(ctx) JS_FreeValue(ctx, v); 312 | } 313 | 314 | 315 | template 316 | T cast() const 317 | { 318 | return detail::js_traits::unwrap(ctx, v); 319 | } 320 | 321 | JSValue release() // dont call freevalue 322 | { 323 | ctx = nullptr; 324 | return v; 325 | } 326 | 327 | operator JSValue()&& 328 | { 329 | return release(); 330 | } 331 | 332 | 333 | // access properties 334 | template 335 | detail::property_proxy operator [](Key key) 336 | { 337 | return {ctx, v, std::move(key)}; 338 | } 339 | 340 | 341 | }; 342 | 343 | 344 | class Runtime 345 | { 346 | public: 347 | JSRuntime * rt; 348 | 349 | Runtime() 350 | { 351 | rt = JS_NewRuntime(); 352 | if(!rt) 353 | throw detail::exception{}; 354 | } 355 | 356 | Runtime(const Runtime&) = delete; 357 | 358 | ~Runtime() 359 | { 360 | JS_FreeRuntime(rt); 361 | } 362 | }; 363 | 364 | 365 | class Context 366 | { 367 | public: 368 | JSContext * ctx; 369 | 370 | class Module 371 | { 372 | friend class Context; 373 | 374 | JSModuleDef * m; 375 | JSContext * ctx; 376 | const char * name; 377 | 378 | std::vector> exports; 379 | public: 380 | Module(JSContext * ctx, const char * name) : ctx(ctx), name(name) 381 | { 382 | m = JS_NewCModule(ctx, name, [](JSContext * ctx, JSModuleDef * m) noexcept { 383 | auto context = reinterpret_cast(JS_GetContextOpaque(ctx)); 384 | if(!context) 385 | return -1; 386 | auto it = std::find_if(context->modules.cbegin(), context->modules.cend(), 387 | [m](const Module& module) { return module.m == m; }); 388 | if(it == context->modules.end()) 389 | return -1; 390 | for(const auto& e : it->exports) 391 | { 392 | if(JS_SetModuleExport(ctx, m, e.first, e.second) != 0) 393 | return -1; 394 | } 395 | return 0; 396 | }); 397 | if(!m) 398 | throw detail::exception{}; 399 | } 400 | 401 | Module& add(const char * name, JSValue value) 402 | { 403 | exports.push_back({name, value}); 404 | JS_AddModuleExport(ctx, m, name); 405 | return *this; 406 | } 407 | 408 | Module& add(const char * name, Value value) 409 | { 410 | return add(name, value.release()); 411 | } 412 | 413 | template 414 | Module& add(const char * name, T value) 415 | { 416 | return add(name, detail::js_traits::wrap(ctx, std::move(value))); 417 | } 418 | 419 | //Module(const Module&) = delete; 420 | }; 421 | 422 | std::vector modules; 423 | private: 424 | public: 425 | Context(Runtime& rt) : Context(rt.rt) 426 | {} 427 | 428 | Context(JSRuntime * rt) 429 | { 430 | ctx = JS_NewContext(rt); 431 | if(!ctx) 432 | throw detail::exception{}; 433 | JS_SetContextOpaque(ctx, this); 434 | } 435 | 436 | Context(JSContext * ctx) : ctx{ctx} 437 | { 438 | JS_SetContextOpaque(ctx, this); 439 | } 440 | 441 | Context(const Context&) = delete; 442 | 443 | ~Context() 444 | { 445 | JS_FreeContext(ctx); 446 | } 447 | 448 | Module& addModule(const char * name) 449 | { 450 | modules.emplace_back(ctx, name); 451 | return modules.back(); 452 | } 453 | 454 | Value global() 455 | { 456 | return Value{ctx, JS_GetGlobalObject(ctx)}; 457 | } 458 | 459 | Value newObject() 460 | { 461 | return Value{ctx, JS_NewObject(ctx)}; 462 | } 463 | 464 | template 465 | void registerClass(const char * name, JSValue proto) 466 | { 467 | detail::js_traits>::register_class(ctx, name, proto); 468 | } 469 | 470 | Value eval(std::string_view buffer, const char * filename, unsigned eval_flags = 0) 471 | { 472 | JSValue v = JS_Eval(ctx, buffer.data(), buffer.size(), filename, eval_flags); 473 | //if(JS_IsException(v)) 474 | //throw detail::exception{}; 475 | return Value{ctx, v}; 476 | } 477 | 478 | Value evalFile(const char * filename, unsigned eval_flags = 0) 479 | { 480 | size_t buf_len; 481 | auto deleter = [this](void * p) { js_free(ctx, p); }; 482 | auto buf = std::unique_ptr{js_load_file(ctx, &buf_len, filename), deleter}; 483 | if(!buf) 484 | throw std::runtime_error{std::string{"evalFile: can't read file: "} + filename}; 485 | return eval({reinterpret_cast(buf.get()), buf_len}, filename, eval_flags); 486 | } 487 | 488 | }; 489 | 490 | 491 | } --------------------------------------------------------------------------------