Przeglądaj źródła

LibJS: Add spec comments to exp{,_double}()

Linus Groh 2 lat temu
rodzic
commit
d74ce90e74
1 zmienionych plików z 77 dodań i 9 usunięć
  1. 77 9
      Userland/Libraries/LibJS/Runtime/Value.cpp

+ 77 - 9
Userland/Libraries/LibJS/Runtime/Value.cpp

@@ -1875,69 +1875,137 @@ ThrowCompletionOr<Value> mod(VM& vm, Value lhs, Value rhs)
     return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "modulo");
     return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "modulo");
 }
 }
 
 
+// 6.1.6.1.3 Number::exponentiate ( base, exponent ), https://tc39.es/ecma262/#sec-numeric-types-number-exponentiate
 static Value exp_double(Value base, Value exponent)
 static Value exp_double(Value base, Value exponent)
 {
 {
     VERIFY(both_number(base, exponent));
     VERIFY(both_number(base, exponent));
+
+    // 1. If exponent is NaN, return NaN.
     if (exponent.is_nan())
     if (exponent.is_nan())
         return js_nan();
         return js_nan();
+
+    // 2. If exponent is +0𝔽 or exponent is -0𝔽, return 1𝔽.
     if (exponent.is_positive_zero() || exponent.is_negative_zero())
     if (exponent.is_positive_zero() || exponent.is_negative_zero())
         return Value(1);
         return Value(1);
+
+    // 3. If base is NaN, return NaN.
     if (base.is_nan())
     if (base.is_nan())
         return js_nan();
         return js_nan();
-    if (base.is_positive_infinity())
+
+    // 4. If base is +∞𝔽, then
+    if (base.is_positive_infinity()) {
+        // a. If exponent > +0𝔽, return +∞𝔽. Otherwise, return +0𝔽.
         return exponent.as_double() > 0 ? js_infinity() : Value(0);
         return exponent.as_double() > 0 ? js_infinity() : Value(0);
+    }
+
+    // 5. If base is -∞𝔽, then
     if (base.is_negative_infinity()) {
     if (base.is_negative_infinity()) {
         auto is_odd_integral_number = exponent.is_integral_number() && (static_cast<i32>(exponent.as_double()) % 2 != 0);
         auto is_odd_integral_number = exponent.is_integral_number() && (static_cast<i32>(exponent.as_double()) % 2 != 0);
-        if (exponent.as_double() > 0)
+
+        // a. If exponent > +0𝔽, then
+        if (exponent.as_double() > 0) {
+            // i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽.
             return is_odd_integral_number ? js_negative_infinity() : js_infinity();
             return is_odd_integral_number ? js_negative_infinity() : js_infinity();
-        else
+        }
+        // b. Else,
+        else {
+            // i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽.
             return is_odd_integral_number ? Value(-0.0) : Value(0);
             return is_odd_integral_number ? Value(-0.0) : Value(0);
+        }
     }
     }
-    if (base.is_positive_zero())
+
+    // 6. If base is +0𝔽, then
+    if (base.is_positive_zero()) {
+        // a. If exponent > +0𝔽, return +0𝔽. Otherwise, return +∞𝔽.
         return exponent.as_double() > 0 ? Value(0) : js_infinity();
         return exponent.as_double() > 0 ? Value(0) : js_infinity();
+    }
+
+    // 7. If base is -0𝔽, then
     if (base.is_negative_zero()) {
     if (base.is_negative_zero()) {
         auto is_odd_integral_number = exponent.is_integral_number() && (static_cast<i32>(exponent.as_double()) % 2 != 0);
         auto is_odd_integral_number = exponent.is_integral_number() && (static_cast<i32>(exponent.as_double()) % 2 != 0);
-        if (exponent.as_double() > 0)
+
+        // a. If exponent > +0𝔽, then
+        if (exponent.as_double() > 0) {
+            // i. If exponent is an odd integral Number, return -0𝔽. Otherwise, return +0𝔽.
             return is_odd_integral_number ? Value(-0.0) : Value(0);
             return is_odd_integral_number ? Value(-0.0) : Value(0);
-        else
+        }
+        // b. Else,
+        else {
+            // i. If exponent is an odd integral Number, return -∞𝔽. Otherwise, return +∞𝔽.
             return is_odd_integral_number ? js_negative_infinity() : js_infinity();
             return is_odd_integral_number ? js_negative_infinity() : js_infinity();
+        }
     }
     }
+
+    // 8. Assert: base is finite and is neither +0𝔽 nor -0𝔽.
     VERIFY(base.is_finite_number() && !base.is_positive_zero() && !base.is_negative_zero());
     VERIFY(base.is_finite_number() && !base.is_positive_zero() && !base.is_negative_zero());
+
+    // 9. If exponent is +∞𝔽, then
     if (exponent.is_positive_infinity()) {
     if (exponent.is_positive_infinity()) {
         auto absolute_base = fabs(base.as_double());
         auto absolute_base = fabs(base.as_double());
+
+        // a. If abs(ℝ(base)) > 1, return +∞𝔽.
         if (absolute_base > 1)
         if (absolute_base > 1)
             return js_infinity();
             return js_infinity();
+        // b. If abs(ℝ(base)) is 1, return NaN.
         else if (absolute_base == 1)
         else if (absolute_base == 1)
             return js_nan();
             return js_nan();
+        // c. If abs(ℝ(base)) < 1, return +0𝔽.
         else if (absolute_base < 1)
         else if (absolute_base < 1)
             return Value(0);
             return Value(0);
     }
     }
+
+    // 10. If exponent is -∞𝔽, then
     if (exponent.is_negative_infinity()) {
     if (exponent.is_negative_infinity()) {
         auto absolute_base = fabs(base.as_double());
         auto absolute_base = fabs(base.as_double());
+
+        // a. If abs(ℝ(base)) > 1, return +0𝔽.
         if (absolute_base > 1)
         if (absolute_base > 1)
             return Value(0);
             return Value(0);
+        // b. If abs(ℝ(base)) is 1, return NaN.
         else if (absolute_base == 1)
         else if (absolute_base == 1)
             return js_nan();
             return js_nan();
+        // a. If abs(ℝ(base)) > 1, return +0𝔽.
         else if (absolute_base < 1)
         else if (absolute_base < 1)
             return js_infinity();
             return js_infinity();
     }
     }
+
+    // 11. Assert: exponent is finite and is neither +0𝔽 nor -0𝔽.
     VERIFY(exponent.is_finite_number() && !exponent.is_positive_zero() && !exponent.is_negative_zero());
     VERIFY(exponent.is_finite_number() && !exponent.is_positive_zero() && !exponent.is_negative_zero());
+
+    // 12. If base < -0𝔽 and exponent is not an integral Number, return NaN.
     if (base.as_double() < 0 && !exponent.is_integral_number())
     if (base.as_double() < 0 && !exponent.is_integral_number())
         return js_nan();
         return js_nan();
+
+    // 13. Return an implementation-approximated Number value representing the result of raising ℝ(base) to the ℝ(exponent) power.
     return Value(::pow(base.as_double(), exponent.as_double()));
     return Value(::pow(base.as_double(), exponent.as_double()));
 }
 }
 
 
 // 13.6 Exponentiation Operator, https://tc39.es/ecma262/#sec-exp-operator
 // 13.6 Exponentiation Operator, https://tc39.es/ecma262/#sec-exp-operator
