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.

implement BigInt bitwise shift operations

+109 -13
+109 -13
src/ant.c
··· 2356 2356 return mkval(T_STR, ofs); 2357 2357 } 2358 2358 2359 + static bool bigint_parse_abs_u64(struct js *js, jsval_t value, uint64_t *out) { 2360 + size_t len = 0; const char *digits = bigint_digits(js, value, &len); 2361 + uint64_t acc = 0; 2362 + 2363 + for (size_t i = 0; i < len; i++) { 2364 + char c = digits[i]; 2365 + if (!is_digit(c)) return false; 2366 + uint64_t digit = (uint64_t)(c - '0'); 2367 + if (acc > UINT64_MAX / 10 || (acc == UINT64_MAX / 10 && digit > (UINT64_MAX % 10))) { 2368 + return false; 2369 + } acc = acc * 10 + digit; 2370 + } 2371 + 2372 + *out = acc; 2373 + return true; 2374 + } 2375 + 2376 + static bool bigint_IsNegative(struct js *js, jsval_t v) { 2377 + jsoff_t ofs = (jsoff_t) vdata(v); 2378 + return js->mem[ofs + sizeof(jsoff_t)] == 1; 2379 + } 2380 + 2381 + static bool bigint_parse_u64(struct js *js, jsval_t value, uint64_t *out) { 2382 + if (bigint_IsNegative(js, value)) return false; 2383 + return bigint_parse_abs_u64(js, value, out); 2384 + } 2385 + 2359 2386 jsval_t js_mkbigint(struct js *js, const char *digits, size_t len, bool negative) { 2360 2387 size_t total = len + 2; 2361 2388 jsoff_t ofs = js_alloc(js, total + sizeof(jsoff_t)); ··· 2366 2393 if (digits) memcpy(&js->mem[ofs + sizeof(header) + 1], digits, len); 2367 2394 js->mem[ofs + sizeof(header) + 1 + len] = 0; 2368 2395 return mkval(T_BIGINT, ofs); 2369 - } 2370 - 2371 - static bool bigint_IsNegative(struct js *js, jsval_t v) { 2372 - jsoff_t ofs = (jsoff_t) vdata(v); 2373 - return js->mem[ofs + sizeof(jsoff_t)] == 1; 2374 2396 } 2375 2397 2376 2398 static const char *bigint_digits(struct js *js, jsval_t v, size_t *len) { ··· 2604 2626 return result; 2605 2627 } 2606 2628 2629 + static inline jsval_t bigint_pow2(struct js *js, uint64_t bits) { 2630 + jsval_t two = js_mkbigint(js, "2", 1, false); 2631 + if (is_err(two)) return two; 2632 + jsval_t exp = bigint_from_u64(js, bits); 2633 + if (is_err(exp)) return exp; 2634 + return bigint_exp(js, two, exp); 2635 + } 2636 + 2637 + static jsval_t bigint_shift_left(struct js *js, jsval_t value, uint64_t shift) { 2638 + if (shift == 0) return value; 2639 + if (shift > 18446744073709551615ULL) return js_mkerr(js, "Shift count too large"); 2640 + 2641 + size_t digits_len; const char *digits = bigint_digits(js, value, &digits_len); 2642 + if (digits_len == 1 && digits[0] == '0') return js_mkbigint(js, "0", 1, false); 2643 + uint64_t u64 = 0; 2644 + if (!bigint_IsNegative(js, value) && shift < 64 && bigint_parse_u64(js, value, &u64)) { 2645 + if (u64 <= (UINT64_MAX >> shift)) return bigint_from_u64(js, u64 << shift); 2646 + } 2647 + 2648 + jsval_t pow = bigint_pow2(js, shift); 2649 + if (is_err(pow)) return pow; 2650 + return bigint_mul(js, value, pow); 2651 + } 2652 + 2653 + static jsval_t bigint_shift_right(struct js *js, jsval_t value, uint64_t shift) { 2654 + if (shift == 0) return value; 2655 + if (shift > 18446744073709551615ULL) return js_mkerr(js, "Shift count too large"); 2656 + 2657 + size_t digits_len; const char *digits = bigint_digits(js, value, &digits_len); 2658 + if (digits_len == 1 && digits[0] == '0') return js_mkbigint(js, "0", 1, false); 2659 + uint64_t u64 = 0; 2660 + if (!bigint_IsNegative(js, value) && bigint_parse_u64(js, value, &u64)) { 2661 + if (shift >= 64) return js_mkbigint(js, "0", 1, false); 2662 + return bigint_from_u64(js, u64 >> shift); 2663 + } 2664 + 2665 + if (bigint_parse_abs_u64(js, value, &u64)) { 2666 + if (shift >= 64) return js_mkbigint( 2667 + js, bigint_IsNegative(js, value) ? "1" : "0", 1, 2668 + bigint_IsNegative(js, value) 2669 + ); 2670 + uint64_t shifted = u64 >> shift; 2671 + if (bigint_IsNegative(js, value)) { 2672 + if ((u64 & ((1ULL << shift) - 1)) != 0) shifted += 1; 2673 + jsval_t pos = bigint_from_u64(js, shifted); 2674 + if (is_err(pos)) return pos; 2675 + return bigint_neg(js, pos); 2676 + } 2677 + return bigint_from_u64(js, shifted); 2678 + } 2679 + 2680 + jsval_t pow = bigint_pow2(js, shift); 2681 + if (is_err(pow)) return pow; 2682 + return bigint_div(js, value, pow); 2683 + } 2684 + 2685 + static inline jsval_t bigint_shift_right_logical(struct js *js, jsval_t value, uint64_t shift) { 2686 + return js_mkerr_typed(js, JS_ERR_TYPE, "BigInts have no unsigned right shift, use >> instead"); 2687 + } 2688 + 2607 2689 static int bigint_compare(struct js *js, jsval_t a, jsval_t b) { 2608 2690 bool aneg = bigint_IsNegative(js, a), bneg = bigint_IsNegative(js, b); 2609 2691 size_t alen, blen; ··· 2666 2748 return js_mkerr(js, "Cannot convert to BigInt"); 2667 2749 } 2668 2750 2669 - static jsval_t bigint_pow2(struct js *js, uint64_t bits) { 2670 - jsval_t two = js_mkbigint(js, "2", 1, false); 2671 - if (is_err(two)) return two; 2672 - jsval_t exp = bigint_from_u64(js, bits); 2673 - if (is_err(exp)) return exp; 2674 - return bigint_exp(js, two, exp); 2751 + static jsval_t bigint_to_u64(struct js *js, jsval_t value, uint64_t *out) { 2752 + if (!bigint_parse_u64(js, value, out)) { 2753 + return js_mkerr_typed(js, JS_ERR_RANGE, "Invalid bits"); 2754 + } 2755 + return js_mkundef(); 2675 2756 } 2676 2757 2677 2758 static jsval_t bigint_asint_bits(struct js *js, jsval_t arg, uint64_t *bits_out) { 2759 + if (vtype(arg) == T_BIGINT) { 2760 + return bigint_to_u64(js, arg, bits_out); 2761 + } 2678 2762 double bits = js_to_number(js, arg); 2679 2763 if (!isfinite(bits) || bits < 0 || bits != floor(bits)) { 2680 2764 return js_mkerr_typed(js, JS_ERR_RANGE, "Invalid bits"); ··· 7473 7557 L_TOK_SHR: 7474 7558 L_TOK_ZSHR: { 7475 7559 uint8_t lt = vtype(l), rtype = vtype(r); 7476 - if (lt == T_BIGINT || rtype == T_BIGINT) 7477 - return js_mkerr(js, "Cannot mix BigInt value and other types"); 7560 + if (lt == T_BIGINT || rtype == T_BIGINT) { 7561 + if (lt != T_BIGINT || rtype != T_BIGINT) 7562 + return js_mkerr(js, "Cannot mix BigInt value and other types"); 7563 + if (op == TOK_AND || op == TOK_OR || op == TOK_XOR) 7564 + return js_mkerr_typed(js, JS_ERR_TYPE, "BigInt does not support bitwise ops"); 7565 + uint64_t shift = 0; 7566 + jsval_t shift_err = bigint_asint_bits(js, r, &shift); 7567 + if (is_err(shift_err)) return shift_err; 7568 + switch (op) { 7569 + case TOK_SHL: return bigint_shift_left(js, l, shift); 7570 + case TOK_SHR: return bigint_shift_right(js, l, shift); 7571 + case TOK_ZSHR: return bigint_shift_right_logical(js, l, shift); 7572 + } 7573 + } 7478 7574 int32_t ai = (lt == T_NUM) ? js_to_int32(tod(l)) : js_to_int32(js_to_number(js, l)); 7479 7575 uint32_t bi = (rtype == T_NUM) ? js_to_uint32(tod(r)) : js_to_uint32(js_to_number(js, r)); 7480 7576 switch (op) {