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.

full limb string migration support

+399 -41
+13
examples/spec/bigint.js
··· 5 5 test('bigint literal', 123n, 123n); 6 6 test('BigInt()', BigInt(456), 456n); 7 7 test('BigInt from string', BigInt('789'), 789n); 8 + test('BigInt from hex string', BigInt('0xff'), 255n); 9 + test('BigInt from binary string', BigInt('0b1010'), 10n); 10 + test('BigInt from octal string', BigInt('0o77'), 63n); 11 + test('BigInt from trimmed string', BigInt(' 42 '), 42n); 12 + test('BigInt from empty string', BigInt(''), 0n); 13 + testThrows('BigInt invalid prefixed string', () => BigInt('0x')); 14 + testThrows('BigInt invalid underscore string', () => BigInt('1_2')); 8 15 9 16 test('bigint addition', 1n + 2n, 3n); 17 + test('bigint prefixed literal addition', 0xffn + 1n, 256n); 10 18 test('bigint subtraction', 10n - 3n, 7n); 11 19 test('bigint multiplication', 4n * 5n, 20n); 12 20 test('bigint division', 10n / 3n, 3n); 13 21 test('bigint modulo', 10n % 3n, 1n); 14 22 test('bigint exponentiation', 2n ** 10n, 1024n); 23 + test('bigint bitwise and', 5n & 3n, 1n); 24 + test('bigint bitwise or', 5n | 2n, 7n); 25 + test('bigint bitwise xor', 5n ^ 1n, 4n); 26 + test('bigint bitwise not', ~0n, -1n); 27 + test('bigint bitwise negative mix', (-8n) | 3n, -5n); 15 28 16 29 test('bigint comparison <', 1n < 2n, true); 17 30 test('bigint comparison >', 5n > 3n, true);
+4
include/modules/bigint.h
··· 16 16 ant_value_t bigint_shift_left(ant_t *js, ant_value_t value, uint64_t shift); 17 17 ant_value_t bigint_shift_right(ant_t *js, ant_value_t value, uint64_t shift); 18 18 ant_value_t bigint_shift_right_logical(ant_t *js, ant_value_t value, uint64_t shift); 19 + ant_value_t bigint_bitand(ant_t *js, ant_value_t a, ant_value_t b); 20 + ant_value_t bigint_bitor(ant_t *js, ant_value_t a, ant_value_t b); 21 + ant_value_t bigint_bitxor(ant_t *js, ant_value_t a, ant_value_t b); 22 + ant_value_t bigint_bitnot(ant_t *js, ant_value_t value); 19 23 ant_value_t bigint_asint_bits(ant_t *js, ant_value_t arg, uint64_t *bits_out); 20 24 21 25 bool bigint_is_negative(ant_t *js, ant_value_t v);
+243 -36
src/modules/bigint.c
··· 5 5 #include "internal.h" 6 6 #include "errors.h" 7 7 #include "runtime.h" 8 + #include "utils.h" 9 + #include "silver/lexer.h" 8 10 9 11 #define BIGINT_BASE ((uint64_t)0x100000000ULL) 10 12 #define BIGINT_DEC_GROUP_BASE 1000000000U ··· 353 355 return (uint32_t)rem; 354 356 } 355 357 358 + static size_t bigint_abs_bitlen_limbs(const uint32_t *limbs, size_t count) { 359 + while (count > 1 && limbs[count - 1] == 0) count--; 360 + if (count == 1 && limbs[0] == 0) return 0; 361 + 362 + uint32_t top = limbs[count - 1]; 363 + #if defined(__GNUC__) || defined(__clang__) 364 + unsigned lead = (unsigned)__builtin_clz(top); 365 + #else 366 + unsigned lead = 0; 367 + while ((top & 0x80000000u) == 0) { 368 + top <<= 1; 369 + lead++; 370 + } 371 + #endif 372 + return (count - 1) * 32u + (32u - (size_t)lead); 373 + } 374 + 375 + static uint32_t *bigint_to_twos_complement_limbs( 376 + const uint32_t *limbs, 377 + size_t count, 378 + bool negative, 379 + size_t width 380 + ) { 381 + if (width == 0) width = 1; 382 + 383 + uint32_t *out = limb_alloc(width); 384 + if (!out) return NULL; 385 + 386 + size_t copy_count = count < width ? count : width; 387 + if (copy_count > 0) memcpy(out, limbs, copy_count * sizeof(uint32_t)); 388 + 389 + if (!negative) return out; 390 + 391 + for (size_t i = 0; i < width; i++) out[i] = ~out[i]; 392 + 393 + uint64_t carry = 1; 394 + for (size_t i = 0; i < width && carry != 0; i++) { 395 + uint64_t cur = (uint64_t)out[i] + carry; 396 + out[i] = (uint32_t)cur; 397 + carry = cur >> 32; 398 + } 399 + 400 + return out; 401 + } 402 + 403 + static uint32_t *bigint_from_twos_complement_limbs( 404 + const uint32_t *twos, 405 + size_t width, 406 + bool *negative_out, 407 + size_t *count_out 408 + ) { 409 + if (width == 0) width = 1; 410 + 411 + bool negative = (twos[width - 1] & 0x80000000u) != 0; 412 + uint32_t *mag = limb_dup(twos, width); 413 + if (!mag) return NULL; 414 + 415 + if (negative) { 416 + for (size_t i = 0; i < width; i++) mag[i] = ~mag[i]; 417 + uint64_t carry = 1; 418 + for (size_t i = 0; i < width && carry != 0; i++) { 419 + uint64_t cur = (uint64_t)mag[i] + carry; 420 + mag[i] = (uint32_t)cur; 421 + carry = cur >> 32; 422 + } 423 + } 424 + 425 + size_t mcount = width; 426 + bigint_normalize_limbs(mag, &mcount); 427 + if (mcount == 1 && mag[0] == 0) negative = false; 428 + 429 + if (negative_out) *negative_out = negative; 430 + if (count_out) *count_out = mcount; 431 + return mag; 432 + } 433 + 434 + typedef enum { 435 + BIGINT_BAND = 0, 436 + BIGINT_BOR, 437 + BIGINT_BXOR 438 + } bigint_bitop_t; 439 + 440 + static ant_value_t bigint_bitwise_binary(ant_t *js, ant_value_t a, ant_value_t b, bigint_bitop_t op) { 441 + bool aneg = bigint_is_negative(js, a); 442 + bool bneg = bigint_is_negative(js, b); 443 + 444 + size_t alen = 0, blen = 0; 445 + const uint32_t *ad = bigint_limbs(js, a, &alen); 446 + const uint32_t *bd = bigint_limbs(js, b, &blen); 447 + 448 + size_t abit = bigint_abs_bitlen_limbs(ad, alen); 449 + size_t bbit = bigint_abs_bitlen_limbs(bd, blen); 450 + size_t width_bits = (abit > bbit ? abit : bbit) + 1; 451 + size_t width = (width_bits + 31u) / 32u; 452 + if (width == 0) width = 1; 453 + 454 + uint32_t *at = bigint_to_twos_complement_limbs(ad, alen, aneg, width); 455 + uint32_t *bt = bigint_to_twos_complement_limbs(bd, blen, bneg, width); 456 + if (!at || !bt) { 457 + free(at); 458 + free(bt); 459 + return js_mkerr(js, "oom"); 460 + } 461 + 462 + for (size_t i = 0; i < width; i++) { 463 + switch (op) { 464 + case BIGINT_BAND: at[i] &= bt[i]; break; 465 + case BIGINT_BOR: at[i] |= bt[i]; break; 466 + case BIGINT_BXOR: at[i] ^= bt[i]; break; 467 + } 468 + } 469 + 470 + bool negative = false; 471 + size_t mcount = 0; 472 + uint32_t *mag = bigint_from_twos_complement_limbs(at, width, &negative, &mcount); 473 + free(at); 474 + free(bt); 475 + if (!mag) return js_mkerr(js, "oom"); 476 + 477 + ant_value_t out = js_mkbigint_limbs(js, mag, mcount, negative); 478 + free(mag); 479 + return out; 480 + } 481 + 482 + ant_value_t bigint_bitand(ant_t *js, ant_value_t a, ant_value_t b) { 483 + return bigint_bitwise_binary(js, a, b, BIGINT_BAND); 484 + } 485 + 486 + ant_value_t bigint_bitor(ant_t *js, ant_value_t a, ant_value_t b) { 487 + return bigint_bitwise_binary(js, a, b, BIGINT_BOR); 488 + } 489 + 490 + ant_value_t bigint_bitxor(ant_t *js, ant_value_t a, ant_value_t b) { 491 + return bigint_bitwise_binary(js, a, b, BIGINT_BXOR); 492 + } 493 + 494 + ant_value_t bigint_bitnot(ant_t *js, ant_value_t value) { 495 + bool neg = bigint_is_negative(js, value); 496 + size_t count = 0; 497 + const uint32_t *limbs = bigint_limbs(js, value, &count); 498 + 499 + size_t bits = bigint_abs_bitlen_limbs(limbs, count); 500 + size_t width_bits = bits + 1; 501 + size_t width = (width_bits + 31u) / 32u; 502 + if (width == 0) width = 1; 503 + 504 + uint32_t *twos = bigint_to_twos_complement_limbs(limbs, count, neg, width); 505 + if (!twos) return js_mkerr(js, "oom"); 506 + for (size_t i = 0; i < width; i++) twos[i] = ~twos[i]; 507 + 508 + bool out_neg = false; 509 + size_t out_count = 0; 510 + 511 + uint32_t *mag = bigint_from_twos_complement_limbs(twos, width, &out_neg, &out_count); 512 + free(twos); if (!mag) return js_mkerr(js, "oom"); 513 + 514 + ant_value_t out = js_mkbigint_limbs(js, mag, out_count, out_neg); 515 + free(mag); 516 + 517 + return out; 518 + } 519 + 356 520 static inline unsigned clz32_nonzero(uint32_t v) { 357 521 #if defined(__GNUC__) || defined(__clang__) 358 522 return (unsigned)__builtin_clz(v); ··· 569 733 return true; 570 734 } 571 735 572 - static ant_value_t bigint_from_decimal_digits(ant_t *js, const char *digits, size_t len, bool negative) { 736 + static ant_value_t bigint_from_string_digits( 737 + ant_t *js, 738 + const char *digits, 739 + size_t len, 740 + bool negative, 741 + bool allow_separators 742 + ) { 573 743 if (!digits || len == 0) { 574 744 uint32_t zero = 0; 575 745 return js_mkbigint_limbs(js, &zero, 1, false); 576 746 } 577 747 578 - while (len > 1 && *digits == '0') { 579 - digits++; 580 - len--; 748 + uint32_t base = 10; 749 + size_t start = 0; 750 + 751 + if (len >= 2 && digits[0] == '0') { 752 + char p = (char)(digits[1] | 0x20); 753 + if (p == 'x') { 754 + base = 16; 755 + start = 2; 756 + } else if (p == 'o') { 757 + base = 8; 758 + start = 2; 759 + } else if (p == 'b') { 760 + base = 2; 761 + start = 2; 762 + } 581 763 } 582 764 583 - size_t cap = len / 9 + 2; 765 + if (start >= len) return js_mkerr(js, "Cannot convert string to BigInt"); 766 + 767 + size_t cap = len / 8 + 2; 768 + if (cap < 4) cap = 4; 584 769 uint32_t *limbs = limb_alloc(cap); 585 770 if (!limbs) return js_mkerr(js, "oom"); 586 771 587 772 size_t count = 1; 773 + bool has_digit = false; 774 + bool prev_sep = false; 588 775 589 - for (size_t i = 0; i < len; i++) { 590 - if (!is_decimal_digit(digits[i])) { 776 + for (size_t i = start; i < len; i++) { 777 + char ch = digits[i]; 778 + 779 + if (ch == '_') { 780 + if (!allow_separators || !has_digit || prev_sep) { 781 + free(limbs); 782 + return js_mkerr(js, "Cannot convert string to BigInt"); 783 + } 784 + prev_sep = true; 785 + continue; 786 + } 787 + 788 + int digit = hex_digit(ch); 789 + if (digit < 0 || (uint32_t)digit >= base) { 591 790 free(limbs); 592 791 return js_mkerr(js, "Cannot convert string to BigInt"); 593 792 } 594 793 595 - uint64_t carry = (uint64_t)(digits[i] - '0'); 794 + has_digit = true; 795 + prev_sep = false; 796 + 797 + uint64_t carry = (uint64_t)digit; 596 798 597 799 for (size_t j = 0; j < count; j++) { 598 - uint64_t cur = (uint64_t)limbs[j] * 10 + carry; 800 + uint64_t cur = (uint64_t)limbs[j] * base + carry; 599 801 limbs[j] = (uint32_t)cur; 600 802 carry = cur >> 32; 601 803 } 602 804 603 805 if (carry != 0) { 604 - if (count == cap) { 605 - size_t new_cap = cap * 2; 606 - uint32_t *new_limbs = (uint32_t *)realloc(limbs, new_cap * sizeof(uint32_t)); 607 - if (!new_limbs) { 608 - free(limbs); 609 - return js_mkerr(js, "oom"); 806 + while (carry != 0) { 807 + if (count == cap) { 808 + size_t new_cap = cap * 2; 809 + uint32_t *new_limbs = (uint32_t *)realloc(limbs, new_cap * sizeof(uint32_t)); 810 + if (!new_limbs) { 811 + free(limbs); 812 + return js_mkerr(js, "oom"); 813 + } 814 + 815 + memset(new_limbs + cap, 0, (new_cap - cap) * sizeof(uint32_t)); 816 + limbs = new_limbs; 817 + cap = new_cap; 610 818 } 611 819 612 - memset(new_limbs + cap, 0, (new_cap - cap) * sizeof(uint32_t)); 613 - limbs = new_limbs; 614 - cap = new_cap; 820 + limbs[count++] = (uint32_t)carry; 821 + carry >>= 32; 615 822 } 616 - 617 - limbs[count++] = (uint32_t)carry; 618 823 } 824 + } 825 + 826 + if (!has_digit || prev_sep) { 827 + free(limbs); 828 + return js_mkerr(js, "Cannot convert string to BigInt"); 619 829 } 620 830 621 831 ant_value_t result = js_mkbigint_limbs(js, limbs, count, negative); ··· 757 967 } 758 968 759 969 ant_value_t js_mkbigint(ant_t *js, const char *digits, size_t len, bool negative) { 760 - return bigint_from_decimal_digits(js, digits, len, negative); 970 + return bigint_from_string_digits(js, digits, len, negative, true); 761 971 } 762 972 763 973 ant_value_t bigint_add(ant_t *js, ant_value_t a, ant_value_t b) { ··· 1099 1309 ant_offset_t off = vstr(js, arg, &slen); 1100 1310 const char *str = (const char *)&js->mem[off]; 1101 1311 1102 - bool neg = false; 1103 - size_t i = 0; 1312 + size_t start = 0; 1313 + size_t end = slen; 1314 + 1315 + while (start < end && is_space((unsigned char)str[start])) start++; 1316 + while (end > start && is_space((unsigned char)str[end - 1])) end--; 1317 + if (start >= end) return js_mkbigint(js, "0", 1, false); 1104 1318 1105 - if (slen > 0 && str[0] == '-') { 1319 + bool neg = false; 1320 + if (str[start] == '-') { 1106 1321 neg = true; 1107 - i++; 1108 - } else if (slen > 0 && str[0] == '+') { 1109 - i++; 1110 - } 1322 + start++; 1323 + } else if (str[start] == '+') start++; 1111 1324 1112 - while (i < slen && str[i] == '0') i++; 1113 - if (i >= slen) return js_mkbigint(js, "0", 1, false); 1114 - 1115 - for (size_t j = i; j < slen; j++) { 1116 - if (!is_decimal_digit(str[j])) return js_mkerr(js, "Cannot convert string to BigInt"); 1117 - } 1118 - 1119 - return js_mkbigint(js, str + i, slen - i, neg); 1325 + if (start >= end) return js_mkerr(js, "Cannot convert string to BigInt"); 1326 + return bigint_from_string_digits(js, str + start, end - start, neg, false); 1120 1327 } 1121 1328 1122 1329 if (vtype(arg) == T_BOOL) return js_mkbigint(js, vdata(arg) ? "1" : "0", 1, false);
+1 -1
src/silver/engine.c
··· 656 656 L_BAND: { VM_CHECK(sv_op_band(vm, js)); NEXT(1); } 657 657 L_BOR: { VM_CHECK(sv_op_bor(vm, js)); NEXT(1); } 658 658 L_BXOR: { VM_CHECK(sv_op_bxor(vm, js)); NEXT(1); } 659 - L_BNOT: { sv_op_bnot(vm, js); NEXT(1); } 659 + L_BNOT: { VM_CHECK(sv_op_bnot(vm, js)); NEXT(1); } 660 660 L_SHL: { VM_CHECK(sv_op_shl(vm, js)); NEXT(1); } 661 661 L_SHR: { VM_CHECK(sv_op_shr(vm, js)); NEXT(1); } 662 662 L_USHR: { VM_CHECK(sv_op_ushr(vm, js)); NEXT(1); }
+20 -4
src/silver/ops/bitwise.h
··· 12 12 if (lt == T_BIGINT || rt == T_BIGINT) { 13 13 if (lt != T_BIGINT || rt != T_BIGINT) 14 14 return js_mkerr(js, "Cannot mix BigInt value and other types"); 15 - return js_mkerr_typed(js, JS_ERR_TYPE, "BigInt does not support bitwise ops"); 15 + ant_value_t res = bigint_bitand(js, l, r); 16 + if (is_err(res)) return res; 17 + vm->stack[vm->sp++] = res; 18 + return tov(0); 16 19 } 17 20 int32_t ai = (lt == T_NUM) ? js_to_int32(tod(l)) : js_to_int32(js_to_number(js, l)); 18 21 int32_t bi = (rt == T_NUM) ? js_to_int32(tod(r)) : js_to_int32(js_to_number(js, r)); ··· 27 30 if (lt == T_BIGINT || rt == T_BIGINT) { 28 31 if (lt != T_BIGINT || rt != T_BIGINT) 29 32 return js_mkerr(js, "Cannot mix BigInt value and other types"); 30 - return js_mkerr_typed(js, JS_ERR_TYPE, "BigInt does not support bitwise ops"); 33 + ant_value_t res = bigint_bitor(js, l, r); 34 + if (is_err(res)) return res; 35 + vm->stack[vm->sp++] = res; 36 + return tov(0); 31 37 } 32 38 int32_t ai = (lt == T_NUM) ? js_to_int32(tod(l)) : js_to_int32(js_to_number(js, l)); 33 39 int32_t bi = (rt == T_NUM) ? js_to_int32(tod(r)) : js_to_int32(js_to_number(js, r)); ··· 42 48 if (lt == T_BIGINT || rt == T_BIGINT) { 43 49 if (lt != T_BIGINT || rt != T_BIGINT) 44 50 return js_mkerr(js, "Cannot mix BigInt value and other types"); 45 - return js_mkerr_typed(js, JS_ERR_TYPE, "BigInt does not support bitwise ops"); 51 + ant_value_t res = bigint_bitxor(js, l, r); 52 + if (is_err(res)) return res; 53 + vm->stack[vm->sp++] = res; 54 + return tov(0); 46 55 } 47 56 int32_t ai = (lt == T_NUM) ? js_to_int32(tod(l)) : js_to_int32(js_to_number(js, l)); 48 57 int32_t bi = (rt == T_NUM) ? js_to_int32(tod(r)) : js_to_int32(js_to_number(js, r)); ··· 50 59 return tov(0); 51 60 } 52 61 53 - static inline void sv_op_bnot(sv_vm_t *vm, ant_t *js) { 62 + static inline ant_value_t sv_op_bnot(sv_vm_t *vm, ant_t *js) { 54 63 ant_value_t a = vm->stack[--vm->sp]; 64 + if (vtype(a) == T_BIGINT) { 65 + ant_value_t res = bigint_bitnot(js, a); 66 + if (is_err(res)) return res; 67 + vm->stack[vm->sp++] = res; 68 + return tov(0); 69 + } 55 70 vm->stack[vm->sp++] = tov((double)(~js_to_int32(js_to_number(js, a)))); 71 + return tov(0); 56 72 } 57 73 58 74 static inline ant_value_t sv_op_shl(sv_vm_t *vm, ant_t *js) {
+97
tests/bench_bigint.js
··· 1 + const now = () => (typeof performance !== 'undefined' && typeof performance.now === 'function' ? performance.now() : Date.now()); 2 + 3 + if (typeof BigInt !== 'function') { 4 + console.log('BigInt is not available in this runtime.'); 5 + } else { 6 + console.log('BigInt Bench (new feature coverage)'); 7 + 8 + let sinkBig = 0n; 9 + let sinkNum = 0; 10 + const HASH_BIAS = 11400714819323198485n; 11 + 12 + const mixBig = x => { 13 + sinkBig ^= x + HASH_BIAS; 14 + }; 15 + 16 + const mixNum = x => { 17 + sinkNum = (sinkNum * 1664525 + (x >>> 0) + 1013904223) >>> 0; 18 + }; 19 + 20 + function bench(name, iterations, fn) { 21 + const start = now(); 22 + for (let i = 0; i < iterations; i++) fn(i); 23 + const ms = now() - start; 24 + const opsPerSec = ms > 0 ? Math.round((iterations * 1000) / ms) : 0; 25 + console.log(`${name}: ${ms.toFixed(2)}ms (${opsPerSec} ops/s)`); 26 + } 27 + 28 + const prefHex = BigInt('0xff'); 29 + const prefBin = BigInt('0b1010101010101010'); 30 + const prefOct = BigInt('0o777777'); 31 + const trimmed = BigInt(' 123456789 '); 32 + const literalSeed = 0xffn + 0b1010n + 0o77n + trimmed; 33 + 34 + const a0 = (1n << 260n) + (1n << 129n) + 12345678901234567890123n + literalSeed; 35 + const b0 = (1n << 192n) + (1n << 67n) + 987654321123456789n + prefHex + prefBin; 36 + const c0 = (1n << 73n) + 12345n + prefOct; 37 + 38 + bench('parse prefixed strings x120000', 120000, i => { 39 + const v = BigInt('0xff') + BigInt('0b1011') + BigInt('0o77') + BigInt(' 42 ') + BigInt(''); 40 + mixBig(v + BigInt(i & 31)); 41 + }); 42 + 43 + bench('prefixed literal arith x180000', 180000, i => { 44 + const v = (0xffn << 12n) + 0b101010n + 0o777n + BigInt(i); 45 + mixBig(v ^ literalSeed); 46 + }); 47 + 48 + bench('add/sub x300000', 300000, i => { 49 + const ai = a0 + BigInt(i); 50 + const bi = b0 - BigInt(i); 51 + mixBig(ai + bi - c0); 52 + }); 53 + 54 + bench('mul x70000', 70000, i => { 55 + const x = (a0 + BigInt(i)) * (c0 + BigInt((i & 31) + 1)); 56 + mixBig(x >> 11n); 57 + }); 58 + 59 + bench('div/mod x70000', 70000, i => { 60 + const x = (a0 << 17n) + BigInt(i); 61 + const q = x / c0; 62 + const r = x % c0; 63 + mixBig(q ^ r); 64 + }); 65 + 66 + bench('shift x250000', 250000, i => { 67 + const s1 = BigInt(i & 63); 68 + const s2 = BigInt((i + 7) & 63); 69 + const x = (a0 << s1) >> s2; 70 + mixBig(x); 71 + }); 72 + 73 + bench('toString(10) x4000', 4000, i => { 74 + const s = (a0 + BigInt(i)).toString(10); 75 + mixNum(s.length + s.charCodeAt(0)); 76 + }); 77 + 78 + bench('toString(16) x6000', 6000, i => { 79 + const s = (b0 + BigInt(i)).toString(16); 80 + mixNum(s.length + s.charCodeAt(s.length - 1)); 81 + }); 82 + 83 + bench('toString(2) x1200', 1200, i => { 84 + const s = (c0 << BigInt((i & 255) + 128)).toString(2); 85 + mixNum(s.length); 86 + }); 87 + 88 + bench('asIntN/asUintN x250000', 250000, i => { 89 + const x = a0 + BigInt(i); 90 + const y = BigInt.asIntN(127, x); 91 + const z = BigInt.asUintN(127, -x); 92 + mixBig(y ^ z); 93 + }); 94 + 95 + console.log('sinkBig:', sinkBig.toString(16)); 96 + console.log('sinkNum:', sinkNum); 97 + }
+21
tests/test_bigint.js
··· 41 41 test('BigInt(-5)', BigInt(-5), '-5'); 42 42 test('BigInt("123")', BigInt("123"), '123'); 43 43 test('BigInt("-456")', BigInt("-456"), '-456'); 44 + test('BigInt("0xff")', BigInt("0xff"), '255'); 45 + test('BigInt("0b1010")', BigInt("0b1010"), '10'); 46 + test('BigInt("0o77")', BigInt("0o77"), '63'); 47 + test('BigInt(" 42 ")', BigInt(" 42 "), '42'); 48 + test('BigInt("")', BigInt(""), '0'); 44 49 test('BigInt(true)', BigInt(true), '1'); 45 50 test('BigInt(false)', BigInt(false), '0'); 51 + testThrows('BigInt("0x") throws', () => BigInt("0x"), 'Cannot convert string to BigInt'); 52 + testThrows('BigInt("1_2") throws', () => BigInt("1_2"), 'Cannot convert string to BigInt'); 46 53 47 54 console.log('\n=== BigInt Addition ==='); 55 + test('0xffn + 1n', 0xffn + 1n, '256'); 56 + test('0b1010n + 0o7n', 0b1010n + 0o7n, '17'); 48 57 test('1n + 2n', 1n + 2n, '3'); 49 58 test('100n + 200n', 100n + 200n, '300'); 50 59 test('999999999999999999n + 1n', 999999999999999999n + 1n, '1000000000000000000'); ··· 79 88 test('100n % 7n', 100n % 7n, '2'); 80 89 test('-10n % 3n', -10n % 3n, '-1'); 81 90 test('10n % (-3n)', 10n % (-3n), '1'); 91 + 92 + console.log('\n=== BigInt Bitwise ==='); 93 + test('5n & 3n', 5n & 3n, '1'); 94 + test('5n | 2n', 5n | 2n, '7'); 95 + test('5n ^ 1n', 5n ^ 1n, '4'); 96 + test('~0n', ~0n, '-1'); 97 + test('~(-1n)', ~(-1n), '0'); 98 + test('(-5n) & 3n', (-5n) & 3n, '3'); 99 + test('(-8n) | 3n', (-8n) | 3n, '-5'); 100 + test('(-8n) ^ 3n', (-8n) ^ 3n, '-5'); 101 + test('0xffn ^ 0b1010n', 0xffn ^ 0b1010n, '245'); 102 + testThrows('1n & 1 throws mixed types', () => (1n & 1), 'Cannot mix BigInt value and other types'); 82 103 83 104 console.log('\n=== BigInt Comparison ==='); 84 105 test('5n == 5n', 5n == 5n, true);