From 67a5e9f0184eac51a7451f540845e49dfdc0b34a Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Mon, 31 May 2021 20:27:44 +0300 Subject: [PATCH] LibJS: Add left shift & right shift operator support for BigIntegers Based on https://tc39.es/ecma262/#sec-numeric-types-bigint-leftShift (This commit also includes the matching tests) --- Userland/Libraries/LibJS/Runtime/Value.cpp | 16 ++++++++++++---- .../LibJS/Tests/builtins/BigInt/bigint-basic.js | 2 ++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp index 98a8c0eec2..62e7c9d19d 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.cpp +++ b/Userland/Libraries/LibJS/Runtime/Value.cpp @@ -787,8 +787,13 @@ Value left_shift(GlobalObject& global_object, Value lhs, Value rhs) auto rhs_u32 = rhs_numeric.to_u32(global_object); return Value(lhs_i32 << rhs_u32); } - if (both_bigint(lhs_numeric, rhs_numeric)) - TODO(); + if (both_bigint(lhs_numeric, rhs_numeric)) { + auto multiplier_divisor = Crypto::SignedBigInteger { Crypto::NumberTheory::Power(Crypto::UnsignedBigInteger(2), rhs_numeric.as_bigint().big_integer().unsigned_value()) }; + if (rhs_numeric.as_bigint().big_integer().is_negative()) + return js_bigint(global_object.heap(), lhs_numeric.as_bigint().big_integer().divided_by(multiplier_divisor).quotient); + else + return js_bigint(global_object.heap(), lhs_numeric.as_bigint().big_integer().multiplied_by(multiplier_divisor)); + } global_object.vm().throw_exception(global_object, ErrorType::BigIntBadOperatorOtherType, "left-shift"); return {}; } @@ -813,8 +818,11 @@ Value right_shift(GlobalObject& global_object, Value lhs, Value rhs) auto rhs_u32 = rhs_numeric.to_u32(global_object); return Value(lhs_i32 >> rhs_u32); } - if (both_bigint(lhs_numeric, rhs_numeric)) - TODO(); + if (both_bigint(lhs_numeric, rhs_numeric)) { + auto rhs_negated = rhs_numeric.as_bigint().big_integer(); + rhs_negated.negate(); + return left_shift(global_object, lhs, js_bigint(global_object.heap(), rhs_negated)); + } global_object.vm().throw_exception(global_object, ErrorType::BigIntBadOperatorOtherType, "right-shift"); return {}; } diff --git a/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js b/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js index eb957020bf..426f92dc62 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js +++ b/Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js @@ -28,6 +28,8 @@ describe("correct behavior", () => { expect(1n | 2n).toBe(3n); expect(5n ^ 3n).toBe(6n); expect(~1n).toBe(-2n); + expect(5n << 2n).toBe(20n); + expect(7n >> 1n).toBe(3n); }); test("increment operators", () => {