浏览代码

LibJS: Implement BigInt IsLessThan according to the spec

Timothy Flynn 3 年之前
父节点
当前提交
02b7bf34c9

+ 10 - 18
Userland/Libraries/LibJS/Runtime/Value.cpp

@@ -48,14 +48,6 @@ static inline bool same_type_for_equality(const Value& lhs, const Value& rhs)
 
 
 static const Crypto::SignedBigInteger BIGINT_ZERO { 0 };
 static const Crypto::SignedBigInteger BIGINT_ZERO { 0 };
 
 
-static bool is_valid_bigint_value(StringView string)
-{
-    string = string.trim_whitespace();
-    if (string.length() > 1 && (string[0] == '-' || string[0] == '+'))
-        string = string.substring_view(1, string.length() - 1);
-    return all_of(string, [](auto ch) { return isdigit(ch); });
-}
-
 ALWAYS_INLINE bool both_number(const Value& lhs, const Value& rhs)
 ALWAYS_INLINE bool both_number(const Value& lhs, const Value& rhs)
 {
 {
     return lhs.is_number() && rhs.is_number();
     return lhs.is_number() && rhs.is_number();
@@ -1513,23 +1505,23 @@ ThrowCompletionOr<TriState> is_less_than(GlobalObject& global_object, bool left_
     }
     }
 
 
     if (x_primitive.is_bigint() && y_primitive.is_string()) {
     if (x_primitive.is_bigint() && y_primitive.is_string()) {
-        auto& y_string = y_primitive.as_string().string();
-        if (!is_valid_bigint_value(y_string))
+        auto y_bigint = y_primitive.string_to_bigint(global_object);
+        if (!y_bigint.has_value())
             return TriState::Unknown;
             return TriState::Unknown;
-        if (x_primitive.as_bigint().big_integer() < Crypto::SignedBigInteger::from_base(10, y_string))
+
+        if (x_primitive.as_bigint().big_integer() < (*y_bigint)->big_integer())
             return TriState::True;
             return TriState::True;
-        else
-            return TriState::False;
+        return TriState::False;
     }
     }
 
 
     if (x_primitive.is_string() && y_primitive.is_bigint()) {
     if (x_primitive.is_string() && y_primitive.is_bigint()) {
-        auto& x_string = x_primitive.as_string().string();
-        if (!is_valid_bigint_value(x_string))
+        auto x_bigint = x_primitive.string_to_bigint(global_object);
+        if (!x_bigint.has_value())
             return TriState::Unknown;
             return TriState::Unknown;
-        if (Crypto::SignedBigInteger::from_base(10, x_string) < y_primitive.as_bigint().big_integer())
+
+        if ((*x_bigint)->big_integer() < y_primitive.as_bigint().big_integer())
             return TriState::True;
             return TriState::True;
-        else
-            return TriState::False;
+        return TriState::False;
     }
     }
 
 
     auto x_numeric = TRY(x_primitive.to_numeric(global_object));
     auto x_numeric = TRY(x_primitive.to_numeric(global_object));

+ 64 - 0
Userland/Libraries/LibJS/Tests/builtins/BigInt/bigint-basic.js

@@ -129,6 +129,70 @@ describe("correct behavior", () => {
         expect(a === a).toBeTrue();
         expect(a === a).toBeTrue();
         expect(a === b).toBeFalse();
         expect(a === b).toBeFalse();
     });
     });
+
+    test("less-than operators", () => {
+        expect(1n < 1n).toBeFalse();
+        expect(1n < 1).toBeFalse();
+        expect(1 < 1n).toBeFalse();
+        expect(1n < 2n).toBeTrue();
+        expect(1n < 2).toBeTrue();
+        expect(1 < 2n).toBeTrue();
+        expect(1n < 1.23).toBeTrue();
+        expect(1.23 < 1n).toBeFalse();
+
+        expect(1n <= 1n).toBeTrue();
+        expect(1n <= 1).toBeTrue();
+        expect(1 <= 1n).toBeTrue();
+        expect(1n <= 2n).toBeTrue();
+        expect(1n <= 2).toBeTrue();
+        expect(1 <= 2n).toBeTrue();
+        expect(1n <= 1.23).toBeTrue();
+        expect(1.23 <= 1n).toBeFalse();
+
+        expect(1n < "1").toBeFalse();
+        expect(1n < "2").toBeTrue();
+        expect(1n < "1.23").toBeFalse();
+
+        expect(1n <= "1").toBeTrue();
+        expect(1n <= "2").toBeTrue();
+        expect(1n <= "1.23").toBeFalse();
+
+        expect(1n < "0b1").toBeFalse();
+        expect(1n < "0B10").toBeTrue();
+        expect(1n < "0o1").toBeFalse();
+        expect(1n < "0O2").toBeTrue();
+        expect(1n < "0x1").toBeFalse();
+        expect(1n < "0X2").toBeTrue();
+
+        expect(1n <= "0b1").toBeTrue();
+        expect(1n <= "0B10").toBeTrue();
+        expect(1n <= "0o1").toBeTrue();
+        expect(1n <= "0O2").toBeTrue();
+        expect(1n <= "0x1").toBeTrue();
+        expect(1n <= "0X2").toBeTrue();
+
+        expect("1" < 1n).toBeFalse();
+        expect("1" < 2n).toBeTrue();
+        expect("1.23" < 1n).toBeFalse();
+
+        expect("1" <= 1n).toBeTrue();
+        expect("1" <= 2n).toBeTrue();
+        expect("1.23" <= 1n).toBeFalse();
+
+        expect("0b1" < 1n).toBeFalse();
+        expect("0B1" < 2n).toBeTrue();
+        expect("0o1" < 1n).toBeFalse();
+        expect("0O1" < 2n).toBeTrue();
+        expect("0x1" < 1n).toBeFalse();
+        expect("0X1" < 2n).toBeTrue();
+
+        expect("0b1" <= 1n).toBeTrue();
+        expect("0B10" <= 2n).toBeTrue();
+        expect("0o1" <= 1n).toBeTrue();
+        expect("0O2" <= 2n).toBeTrue();
+        expect("0x1" <= 1n).toBeTrue();
+        expect("0X2" <= 2n).toBeTrue();
+    });
 });
 });
 
 
 describe("errors", () => {
 describe("errors", () => {