MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at mir/inline-method 1356 lines 47 kB view raw
1// TODO: split module into smaller files 2 3#include <compat.h> // IWYU pragma: keep 4 5#include <ctype.h> 6#include <math.h> 7#include <stdbool.h> 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11 12#include "ant.h" 13#include "internal.h" 14#include "esm/library.h" 15#include "silver/engine.h" 16 17#include "modules/buffer.h" 18#include "modules/date.h" 19#include "modules/json.h" 20#include "modules/symbol.h" 21#include "modules/util.h" 22#include "modules/abort.h" 23#include "modules/collections.h" 24 25typedef struct { 26 char *buf; 27 size_t len; 28 size_t cap; 29} util_sb_t; 30 31typedef struct { 32 const char *name; 33 const char *open; 34 const char *close; 35} util_style_entry_t; 36 37typedef enum { 38 UTIL_PARSE_ARG_TYPE_BOOLEAN = 0, 39 UTIL_PARSE_ARG_TYPE_STRING, 40} util_parse_arg_type_t; 41 42typedef struct { 43 char *name; 44 char short_name; 45 util_parse_arg_type_t type; 46 bool multiple; 47 ant_value_t default_value; 48} util_parse_arg_option_t; 49 50// TODO: migrate to crprintf 51static const util_style_entry_t util_styles[] = { 52 {"bold", "\x1b[1m", "\x1b[22m"}, 53 {"dim", "\x1b[2m", "\x1b[22m"}, 54 {"italic", "\x1b[3m", "\x1b[23m"}, 55 {"underline", "\x1b[4m", "\x1b[24m"}, 56 {"inverse", "\x1b[7m", "\x1b[27m"}, 57 {"hidden", "\x1b[8m", "\x1b[28m"}, 58 {"strikethrough", "\x1b[9m", "\x1b[29m"}, 59 {"black", "\x1b[30m", "\x1b[39m"}, 60 {"red", "\x1b[31m", "\x1b[39m"}, 61 {"green", "\x1b[32m", "\x1b[39m"}, 62 {"yellow", "\x1b[33m", "\x1b[39m"}, 63 {"blue", "\x1b[34m", "\x1b[39m"}, 64 {"magenta", "\x1b[35m", "\x1b[39m"}, 65 {"cyan", "\x1b[36m", "\x1b[39m"}, 66 {"white", "\x1b[37m", "\x1b[39m"}, 67 {"gray", "\x1b[90m", "\x1b[39m"}, 68 {"grey", "\x1b[90m", "\x1b[39m"}, 69 {"bgBlack", "\x1b[40m", "\x1b[49m"}, 70 {"bgRed", "\x1b[41m", "\x1b[49m"}, 71 {"bgGreen", "\x1b[42m", "\x1b[49m"}, 72 {"bgYellow", "\x1b[43m", "\x1b[49m"}, 73 {"bgBlue", "\x1b[44m", "\x1b[49m"}, 74 {"bgMagenta", "\x1b[45m", "\x1b[49m"}, 75 {"bgCyan", "\x1b[46m", "\x1b[49m"}, 76 {"bgWhite", "\x1b[47m", "\x1b[49m"}, 77}; 78 79static bool util_sb_reserve(util_sb_t *sb, size_t extra) { 80 size_t need = sb->len + extra + 1; 81 if (need <= sb->cap) return true; 82 83 size_t next = sb->cap ? sb->cap : 128; 84 while (next < need) next *= 2; 85 86 char *buf = (char *)realloc(sb->buf, next); 87 if (!buf) return false; 88 89 sb->buf = buf; 90 sb->cap = next; 91 return true; 92} 93 94static bool util_sb_append_n(util_sb_t *sb, const char *s, size_t n) { 95 if (n == 0) return true; 96 if (!util_sb_reserve(sb, n)) return false; 97 memcpy(sb->buf + sb->len, s, n); 98 sb->len += n; 99 sb->buf[sb->len] = '\0'; 100 return true; 101} 102 103static bool util_sb_append_c(util_sb_t *sb, char c) { 104 if (!util_sb_reserve(sb, 1)) return false; 105 sb->buf[sb->len++] = c; 106 sb->buf[sb->len] = '\0'; 107 return true; 108} 109 110static bool util_sb_append_jsval(ant_t *js, util_sb_t *sb, ant_value_t v) { 111 char cbuf[512]; 112 js_cstr_t cstr = js_to_cstr(js, v, cbuf, sizeof(cbuf)); 113 size_t len = strlen(cstr.ptr); 114 bool ok = util_sb_append_n(sb, cstr.ptr, len); 115 if (cstr.needs_free) free((void *)cstr.ptr); 116 return ok; 117} 118 119static bool util_sb_append_json(ant_t *js, util_sb_t *sb, ant_value_t v) { 120 ant_value_t json = json_stringify_value(js, v); 121 if (vtype(json) != T_STR) { 122 return util_sb_append_n(sb, "[Circular]", 10); 123 } 124 size_t len = 0; 125 const char *s = js_getstr(js, json, &len); 126 return s ? util_sb_append_n(sb, s, len) : util_sb_append_n(sb, "[Circular]", 10); 127} 128 129static bool util_set_named_value( 130 ant_t *js, 131 ant_value_t values, 132 const char *name, 133 ant_value_t value, 134 bool multiple 135) { 136 if (!multiple) { 137 js_set(js, values, name, value); 138 return !js->thrown_exists; 139 } 140 141 ant_value_t existing = js_get(js, values, name); 142 if (is_err(existing)) return false; 143 144 if (vtype(existing) == T_UNDEF) { 145 ant_value_t arr = js_mkarr(js); 146 js_arr_push(js, arr, value); 147 js_set(js, values, name, arr); 148 return !js->thrown_exists; 149 } 150 151 if (vtype(existing) == T_ARR) { 152 js_arr_push(js, existing, value); 153 return !js->thrown_exists; 154 } 155 156 ant_value_t arr = js_mkarr(js); 157 js_arr_push(js, arr, existing); 158 js_arr_push(js, arr, value); 159 js_set(js, values, name, arr); 160 return !js->thrown_exists; 161} 162 163static util_parse_arg_option_t *util_find_option_by_name( 164 util_parse_arg_option_t *options, 165 size_t option_count, 166 const char *name 167) { 168 for (size_t i = 0; i < option_count; i++) { 169 if (strcmp(options[i].name, name) == 0) return &options[i]; 170 } 171 return NULL; 172} 173 174static util_parse_arg_option_t *util_find_option_by_short( 175 util_parse_arg_option_t *options, 176 size_t option_count, 177 char short_name 178) { 179 for (size_t i = 0; i < option_count; i++) { 180 if (options[i].short_name == short_name) return &options[i]; 181 } 182 return NULL; 183} 184 185static void util_free_parse_options(util_parse_arg_option_t *options, size_t option_count) { 186 if (!options) return; 187 for (size_t i = 0; i < option_count; i++) free(options[i].name); 188 free(options); 189} 190 191static ant_value_t util_parse_args(ant_t *js, ant_value_t *args, int nargs) { 192 ant_value_t config = nargs > 0 ? args[0] : js_mkundef(); 193 if (!is_object_type(config)) { 194 return js_mkerr_typed(js, JS_ERR_TYPE, "parseArgs(config) requires an options object"); 195 } 196 197 ant_value_t args_list = js_get(js, config, "args"); 198 if (is_err(args_list)) return args_list; 199 if (vtype(args_list) == T_UNDEF) { 200 ant_value_t process_obj = js_get(js, js_glob(js), "process"); 201 if (is_err(process_obj)) return process_obj; 202 args_list = js_get(js, process_obj, "argv"); 203 if (is_err(args_list)) return args_list; 204 } 205 206 ant_value_t options_obj = js_get(js, config, "options"); 207 if (is_err(options_obj)) return options_obj; 208 if (!is_object_type(options_obj)) options_obj = js_mkobj(js); 209 210 bool strict = js_truthy(js, js_get(js, config, "strict")); 211 if (vtype(js_get(js, config, "strict")) == T_UNDEF) strict = true; 212 bool allow_positionals = js_truthy(js, js_get(js, config, "allowPositionals")); 213 214 size_t option_count = 0; 215 { 216 ant_iter_t iter = js_prop_iter_begin(js, options_obj); 217 const char *key = NULL; 218 size_t key_len = 0; 219 while (js_prop_iter_next(&iter, &key, &key_len, NULL)) option_count++; 220 js_prop_iter_end(&iter); 221 } 222 223 util_parse_arg_option_t *options = NULL; 224 if (option_count > 0) { 225 options = calloc(option_count, sizeof(*options)); 226 if (!options) return js_mkerr(js, "Out of memory"); 227 228 ant_iter_t iter = js_prop_iter_begin(js, options_obj); 229 const char *key = NULL; 230 size_t key_len = 0; 231 size_t idx = 0; 232 233 while (idx < option_count && js_prop_iter_next(&iter, &key, &key_len, NULL)) { 234 ant_value_t spec = js_get(js, options_obj, key); 235 ant_value_t type_val = is_object_type(spec) ? js_get(js, spec, "type") : js_mkundef(); 236 ant_value_t short_val = is_object_type(spec) ? js_get(js, spec, "short") : js_mkundef(); 237 ant_value_t multiple_val = is_object_type(spec) ? js_get(js, spec, "multiple") : js_mkundef(); 238 ant_value_t default_val = is_object_type(spec) ? js_get(js, spec, "default") : js_mkundef(); 239 240 options[idx].name = strndup(key, key_len); 241 if (!options[idx].name) { 242 js_prop_iter_end(&iter); 243 util_free_parse_options(options, option_count); 244 return js_mkerr(js, "Out of memory"); 245 } 246 247 options[idx].type = UTIL_PARSE_ARG_TYPE_BOOLEAN; 248 if (vtype(type_val) == T_STR) { 249 size_t type_len = 0; 250 const char *type_str = js_getstr(js, type_val, &type_len); 251 if (type_str && type_len == 6 && memcmp(type_str, "string", 6) == 0) { 252 options[idx].type = UTIL_PARSE_ARG_TYPE_STRING; 253 } 254 } 255 256 if (vtype(short_val) == T_STR) { 257 size_t short_len = 0; 258 const char *short_str = js_getstr(js, short_val, &short_len); 259 if (short_str && short_len > 0) options[idx].short_name = short_str[0]; 260 } 261 262 options[idx].multiple = js_truthy(js, multiple_val); 263 options[idx].default_value = default_val; 264 idx++; 265 } 266 267 js_prop_iter_end(&iter); 268 } 269 270 ant_value_t values = js_mkobj(js); 271 ant_value_t positionals = js_mkarr(js); 272 ant_value_t out = js_mkobj(js); 273 274 for (size_t i = 0; i < option_count; i++) { 275 if (vtype(options[i].default_value) != T_UNDEF) { 276 if (!util_set_named_value(js, values, options[i].name, options[i].default_value, options[i].multiple)) { 277 util_free_parse_options(options, option_count); 278 return js->thrown_exists ? js->thrown_value : js_mkerr(js, "parseArgs failed to set default"); 279 }}} 280 281 ant_offset_t arg_len = js_arr_len(js, args_list); 282 bool stop_parsing = false; 283 284 for (ant_offset_t i = 0; i < arg_len; i++) { 285 ant_value_t arg_val = js_arr_get(js, args_list, i); 286 if (vtype(arg_val) != T_STR) continue; 287 288 size_t arg_slen = 0; 289 const char *arg = js_getstr(js, arg_val, &arg_slen); 290 if (!arg) continue; 291 292 if (stop_parsing) { 293 js_arr_push(js, positionals, arg_val); 294 continue; 295 } 296 297 if (arg_slen == 2 && memcmp(arg, "--", 2) == 0) { 298 stop_parsing = true; 299 continue; 300 } 301 302 if (arg_slen > 2 && arg[0] == '-' && arg[1] == '-') { 303 const char *name = arg + 2; 304 size_t name_len = arg_slen - 2; 305 const char *inline_value = NULL; 306 size_t inline_len = 0; 307 const char *eq = memchr(name, '=', name_len); 308 309 if (eq) { 310 name_len = (size_t)(eq - name); 311 inline_value = eq + 1; 312 inline_len = (size_t)(arg + arg_slen - inline_value); 313 } 314 315 char *name_buf = strndup(name, name_len); 316 if (!name_buf) { 317 util_free_parse_options(options, option_count); 318 return js_mkerr(js, "Out of memory"); 319 } 320 321 util_parse_arg_option_t *opt = util_find_option_by_name(options, option_count, name_buf); 322 if (!opt) { 323 if (strict) { 324 free(name_buf); 325 util_free_parse_options(options, option_count); 326 return js_mkerr_typed(js, JS_ERR_TYPE, "Unknown option '--%.*s'", (int)name_len, name); 327 } 328 329 ant_value_t unknown = inline_value 330 ? js_mkstr(js, inline_value, inline_len) 331 : js_true; 332 333 js_set(js, values, name_buf, unknown); 334 free(name_buf); 335 336 continue; 337 } 338 339 ant_value_t parsed_value = js_true; 340 if (opt->type == UTIL_PARSE_ARG_TYPE_STRING) { 341 if (inline_value) parsed_value = js_mkstr(js, inline_value, inline_len); 342 else if (i + 1 < arg_len) parsed_value = js_arr_get(js, args_list, ++i); 343 else { 344 free(name_buf); 345 util_free_parse_options(options, option_count); 346 return js_mkerr_typed(js, JS_ERR_TYPE, "Option '--%s' requires a value", opt->name); 347 } 348 } else if (inline_value) parsed_value = js_mkstr(js, inline_value, inline_len); 349 350 if (!util_set_named_value(js, values, opt->name, parsed_value, opt->multiple)) { 351 free(name_buf); 352 util_free_parse_options(options, option_count); 353 return js->thrown_exists ? js->thrown_value : js_mkerr(js, "parseArgs failed"); 354 } 355 356 free(name_buf); 357 continue; 358 } 359 360 if (arg_slen > 1 && arg[0] == '-') { 361 for (size_t j = 1; j < arg_slen; j++) { 362 util_parse_arg_option_t *opt = util_find_option_by_short(options, option_count, arg[j]); 363 if (!opt) { 364 if (strict) { 365 util_free_parse_options(options, option_count); 366 return js_mkerr_typed(js, JS_ERR_TYPE, "Unknown option '-%c'", arg[j]); 367 } 368 char key[2] = {arg[j], '\0'}; 369 js_set(js, values, key, js_true); 370 continue; 371 } 372 373 ant_value_t parsed_value = js_true; 374 if (opt->type == UTIL_PARSE_ARG_TYPE_STRING) { 375 if (j + 1 < arg_slen) { 376 parsed_value = js_mkstr(js, arg + j + 1, arg_slen - (j + 1)); 377 j = arg_slen; 378 } else if (i + 1 < arg_len) { 379 parsed_value = js_arr_get(js, args_list, ++i); 380 j = arg_slen; 381 } else { 382 util_free_parse_options(options, option_count); 383 return js_mkerr_typed(js, JS_ERR_TYPE, "Option '-%c' requires a value", arg[j]); 384 } 385 } 386 387 if (!util_set_named_value(js, values, opt->name, parsed_value, opt->multiple)) { 388 util_free_parse_options(options, option_count); 389 return js->thrown_exists ? js->thrown_value : js_mkerr(js, "parseArgs failed"); 390 } 391 392 if (opt->type == UTIL_PARSE_ARG_TYPE_STRING) break; 393 } 394 continue; 395 } 396 397 if (!allow_positionals) { 398 util_free_parse_options(options, option_count); 399 return js_mkerr_typed(js, JS_ERR_TYPE, "Unexpected positional argument '%s'", arg); 400 } 401 js_arr_push(js, positionals, arg_val); 402 } 403 404 util_free_parse_options(options, option_count); 405 js_set(js, out, "values", values); 406 js_set(js, out, "positionals", positionals); 407 408 return out; 409} 410 411static ant_value_t util_format_impl(ant_t *js, ant_value_t *args, int nargs, int fmt_index) { 412 util_sb_t sb = {0}; 413 if (fmt_index >= nargs) { 414 ant_value_t out = js_mkstr(js, "", 0); 415 free(sb.buf); 416 return out; 417 } 418 419 if (vtype(args[fmt_index]) != T_STR) { 420 for (int i = fmt_index; i < nargs; i++) { 421 if (i > fmt_index) util_sb_append_c(&sb, ' '); 422 util_sb_append_jsval(js, &sb, args[i]); 423 } 424 ant_value_t out = js_mkstr(js, sb.buf ? sb.buf : "", sb.len); 425 free(sb.buf); 426 return out; 427 } 428 429 size_t fmt_len = 0; 430 const char *fmt = js_getstr(js, args[fmt_index], &fmt_len); 431 int argi = fmt_index + 1; 432 433 for (size_t i = 0; i < fmt_len; i++) { 434 if (fmt[i] != '%' || i + 1 >= fmt_len) { 435 util_sb_append_c(&sb, fmt[i]); 436 continue; 437 } 438 439 char spec = fmt[i + 1]; 440 if (spec == '%') { 441 util_sb_append_c(&sb, '%'); 442 i++; 443 continue; 444 } 445 446 bool known = ( 447 spec == 's' || spec == 'd' || spec == 'i' || spec == 'f' || 448 spec == 'j' || spec == 'o' || spec == 'O' || spec == 'c' 449 ); 450 451 if (!known) { 452 util_sb_append_c(&sb, '%'); 453 util_sb_append_c(&sb, spec); 454 i++; 455 continue; 456 } 457 458 ant_value_t v = (argi < nargs) ? args[argi++] : js_mkundef(); 459 460 if (spec == 's') { 461 util_sb_append_jsval(js, &sb, v); 462 } else if (spec == 'd' || spec == 'i') { 463 double d = js_to_number(js, v); 464 char nb[64]; 465 if (isnan(d)) snprintf(nb, sizeof(nb), "NaN"); 466 else if (!isfinite(d)) snprintf(nb, sizeof(nb), d < 0 ? "-Infinity" : "Infinity"); 467 else snprintf(nb, sizeof(nb), "%lld", (long long)d); 468 util_sb_append_n(&sb, nb, strlen(nb)); 469 } else if (spec == 'f') { 470 double d = js_to_number(js, v); 471 char nb[64]; 472 if (isnan(d)) snprintf(nb, sizeof(nb), "NaN"); 473 else if (!isfinite(d)) snprintf(nb, sizeof(nb), d < 0 ? "-Infinity" : "Infinity"); 474 else snprintf(nb, sizeof(nb), "%g", d); 475 util_sb_append_n(&sb, nb, strlen(nb)); 476 } else if (spec == 'j') { 477 util_sb_append_json(js, &sb, v); 478 } else if (spec == 'o' || spec == 'O') { 479 util_sb_append_jsval(js, &sb, v); 480 } else if (spec == 'c') { 481 // style placeholder: consume arg, emit nothing. 482 } 483 484 i++; 485 } 486 487 for (; argi < nargs; argi++) { 488 util_sb_append_c(&sb, ' '); 489 util_sb_append_jsval(js, &sb, args[argi]); 490 } 491 492 ant_value_t out = js_mkstr(js, sb.buf ? sb.buf : "", sb.len); 493 free(sb.buf); 494 return out; 495} 496 497static ant_value_t util_format(ant_t *js, ant_value_t *args, int nargs) { 498 return util_format_impl(js, args, nargs, 0); 499} 500 501static ant_value_t util_format_with_options(ant_t *js, ant_value_t *args, int nargs) { 502 if (nargs <= 1) return js_mkstr(js, "", 0); 503 return util_format_impl(js, args, nargs, 1); 504} 505 506static ant_value_t util_inspect(ant_t *js, ant_value_t *args, int nargs) { 507 if (nargs < 1) return js_mkstr(js, "undefined", 9); 508 char cbuf[512]; 509 js_cstr_t cstr = js_to_cstr(js, args[0], cbuf, sizeof(cbuf)); 510 ant_value_t out = js_mkstr(js, cstr.ptr, strlen(cstr.ptr)); 511 if (cstr.needs_free) free((void *)cstr.ptr); 512 return out; 513} 514 515static bool util_has_proto_in_chain(ant_t *js, ant_value_t value, ant_value_t proto) { 516 if (!is_special_object(proto)) return false; 517 518 ant_value_t current = value; 519 while (is_special_object(current)) { 520 current = js_get_proto(js, current); 521 if (current == proto) return true; 522 } 523 524 return false; 525} 526 527static bool util_is_boxed_primitive(ant_value_t value, uint8_t *type_out) { 528 ant_value_t primitive; 529 530 if (!is_object_type(value)) return false; 531 primitive = js_get_slot(value, SLOT_PRIMITIVE); 532 if (vtype(primitive) == T_UNDEF) return false; 533 534 if (type_out) *type_out = vtype(primitive); 535 return true; 536} 537 538static bool util_has_to_string_tag(ant_t *js, ant_value_t value, const char *tag, size_t tag_len) { 539 ant_value_t to_string_tag; 540 size_t actual_len = 0; 541 const char *actual; 542 543 if (!is_object_type(value)) return false; 544 545 to_string_tag = js_get_sym(js, value, get_toStringTag_sym()); 546 if (vtype(to_string_tag) != T_STR) return false; 547 548 actual = js_getstr(js, to_string_tag, &actual_len); 549 return actual != NULL && actual_len == tag_len && memcmp(actual, tag, tag_len) == 0; 550} 551 552static bool util_is_arguments_object_value(ant_t *js, ant_value_t value) { 553 ant_value_t callee = js_mkundef(); 554 555 if (vtype(value) != T_ARR) return false; 556 if (js_get_slot(value, SLOT_STRICT_ARGS) == js_true) return true; 557 if (!util_has_to_string_tag(js, value, "Arguments", 9)) return false; 558 559 return js_try_get_own_data_prop(js, value, "callee", 6, &callee); 560} 561 562static ant_value_t util_types_is_any_array_buffer(ant_t *js, ant_value_t *args, int nargs) { 563 ArrayBufferData *buffer = (nargs > 0) ? buffer_get_arraybuffer_data(args[0]) : NULL; 564 return js_bool(buffer != NULL); 565} 566 567static ant_value_t util_types_is_array_buffer(ant_t *js, ant_value_t *args, int nargs) { 568 ArrayBufferData *buffer = (nargs > 0) ? buffer_get_arraybuffer_data(args[0]) : NULL; 569 return js_bool(buffer != NULL && !buffer->is_shared); 570} 571 572static ant_value_t util_types_is_shared_array_buffer(ant_t *js, ant_value_t *args, int nargs) { 573 ArrayBufferData *buffer = (nargs > 0) ? buffer_get_arraybuffer_data(args[0]) : NULL; 574 return js_bool(buffer != NULL && buffer->is_shared); 575} 576 577static ant_value_t util_types_is_array_buffer_view(ant_t *js, ant_value_t *args, int nargs) { 578 if (nargs < 1) return js_false; 579 return js_bool(buffer_is_dataview(args[0]) || buffer_get_typedarray_data(args[0]) != NULL); 580} 581 582static ant_value_t util_types_is_data_view(ant_t *js, ant_value_t *args, int nargs) { 583 if (nargs < 1) return js_false; 584 return js_bool(buffer_is_dataview(args[0])); 585} 586 587static ant_value_t util_types_is_typed_array(ant_t *js, ant_value_t *args, int nargs) { 588 if (nargs < 1) return js_false; 589 return js_bool(buffer_get_typedarray_data(args[0]) != NULL); 590} 591 592static ant_value_t util_types_is_float16_array(ant_t *js, ant_value_t *args, int nargs) { 593 TypedArrayData *typed_array = (nargs > 0) ? buffer_get_typedarray_data(args[0]) : NULL; 594 if (!typed_array) return js_false; 595 return js_bool(typed_array != NULL && typed_array->type == TYPED_ARRAY_FLOAT16); 596} 597 598#define DEFINE_TYPED_ARRAY_CHECK(fn_name, typed_array_kind) \ 599 static ant_value_t fn_name(ant_t *js, ant_value_t *args, int nargs) { \ 600 TypedArrayData *typed_array = (nargs > 0) ? buffer_get_typedarray_data(args[0]) : NULL; \ 601 if (!typed_array) return js_false; \ 602 return js_bool(typed_array != NULL && typed_array->type == typed_array_kind); \ 603 } 604 605DEFINE_TYPED_ARRAY_CHECK(util_types_is_int8_array, TYPED_ARRAY_INT8) 606DEFINE_TYPED_ARRAY_CHECK(util_types_is_uint8_array, TYPED_ARRAY_UINT8) 607DEFINE_TYPED_ARRAY_CHECK(util_types_is_int16_array, TYPED_ARRAY_INT16) 608DEFINE_TYPED_ARRAY_CHECK(util_types_is_uint16_array, TYPED_ARRAY_UINT16) 609DEFINE_TYPED_ARRAY_CHECK(util_types_is_int32_array, TYPED_ARRAY_INT32) 610DEFINE_TYPED_ARRAY_CHECK(util_types_is_uint32_array, TYPED_ARRAY_UINT32) 611DEFINE_TYPED_ARRAY_CHECK(util_types_is_float32_array, TYPED_ARRAY_FLOAT32) 612DEFINE_TYPED_ARRAY_CHECK(util_types_is_float64_array, TYPED_ARRAY_FLOAT64) 613DEFINE_TYPED_ARRAY_CHECK(util_types_is_bigint64_array, TYPED_ARRAY_BIGINT64) 614DEFINE_TYPED_ARRAY_CHECK(util_types_is_biguint64_array, TYPED_ARRAY_BIGUINT64) 615DEFINE_TYPED_ARRAY_CHECK(util_types_is_uint8_clamped_array, TYPED_ARRAY_UINT8_CLAMPED) 616 617static ant_value_t util_types_is_promise(ant_t *js, ant_value_t *args, int nargs) { 618 if (nargs < 1) return js_false; 619 return js_bool(vtype(args[0]) == T_PROMISE); 620} 621 622static ant_value_t util_types_is_proxy(ant_t *js, ant_value_t *args, int nargs) { 623 if (nargs < 1 || !is_object_type(args[0])) return js_false; 624 return js_bool(is_proxy(args[0])); 625} 626 627static ant_value_t util_types_is_regexp(ant_t *js, ant_value_t *args, int nargs) { 628 ant_value_t regexp_proto; 629 if (nargs < 1 || !is_object_type(args[0])) return js_false; 630 regexp_proto = js_get_ctor_proto(js, "RegExp", 6); 631 return js_bool(util_has_proto_in_chain(js, args[0], regexp_proto)); 632} 633 634static ant_value_t util_types_is_date(ant_t *js, ant_value_t *args, int nargs) { 635 if (nargs < 1) return js_false; 636 return js_bool(is_date_instance(args[0])); 637} 638 639static ant_value_t util_types_is_map(ant_t *js, ant_value_t *args, int nargs) { 640 if (nargs < 1 || vtype(args[0]) != T_OBJ) return js_false; 641 return js_bool(js_obj_ptr(args[0])->type_tag == T_MAP); 642} 643 644static ant_value_t util_types_is_set(ant_t *js, ant_value_t *args, int nargs) { 645 if (nargs < 1 || vtype(args[0]) != T_OBJ) return js_false; 646 return js_bool(js_obj_ptr(args[0])->type_tag == T_SET); 647} 648 649static ant_value_t util_types_is_weak_map(ant_t *js, ant_value_t *args, int nargs) { 650 if (nargs < 1 || vtype(args[0]) != T_OBJ) return js_false; 651 return js_bool(js_obj_ptr(args[0])->type_tag == T_WEAKMAP); 652} 653 654static ant_value_t util_types_is_weak_set(ant_t *js, ant_value_t *args, int nargs) { 655 if (nargs < 1 || vtype(args[0]) != T_OBJ) return js_false; 656 return js_bool(js_obj_ptr(args[0])->type_tag == T_WEAKSET); 657} 658 659static ant_value_t util_types_is_async_function(ant_t *js, ant_value_t *args, int nargs) { 660 ant_value_t func_obj; 661 if (nargs < 1 || vtype(args[0]) != T_FUNC) return js_false; 662 func_obj = js_func_obj(args[0]); 663 return js_bool(js_get_slot(func_obj, SLOT_ASYNC) == js_true); 664} 665 666static ant_value_t util_types_is_generator_function(ant_t *js, ant_value_t *args, int nargs) { 667 sv_closure_t *closure; 668 669 if (nargs < 1 || vtype(args[0]) != T_FUNC) return js_false; 670 671 closure = js_func_closure(args[0]); 672 return js_bool(closure != NULL && closure->func != NULL && closure->func->is_generator); 673} 674 675static ant_value_t util_types_is_generator_object(ant_t *js, ant_value_t *args, int nargs) { 676 if (nargs < 1) return js_false; 677 return js_bool(vtype(args[0]) == T_GENERATOR); 678} 679 680static ant_value_t util_types_is_arguments_object(ant_t *js, ant_value_t *args, int nargs) { 681 if (nargs < 1) return js_false; 682 return js_bool(util_is_arguments_object_value(js, args[0])); 683} 684 685static ant_value_t util_types_is_native_error(ant_t *js, ant_value_t *args, int nargs) { 686 if (nargs < 1 || !is_object_type(args[0])) return js_false; 687 return js_bool(js_get_slot(args[0], SLOT_ERROR_BRAND) == js_true); 688} 689 690static ant_value_t util_types_is_boxed_primitive(ant_t *js, ant_value_t *args, int nargs) { 691 return js_bool(nargs > 0 && util_is_boxed_primitive(args[0], NULL)); 692} 693 694static ant_value_t util_types_is_boolean_object(ant_t *js, ant_value_t *args, int nargs) { 695 uint8_t type = T_UNDEF; 696 return js_bool(nargs > 0 && util_is_boxed_primitive(args[0], &type) && type == T_BOOL); 697} 698 699static ant_value_t util_types_is_number_object(ant_t *js, ant_value_t *args, int nargs) { 700 uint8_t type = T_UNDEF; 701 return js_bool(nargs > 0 && util_is_boxed_primitive(args[0], &type) && type == T_NUM); 702} 703 704static ant_value_t util_types_is_string_object(ant_t *js, ant_value_t *args, int nargs) { 705 uint8_t type = T_UNDEF; 706 return js_bool(nargs > 0 && util_is_boxed_primitive(args[0], &type) && type == T_STR); 707} 708 709static ant_value_t util_types_is_symbol_object(ant_t *js, ant_value_t *args, int nargs) { 710 uint8_t type = T_UNDEF; 711 return js_bool(nargs > 0 && util_is_boxed_primitive(args[0], &type) && type == T_SYMBOL); 712} 713 714static ant_value_t util_types_is_bigint_object(ant_t *js, ant_value_t *args, int nargs) { 715 uint8_t type = T_UNDEF; 716 return js_bool(nargs > 0 && util_is_boxed_primitive(args[0], &type) && type == T_BIGINT); 717} 718 719static ant_value_t util_types_is_map_iterator(ant_t *js, ant_value_t *args, int nargs) { 720 if (nargs < 1 || !is_object_type(args[0])) return js_false; 721 return js_bool(util_has_proto_in_chain(js, args[0], g_map_iter_proto)); 722} 723 724static ant_value_t util_types_is_set_iterator(ant_t *js, ant_value_t *args, int nargs) { 725 if (nargs < 1 || !is_object_type(args[0])) return js_false; 726 return js_bool(util_has_proto_in_chain(js, args[0], g_set_iter_proto)); 727} 728 729static ant_value_t util_types_is_module_namespace_object(ant_t *js, ant_value_t *args, int nargs) { 730 if (nargs < 1) return js_false; 731 return js_bool(js_check_brand(args[0], BRAND_MODULE_NAMESPACE)); 732} 733 734ant_value_t util_types_library(ant_t *js) { 735 ant_value_t types = js_mkobj(js); 736 737 js_set(js, types, "isAnyArrayBuffer", js_mkfun(util_types_is_any_array_buffer)); 738 js_set(js, types, "isArrayBuffer", js_mkfun(util_types_is_array_buffer)); 739 js_set(js, types, "isArgumentsObject", js_mkfun(util_types_is_arguments_object)); 740 js_set(js, types, "isArrayBufferView", js_mkfun(util_types_is_array_buffer_view)); 741 js_set(js, types, "isAsyncFunction", js_mkfun(util_types_is_async_function)); 742 js_set(js, types, "isBigInt64Array", js_mkfun(util_types_is_bigint64_array)); 743 js_set(js, types, "isBigIntObject", js_mkfun(util_types_is_bigint_object)); 744 js_set(js, types, "isBigUint64Array", js_mkfun(util_types_is_biguint64_array)); 745 js_set(js, types, "isBooleanObject", js_mkfun(util_types_is_boolean_object)); 746 js_set(js, types, "isBoxedPrimitive", js_mkfun(util_types_is_boxed_primitive)); 747 js_set(js, types, "isDataView", js_mkfun(util_types_is_data_view)); 748 js_set(js, types, "isDate", js_mkfun(util_types_is_date)); 749 js_set(js, types, "isFloat16Array", js_mkfun(util_types_is_float16_array)); 750 js_set(js, types, "isFloat32Array", js_mkfun(util_types_is_float32_array)); 751 js_set(js, types, "isFloat64Array", js_mkfun(util_types_is_float64_array)); 752 js_set(js, types, "isGeneratorFunction", js_mkfun(util_types_is_generator_function)); 753 js_set(js, types, "isGeneratorObject", js_mkfun(util_types_is_generator_object)); 754 js_set(js, types, "isInt8Array", js_mkfun(util_types_is_int8_array)); 755 js_set(js, types, "isInt16Array", js_mkfun(util_types_is_int16_array)); 756 js_set(js, types, "isInt32Array", js_mkfun(util_types_is_int32_array)); 757 js_set(js, types, "isMap", js_mkfun(util_types_is_map)); 758 js_set(js, types, "isMapIterator", js_mkfun(util_types_is_map_iterator)); 759 js_set(js, types, "isModuleNamespaceObject", js_mkfun(util_types_is_module_namespace_object)); 760 js_set(js, types, "isNativeError", js_mkfun(util_types_is_native_error)); 761 js_set(js, types, "isNumberObject", js_mkfun(util_types_is_number_object)); 762 js_set(js, types, "isPromise", js_mkfun(util_types_is_promise)); 763 js_set(js, types, "isProxy", js_mkfun(util_types_is_proxy)); 764 js_set(js, types, "isRegExp", js_mkfun(util_types_is_regexp)); 765 js_set(js, types, "isSet", js_mkfun(util_types_is_set)); 766 js_set(js, types, "isSetIterator", js_mkfun(util_types_is_set_iterator)); 767 js_set(js, types, "isSharedArrayBuffer", js_mkfun(util_types_is_shared_array_buffer)); 768 js_set(js, types, "isStringObject", js_mkfun(util_types_is_string_object)); 769 js_set(js, types, "isSymbolObject", js_mkfun(util_types_is_symbol_object)); 770 js_set(js, types, "isTypedArray", js_mkfun(util_types_is_typed_array)); 771 js_set(js, types, "isUint8Array", js_mkfun(util_types_is_uint8_array)); 772 js_set(js, types, "isUint8ClampedArray", js_mkfun(util_types_is_uint8_clamped_array)); 773 js_set(js, types, "isUint16Array", js_mkfun(util_types_is_uint16_array)); 774 js_set(js, types, "isUint32Array", js_mkfun(util_types_is_uint32_array)); 775 js_set(js, types, "isWeakMap", js_mkfun(util_types_is_weak_map)); 776 js_set(js, types, "isWeakSet", js_mkfun(util_types_is_weak_set)); 777 778 return types; 779} 780 781static ant_value_t util_get_types_object(ant_t *js) { 782 bool loaded = false; 783 ant_value_t types = js_esm_load_registered_library(js, "util/types", 10, &loaded); 784 return loaded ? types : util_types_library(js); 785} 786 787static ant_value_t util_debuglog_call(ant_params_t) { 788 return js_mkundef(); 789} 790 791static ant_value_t util_debuglog(ant_params_t) { 792 ant_value_t logger = js_mkfun(util_debuglog_call); 793 js_set(js, logger, "enabled", js_false); 794 795 if (nargs >= 2 && is_callable(args[1])) { 796 ant_value_t cb_args[1] = { logger }; 797 ant_value_t result = sv_vm_call(js->vm, js, args[1], js_mkundef(), cb_args, 1, NULL, false); 798 if (is_err(result) || js->thrown_exists) return result; 799 } 800 801 return logger; 802} 803 804static ant_value_t util_strip_vt_control_characters(ant_t *js, ant_value_t *args, int nargs) { 805 if (nargs < 1) return js_mkstr(js, "", 0); 806 807 char cbuf[512]; 808 js_cstr_t cstr = js_to_cstr(js, args[0], cbuf, sizeof(cbuf)); 809 const char *src = cstr.ptr; 810 size_t len = strlen(src); 811 812 util_sb_t sb = {0}; 813 for (size_t i = 0; i < len; i++) { 814 unsigned char ch = (unsigned char)src[i]; 815 if (ch != 0x1b) { 816 util_sb_append_c(&sb, (char)ch); 817 continue; 818 } 819 820 if (i + 1 < len && src[i + 1] == '[') { 821 i += 2; 822 while (i < len) { 823 unsigned char c = (unsigned char)src[i]; 824 if (c >= '@' && c <= '~') break; 825 i++; 826 } 827 continue; 828 } 829 830 if (i + 1 < len && src[i + 1] == ']') { 831 i += 2; 832 while (i < len) { 833 if ((unsigned char)src[i] == 0x07) break; 834 if ((unsigned char)src[i] == 0x1b && i + 1 < len && src[i + 1] == '\\') { 835 i++; 836 break; 837 } 838 i++; 839 } 840 continue; 841 } 842 } 843 844 ant_value_t out = js_mkstr(js, sb.buf ? sb.buf : "", sb.len); 845 if (cstr.needs_free) free((void *)cstr.ptr); 846 free(sb.buf); 847 return out; 848} 849 850static inline bool util_env_is_inline_ws(char ch) { 851 return ch == ' ' || ch == '\t' || ch == '\r'; 852} 853 854static inline bool util_env_is_ident_start(char ch) { 855 return 856 (ch >= 'A' && ch <= 'Z') || 857 (ch >= 'a' && ch <= 'z') || 858 ch == '_'; 859} 860 861static inline bool util_env_is_ident_continue(char ch) { 862 return util_env_is_ident_start(ch) || (ch >= '0' && ch <= '9'); 863} 864 865static void util_env_skip_inline_ws(const char *src, size_t len, size_t *cursor) { 866 while (*cursor < len && util_env_is_inline_ws(src[*cursor])) (*cursor)++; 867} 868 869static void util_env_skip_line(const char *src, size_t len, size_t *cursor) { 870 while (*cursor < len && src[*cursor] != '\n') (*cursor)++; 871 if (*cursor < len && src[*cursor] == '\n') (*cursor)++; 872} 873 874static bool util_env_consume_export(const char *src, size_t len, size_t *cursor) { 875 if (*cursor + 6 > len) return false; 876 if (memcmp(src + *cursor, "export", 6) != 0) return false; 877 878 if ( 879 *cursor + 6 < len && 880 !util_env_is_inline_ws(src[*cursor + 6]) && 881 src[*cursor + 6] != '\n' 882 ) return false; 883 884 *cursor += 6; 885 util_env_skip_inline_ws(src, len, cursor); 886 return true; 887} 888 889static bool util_env_parse_key( 890 const char *src, size_t len, size_t *cursor, 891 size_t *key_start, size_t *key_end 892) { 893 if (*cursor >= len || !util_env_is_ident_start(src[*cursor])) return false; 894 *key_start = *cursor; (*cursor)++; 895 896 while (*cursor < len && util_env_is_ident_continue(src[*cursor])) (*cursor)++; 897 *key_end = *cursor; 898 899 return true; 900} 901 902static void util_env_set_entry( 903 ant_t *js, ant_value_t obj, const char *key, 904 size_t key_len, ant_value_t value 905) { 906 ant_value_t key_str = js_mkstr(js, key, key_len); 907 js_setprop(js, obj, key_str, value); 908} 909 910static ant_value_t util_env_parse_quoted_value( 911 ant_t *js, const char *src, 912 size_t len, size_t *cursor 913) { 914 util_sb_t sb = {0}; 915 ant_value_t value = js_mkstr(js, "", 0); 916 char quote; 917 918 if (*cursor >= len) return value; 919 quote = src[(*cursor)++]; 920 921 while (*cursor < len) { 922 char ch = src[(*cursor)++]; 923 if (ch == quote) goto done; 924 if (ch != '\\' || *cursor >= len) { 925 util_sb_append_c(&sb, ch); 926 continue; 927 } 928 929 char esc = src[(*cursor)++]; 930 if (quote != '"') { 931 util_sb_append_c(&sb, esc); 932 continue; 933 } 934 935 switch (esc) { 936 case 'n': util_sb_append_c(&sb, '\n'); break; 937 case 'r': util_sb_append_c(&sb, '\r'); break; 938 case 't': util_sb_append_c(&sb, '\t'); break; 939 case '\\': util_sb_append_c(&sb, '\\'); break; 940 case '"': util_sb_append_c(&sb, '"'); break; 941 default: util_sb_append_c(&sb, esc); break; 942 } 943 } 944 945done: 946 value = js_mkstr(js, sb.buf ? sb.buf : "", sb.len); 947 free(sb.buf); 948 949 while (*cursor < len && src[*cursor] != '\n') { 950 if (src[*cursor] == '#') break; 951 (*cursor)++; 952 } 953 954 return value; 955} 956 957static ant_value_t util_env_parse_unquoted_value( 958 ant_t *js, const char *src, 959 size_t len, size_t *cursor 960) { 961 size_t value_start = *cursor; 962 size_t value_end = *cursor; 963 bool saw_space = false; 964 965 while (*cursor < len && src[*cursor] != '\n' && src[*cursor] != '\r') { 966 if (src[*cursor] == '#') { 967 if (*cursor == value_start || saw_space) goto done; 968 } 969 970 saw_space = util_env_is_inline_ws(src[*cursor]); 971 (*cursor)++; 972 value_end = *cursor; 973 } 974 975done: 976 while (value_start < value_end && util_env_is_inline_ws(src[value_start])) { 977 value_start++; 978 } 979 while (value_end > value_start && util_env_is_inline_ws(src[value_end - 1])) { 980 value_end--; 981 } 982 983 return js_mkstr(js, src + value_start, value_end - value_start); 984} 985 986static ant_value_t util_parse_env(ant_t *js, ant_value_t *args, int nargs) { 987 ant_value_t out = js_mkobj(js); 988 if (nargs < 1) return out; 989 990 char cbuf[512]; 991 js_cstr_t cstr = js_to_cstr(js, args[0], cbuf, sizeof(cbuf)); 992 const char *src = cstr.ptr; 993 size_t len = strlen(src); 994 size_t i = 0; 995 996 if (len >= 3 && 997 (unsigned char)src[0] == 0xEF && 998 (unsigned char)src[1] == 0xBB && 999 (unsigned char)src[2] == 0xBF) { 1000 i = 3; 1001 } 1002 1003 while (i < len) { 1004 size_t key_start = 0; 1005 size_t key_end = 0; 1006 ant_value_t value = js_mkstr(js, "", 0); 1007 1008 util_env_skip_inline_ws(src, len, &i); 1009 if (i >= len) break; 1010 if (src[i] == '\n') { 1011 i++; 1012 continue; 1013 } 1014 if (src[i] == '#') goto skip_line; 1015 1016 util_env_consume_export(src, len, &i); 1017 if (!util_env_parse_key(src, len, &i, &key_start, &key_end)) goto skip_line; 1018 1019 util_env_skip_inline_ws(src, len, &i); 1020 if (i >= len || src[i] != '=') goto skip_line; 1021 i++; 1022 util_env_skip_inline_ws(src, len, &i); 1023 1024 if (i < len && (src[i] == '"' || src[i] == '\'' || src[i] == '`')) { 1025 value = util_env_parse_quoted_value(js, src, len, &i); 1026 } else { 1027 value = util_env_parse_unquoted_value(js, src, len, &i); 1028 } 1029 1030 util_env_set_entry(js, out, src + key_start, key_end - key_start, value); 1031 1032skip_line: 1033 util_env_skip_line(src, len, &i); 1034 } 1035 1036 if (cstr.needs_free) free((void *)cstr.ptr); 1037 return out; 1038} 1039 1040static const util_style_entry_t *util_find_style(const char *name) { 1041 for (size_t i = 0; i < sizeof(util_styles) / sizeof(util_styles[0]); i++) { 1042 if (strcmp(name, util_styles[i].name) == 0) return &util_styles[i]; 1043 } 1044 return NULL; 1045} 1046 1047static ant_value_t util_style_text(ant_t *js, ant_value_t *args, int nargs) { 1048 if (nargs < 2) return js_mkstr(js, "", 0); 1049 1050 char text_buf[512]; 1051 js_cstr_t text_cstr = js_to_cstr(js, args[1], text_buf, sizeof(text_buf)); 1052 1053 const util_style_entry_t *picked[16]; 1054 int picked_n = 0; 1055 1056 if (vtype(args[0]) == T_STR) { 1057 const char *name = js_getstr(js, args[0], NULL); 1058 const util_style_entry_t *e = name ? util_find_style(name) : NULL; 1059 if (e) picked[picked_n++] = e; 1060 } else if (vtype(args[0]) == T_ARR) { 1061 ant_offset_t len = js_arr_len(js, args[0]); 1062 for (ant_offset_t i = 0; i < len && picked_n < (int)(sizeof(picked) / sizeof(picked[0])); i++) { 1063 ant_value_t item = js_arr_get(js, args[0], i); 1064 if (vtype(item) != T_STR) continue; 1065 const char *name = js_getstr(js, item, NULL); 1066 const util_style_entry_t *e = name ? util_find_style(name) : NULL; 1067 if (e) picked[picked_n++] = e; 1068 } 1069 } 1070 1071 if (picked_n == 0) { 1072 ant_value_t out = js_mkstr(js, text_cstr.ptr, strlen(text_cstr.ptr)); 1073 if (text_cstr.needs_free) free((void *)text_cstr.ptr); 1074 return out; 1075 } 1076 1077 util_sb_t sb = {0}; 1078 for (int i = 0; i < picked_n; i++) { 1079 util_sb_append_n(&sb, picked[i]->open, strlen(picked[i]->open)); 1080 } 1081 util_sb_append_n(&sb, text_cstr.ptr, strlen(text_cstr.ptr)); 1082 for (int i = picked_n - 1; i >= 0; i--) { 1083 util_sb_append_n(&sb, picked[i]->close, strlen(picked[i]->close)); 1084 } 1085 1086 ant_value_t out = js_mkstr(js, sb.buf ? sb.buf : "", sb.len); 1087 if (text_cstr.needs_free) free((void *)text_cstr.ptr); 1088 free(sb.buf); 1089 return out; 1090} 1091 1092static ant_value_t util_promisify_callback(ant_t *js, ant_value_t *args, int nargs) { 1093 ant_value_t fn = js_getcurrentfunc(js); 1094 ant_value_t ctx = js_get_slot(fn, SLOT_DATA); 1095 if (!is_object_type(ctx)) return js_mkundef(); 1096 1097 ant_value_t settled = js_get_slot(ctx, SLOT_SETTLED); 1098 if (vtype(settled) == T_BOOL && settled == js_true) return js_mkundef(); 1099 js_set_slot(ctx, SLOT_SETTLED, js_true); 1100 1101 ant_value_t promise = js_get_slot(ctx, SLOT_DATA); 1102 if (!is_object_type(promise)) return js_mkundef(); 1103 1104 if (nargs > 0 && !is_null(args[0]) && !is_undefined(args[0])) { 1105 js_reject_promise(js, promise, args[0]); 1106 return js_mkundef(); 1107 } 1108 1109 if (nargs <= 1) { 1110 js_resolve_promise(js, promise, js_mkundef()); 1111 return js_mkundef(); 1112 } 1113 1114 if (nargs == 2) { 1115 js_resolve_promise(js, promise, args[1]); 1116 return js_mkundef(); 1117 } 1118 1119 ant_value_t arr = js_mkarr(js); 1120 for (int i = 1; i < nargs; i++) js_arr_push(js, arr, args[i]); 1121 js_resolve_promise(js, promise, arr); 1122 return js_mkundef(); 1123} 1124 1125static ant_value_t util_promisified_call(ant_t *js, ant_value_t *args, int nargs) { 1126 ant_value_t fn = js_getcurrentfunc(js); 1127 ant_value_t original = js_get_slot(fn, SLOT_DATA); 1128 if (!is_callable(original)) return js_mkerr(js, "promisified target is not callable"); 1129 1130 ant_value_t promise = js_mkpromise(js); 1131 ant_value_t ctx = js_mkobj(js); 1132 js_set_slot(ctx, SLOT_DATA, promise); 1133 js_set_slot(ctx, SLOT_SETTLED, js_false); 1134 ant_value_t cb = js_heavy_mkfun(js, util_promisify_callback, ctx); 1135 1136 ant_value_t *call_args = (ant_value_t *)malloc((size_t)(nargs + 1) * sizeof(ant_value_t)); 1137 if (!call_args) { 1138 js_reject_promise(js, promise, js_mkerr(js, "Out of memory")); 1139 return promise; 1140 } 1141 for (int i = 0; i < nargs; i++) call_args[i] = args[i]; 1142 call_args[nargs] = cb; 1143 1144 ant_value_t this_arg = js_getthis(js); 1145 ant_value_t call_result = sv_vm_call( 1146 js->vm, js, original, this_arg, call_args, nargs + 1, NULL, false 1147 ); 1148 free(call_args); 1149 1150 ant_value_t settled = js_get_slot(ctx, SLOT_SETTLED); 1151 bool is_settled = (vtype(settled) == T_BOOL && settled == js_true); 1152 if (!is_settled && (is_err(call_result) || js->thrown_exists)) { 1153 ant_value_t ex = js->thrown_exists ? js->thrown_value : call_result; 1154 js->thrown_exists = false; 1155 js->thrown_value = js_mkundef(); 1156 js->thrown_stack = js_mkundef(); 1157 js_set_slot(ctx, SLOT_SETTLED, js_true); 1158 js_reject_promise(js, promise, ex); 1159 } 1160 1161 return promise; 1162} 1163 1164static ant_value_t util_callbackify_success(ant_t *js, ant_value_t *args, int nargs) { 1165 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 1166 if (!is_object_type(state)) return js_mkundef(); 1167 1168 ant_value_t callback = js_get_slot(state, SLOT_DATA); 1169 if (!is_callable(callback)) return js_mkundef(); 1170 1171 ant_value_t cb_args[2] = { 1172 js_mknull(), 1173 nargs > 0 ? args[0] : js_mkundef() 1174 }; 1175 1176 return sv_vm_call(js->vm, js, callback, js_mkundef(), cb_args, 2, NULL, false); 1177} 1178 1179static ant_value_t util_callbackify_error(ant_t *js, ant_value_t *args, int nargs) { 1180 ant_value_t state = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 1181 if (!is_object_type(state)) return js_mkundef(); 1182 1183 ant_value_t callback = js_get_slot(state, SLOT_DATA); 1184 if (!is_callable(callback)) return js_mkundef(); 1185 1186 ant_value_t err = nargs > 0 ? args[0] : js_mkerr(js, "Promise was rejected"); 1187 ant_value_t cb_args[1] = { err }; 1188 return sv_vm_call(js->vm, js, callback, js_mkundef(), cb_args, 1, NULL, false); 1189} 1190 1191static ant_value_t util_callbackified_call(ant_t *js, ant_value_t *args, int nargs) { 1192 ant_value_t fn = js_getcurrentfunc(js); 1193 ant_value_t original = js_get_slot(fn, SLOT_DATA); 1194 1195 if (!is_callable(original)) return js_mkerr(js, "callbackified target is not callable"); 1196 if (nargs < 1 || !is_callable(args[nargs - 1])) 1197 return js_mkerr_typed(js, JS_ERR_TYPE, "callbackified function requires a callback"); 1198 1199 ant_value_t callback = args[nargs - 1]; 1200 int call_nargs = nargs - 1; 1201 ant_value_t *call_args = NULL; 1202 1203 if (call_nargs > 0) { 1204 call_args = (ant_value_t *)malloc((size_t)call_nargs * sizeof(ant_value_t)); 1205 if (!call_args) return js_mkerr(js, "Out of memory"); 1206 for (int i = 0; i < call_nargs; i++) call_args[i] = args[i]; 1207 } 1208 1209 ant_value_t result = sv_vm_call(js->vm, js, original, js_getthis(js), call_args, call_nargs, NULL, false); 1210 free(call_args); 1211 1212 if (is_err(result) || js->thrown_exists) { 1213 ant_value_t ex = js->thrown_exists ? js->thrown_value : result; 1214 js->thrown_exists = false; 1215 js->thrown_value = js_mkundef(); 1216 js->thrown_stack = js_mkundef(); 1217 ant_value_t cb_args[1] = { ex }; 1218 sv_vm_call(js->vm, js, callback, js_mkundef(), cb_args, 1, NULL, false); 1219 return js_mkundef(); 1220 } 1221 1222 if (vtype(result) != T_PROMISE) { 1223 ant_value_t cb_args[2] = { js_mknull(), result }; 1224 sv_vm_call(js->vm, js, callback, js_mkundef(), cb_args, 2, NULL, false); 1225 return js_mkundef(); 1226 } 1227 1228 ant_value_t state = js_mkobj(js); 1229 js_set_slot(state, SLOT_DATA, callback); 1230 ant_value_t success = js_heavy_mkfun(js, util_callbackify_success, state); 1231 ant_value_t error = js_heavy_mkfun(js, util_callbackify_error, state); 1232 js_promise_then(js, result, success, error); 1233 1234 return js_mkundef(); 1235} 1236 1237static ant_value_t util_deprecated_call(ant_t *js, ant_value_t *args, int nargs) { 1238 ant_value_t fn = js_getcurrentfunc(js); 1239 ant_value_t ctx = js_get_slot(fn, SLOT_DATA); 1240 if (!is_object_type(ctx)) return js_mkundef(); 1241 1242 ant_value_t warned = js_get_slot(ctx, SLOT_SETTLED); 1243 if (!(vtype(warned) == T_BOOL && warned == js_true)) { 1244 js_set_slot(ctx, SLOT_SETTLED, js_true); 1245 ant_value_t msg_val = js_get(js, ctx, "msg"); 1246 const char *msg = js_getstr(js, msg_val, NULL); 1247 if (msg) fprintf(stderr, "DeprecationWarning: %s\n", msg); 1248 } 1249 1250 ant_value_t original = js_get_slot(ctx, SLOT_DATA); 1251 ant_value_t this_arg = js_getthis(js); 1252 return sv_vm_call(js->vm, js, original, this_arg, args, nargs, NULL, false); 1253} 1254 1255static ant_value_t util_deprecate(ant_t *js, ant_value_t *args, int nargs) { 1256 if (nargs < 1 || !is_callable(args[0])) { 1257 return js_mkerr(js, "deprecate(fn, msg) requires a function"); 1258 } 1259 1260 ant_value_t ctx = js_mkobj(js); 1261 js_set_slot(ctx, SLOT_DATA, args[0]); 1262 js_set_slot(ctx, SLOT_SETTLED, js_false); 1263 if (nargs >= 2) js_set(js, ctx, "msg", args[1]); 1264 1265 return js_heavy_mkfun(js, util_deprecated_call, ctx); 1266} 1267 1268static ant_value_t util_promisify(ant_t *js, ant_value_t *args, int nargs) { 1269 if (nargs < 1 || !is_callable(args[0])) { 1270 return js_mkerr(js, "promisify(fn) requires a function"); 1271 } 1272 1273 ant_value_t custom = js_get_symbol(js, args[0], "nodejs.util.promisify.custom"); 1274 if (is_callable(custom)) return custom; 1275 1276 return js_heavy_mkfun(js, util_promisified_call, args[0]); 1277} 1278 1279static ant_value_t util_callbackify(ant_t *js, ant_value_t *args, int nargs) { 1280 if (nargs < 1 || !is_callable(args[0])) { 1281 return js_mkerr(js, "callbackify(fn) requires a function"); 1282 } 1283 return js_heavy_mkfun(js, util_callbackified_call, args[0]); 1284} 1285 1286static ant_value_t util_aborted_listener(ant_t *js, ant_value_t *args, int nargs) { 1287 ant_value_t promise = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); 1288 if (vtype(promise) == T_PROMISE) js_resolve_promise(js, promise, js_mkundef()); 1289 return js_mkundef(); 1290} 1291 1292static ant_value_t util_aborted(ant_t *js, ant_value_t *args, int nargs) { 1293 if (nargs < 1 || !abort_signal_is_signal(args[0])) 1294 return js_mkerr_typed(js, JS_ERR_TYPE, "aborted(signal, resource) requires an AbortSignal"); 1295 1296 ant_value_t promise = js_mkpromise(js); 1297 if (abort_signal_is_aborted(args[0])) { 1298 js_resolve_promise(js, promise, js_mkundef()); 1299 return promise; 1300 } 1301 1302 abort_signal_add_listener(js, args[0], js_heavy_mkfun(js, util_aborted_listener, promise)); 1303 return promise; 1304} 1305 1306static ant_value_t util_inherits(ant_t *js, ant_value_t *args, int nargs) { 1307 if (nargs < 2 || !is_callable(args[0]) || !is_callable(args[1])) { 1308 return js_mkerr(js, "inherits(ctor, superCtor) requires constructor functions"); 1309 } 1310 1311 ant_value_t ctor = args[0]; 1312 ant_value_t super_ctor = args[1]; 1313 ant_value_t ctor_proto = js_get(js, ctor, "prototype"); 1314 ant_value_t super_proto = js_get(js, super_ctor, "prototype"); 1315 1316 if (!is_object_type(ctor_proto) || !is_object_type(super_proto)) { 1317 return js_mkerr(js, "inherits(ctor, superCtor) requires prototype objects"); 1318 } 1319 1320 js_set(js, ctor, "super_", super_ctor); 1321 js_set_proto_init(ctor_proto, super_proto); 1322 1323 return js_mkundef(); 1324} 1325 1326static ant_value_t util_is_deep_strict_equal(ant_t *js, ant_value_t *args, int nargs) { 1327 if (nargs < 2) return js_bool(true); 1328 return js_bool(js_deep_equal(js, args[0], args[1], true)); 1329} 1330 1331ant_value_t util_library(ant_t *js) { 1332 ant_value_t lib = js_mkobj(js); 1333 ant_value_t types = util_get_types_object(js); 1334 1335 ant_value_t promisify = js_heavy_mkfun(js, util_promisify, js_mkundef()); 1336 js_set(js, promisify, "custom", js_mksym_for(js, "nodejs.util.promisify.custom")); 1337 1338 js_set(js, lib, "format", js_mkfun(util_format)); 1339 js_set(js, lib, "formatWithOptions", js_mkfun(util_format_with_options)); 1340 js_set(js, lib, "debuglog", js_mkfun(util_debuglog)); 1341 js_set(js, lib, "inspect", js_mkfun(util_inspect)); 1342 js_set(js, lib, "deprecate", js_mkfun(util_deprecate)); 1343 js_set(js, lib, "inherits", js_mkfun(util_inherits)); 1344 js_set(js, lib, "isDeepStrictEqual", js_mkfun(util_is_deep_strict_equal)); 1345 js_set(js, lib, "parseArgs", js_mkfun(util_parse_args)); 1346 js_set(js, lib, "parseEnv", js_mkfun(util_parse_env)); 1347 js_set(js, lib, "promisify", promisify); 1348 js_set(js, lib, "callbackify", js_mkfun(util_callbackify)); 1349 js_set(js, lib, "aborted", js_mkfun(util_aborted)); 1350 js_set(js, lib, "stripVTControlCharacters", js_mkfun(util_strip_vt_control_characters)); 1351 js_set(js, lib, "styleText", js_mkfun(util_style_text)); 1352 js_set(js, lib, "types", types); 1353 1354 js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "util", 4)); 1355 return lib; 1356}