+// ExponentiationExpression : UpdateExpression ** ExponentiationExpression
 ThrowCompletionOr<Value> exp(VM& vm, Value lhs, Value rhs)
 ThrowCompletionOr<Value> exp(VM& vm, Value lhs, Value rhs)
 {
 {
+    // 3. Let lnum be ? ToNumeric(lval).
     auto lhs_numeric = TRY(lhs.to_numeric(vm));
     auto lhs_numeric = TRY(lhs.to_numeric(vm));
+
+    // 4. Let rnum be ? ToNumeric(rval).
     auto rhs_numeric = TRY(rhs.to_numeric(vm));
     auto rhs_numeric = TRY(rhs.to_numeric(vm));
-    if (both_number(lhs_numeric, rhs_numeric))
+
+    // 7. Let operation be the abstract operation associated with opText and Type(lnum) in the following table:
+    // [...]
+    // 8. Return operation(lnum, rnum).
+    if (both_number(lhs_numeric, rhs_numeric)) {
         return exp_double(lhs_numeric, rhs_numeric);
         return exp_double(lhs_numeric, rhs_numeric);
+    }
     if (both_bigint(lhs_numeric, rhs_numeric)) {
     if (both_bigint(lhs_numeric, rhs_numeric)) {
-        if (rhs_numeric.as_bigint().big_integer().is_negative())
+        // 6.1.6.2.3 BigInt::exponentiate ( base, exponent ), https://tc39.es/ecma262/#sec-numeric-types-bigint-exponentiate
+        auto base = lhs_numeric.as_bigint().big_integer();
+        auto exponent = rhs_numeric.as_bigint().big_integer();
+        // 1. If exponent < 0ℤ, throw a RangeError exception.
+        if (exponent.is_negative())
             return vm.throw_completion<RangeError>(ErrorType::NegativeExponent);
             return vm.throw_completion<RangeError>(ErrorType::NegativeExponent);
-        return BigInt::create(vm, Crypto::NumberTheory::Power(lhs_numeric.as_bigint().big_integer(), rhs_numeric.as_bigint().big_integer()));
+        // 2. If base is 0ℤ and exponent is 0ℤ, return 1ℤ.
+        // 3. Return the BigInt value that represents ℝ(base) raised to the power ℝ(exponent).
+        return BigInt::create(vm, Crypto::NumberTheory::Power(base, exponent));
     }
     }
     return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "exponentiation");
     return vm.throw_completion<TypeError>(ErrorType::BigIntBadOperatorOtherType, "exponentiation");
 }
 }