1// Copyright 2019 the V8 project authors. All rights reserved. Use of this
2// source code is governed by a BSD-style license that can be found in the
3// LICENSE file.
4
5namespace runtime {
6  extern transitioning runtime
7  DoubleToStringWithRadix(implicit context: Context)(Number, Number): String;
8}  // namespace runtime
9
10namespace number {
11  extern macro NaNStringConstant(): String;
12  extern macro ZeroStringConstant(): String;
13  extern macro InfinityStringConstant(): String;
14  extern macro MinusInfinityStringConstant(): String;
15
16  const kAsciiZero: constexpr int32 = 48;        // '0' (ascii)
17  const kAsciiLowerCaseA: constexpr int32 = 97;  // 'a' (ascii)
18
19  transitioning macro ThisNumberValue(implicit context: Context)(
20      receiver: JSAny, method: constexpr string): Number {
21    return UnsafeCast<Number>(
22        ToThisValue(receiver, PrimitiveType::kNumber, method));
23  }
24
25  // https://tc39.github.io/ecma262/#sec-number.prototype.tostring
26  transitioning javascript builtin NumberPrototypeToString(
27      js-implicit context: NativeContext,
28      receiver: JSAny)(...arguments): String {
29    // 1. Let x be ? thisNumberValue(this value).
30    const x = ThisNumberValue(receiver, 'Number.prototype.toString');
31
32    // 2. If radix is not present, let radixNumber be 10.
33    // 3. Else if radix is undefined, let radixNumber be 10.
34    // 4. Else, let radixNumber be ? ToInteger(radix).
35    const radix: JSAny = arguments[0];
36    const radixNumber: Number =
37        radix == Undefined ? 10 : ToInteger_Inline(radix);
38
39    // 5. If radixNumber < 2 or radixNumber > 36, throw a RangeError exception.
40    if (radixNumber < 2 || radixNumber > 36) {
41      ThrowRangeError(MessageTemplate::kToRadixFormatRange);
42    }
43
44    // 6. If radixNumber = 10, return ! ToString(x).
45    if (radixNumber == 10) {
46      return NumberToString(x);
47    }
48
49    // 7. Return the String representation of this Number
50    //    value using the radix specified by radixNumber.
51
52    // Fast case where the result is a one character string.
53    if (TaggedIsPositiveSmi(x) && x < radixNumber) {
54      let charCode = Convert<int32>(UnsafeCast<Smi>(x));
55      if (charCode < 10) {
56        charCode += kAsciiZero;
57      } else {
58        charCode = charCode - 10 + kAsciiLowerCaseA;
59      }
60      return StringFromSingleCharCode(charCode);
61    }
62
63    if (x == -0) {
64      return ZeroStringConstant();
65    } else if (NumberIsNaN(x)) {
66      return NaNStringConstant();
67    } else if (x == V8_INFINITY) {
68      return InfinityStringConstant();
69    } else if (x == MINUS_V8_INFINITY) {
70      return MinusInfinityStringConstant();
71    }
72
73    return runtime::DoubleToStringWithRadix(x, radixNumber);
74  }
75}
76