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 1371 lines 43 kB view raw
1#include <compat.h> // IWYU pragma: keep 2 3#include <math.h> 4#include <stdint.h> 5#include <stdio.h> 6#include <stdlib.h> 7#include <string.h> 8 9#ifdef _WIN32 10#define WIN32_LEAN_AND_MEAN 11#include <windows.h> 12#include <sys/timeb.h> 13#else 14#include <sys/time.h> 15#endif 16 17#include "ant.h" 18#include "internal.h" 19#include "errors.h" 20#include "descriptors.h" 21#include "runtime.h" 22#include "silver/engine.h" 23#include "modules/date.h" 24#include "modules/symbol.h" 25 26static const int month_days[] = { 27 31, 28, 31, 30, 31, 30, 28 31, 31, 30, 31, 30, 31 29}; 30 31static const char month_names[] = 32 "Jan" "Feb" "Mar" "Apr" "May" "Jun" 33 "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"; 34 35static const char day_names[] = 36 "Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat"; 37 38static inline double *date_fields_slot(date_fields_t *f, date_field_index_t index) { 39switch (index) { 40 case DATE_FIELD_YEAR: return &f->year; 41 case DATE_FIELD_MONTH: return &f->month; 42 case DATE_FIELD_DAY_OF_MONTH: return &f->day; 43 case DATE_FIELD_HOUR: return &f->hour; 44 case DATE_FIELD_MINUTE: return &f->minute; 45 case DATE_FIELD_SECOND: return &f->second; 46 case DATE_FIELD_MILLISECOND: return &f->millisecond; 47 case DATE_FIELD_DAY_OF_WEEK: return &f->weekday; 48 case DATE_FIELD_TZ_MINUTES: return &f->tz_minutes; 49 default: return NULL; 50}} 51 52static inline double date_fields_get(const date_fields_t *f, date_field_index_t index) { 53 double *slot = date_fields_slot((date_fields_t *)f, index); 54 return slot ? *slot : 0.0; 55} 56 57static inline void date_fields_set(date_fields_t *f, date_field_index_t index, double value) { 58 double *slot = date_fields_slot(f, index); 59 if (slot) *slot = value; 60} 61 62static inline int date_min_int(int a, int b) { 63 return (a < b) ? a : b; 64} 65 66static inline int to_upper_ascii(int c) { 67 if (c >= 'a' && c <= 'z') return c - ('a' - 'A'); 68 return c; 69} 70 71static inline bool date_is_primitive(ant_value_t v) { 72 uint8_t t = vtype(v); 73 return 74 t == T_STR 75 || t == T_NUM 76 || t == T_BOOL 77 || t == T_NULL 78 || t == T_UNDEF 79 || t == T_SYMBOL 80 || t == T_BIGINT; 81} 82 83bool is_date_instance(ant_value_t value) { 84 if (!is_object_type(value)) return false; 85 ant_value_t brand = js_get_slot(js_as_obj(value), SLOT_BRAND); 86 return vtype(brand) == T_NUM && (int)js_getnum(brand) == BRAND_DATE; 87} 88 89static bool date_this_time_value(ant_t *js, ant_value_t this_val, double *out, ant_value_t *err) { 90 if (!is_date_instance(this_val)) { 91 if (err) *err = js_mkerr_typed(js, JS_ERR_TYPE, "not a Date object"); 92 return false; 93 } 94 95 ant_value_t t = js_get_slot(js_as_obj(this_val), SLOT_DATA); 96 *out = (vtype(t) == T_NUM) ? tod(t) : JS_NAN; 97 return true; 98} 99 100static ant_value_t date_set_this_time_value(ant_t *js, ant_value_t this_val, double v) { 101 if (!is_date_instance(this_val)) { 102 return js_mkerr_typed(js, JS_ERR_TYPE, "not a Date object"); 103 } 104 105 js_set_slot(js_as_obj(this_val), SLOT_DATA, tov(v)); 106 return tov(v); 107} 108 109static int64_t math_mod(int64_t a, int64_t b) { 110 int64_t m = a % b; 111 return m + (m < 0) * b; 112} 113 114static int64_t floor_div_int64(int64_t a, int64_t b) { 115 int64_t m = a % b; 116 return (a - (m + (m < 0) * b)) / b; 117} 118 119static double date_timeclip(double t) { 120 if (t >= -8.64e15 && t <= 8.64e15) return trunc(t) + 0.0; 121 return JS_NAN; 122} 123 124static int64_t days_in_year(int64_t y) { 125 return 365 + !(y % 4) - !(y % 100) + !(y % 400); 126} 127 128static int64_t days_from_year(int64_t y) { 129 return 365 * (y - 1970) 130 + floor_div_int64(y - 1969, 4) 131 - floor_div_int64(y - 1901, 100) 132 + floor_div_int64(y - 1601, 400); 133} 134 135static int64_t year_from_days(int64_t *days) { 136 int64_t y, d1, nd, d = *days; 137 y = floor_div_int64(d * 10000, 3652425) + 1970; 138 139 while (true) { 140 d1 = d - days_from_year(y); 141 142 if (d1 < 0) { 143 y--; 144 d1 += days_in_year(y); 145 continue; 146 } 147 148 nd = days_in_year(y); 149 if (d1 < nd) break; 150 151 d1 -= nd; 152 y++; 153 } 154 155 *days = d1; 156 return y; 157} 158 159static int get_timezone_offset(int64_t time_ms) { 160#ifdef _WIN32 161 DWORD r; 162 TIME_ZONE_INFORMATION tzi; 163 r = GetTimeZoneInformation(&tzi); 164 if (r == TIME_ZONE_ID_INVALID) return 0; 165 if (r == TIME_ZONE_ID_DAYLIGHT) return (int)(tzi.Bias + tzi.DaylightBias); 166 return (int)tzi.Bias; 167#else 168 time_t ti; 169 struct tm tm_local; 170 171 int64_t time_s = time_ms / 1000; 172 if (sizeof(time_t) == 4) { 173 if ((time_t)-1 < 0) { 174 if (time_s < INT32_MIN) time_s = INT32_MIN; 175 else if (time_s > INT32_MAX) time_s = INT32_MAX; 176 } else { 177 if (time_s < 0) time_s = 0; 178 else if (time_s > UINT32_MAX) time_s = UINT32_MAX; 179 } 180 } 181 182 ti = (time_t)time_s; 183#ifdef _WIN32 184 localtime_s(&tm_local, &ti); 185#else 186 localtime_r(&ti, &tm_local); 187#endif 188 189#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__GLIBC__) 190 return (int)(-tm_local.tm_gmtoff / 60); 191#else 192 struct tm tm_gmt; 193#ifdef _WIN32 194 gmtime_s(&tm_gmt, &ti); 195#else 196 gmtime_r(&ti, &tm_gmt); 197#endif 198 tm_local.tm_isdst = 0; 199 return (int)(difftime(mktime(&tm_gmt), mktime(&tm_local)) / 60); 200#endif 201#endif 202} 203 204static int date_extract_fields_from_time(double dval, date_fields_t *fields, int is_local, int force) { 205 int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0; 206 207 if (isnan(dval)) { 208 if (!force) return 0; 209 d = 0; 210 } else { 211 d = (int64_t)dval; 212 if (is_local) { 213 tz = -get_timezone_offset(d); 214 d += tz * 60000; 215 } 216 } 217 218 h = math_mod(d, 86400000); 219 days = (d - h) / 86400000; 220 ms = h % 1000; 221 h = (h - ms) / 1000; 222 s = h % 60; 223 h = (h - s) / 60; 224 m = h % 60; 225 h = (h - m) / 60; 226 wd = math_mod(days + 4, 7); 227 y = year_from_days(&days); 228 229 for (i = 0; i < 11; i++) { 230 md = month_days[i]; 231 if (i == 1) md += (int)days_in_year(y) - 365; 232 if (days < md) break; 233 days -= md; 234 } 235 236 fields->year = (double)y; 237 fields->month = (double)i; 238 fields->day = (double)(days + 1); 239 fields->hour = (double)h; 240 fields->minute = (double)m; 241 fields->second = (double)s; 242 fields->millisecond = (double)ms; 243 fields->weekday = (double)wd; 244 fields->tz_minutes = (double)tz; 245 246 return 1; 247} 248 249static int date_extract_fields( 250 ant_t *js, ant_value_t this_val, 251 date_fields_t *fields, 252 int is_local, int force, ant_value_t *err 253) { 254 double dval; 255 if (!date_this_time_value(js, this_val, &dval, err)) return -1; 256 return date_extract_fields_from_time(dval, fields, is_local, force); 257} 258 259static double date_make_fields(const date_fields_t *fields, int is_local) { 260 double y, m, dt, ym, mn, day, h, s, milli, time, tv; 261 int yi, mi, i; 262 int64_t days; 263 volatile double temp; 264 double d = JS_NAN; 265 266 y = fields->year; 267 m = fields->month; 268 dt = fields->day; 269 270 ym = y + floor(m / 12); 271 mn = fmod(m, 12); 272 if (mn < 0) mn += 12; 273 274 if (ym < -271821 || ym > 275760) return JS_NAN; 275 276 yi = (int)ym; 277 mi = (int)mn; 278 279 days = days_from_year(yi); 280 for (i = 0; i < mi; i++) { 281 days += month_days[i]; 282 if (i == 1) days += days_in_year(yi) - 365; 283 } 284 day = (double)days + dt - 1; 285 286 h = fields->hour; 287 m = fields->minute; 288 s = fields->second; 289 milli = fields->millisecond; 290 291 time = h * 3600000; 292 time += (temp = m * 60000); 293 time += (temp = s * 1000); 294 time += milli; 295 296 tv = (temp = day * 86400000) + time; 297 if (!isfinite(tv)) return JS_NAN; 298 299 if (is_local) { 300 int64_t ti; 301 if (tv < (double)INT64_MIN) ti = INT64_MIN; 302 else if (tv >= 0x1p63) ti = INT64_MAX; 303 else ti = (int64_t)tv; 304 tv += (double)get_timezone_offset(ti) * 60000.0; 305 } 306 307 d = date_timeclip(tv); 308 return d; 309} 310 311ant_value_t get_date_string(ant_t *js, ant_value_t this_val, date_string_spec_t spec) { 312 char buf[96]; 313 date_fields_t fields; 314 315 int res, fmt, pos; 316 int y, mon, d, h, m, s, ms, wd, tz; 317 ant_value_t err; 318 319 fmt = (int)spec.fmt; 320 res = date_extract_fields( 321 js, this_val, 322 &fields, spec.fmt == DATE_STRING_FMT_LOCAL, 323 0, &err 324 ); 325 326 if (res < 0) return err; 327 if (!res) { 328 if (spec.fmt == DATE_STRING_FMT_ISO) return js_mkerr_typed(js, JS_ERR_RANGE, "Date value is NaN"); 329 return js_mkstr(js, "Invalid Date", 12); 330 } 331 332 y = (int)fields.year; 333 mon = (int)fields.month; 334 d = (int)fields.day; 335 h = (int)fields.hour; 336 m = (int)fields.minute; 337 s = (int)fields.second; 338 ms = (int)fields.millisecond; 339 wd = (int)fields.weekday; 340 tz = (int)fields.tz_minutes; 341 pos = 0; 342 343 if (spec.part & DATE_STRING_PART_DATE) { 344 switch (fmt) { 345 case 0: 346 pos += snprintf( 347 buf + pos, sizeof(buf) - (size_t)pos, 348 "%.3s, %02d %.3s %0*d ", 349 day_names + wd * 3, d, month_names + mon * 3, 4 + (y < 0), y); 350 break; 351 case 1: 352 pos += snprintf( 353 buf + pos, sizeof(buf) - (size_t)pos, 354 "%.3s %.3s %02d %0*d", 355 day_names + wd * 3, month_names + mon * 3, d, 4 + (y < 0), y); 356 if (spec.part == DATE_STRING_PART_ALL) buf[pos++] = ' '; 357 break; 358 case 2: 359 if (y >= 0 && y <= 9999) { 360 pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "%04d", y); 361 } else pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "%+07d", y); 362 pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "-%02d-%02dT", mon + 1, d); 363 break; 364 case 3: 365 pos += snprintf( 366 buf + pos, sizeof(buf) - (size_t)pos, 367 "%02d/%02d/%0*d", mon + 1, d, 4 + (y < 0), y); 368 if (spec.part == DATE_STRING_PART_ALL) { 369 buf[pos++] = ','; 370 buf[pos++] = ' '; 371 } 372 break; 373 default: break; 374 } 375 } 376 377 if (spec.part & DATE_STRING_PART_TIME) { 378 switch (fmt) { 379 case 0: 380 pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "%02d:%02d:%02d GMT", h, m, s); 381 break; 382 case 1: 383 pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "%02d:%02d:%02d GMT", h, m, s); 384 if (tz < 0) { 385 buf[pos++] = '-'; 386 tz = -tz; 387 } else buf[pos++] = '+'; 388 pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "%02d%02d", tz / 60, tz % 60); 389 break; 390 case 2: 391 pos += snprintf(buf + pos, sizeof(buf) - (size_t)pos, "%02d:%02d:%02d.%03dZ", h, m, s, ms); 392 break; 393 case 3: 394 pos += snprintf( 395 buf + pos, sizeof(buf) - (size_t)pos, 396 "%02d:%02d:%02d %cM", (h + 11) % 12 + 1, m, s, (h < 12) ? 'A' : 'P'); 397 break; 398 default: break; 399 } 400 } 401 402 if (pos <= 0) return js_mkstr(js, "", 0); 403 return js_mkstr(js, buf, (size_t)pos); 404} 405 406static int64_t date_now(void) { 407 struct timeval tv; 408 gettimeofday(&tv, NULL); 409 return (int64_t)tv.tv_sec * 1000 + (int64_t)(tv.tv_usec / 1000); 410} 411 412static bool string_skip_char(const uint8_t *sp, int *pp, int c) { 413 if (sp[*pp] == c) { *pp += 1; return true; } 414 return false; 415} 416 417static int string_skip_spaces(const uint8_t *sp, int *pp) { 418 int c; 419 while ((c = sp[*pp]) == ' ') *pp += 1; 420 return c; 421} 422 423static int string_skip_separators(const uint8_t *sp, int *pp) { 424 int c; 425 while ((c = sp[*pp]) == '-' || c == '/' || c == '.' || c == ',') *pp += 1; 426 return c; 427} 428 429static int string_skip_until(const uint8_t *sp, int *pp, const char *stoplist) { 430 int c; 431 while (!strchr(stoplist, c = sp[*pp])) *pp += 1; 432 return c; 433} 434 435static bool string_get_digits(const uint8_t *sp, int *pp, int *pval, int min_digits, int max_digits) { 436 int v = 0; int c; 437 int p = *pp; 438 int p_start = p; 439 440 while ((c = sp[p]) >= '0' && c <= '9') { 441 if (v >= 100000000) return false; 442 v = v * 10 + c - '0'; 443 p++; 444 if (max_digits > 0 && p - p_start == max_digits) break; 445 } 446 447 if (p - p_start < min_digits) return false; 448 *pval = v; 449 *pp = p; 450 451 return true; 452} 453 454static bool string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) { 455 int mul = 100; int ms = 0; 456 int c; int p_start; int p = *pp; 457 458 c = sp[p]; 459 if (c == '.' || c == ',') { 460 p++; 461 p_start = p; 462 463 while ((c = sp[p]) >= '0' && c <= '9') { 464 ms += (c - '0') * mul; 465 mul /= 10; 466 p++; 467 if (p - p_start == 9) break; 468 } 469 470 if (p > p_start) { 471 *pval = ms; 472 *pp = p; 473 } 474 } 475 476 return true; 477} 478 479static bool string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, bool strict) { 480 int tz = 0; int p = *pp; 481 int sgn; int hh; int mm; 482 483 sgn = sp[p++]; 484 if (sgn == '+' || sgn == '-') { 485 int n = p; 486 if (!string_get_digits(sp, &p, &hh, 1, 0)) return false; 487 n = p - n; 488 if (strict && n != 2 && n != 4) return false; 489 490 while (n > 4) { 491 n -= 2; 492 hh /= 100; 493 } 494 495 if (n > 2) { 496 mm = hh % 100; 497 hh = hh / 100; 498 } else { 499 mm = 0; 500 if (string_skip_char(sp, &p, ':') && !string_get_digits(sp, &p, &mm, 2, 2)) return false; 501 } 502 503 if (hh > 23 || mm > 59) return false; 504 505 tz = hh * 60 + mm; 506 if (sgn != '+') tz = -tz; 507 } else if (sgn != 'Z') return false; 508 509 *pp = p; 510 *tzp = tz; 511 512 return true; 513} 514 515static bool string_match(const uint8_t *sp, int *pp, const char *s) { 516 int p = *pp; 517 518 while (*s != '\0') { 519 if (to_upper_ascii(sp[p]) != to_upper_ascii(*s++)) return false; 520 p++; 521 } 522 523 *pp = p; 524 return true; 525} 526 527static int find_abbrev(const uint8_t *sp, int p, const char *list, int count) { 528 int n; int i; 529 for (n = 0; n < count; n++) { 530 for (i = 0;; i++) { 531 if (to_upper_ascii(sp[p + i]) != to_upper_ascii(list[n * 3 + i])) break; 532 if (i == 2) return n; 533 } 534 } 535 return -1; 536} 537 538static bool string_get_month(const uint8_t *sp, int *pp, int *pval) { 539 int n = find_abbrev(sp, *pp, month_names, 12); 540 if (n < 0) return false; 541 *pval = n + 1; 542 *pp += 3; 543 return true; 544} 545 546static bool parse_isostring(const uint8_t *sp, int fields[9], bool *is_local) { 547 int sgn; 548 int i; 549 int p = 0; 550 551 for (i = 0; i < 9; i++) fields[i] = (i == 2); 552 *is_local = false; 553 554 sgn = sp[p]; 555 if (sgn == '-' || sgn == '+') { 556 p++; 557 if (!string_get_digits(sp, &p, &fields[0], 6, 6)) return false; 558 if (sgn == '-') { 559 if (fields[0] == 0) return false; 560 fields[0] = -fields[0]; 561 } 562 } else { 563 if (!string_get_digits(sp, &p, &fields[0], 4, 4)) return false; 564 } 565 566 if (string_skip_char(sp, &p, '-')) { 567 if (!string_get_digits(sp, &p, &fields[1], 2, 2)) return false; 568 if (fields[1] < 1) return false; 569 fields[1] -= 1; 570 571 if (string_skip_char(sp, &p, '-')) { 572 if (!string_get_digits(sp, &p, &fields[2], 2, 2)) return false; 573 if (fields[2] < 1) return false; 574 } 575 } 576 577 if (string_skip_char(sp, &p, 'T')) { 578 *is_local = true; 579 if (!string_get_digits(sp, &p, &fields[3], 2, 2) 580 || !string_skip_char(sp, &p, ':') 581 || !string_get_digits(sp, &p, &fields[4], 2, 2)) { 582 fields[3] = 100; 583 return true; 584 } 585 586 if (string_skip_char(sp, &p, ':')) { 587 if (!string_get_digits(sp, &p, &fields[5], 2, 2)) return false; 588 string_get_milliseconds(sp, &p, &fields[6]); 589 } 590 } 591 592 if (sp[p]) { 593 *is_local = false; 594 if (!string_get_tzoffset(sp, &p, &fields[8], true)) return false; 595 } 596 597 return sp[p] == '\0'; 598} 599 600typedef struct { 601 char name[6]; 602 int16_t offset; 603} tzabbr_t; 604 605static const tzabbr_t js_tzabbr[] = { 606 {"GMT", 0}, {"UTC", 0}, {"UT", 0}, {"Z", 0}, 607 {"EDT", -4 * 60}, {"EST", -5 * 60}, 608 {"CDT", -5 * 60}, {"CST", -6 * 60}, 609 {"MDT", -6 * 60}, {"MST", -7 * 60}, 610 {"PDT", -7 * 60}, {"PST", -8 * 60}, 611 {"WET", 0}, {"WEST", +1 * 60}, 612 {"CET", +1 * 60}, {"CEST", +2 * 60}, 613 {"EET", +2 * 60}, {"EEST", +3 * 60}, 614}; 615 616static bool string_get_tzabbr(const uint8_t *sp, int *pp, int *offset) { 617 for (int i = 0; i < DATE_COUNT_OF(js_tzabbr); i++) { 618 if (string_match(sp, pp, js_tzabbr[i].name)) { 619 *offset = js_tzabbr[i].offset; 620 return true; 621 } 622 } 623 return false; 624} 625 626static bool parse_otherstring(const uint8_t *sp, int fields[9], bool *is_local) { 627 int c; int i; int val; 628 int p = 0; 629 int p_start; 630 int num[3]; 631 632 bool has_year = false; 633 bool has_mon = false; 634 bool has_time = false; 635 int num_index = 0; 636 637 fields[0] = 2001; 638 fields[1] = 1; 639 fields[2] = 1; 640 641 for (i = 3; i < 9; i++) fields[i] = 0; 642 *is_local = true; 643 644 while (string_skip_spaces(sp, &p)) { 645 p_start = p; 646 647 if ((c = sp[p]) == '+' || c == '-') { 648 if (has_time && string_get_tzoffset(sp, &p, &fields[8], false)) { 649 *is_local = false; 650 } else { 651 p++; 652 if (string_get_digits(sp, &p, &val, 1, 0)) { 653 if (c == '-') { 654 if (val == 0) return false; 655 val = -val; 656 } 657 fields[0] = val; 658 has_year = true; 659 } 660 } 661 } else if (string_get_digits(sp, &p, &val, 1, 0)) { 662 if (string_skip_char(sp, &p, ':')) { 663 fields[3] = val; 664 if (!string_get_digits(sp, &p, &fields[4], 1, 2)) return false; 665 666 if (string_skip_char(sp, &p, ':')) { 667 if (!string_get_digits(sp, &p, &fields[5], 1, 2)) return false; 668 string_get_milliseconds(sp, &p, &fields[6]); 669 } else if (sp[p] != '\0' && sp[p] != ' ') return false; 670 671 has_time = true; 672 } else { 673 if (p - p_start > 2) { 674 fields[0] = val; 675 has_year = true; 676 } else if (val < 1 || val > 31) { 677 fields[0] = val + (val < 100) * 1900 + (val < 50) * 100; 678 has_year = true; 679 } else { 680 if (num_index == 3) return false; 681 num[num_index++] = val; 682 } 683 } 684 } else if (string_get_month(sp, &p, &fields[1])) { 685 has_mon = true; 686 string_skip_until(sp, &p, "0123456789 -/("); 687 } else if (has_time && string_match(sp, &p, "PM")) { 688 if (fields[3] != 12) fields[3] += 12; 689 continue; 690 } else if (has_time && string_match(sp, &p, "AM")) { 691 if (fields[3] > 12) return false; 692 if (fields[3] == 12) fields[3] -= 12; 693 continue; 694 } else if (string_get_tzabbr(sp, &p, &fields[8])) { 695 *is_local = false; 696 continue; 697 } else if (c == '(') { 698 int level = 0; 699 while ((c = sp[p]) != '\0') { 700 p++; 701 level += (c == '('); 702 level -= (c == ')'); 703 if (!level) break; 704 } 705 if (level > 0) return false; 706 } else if (c == ')') { 707 return false; 708 } else { 709 if ((int)has_year + (int)has_mon + (int)has_time + num_index) return false; 710 string_skip_until(sp, &p, " -/("); 711 } 712 713 string_skip_separators(sp, &p); 714 } 715 716 if (num_index + (int)has_year + (int)has_mon > 3) return false; 717 718 switch (num_index) { 719 case 0: 720 if (!has_year) return false; 721 break; 722 case 1: 723 if (has_mon) fields[2] = num[0]; 724 else fields[1] = num[0]; 725 break; 726 case 2: 727 if (has_year) { 728 fields[1] = num[0]; 729 fields[2] = num[1]; 730 } else if (has_mon) { 731 fields[0] = num[1] + (num[1] < 100) * 1900 + (num[1] < 50) * 100; 732 fields[2] = num[0]; 733 } else { 734 fields[1] = num[0]; 735 fields[2] = num[1]; 736 } 737 break; 738 case 3: 739 fields[0] = num[2] + (num[2] < 100) * 1900 + (num[2] < 50) * 100; 740 fields[1] = num[0]; 741 fields[2] = num[1]; 742 break; 743 default: return false; 744 } 745 746 if (fields[1] < 1 || fields[2] < 1) return false; 747 fields[1] -= 1; 748 749 return true; 750} 751 752static bool date_parse_string_to_ms(ant_t *js, ant_value_t arg, double *out_ms) { 753 ant_value_t s = coerce_to_str(js, arg); 754 if (is_err(s)) return false; 755 756 ant_offset_t len = 0; 757 ant_offset_t off = vstr(js, s, &len); 758 759 char *buf = (char *)malloc((size_t)len + 1); 760 if (!buf) { 761 *out_ms = JS_NAN; 762 return true; 763 } 764 765 memcpy(buf, (const void *)(uintptr_t)off, (size_t)len); 766 buf[len] = '\0'; 767 768 int fields[9]; 769 date_fields_t fields1 = {0}; 770 771 bool is_local = false; 772 bool ok = 773 parse_isostring((const uint8_t *)buf, fields, &is_local) || 774 parse_otherstring((const uint8_t *)buf, fields, &is_local); 775 776 free(buf); 777 778 if (!ok) { 779 *out_ms = JS_NAN; 780 return true; 781 } 782 783 static const int field_max[6] = {0, 11, 31, 24, 59, 59}; 784 bool valid = true; 785 786 for (int i = 1; i < 6; i++) { 787 if (fields[i] > field_max[i]) valid = false; 788 } 789 if (fields[3] == 24 && (fields[4] | fields[5] | fields[6])) valid = false; 790 791 if (!valid) { 792 *out_ms = JS_NAN; 793 return true; 794 } 795 796 fields1.year = (double)fields[0]; 797 fields1.month = (double)fields[1]; 798 fields1.day = (double)fields[2]; 799 fields1.hour = (double)fields[3]; 800 fields1.minute = (double)fields[4]; 801 fields1.second = (double)fields[5]; 802 fields1.millisecond = (double)fields[6]; 803 *out_ms = date_make_fields(&fields1, is_local ? 1 : 0) - (double)fields[8] * 60000.0; 804 805 return true; 806} 807 808static ant_value_t builtin_Date(ant_t *js, ant_value_t *args, int nargs) { 809 double val; 810 static const date_string_spec_t kDateToStringSpec = { 811 DATE_STRING_FMT_LOCAL, 812 DATE_STRING_PART_ALL 813 }; 814 815 if (vtype(js->new_target) == T_UNDEF) { 816 val = (double)date_now(); 817 818 ant_value_t tmp = js_mkobj(js); 819 ant_value_t date_proto = js_get_ctor_proto(js, "Date", 4); 820 if (is_object_type(date_proto)) js_set_proto_init(tmp, date_proto); 821 822 js_set_slot(tmp, SLOT_DATA, tov(val)); 823 js_set_slot(tmp, SLOT_BRAND, js_mknum(BRAND_DATE)); 824 825 return get_date_string(js, tmp, kDateToStringSpec); 826 } 827 828 if (nargs == 0) { 829 val = (double)date_now(); 830 } else if (nargs == 1) { 831 ant_value_t input = args[0]; 832 833 if (is_object_type(input) && is_date_instance(input)) { 834 ant_value_t tv = js_get_slot(js_as_obj(input), SLOT_DATA); 835 val = (vtype(tv) == T_NUM) ? tod(tv) : JS_NAN; 836 val = date_timeclip(val); 837 } else { 838 ant_value_t prim = js_to_primitive(js, input, 0); 839 if (is_err(prim)) return prim; 840 if (vtype(prim) == T_STR) { 841 if (!date_parse_string_to_ms(js, prim, &val)) return js_mkerr_typed(js, JS_ERR_INTERNAL, "Date parse failed"); 842 } else val = js_to_number(js, prim); 843 val = date_timeclip(val); 844 } 845 } else { 846 date_fields_t fields = {0}; 847 fields.day = 1; 848 int n = nargs; 849 if (n > 7) n = 7; 850 851 int i; 852 for (i = 0; i < n; i++) { 853 double a = js_to_number(js, args[i]); 854 if (!isfinite(a)) break; 855 double t = trunc(a); 856 date_fields_set(&fields, (date_field_index_t)i, t); 857 if (i == 0 && fields.year >= 0 && fields.year < 100) fields.year += 1900; 858 } 859 860 val = (i == n) ? date_make_fields(&fields, 1) : JS_NAN; 861 } 862 863 js_set_slot(js_as_obj(js->this_val), SLOT_DATA, tov(val)); 864 js_set_slot(js_as_obj(js->this_val), SLOT_BRAND, js_mknum(BRAND_DATE)); 865 866 return js->this_val; 867} 868 869static ant_value_t builtin_Date_UTC(ant_t *js, ant_value_t *args, int nargs) { 870 if (nargs == 0) return tov(JS_NAN); 871 872 date_fields_t fields = {0}; 873 fields.day = 1; 874 int n = nargs; 875 if (n > 7) n = 7; 876 877 for (int i = 0; i < n; i++) { 878 double a = js_to_number(js, args[i]); 879 if (!isfinite(a)) return tov(JS_NAN); 880 double t = trunc(a); 881 date_fields_set(&fields, (date_field_index_t)i, t); 882 if (i == 0 && fields.year >= 0 && fields.year < 100) fields.year += 1900; 883 } 884 885 return tov(date_make_fields(&fields, 0)); 886} 887 888static ant_value_t builtin_Date_parse(ant_t *js, ant_value_t *args, int nargs) { 889 if (nargs < 1) return tov(JS_NAN); 890 double v; 891 if (!date_parse_string_to_ms(js, args[0], &v)) { 892 return js_mkerr_typed(js, JS_ERR_INTERNAL, "Date parse failed"); 893 } 894 return tov(v); 895} 896 897static ant_value_t builtin_Date_now(ant_t *js, ant_value_t *args, int nargs) { 898 return tov((double)date_now()); 899} 900 901static ant_value_t date_get_field(ant_t *js, date_get_field_spec_t spec) { 902 date_fields_t fields; 903 ant_value_t err; 904 905 int res = date_extract_fields(js, js->this_val, &fields, spec.local_time, 0, &err); 906 if (res < 0) return err; 907 if (!res) return tov(JS_NAN); 908 909 if (spec.legacy_get_year) fields.year -= 1900; 910 return tov(date_fields_get(&fields, spec.field)); 911} 912 913static ant_value_t date_set_field(ant_t *js, ant_value_t *args, int nargs, date_set_field_spec_t spec) { 914 date_fields_t fields; 915 ant_value_t err; 916 double d = JS_NAN; 917 918 int res = date_extract_fields( 919 js, js->this_val, 920 &fields, spec.local_time, 921 spec.first_field == DATE_FIELD_YEAR, &err 922 ); 923 924 if (res < 0) return err; 925 int n = date_min_int(nargs, spec.end_field_exclusive - spec.first_field); 926 927 for (int i = 0; i < n; i++) { 928 double a = js_to_number(js, args[i]); 929 if (!isfinite(a)) return date_set_this_time_value(js, js->this_val, JS_NAN); 930 date_fields_set(&fields, (date_field_index_t)(spec.first_field + i), trunc(a)); 931 } 932 933 if (!res) return tov(JS_NAN); 934 if (nargs > 0) d = date_make_fields(&fields, spec.local_time); 935 936 return date_set_this_time_value(js, js->this_val, d); 937} 938 939static ant_value_t builtin_Date_valueOf(ant_t *js, ant_value_t *args, int nargs) { 940 double v; 941 ant_value_t err; 942 if (!date_this_time_value(js, js->this_val, &v, &err)) return err; 943 return tov(v); 944} 945 946static ant_value_t builtin_Date_getTime(ant_t *js, ant_value_t *args, int nargs) { 947 return builtin_Date_valueOf(js, args, nargs); 948} 949 950static ant_value_t builtin_Date_toUTCString(ant_t *js, ant_value_t *args, int nargs) { 951 static const date_string_spec_t kSpec = {DATE_STRING_FMT_UTC, DATE_STRING_PART_ALL}; 952 return get_date_string(js, js->this_val, kSpec); 953} 954 955static ant_value_t builtin_Date_toString(ant_t *js, ant_value_t *args, int nargs) { 956 static const date_string_spec_t kSpec = {DATE_STRING_FMT_LOCAL, DATE_STRING_PART_ALL}; 957 return get_date_string(js, js->this_val, kSpec); 958} 959 960static ant_value_t builtin_Date_toISOString(ant_t *js, ant_value_t *args, int nargs) { 961 static const date_string_spec_t kSpec = {DATE_STRING_FMT_ISO, DATE_STRING_PART_ALL}; 962 return get_date_string(js, js->this_val, kSpec); 963} 964 965static ant_value_t builtin_Date_toDateString(ant_t *js, ant_value_t *args, int nargs) { 966 static const date_string_spec_t kSpec = {DATE_STRING_FMT_LOCAL, DATE_STRING_PART_DATE}; 967 return get_date_string(js, js->this_val, kSpec); 968} 969 970static ant_value_t builtin_Date_toTimeString(ant_t *js, ant_value_t *args, int nargs) { 971 static const date_string_spec_t kSpec = {DATE_STRING_FMT_LOCAL, DATE_STRING_PART_TIME}; 972 return get_date_string(js, js->this_val, kSpec); 973} 974 975static ant_value_t builtin_Date_toLocaleString(ant_t *js, ant_value_t *args, int nargs) { 976 static const date_string_spec_t kSpec = {DATE_STRING_FMT_LOCALE, DATE_STRING_PART_ALL}; 977 return get_date_string(js, js->this_val, kSpec); 978} 979 980static ant_value_t builtin_Date_toLocaleDateString(ant_t *js, ant_value_t *args, int nargs) { 981 static const date_string_spec_t kSpec = {DATE_STRING_FMT_LOCALE, DATE_STRING_PART_DATE}; 982 return get_date_string(js, js->this_val, kSpec); 983} 984 985static ant_value_t builtin_Date_toLocaleTimeString(ant_t *js, ant_value_t *args, int nargs) { 986 static const date_string_spec_t kSpec = {DATE_STRING_FMT_LOCALE, DATE_STRING_PART_TIME}; 987 return get_date_string(js, js->this_val, kSpec); 988} 989 990static ant_value_t builtin_Date_getTimezoneOffset(ant_t *js, ant_value_t *args, int nargs) { 991 double v; 992 ant_value_t err; 993 if (!date_this_time_value(js, js->this_val, &v, &err)) return err; 994 if (isnan(v)) return tov(JS_NAN); 995 return tov((double)get_timezone_offset((int64_t)trunc(v))); 996} 997 998static ant_value_t builtin_Date_setTime(ant_t *js, ant_value_t *args, int nargs) { 999 double cur; 1000 ant_value_t err; 1001 if (!date_this_time_value(js, js->this_val, &cur, &err)) return err; 1002 1003 double v = (nargs > 0) ? js_to_number(js, args[0]) : JS_NAN; 1004 return date_set_this_time_value(js, js->this_val, date_timeclip(v)); 1005} 1006 1007static ant_value_t builtin_Date_getYear(ant_t *js, ant_value_t *args, int nargs) { 1008 static const date_get_field_spec_t kSpec = {DATE_FIELD_YEAR, true, true}; 1009 return date_get_field(js, kSpec); 1010} 1011 1012static ant_value_t builtin_Date_getFullYear(ant_t *js, ant_value_t *args, int nargs) { 1013 static const date_get_field_spec_t kSpec = {DATE_FIELD_YEAR, true, false}; 1014 return date_get_field(js, kSpec); 1015} 1016 1017static ant_value_t builtin_Date_getUTCFullYear(ant_t *js, ant_value_t *args, int nargs) { 1018 static const date_get_field_spec_t kSpec = {DATE_FIELD_YEAR, false, false}; 1019 return date_get_field(js, kSpec); 1020} 1021 1022static ant_value_t builtin_Date_getMonth(ant_t *js, ant_value_t *args, int nargs) { 1023 static const date_get_field_spec_t kSpec = {DATE_FIELD_MONTH, true, false}; 1024 return date_get_field(js, kSpec); 1025} 1026 1027static ant_value_t builtin_Date_getUTCMonth(ant_t *js, ant_value_t *args, int nargs) { 1028 static const date_get_field_spec_t kSpec = {DATE_FIELD_MONTH, false, false}; 1029 return date_get_field(js, kSpec); 1030} 1031 1032static ant_value_t builtin_Date_getDate(ant_t *js, ant_value_t *args, int nargs) { 1033 static const date_get_field_spec_t kSpec = {DATE_FIELD_DAY_OF_MONTH, true, false}; 1034 return date_get_field(js, kSpec); 1035} 1036 1037static ant_value_t builtin_Date_getUTCDate(ant_t *js, ant_value_t *args, int nargs) { 1038 static const date_get_field_spec_t kSpec = {DATE_FIELD_DAY_OF_MONTH, false, false}; 1039 return date_get_field(js, kSpec); 1040} 1041 1042static ant_value_t builtin_Date_getHours(ant_t *js, ant_value_t *args, int nargs) { 1043 static const date_get_field_spec_t kSpec = {DATE_FIELD_HOUR, true, false}; 1044 return date_get_field(js, kSpec); 1045} 1046 1047static ant_value_t builtin_Date_getUTCHours(ant_t *js, ant_value_t *args, int nargs) { 1048 static const date_get_field_spec_t kSpec = {DATE_FIELD_HOUR, false, false}; 1049 return date_get_field(js, kSpec); 1050} 1051 1052static ant_value_t builtin_Date_getMinutes(ant_t *js, ant_value_t *args, int nargs) { 1053 static const date_get_field_spec_t kSpec = {DATE_FIELD_MINUTE, true, false}; 1054 return date_get_field(js, kSpec); 1055} 1056 1057static ant_value_t builtin_Date_getUTCMinutes(ant_t *js, ant_value_t *args, int nargs) { 1058 static const date_get_field_spec_t kSpec = {DATE_FIELD_MINUTE, false, false}; 1059 return date_get_field(js, kSpec); 1060} 1061 1062static ant_value_t builtin_Date_getSeconds(ant_t *js, ant_value_t *args, int nargs) { 1063 static const date_get_field_spec_t kSpec = {DATE_FIELD_SECOND, true, false}; 1064 return date_get_field(js, kSpec); 1065} 1066 1067static ant_value_t builtin_Date_getUTCSeconds(ant_t *js, ant_value_t *args, int nargs) { 1068 static const date_get_field_spec_t kSpec = {DATE_FIELD_SECOND, false, false}; 1069 return date_get_field(js, kSpec); 1070} 1071 1072static ant_value_t builtin_Date_getMilliseconds(ant_t *js, ant_value_t *args, int nargs) { 1073 static const date_get_field_spec_t kSpec = {DATE_FIELD_MILLISECOND, true, false}; 1074 return date_get_field(js, kSpec); 1075} 1076 1077static ant_value_t builtin_Date_getUTCMilliseconds(ant_t *js, ant_value_t *args, int nargs) { 1078 static const date_get_field_spec_t kSpec = {DATE_FIELD_MILLISECOND, false, false}; 1079 return date_get_field(js, kSpec); 1080} 1081 1082static ant_value_t builtin_Date_getDay(ant_t *js, ant_value_t *args, int nargs) { 1083 static const date_get_field_spec_t kSpec = {DATE_FIELD_DAY_OF_WEEK, true, false}; 1084 return date_get_field(js, kSpec); 1085} 1086 1087static ant_value_t builtin_Date_getUTCDay(ant_t *js, ant_value_t *args, int nargs) { 1088 static const date_get_field_spec_t kSpec = {DATE_FIELD_DAY_OF_WEEK, false, false}; 1089 return date_get_field(js, kSpec); 1090} 1091 1092static ant_value_t builtin_Date_setMilliseconds(ant_t *js, ant_value_t *args, int nargs) { 1093 static const date_set_field_spec_t kSpec = {DATE_FIELD_MILLISECOND, DATE_FIELD_DAY_OF_WEEK, true}; 1094 return date_set_field(js, args, nargs, kSpec); 1095} 1096 1097static ant_value_t builtin_Date_setUTCMilliseconds(ant_t *js, ant_value_t *args, int nargs) { 1098 static const date_set_field_spec_t kSpec = {DATE_FIELD_MILLISECOND, DATE_FIELD_DAY_OF_WEEK, false}; 1099 return date_set_field(js, args, nargs, kSpec); 1100} 1101 1102static ant_value_t builtin_Date_setSeconds(ant_t *js, ant_value_t *args, int nargs) { 1103 static const date_set_field_spec_t kSpec = {DATE_FIELD_SECOND, DATE_FIELD_DAY_OF_WEEK, true}; 1104 return date_set_field(js, args, nargs, kSpec); 1105} 1106 1107static ant_value_t builtin_Date_setUTCSeconds(ant_t *js, ant_value_t *args, int nargs) { 1108 static const date_set_field_spec_t kSpec = {DATE_FIELD_SECOND, DATE_FIELD_DAY_OF_WEEK, false}; 1109 return date_set_field(js, args, nargs, kSpec); 1110} 1111 1112static ant_value_t builtin_Date_setMinutes(ant_t *js, ant_value_t *args, int nargs) { 1113 static const date_set_field_spec_t kSpec = {DATE_FIELD_MINUTE, DATE_FIELD_DAY_OF_WEEK, true}; 1114 return date_set_field(js, args, nargs, kSpec); 1115} 1116 1117static ant_value_t builtin_Date_setUTCMinutes(ant_t *js, ant_value_t *args, int nargs) { 1118 static const date_set_field_spec_t kSpec = {DATE_FIELD_MINUTE, DATE_FIELD_DAY_OF_WEEK, false}; 1119 return date_set_field(js, args, nargs, kSpec); 1120} 1121 1122static ant_value_t builtin_Date_setHours(ant_t *js, ant_value_t *args, int nargs) { 1123 static const date_set_field_spec_t kSpec = {DATE_FIELD_HOUR, DATE_FIELD_DAY_OF_WEEK, true}; 1124 return date_set_field(js, args, nargs, kSpec); 1125} 1126 1127static ant_value_t builtin_Date_setUTCHours(ant_t *js, ant_value_t *args, int nargs) { 1128 static const date_set_field_spec_t kSpec = {DATE_FIELD_HOUR, DATE_FIELD_DAY_OF_WEEK, false}; 1129 return date_set_field(js, args, nargs, kSpec); 1130} 1131 1132static ant_value_t builtin_Date_setDate(ant_t *js, ant_value_t *args, int nargs) { 1133 static const date_set_field_spec_t kSpec = {DATE_FIELD_DAY_OF_MONTH, DATE_FIELD_HOUR, true}; 1134 return date_set_field(js, args, nargs, kSpec); 1135} 1136 1137static ant_value_t builtin_Date_setUTCDate(ant_t *js, ant_value_t *args, int nargs) { 1138 static const date_set_field_spec_t kSpec = {DATE_FIELD_DAY_OF_MONTH, DATE_FIELD_HOUR, false}; 1139 return date_set_field(js, args, nargs, kSpec); 1140} 1141 1142static ant_value_t builtin_Date_setMonth(ant_t *js, ant_value_t *args, int nargs) { 1143 static const date_set_field_spec_t kSpec = {DATE_FIELD_MONTH, DATE_FIELD_DAY_OF_MONTH, true}; 1144 return date_set_field(js, args, nargs, kSpec); 1145} 1146 1147static ant_value_t builtin_Date_setUTCMonth(ant_t *js, ant_value_t *args, int nargs) { 1148 static const date_set_field_spec_t kSpec = {DATE_FIELD_MONTH, DATE_FIELD_DAY_OF_MONTH, false}; 1149 return date_set_field(js, args, nargs, kSpec); 1150} 1151 1152static ant_value_t builtin_Date_setFullYear(ant_t *js, ant_value_t *args, int nargs) { 1153 static const date_set_field_spec_t kSpec = {DATE_FIELD_YEAR, DATE_FIELD_HOUR, true}; 1154 return date_set_field(js, args, nargs, kSpec); 1155} 1156 1157static ant_value_t builtin_Date_setUTCFullYear(ant_t *js, ant_value_t *args, int nargs) { 1158 static const date_set_field_spec_t kSpec = {DATE_FIELD_YEAR, DATE_FIELD_HOUR, false}; 1159 return date_set_field(js, args, nargs, kSpec); 1160} 1161 1162static ant_value_t builtin_Date_setYear(ant_t *js, ant_value_t *args, int nargs) { 1163 double y; 1164 ant_value_t err; 1165 if (!date_this_time_value(js, js->this_val, &y, &err)) return err; 1166 1167 y = (nargs > 0) ? js_to_number(js, args[0]) : JS_NAN; 1168 if (isnan(y)) return date_set_this_time_value(js, js->this_val, y); 1169 1170 if (isfinite(y)) { 1171 y = trunc(y); 1172 if (y >= 0 && y < 100) y += 1900; 1173 } 1174 1175 ant_value_t darg = tov(y); 1176 static const date_set_field_spec_t kSetYearSpec = { 1177 DATE_FIELD_YEAR, DATE_FIELD_MONTH, true 1178 }; 1179 return date_set_field(js, &darg, 1, kSetYearSpec); 1180} 1181 1182static ant_value_t date_to_primitive_number(ant_t *js, ant_value_t obj) { 1183 ant_value_t to_primitive_sym = get_toPrimitive_sym(); 1184 if (vtype(to_primitive_sym) == T_SYMBOL) { 1185 ant_value_t ex = js_get_sym(js, obj, to_primitive_sym); 1186 uint8_t et = vtype(ex); 1187 if (et == T_FUNC || et == T_CFUNC) { 1188 ant_value_t hint = js_mkstr(js, "number", 6); 1189 ant_value_t result = sv_vm_call(js->vm, js, ex, obj, &hint, 1, NULL, false); 1190 if (is_err(result)) return result; 1191 if (date_is_primitive(result)) return result; 1192 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert object to primitive value"); 1193 } 1194 if (et != T_UNDEF) { 1195 return js_mkerr_typed(js, JS_ERR_TYPE, "Symbol.toPrimitive is not a function"); 1196 } 1197 } 1198 1199 const char *methods[2] = {"valueOf", "toString"}; 1200 for (int i = 0; i < 2; i++) { 1201 ant_value_t method = js_getprop_fallback(js, obj, methods[i]); 1202 uint8_t mt = vtype(method); 1203 if (mt == T_FUNC || mt == T_CFUNC) { 1204 ant_value_t result = sv_vm_call(js->vm, js, method, obj, NULL, 0, NULL, false); 1205 if (is_err(result)) return result; 1206 if (date_is_primitive(result)) return result; 1207 } 1208 } 1209 1210 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert object to primitive value"); 1211} 1212 1213static ant_value_t builtin_Date_toJSON(ant_t *js, ant_value_t *args, int nargs) { 1214 ant_value_t obj = js->this_val; 1215 if (!is_object_type(obj)) { 1216 return js_mkerr_typed(js, JS_ERR_TYPE, "Date.prototype.toJSON called on non-object"); 1217 } 1218 1219 ant_value_t tv = date_to_primitive_number(js, obj); 1220 if (is_err(tv)) return tv; 1221 1222 if (vtype(tv) == T_NUM && !isfinite(tod(tv))) { 1223 return js_mknull(); 1224 } 1225 1226 ant_value_t method = js_getprop_fallback(js, obj, "toISOString"); 1227 uint8_t mt = vtype(method); 1228 if (mt != T_FUNC && mt != T_CFUNC) { 1229 return js_mkerr_typed(js, JS_ERR_TYPE, "object needs toISOString method"); 1230 } 1231 1232 return sv_vm_call(js->vm, js, method, obj, NULL, 0, NULL, false); 1233} 1234 1235static ant_value_t date_toPrimitive(ant_t *js, ant_value_t *args, int nargs) { 1236 ant_value_t this_val = js_getthis(js); 1237 if (!is_object_type(this_val)) { 1238 return js_mkerr_typed(js, JS_ERR_TYPE, "Not an object"); 1239 } 1240 1241 int hint_num; 1242 if (nargs > 0 && vtype(args[0]) == T_STR) { 1243 size_t hint_len = 0; 1244 const char *hint = js_getstr(js, args[0], &hint_len); 1245 if (!hint) return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid hint"); 1246 1247 if ((hint_len == 6 && memcmp(hint, "number", 6) == 0) 1248 || (hint_len == 7 && memcmp(hint, "integer", 7) == 0)) { 1249 hint_num = 1; 1250 } else if ( 1251 (hint_len == 6 && memcmp(hint, "string", 6) == 0) 1252 || (hint_len == 7 && memcmp(hint, "default", 7) == 0)) { 1253 hint_num = 0; 1254 } else { 1255 return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid hint"); 1256 } 1257 } else return js_mkerr_typed(js, JS_ERR_TYPE, "Invalid hint"); 1258 1259 const char *methods0[2] = {"toString", "valueOf"}; 1260 const char *methods1[2] = {"valueOf", "toString"}; 1261 const char **methods = hint_num ? methods1 : methods0; 1262 1263 for (int i = 0; i < 2; i++) { 1264 ant_value_t method = js_getprop_fallback(js, this_val, methods[i]); 1265 uint8_t mt = vtype(method); 1266 if (mt == T_FUNC || mt == T_CFUNC) { 1267 ant_value_t result = sv_vm_call(js->vm, js, method, this_val, NULL, 0, NULL, false); 1268 if (is_err(result)) return result; 1269 if (date_is_primitive(result)) return result; 1270 } 1271 } 1272 1273 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert object to primitive value"); 1274} 1275 1276static void date_define_methods( 1277 ant_t *js, ant_value_t target, 1278 const date_method_entry_t *methods, 1279 size_t count 1280) { 1281 for (size_t i = 0; i < count; i++) js_setprop(js,target, 1282 js_mkstr(js, methods[i].name, methods[i].len), 1283 js_mkfun_dyn(methods[i].fn) 1284 ); 1285} 1286 1287void init_date_module(void) { 1288 ant_t *js = rt->js; 1289 ant_value_t glob = js->global; 1290 ant_value_t object_proto = js->sym.object_proto; 1291 1292 ant_value_t function_proto = js_get_ctor_proto(js, "Function", 8); 1293 ant_value_t date_proto = js_mkobj(js); 1294 1295 js_set_proto_init(date_proto, object_proto); 1296 1297 static const date_method_entry_t kDateProtoMethods[] = { 1298 DATE_METHOD_ENTRY("valueOf", builtin_Date_valueOf), 1299 DATE_METHOD_ENTRY("toString", builtin_Date_toString), 1300 DATE_METHOD_ENTRY("toUTCString", builtin_Date_toUTCString), 1301 DATE_METHOD_ENTRY("toGMTString", builtin_Date_toUTCString), 1302 DATE_METHOD_ENTRY("toISOString", builtin_Date_toISOString), 1303 DATE_METHOD_ENTRY("toDateString", builtin_Date_toDateString), 1304 DATE_METHOD_ENTRY("toTimeString", builtin_Date_toTimeString), 1305 DATE_METHOD_ENTRY("toLocaleString", builtin_Date_toLocaleString), 1306 DATE_METHOD_ENTRY("toLocaleDateString", builtin_Date_toLocaleDateString), 1307 DATE_METHOD_ENTRY("toLocaleTimeString", builtin_Date_toLocaleTimeString), 1308 DATE_METHOD_ENTRY("getTimezoneOffset", builtin_Date_getTimezoneOffset), 1309 DATE_METHOD_ENTRY("getTime", builtin_Date_getTime), 1310 DATE_METHOD_ENTRY("getYear", builtin_Date_getYear), 1311 DATE_METHOD_ENTRY("getFullYear", builtin_Date_getFullYear), 1312 DATE_METHOD_ENTRY("getUTCFullYear", builtin_Date_getUTCFullYear), 1313 DATE_METHOD_ENTRY("getMonth", builtin_Date_getMonth), 1314 DATE_METHOD_ENTRY("getUTCMonth", builtin_Date_getUTCMonth), 1315 DATE_METHOD_ENTRY("getDate", builtin_Date_getDate), 1316 DATE_METHOD_ENTRY("getUTCDate", builtin_Date_getUTCDate), 1317 DATE_METHOD_ENTRY("getHours", builtin_Date_getHours), 1318 DATE_METHOD_ENTRY("getUTCHours", builtin_Date_getUTCHours), 1319 DATE_METHOD_ENTRY("getMinutes", builtin_Date_getMinutes), 1320 DATE_METHOD_ENTRY("getUTCMinutes", builtin_Date_getUTCMinutes), 1321 DATE_METHOD_ENTRY("getSeconds", builtin_Date_getSeconds), 1322 DATE_METHOD_ENTRY("getUTCSeconds", builtin_Date_getUTCSeconds), 1323 DATE_METHOD_ENTRY("getMilliseconds", builtin_Date_getMilliseconds), 1324 DATE_METHOD_ENTRY("getUTCMilliseconds", builtin_Date_getUTCMilliseconds), 1325 DATE_METHOD_ENTRY("getDay", builtin_Date_getDay), 1326 DATE_METHOD_ENTRY("getUTCDay", builtin_Date_getUTCDay), 1327 DATE_METHOD_ENTRY("setTime", builtin_Date_setTime), 1328 DATE_METHOD_ENTRY("setMilliseconds", builtin_Date_setMilliseconds), 1329 DATE_METHOD_ENTRY("setUTCMilliseconds", builtin_Date_setUTCMilliseconds), 1330 DATE_METHOD_ENTRY("setSeconds", builtin_Date_setSeconds), 1331 DATE_METHOD_ENTRY("setUTCSeconds", builtin_Date_setUTCSeconds), 1332 DATE_METHOD_ENTRY("setMinutes", builtin_Date_setMinutes), 1333 DATE_METHOD_ENTRY("setUTCMinutes", builtin_Date_setUTCMinutes), 1334 DATE_METHOD_ENTRY("setHours", builtin_Date_setHours), 1335 DATE_METHOD_ENTRY("setUTCHours", builtin_Date_setUTCHours), 1336 DATE_METHOD_ENTRY("setDate", builtin_Date_setDate), 1337 DATE_METHOD_ENTRY("setUTCDate", builtin_Date_setUTCDate), 1338 DATE_METHOD_ENTRY("setMonth", builtin_Date_setMonth), 1339 DATE_METHOD_ENTRY("setUTCMonth", builtin_Date_setUTCMonth), 1340 DATE_METHOD_ENTRY("setYear", builtin_Date_setYear), 1341 DATE_METHOD_ENTRY("setFullYear", builtin_Date_setFullYear), 1342 DATE_METHOD_ENTRY("setUTCFullYear", builtin_Date_setUTCFullYear), 1343 DATE_METHOD_ENTRY("toJSON", builtin_Date_toJSON), 1344 }; 1345 date_define_methods(js, date_proto, kDateProtoMethods, DATE_COUNT_OF(kDateProtoMethods)); 1346 1347 ant_value_t to_primitive_sym = get_toPrimitive_sym(); 1348 if (vtype(to_primitive_sym) == T_SYMBOL) { 1349 js_set_sym(js, date_proto, to_primitive_sym, js_mkfun(date_toPrimitive)); 1350 } 1351 1352 ant_value_t date_ctor_obj = js_mkobj(js); 1353 js_set_proto_init(date_ctor_obj, function_proto); 1354 js_set_slot(date_ctor_obj, SLOT_CFUNC, js_mkfun(builtin_Date)); 1355 1356 static const date_method_entry_t kDateCtorMethods[] = { 1357 DATE_METHOD_ENTRY("now", builtin_Date_now), 1358 DATE_METHOD_ENTRY("parse", builtin_Date_parse), 1359 DATE_METHOD_ENTRY("UTC", builtin_Date_UTC), 1360 }; 1361 1362 date_define_methods(js, date_ctor_obj, kDateCtorMethods, DATE_COUNT_OF(kDateCtorMethods)); 1363 js_setprop_nonconfigurable(js, date_ctor_obj, "prototype", 9, date_proto); 1364 js_setprop(js, date_ctor_obj, ANT_STRING("name"), ANT_STRING("Date")); 1365 1366 ant_value_t date_ctor_func = js_obj_to_func(date_ctor_obj); 1367 js_setprop(js, glob, js_mkstr(js, "Date", 4), date_ctor_func); 1368 1369 js_setprop(js, date_proto, js_mkstr(js, "constructor", 11), date_ctor_func); 1370 js_set_descriptor(js, date_proto, "constructor", 11, JS_DESC_W | JS_DESC_C); 1371}