24 #include "number_object.h"
25 #include "number_object.lut.h"
28 #include "error_object.h"
29 #include "operations.h"
30 #include <wtf/Assertions.h>
31 #include <wtf/MathExtras.h>
32 #include <wtf/Vector.h>
44 static const double MAX_SAFE_INTEGER = 9007199254740991.0;
45 static const double MIN_SAFE_INTEGER = -9007199254740991.0;
49 const ClassInfo NumberInstance::info = {
"Number",
nullptr,
nullptr,
nullptr};
51 NumberInstance::NumberInstance(JSObject *proto)
52 : JSWrapperObject(proto)
56 JSObject *NumberInstance::valueClone(Interpreter *targetCtx)
const
58 NumberInstance *
copy =
new NumberInstance(targetCtx->builtinNumberPrototype());
59 copy->setInternalValue(internalValue());
67 NumberPrototype::NumberPrototype(ExecState *exec, ObjectPrototype *objProto, FunctionPrototype *funcProto)
68 : NumberInstance(objProto)
70 setInternalValue(jsNumber(0));
74 putDirectFunction(
new NumberProtoFunc(exec, funcProto, NumberProtoFunc::ToString, 1, exec->propertyNames().toString), DontEnum);
75 putDirectFunction(
new NumberProtoFunc(exec, funcProto, NumberProtoFunc::ToLocaleString, 0, exec->propertyNames().toLocaleString), DontEnum);
76 putDirectFunction(
new NumberProtoFunc(exec, funcProto, NumberProtoFunc::ValueOf, 0, exec->propertyNames().valueOf), DontEnum);
77 putDirectFunction(
new NumberProtoFunc(exec, funcProto, NumberProtoFunc::ToFixed, 1, exec->propertyNames().toFixed), DontEnum);
78 putDirectFunction(
new NumberProtoFunc(exec, funcProto, NumberProtoFunc::ToExponential, 1, exec->propertyNames().toExponential), DontEnum);
79 putDirectFunction(
new NumberProtoFunc(exec, funcProto, NumberProtoFunc::ToPrecision, 1, exec->propertyNames().toPrecision), DontEnum);
84 NumberProtoFunc::NumberProtoFunc(ExecState *exec, FunctionPrototype *funcProto,
int i,
int len,
const Identifier &name)
85 : InternalFunctionImp(funcProto,
name)
88 putDirect(exec->propertyNames().length, len, DontDelete | ReadOnly | DontEnum);
91 static UString integer_part_noexp(
double d)
95 char *result = kjs_dtoa(d, 0, 0, &decimalPoint, &sign,
nullptr);
96 bool resultIsInfOrNan = (decimalPoint == 9999);
97 size_t length = strlen(result);
99 UString str = sign ?
"-" :
"";
100 if (resultIsInfOrNan) {
102 }
else if (decimalPoint <= 0) {
105 Vector<char, 1024> buf(decimalPoint + 1);
107 if (
static_cast<int>(length) <= decimalPoint) {
108 strcpy(buf.data(), result);
109 memset(buf.data() + length,
'0', decimalPoint - length);
111 strncpy(buf.data(), result, decimalPoint);
114 buf[decimalPoint] =
'\0';
115 str += UString(buf.data());
118 kjs_freedtoa(result);
123 static UString char_sequence(
char c,
int count)
125 Vector<char, 2048> buf(count + 1, c);
128 return UString(buf.data());
131 static double intPow10(
int e)
142 bool negative = e < 0;
143 unsigned exp = negative ? -e : e;
145 long double result = 10.0;
146 bool foundOne =
false;
147 for (
int bit = 31; bit >= 0; bit--) {
149 if ((exp >> bit) & 1) {
153 result = result * result;
154 if ((exp >> bit) & 1) {
155 result = result * 10.0;
161 return static_cast<double>(1.0 / result);
163 return static_cast<double>(result);
166 static JSValue *
numberToString(ExecState *exec, JSValue *v,
const List &args)
168 double radixAsDouble = JSValue::toInteger(args[0], exec);
169 if (radixAsDouble == 10 || JSValue::isUndefined(args[0])) {
170 return jsString(JSValue::toString(v, exec));
173 if (radixAsDouble < 2 || radixAsDouble > 36) {
174 return throwError(exec, RangeError,
"toString() radix argument must be between 2 and 36");
177 int radix =
static_cast<int>(radixAsDouble);
178 const char digits[] =
"0123456789abcdefghijklmnopqrstuvwxyz";
183 const char *lastCharInString = s +
sizeof(s) - 1;
184 double x = JSValue::toNumber(v, exec);
189 bool isNegative = x < 0.0;
194 double integerPart = floor(x);
195 char *decimalPoint = s +
sizeof(s) / 2;
198 char *p = decimalPoint;
199 double d = integerPart;
201 int remainderDigit =
static_cast<int>(fmod(d, radix));
202 *--p = digits[remainderDigit];
204 }
while ((d <= -1.0 || d >= 1.0) && s < p);
209 char *startOfResultString = p;
210 ASSERT(s <= startOfResultString);
214 const double epsilon = 0.001;
215 bool hasFractionalPart = (d < -epsilon || d > epsilon);
216 if (hasFractionalPart) {
220 const int digit =
static_cast<int>(d);
221 *p++ = digits[digit];
223 }
while ((d < -epsilon || d > epsilon) && p < lastCharInString);
226 ASSERT(p < s +
sizeof(s));
228 return jsString(startOfResultString);
231 static JSValue *numberToFixed(ExecState *exec, JSValue *v,
const List &args)
233 JSValue *fractionDigits = args[0];
234 double df = JSValue::toInteger(fractionDigits, exec);
235 if (!(df >= 0 && df <= 20)) {
236 return throwError(exec, RangeError,
"toFixed() digits argument must be between 0 and 20");
240 double x = JSValue::toNumber(v, exec);
242 return jsString(
"NaN");
249 }
else if (x == -0.0) {
253 if (x >= pow(10.0, 21.0)) {
257 const double tenToTheF = pow(10.0, f);
258 double n = floor(x * tenToTheF);
259 if (fabs(n / tenToTheF - x) >= fabs((n + 1) / tenToTheF - x)) {
263 UString m = integer_part_noexp(n);
268 for (
int i = 0; i < f + 1 - k; i++) {
273 ASSERT(k == m.size());
276 if (kMinusf < m.size()) {
277 return jsString(s + m.substr(0, kMinusf) +
"." + m.substr(kMinusf));
279 return jsString(s + m.substr(0, kMinusf));
282 void fractionalPartToString(
char *buf,
int &i,
const char *result,
int resultLength,
int fractionalDigits)
284 if (fractionalDigits <= 0) {
288 int fDigitsInResult =
static_cast<int>(resultLength) - 1;
290 if (fDigitsInResult > 0) {
291 if (fractionalDigits < fDigitsInResult) {
292 strncpy(buf + i, result + 1, fractionalDigits);
293 i += fractionalDigits;
295 strcpy(buf + i, result + 1);
296 i +=
static_cast<int>(resultLength) - 1;
300 for (
int j = 0; j < fractionalDigits - fDigitsInResult; j++) {
305 void exponentialPartToString(
char *buf,
int &i,
int decimalPoint)
308 buf[i++] = (decimalPoint >= 0) ?
'+' :
'-';
311 int exponential = decimalPoint - 1;
312 if (exponential < 0) {
315 if (exponential >= 100) {
316 buf[i++] =
static_cast<char>(
'0' + exponential / 100);
318 if (exponential >= 10) {
319 buf[i++] =
static_cast<char>(
'0' + (exponential % 100) / 10);
321 buf[i++] =
static_cast<char>(
'0' + exponential % 10);
324 static JSValue *numberToExponential(ExecState *exec, JSValue *v,
const List &args)
326 double x = JSValue::toNumber(v, exec);
332 JSValue *fractionalDigitsValue = args[0];
333 double df = JSValue::toInteger(fractionalDigitsValue, exec);
334 if (!(df >= 0 && df <= 20)) {
335 return throwError(exec, RangeError,
"toExponential() argument must between 0 and 20");
337 int fractionalDigits = (int)df;
338 bool includeAllDigits = JSValue::isUndefined(fractionalDigitsValue);
340 int decimalAdjust = 0;
341 if (x && !includeAllDigits) {
342 double logx = floor(log10(fabs(x)));
343 x /= pow(10.0, logx);
344 const double tenToTheF = pow(10.0, fractionalDigits);
345 double fx = floor(x * tenToTheF) / tenToTheF;
346 double cx = ceil(x * tenToTheF) / tenToTheF;
348 if (fabs(fx - x) < fabs(cx - x)) {
354 decimalAdjust =
static_cast<int>(logx);
358 return jsString(
"NaN");
367 char *result = kjs_dtoa(x, 0, 0, &decimalPoint, &sign,
nullptr);
368 size_t resultLength = strlen(result);
369 decimalPoint += decimalAdjust;
377 if (decimalPoint == 999) {
378 strcpy(buf + i, result);
380 buf[i++] = result[0];
382 if (includeAllDigits) {
383 fractionalDigits =
static_cast<int>(resultLength) - 1;
386 fractionalPartToString(buf, i, result, resultLength, fractionalDigits);
387 exponentialPartToString(buf, i, decimalPoint);
392 kjs_freedtoa(result);
394 return jsString(buf);
397 static JSValue *numberToPrecision(ExecState *exec, JSValue *v,
const List &args)
399 double doublePrecision = JSValue::toIntegerPreserveNaN(args[0], exec);
400 double x = JSValue::toNumber(v, exec);
401 if (JSValue::isUndefined(args[0]) ||
isNaN(x) ||
isInf(x)) {
402 return jsString(JSValue::toString(v, exec));
411 if (!(doublePrecision >= 1 && doublePrecision <= 21)) {
412 return throwError(exec, RangeError,
"toPrecision() argument must be between 1 and 21");
414 int precision = (int)doublePrecision;
419 e =
static_cast<int>(log10(x));
420 double tens = intPow10(e - precision + 1);
421 double n = floor(x / tens);
422 if (n < intPow10(precision - 1)) {
424 tens = intPow10(e - precision + 1);
428 if (fabs((n + 1.0) * tens - x) <= fabs(n * tens - x)) {
432 if (n >= intPow10(precision)) {
436 ASSERT(intPow10(precision - 1) <= n);
437 ASSERT(n < intPow10(precision));
439 m = integer_part_noexp(n);
440 if (e < -6 || e >= precision) {
442 m = m.substr(0, 1) +
"." + m.substr(1);
450 m = char_sequence(
'0', precision);
454 if (e == precision - 1) {
455 return jsString(s + m);
457 if (e + 1 < m.size()) {
458 return jsString(s + m.substr(0, e + 1) +
"." + m.substr(e + 1));
460 return jsString(s + m);
462 return jsString(s +
"0." + char_sequence(
'0', -(e + 1)) + m);
466 JSValue *NumberProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj,
const List &args)
469 if (!thisObj->inherits(&NumberInstance::info)) {
470 return throwError(exec, TypeError);
473 JSValue *v =
static_cast<NumberInstance *
>(thisObj)->internalValue();
478 return jsString(JSValue::toString(v, exec));
480 return jsNumber(JSValue::toNumber(v, exec));
482 return numberToFixed(exec, v, args);
484 return numberToExponential(exec, v, args);
486 return numberToPrecision(exec, v, args);
493 const ClassInfo NumberObjectImp::info = {
"Function", &InternalFunctionImp::info, &numberTable,
nullptr};
513 NumberObjectImp::NumberObjectImp(ExecState *exec, FunctionPrototype *funcProto, NumberPrototype *numberProto)
514 : InternalFunctionImp(funcProto)
517 putDirect(exec->propertyNames().prototype, numberProto, DontEnum | DontDelete | ReadOnly);
520 putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
523 bool NumberObjectImp::getOwnPropertySlot(ExecState *exec,
const Identifier &propertyName, PropertySlot &slot)
525 return getStaticPropertySlot<NumberFuncImp, NumberObjectImp, InternalFunctionImp>(exec, &numberTable,
this, propertyName, slot);
528 JSValue *NumberObjectImp::getValueProperty(ExecState *,
int token)
const
535 return jsNumberCell(-Inf);
537 return jsNumberCell(Inf);
539 return jsNumberCell(1.7976931348623157E+308);
541 return jsNumberCell(5E-324);
543 return jsNumber(MAX_SAFE_INTEGER);
545 return jsNumber(MIN_SAFE_INTEGER);
550 bool NumberObjectImp::implementsConstruct()
const
556 JSObject *NumberObjectImp::construct(ExecState *exec,
const List &args)
558 JSObject *proto = exec->lexicalInterpreter()->builtinNumberPrototype();
559 NumberInstance *obj =
new NumberInstance(proto);
561 double n = args.isEmpty() ? 0 : JSValue::toNumber(args[0], exec);
562 obj->setInternalValue(jsNumber(n));
567 JSValue *NumberObjectImp::callAsFunction(ExecState *exec, JSObject *,
const List &args)
569 double n = args.isEmpty() ? 0 : JSValue::toNumber(args[0], exec);
573 NumberFuncImp::NumberFuncImp(ExecState* exec,
int i,
int l,
const Identifier& name)
574 : InternalFunctionImp(static_cast<FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()),
name)
577 putDirect(exec->propertyNames().length, l, DontDelete|ReadOnly|DontEnum);
582 double arg = JSValue::toNumber(args[0], exec);
585 case NumberObjectImp::IsFinite:
586 if (JSValue::type(args[0]) != NumberType)
587 return jsBoolean(
false);
590 case NumberObjectImp::IsInteger:
592 if (JSValue::type(args[0]) != NumberType)
593 return jsBoolean(
false);
595 return jsBoolean(
false);
596 double num = JSValue::toInteger(args[0], exec);
597 return jsBoolean(num == arg);
599 case NumberObjectImp::IsNaN:
600 if (JSValue::type(args[0]) != NumberType)
601 return jsBoolean(
false);
602 return jsBoolean(
isNaN(arg));
604 case NumberObjectImp::IsSafeInteger:
606 if (JSValue::type(args[0]) != NumberType)
607 return jsBoolean(
false);
609 return jsBoolean(
false);
610 double num = JSValue::toInteger(args[0], exec);
612 return jsBoolean(
false);
613 return jsBoolean(fabs(num) <= MAX_SAFE_INTEGER);
615 case NumberObjectImp::ParseInt:
616 return jsNumber(KJS::parseInt(JSValue::toString(args[0], exec), JSValue::toInt32(args[1], exec)));
617 case NumberObjectImp::ParseFloat:
618 return jsNumber(KJS::parseFloat(JSValue::toString(args[0], exec)));
620 return jsUndefined();