number.tq 2.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
// Copyright 2019 the V8 project authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.

namespace runtime {
  extern transitioning runtime
  DoubleToStringWithRadix(implicit context: Context)(Number, Number): String;
}  // namespace runtime

namespace number {
  const kToRadixFormatRange: constexpr MessageTemplate
  generates 'MessageTemplate::kToRadixFormatRange';

  extern macro NaNStringConstant(): String;
  extern macro ZeroStringConstant(): String;
  extern macro InfinityStringConstant(): String;
  extern macro MinusInfinityStringConstant(): String;

  const kAsciiZero: constexpr int32 = 48;        // '0' (ascii)
  const kAsciiLowerCaseA: constexpr int32 = 97;  // 'a' (ascii)

  transitioning macro ThisNumberValue(implicit context: Context)(
      receiver: JSAny, method: constexpr string): Number {
    return UnsafeCast<Number>(ToThisValue(receiver, kNumber, method));
  }

  // https://tc39.github.io/ecma262/#sec-number.prototype.tostring
  transitioning javascript builtin NumberPrototypeToString(
29 30
      js-implicit context: NativeContext,
      receiver: JSAny)(...arguments): String {
31 32 33 34 35 36 37
    // 1. Let x be ? thisNumberValue(this value).
    const x = ThisNumberValue(receiver, 'Number.prototype.toString');

    // 2. If radix is not present, let radixNumber be 10.
    // 3. Else if radix is undefined, let radixNumber be 10.
    // 4. Else, let radixNumber be ? ToInteger(radix).
    const radix: JSAny = arguments[0];
38 39
    const radixNumber: Number =
        radix == Undefined ? 10 : ToInteger_Inline(radix, kTruncateMinusZero);
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

    // 5. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
    if (radixNumber < 2 || radixNumber > 36) {
      ThrowRangeError(kToRadixFormatRange);
    }

    // 6. If radixNumber = 10, return ! ToString(x).
    if (radixNumber == 10) {
      return NumberToString(x);
    }

    // 7. Return the String representation of this Number
    //    value using the radix specified by radixNumber.

    // Fast case where the result is a one character string.
    if (TaggedIsPositiveSmi(x) && x < radixNumber) {
      let charCode = Convert<int32>(UnsafeCast<Smi>(x));
      if (charCode < 10) {
        charCode += kAsciiZero;
      } else {
        charCode = charCode - 10 + kAsciiLowerCaseA;
      }
      return StringFromSingleCharCode(charCode);
    }

    if (x == -0) {
      return ZeroStringConstant();
    } else if (NumberIsNaN(x)) {
      return NaNStringConstant();
    } else if (x == V8_INFINITY) {
      return InfinityStringConstant();
    } else if (x == MINUS_V8_INFINITY) {
      return MinusInfinityStringConstant();
    }

    return runtime::DoubleToStringWithRadix(x, radixNumber);
  }
}