V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
builtins-number.cc
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/builtins/builtins-utils-inl.h"
6 #include "src/builtins/builtins.h"
7 #include "src/code-factory.h"
8 #include "src/conversions.h"
9 #include "src/counters.h"
10 #include "src/objects-inl.h"
11 #ifdef V8_INTL_SUPPORT
12 #include "src/objects/intl-objects.h"
13 #endif
14 
15 namespace v8 {
16 namespace internal {
17 
18 // -----------------------------------------------------------------------------
19 // ES6 section 20.1 Number Objects
20 
21 // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits )
22 BUILTIN(NumberPrototypeToExponential) {
23  HandleScope scope(isolate);
24  Handle<Object> value = args.at(0);
25  Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1);
26 
27  // Unwrap the receiver {value}.
28  if (value->IsJSValue()) {
29  value = handle(Handle<JSValue>::cast(value)->value(), isolate);
30  }
31  if (!value->IsNumber()) {
32  THROW_NEW_ERROR_RETURN_FAILURE(
33  isolate, NewTypeError(MessageTemplate::kNotGeneric,
34  isolate->factory()->NewStringFromAsciiChecked(
35  "Number.prototype.toExponential"),
36  isolate->factory()->Number_string()));
37  }
38  double const value_number = value->Number();
39 
40  // Convert the {fraction_digits} to an integer first.
41  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
42  isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits));
43  double const fraction_digits_number = fraction_digits->Number();
44 
45  if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
46  if (std::isinf(value_number)) {
47  return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
48  : ReadOnlyRoots(isolate).Infinity_string();
49  }
50  if (fraction_digits_number < 0.0 ||
51  fraction_digits_number > kMaxFractionDigits) {
52  THROW_NEW_ERROR_RETURN_FAILURE(
53  isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
54  isolate->factory()->NewStringFromAsciiChecked(
55  "toExponential()")));
56  }
57  int const f = args.atOrUndefined(isolate, 1)->IsUndefined(isolate)
58  ? -1
59  : static_cast<int>(fraction_digits_number);
60  char* const str = DoubleToExponentialCString(value_number, f);
61  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
62  DeleteArray(str);
63  return *result;
64 }
65 
66 // ES6 section 20.1.3.3 Number.prototype.toFixed ( fractionDigits )
67 BUILTIN(NumberPrototypeToFixed) {
68  HandleScope scope(isolate);
69  Handle<Object> value = args.at(0);
70  Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1);
71 
72  // Unwrap the receiver {value}.
73  if (value->IsJSValue()) {
74  value = handle(Handle<JSValue>::cast(value)->value(), isolate);
75  }
76  if (!value->IsNumber()) {
77  THROW_NEW_ERROR_RETURN_FAILURE(
78  isolate, NewTypeError(MessageTemplate::kNotGeneric,
79  isolate->factory()->NewStringFromAsciiChecked(
80  "Number.prototype.toFixed"),
81  isolate->factory()->Number_string()));
82  }
83  double const value_number = value->Number();
84 
85  // Convert the {fraction_digits} to an integer first.
86  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
87  isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits));
88  double const fraction_digits_number = fraction_digits->Number();
89 
90  // Check if the {fraction_digits} are in the supported range.
91  if (fraction_digits_number < 0.0 ||
92  fraction_digits_number > kMaxFractionDigits) {
93  THROW_NEW_ERROR_RETURN_FAILURE(
94  isolate, NewRangeError(MessageTemplate::kNumberFormatRange,
95  isolate->factory()->NewStringFromAsciiChecked(
96  "toFixed() digits")));
97  }
98 
99  if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
100  if (std::isinf(value_number)) {
101  return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
102  : ReadOnlyRoots(isolate).Infinity_string();
103  }
104  char* const str = DoubleToFixedCString(
105  value_number, static_cast<int>(fraction_digits_number));
106  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
107  DeleteArray(str);
108  return *result;
109 }
110 
111 // ES6 section 20.1.3.4 Number.prototype.toLocaleString ( [ r1 [ , r2 ] ] )
112 BUILTIN(NumberPrototypeToLocaleString) {
113  HandleScope scope(isolate);
114 
115  isolate->CountUsage(v8::Isolate::UseCounterFeature::kNumberToLocaleString);
116 
117  Handle<Object> value = args.at(0);
118 
119  // Unwrap the receiver {value}.
120  if (value->IsJSValue()) {
121  value = handle(Handle<JSValue>::cast(value)->value(), isolate);
122  }
123  // 1. Let x be ? thisNumberValue(this value)
124  if (!value->IsNumber()) {
125  THROW_NEW_ERROR_RETURN_FAILURE(
126  isolate, NewTypeError(MessageTemplate::kNotGeneric,
127  isolate->factory()->NewStringFromAsciiChecked(
128  "Number.prototype.toLocaleString"),
129  isolate->factory()->Number_string()));
130  }
131 
132 #ifdef V8_INTL_SUPPORT
133  RETURN_RESULT_OR_FAILURE(
134  isolate,
135  Intl::NumberToLocaleString(isolate, value, args.atOrUndefined(isolate, 1),
136  args.atOrUndefined(isolate, 2)));
137 #else
138  // Turn the {value} into a String.
139  return *isolate->factory()->NumberToString(value);
140 #endif // V8_INTL_SUPPORT
141 }
142 
143 // ES6 section 20.1.3.5 Number.prototype.toPrecision ( precision )
144 BUILTIN(NumberPrototypeToPrecision) {
145  HandleScope scope(isolate);
146  Handle<Object> value = args.at(0);
147  Handle<Object> precision = args.atOrUndefined(isolate, 1);
148 
149  // Unwrap the receiver {value}.
150  if (value->IsJSValue()) {
151  value = handle(Handle<JSValue>::cast(value)->value(), isolate);
152  }
153  if (!value->IsNumber()) {
154  THROW_NEW_ERROR_RETURN_FAILURE(
155  isolate, NewTypeError(MessageTemplate::kNotGeneric,
156  isolate->factory()->NewStringFromAsciiChecked(
157  "Number.prototype.toPrecision"),
158  isolate->factory()->Number_string()));
159  }
160  double const value_number = value->Number();
161 
162  // If no {precision} was specified, just return ToString of {value}.
163  if (precision->IsUndefined(isolate)) {
164  return *isolate->factory()->NumberToString(value);
165  }
166 
167  // Convert the {precision} to an integer first.
168  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, precision,
169  Object::ToInteger(isolate, precision));
170  double const precision_number = precision->Number();
171 
172  if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
173  if (std::isinf(value_number)) {
174  return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
175  : ReadOnlyRoots(isolate).Infinity_string();
176  }
177  if (precision_number < 1.0 || precision_number > kMaxFractionDigits) {
178  THROW_NEW_ERROR_RETURN_FAILURE(
179  isolate, NewRangeError(MessageTemplate::kToPrecisionFormatRange));
180  }
181  char* const str = DoubleToPrecisionCString(
182  value_number, static_cast<int>(precision_number));
183  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
184  DeleteArray(str);
185  return *result;
186 }
187 
188 // ES6 section 20.1.3.6 Number.prototype.toString ( [ radix ] )
189 BUILTIN(NumberPrototypeToString) {
190  HandleScope scope(isolate);
191  Handle<Object> value = args.at(0);
192  Handle<Object> radix = args.atOrUndefined(isolate, 1);
193 
194  // Unwrap the receiver {value}.
195  if (value->IsJSValue()) {
196  value = handle(Handle<JSValue>::cast(value)->value(), isolate);
197  }
198  if (!value->IsNumber()) {
199  THROW_NEW_ERROR_RETURN_FAILURE(
200  isolate, NewTypeError(MessageTemplate::kNotGeneric,
201  isolate->factory()->NewStringFromAsciiChecked(
202  "Number.prototype.toString"),
203  isolate->factory()->Number_string()));
204  }
205  double const value_number = value->Number();
206 
207  // If no {radix} was specified, just return ToString of {value}.
208  if (radix->IsUndefined(isolate)) {
209  return *isolate->factory()->NumberToString(value);
210  }
211 
212  // Convert the {radix} to an integer first.
213  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix,
214  Object::ToInteger(isolate, radix));
215  double const radix_number = radix->Number();
216 
217  // If {radix} is 10, just return ToString of {value}.
218  if (radix_number == 10.0) return *isolate->factory()->NumberToString(value);
219 
220  // Make sure the {radix} is within the valid range.
221  if (radix_number < 2.0 || radix_number > 36.0) {
222  THROW_NEW_ERROR_RETURN_FAILURE(
223  isolate, NewRangeError(MessageTemplate::kToRadixFormatRange));
224  }
225 
226  // Fast case where the result is a one character string.
227  if ((IsUint32Double(value_number) && value_number < radix_number) ||
228  value_number == -0.0) {
229  // Character array used for conversion.
230  static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
231  return *isolate->factory()->LookupSingleCharacterStringFromCode(
232  kCharTable[static_cast<uint32_t>(value_number)]);
233  }
234 
235  // Slow case.
236  if (std::isnan(value_number)) return ReadOnlyRoots(isolate).NaN_string();
237  if (std::isinf(value_number)) {
238  return (value_number < 0.0) ? ReadOnlyRoots(isolate).minus_Infinity_string()
239  : ReadOnlyRoots(isolate).Infinity_string();
240  }
241  char* const str =
242  DoubleToRadixCString(value_number, static_cast<int>(radix_number));
243  Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str);
244  DeleteArray(str);
245  return *result;
246 }
247 
248 } // namespace internal
249 } // namespace v8
Definition: libplatform.h:13