18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/* 28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org) 38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. 48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * This library is free software; you can redistribute it and/or 68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modify it under the terms of the GNU Lesser General Public 78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * License as published by the Free Software Foundation; either 88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * version 2 of the License, or (at your option) any later version. 98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * This library is distributed in the hope that it will be useful, 118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * but WITHOUT ANY WARRANTY; without even the implied warranty of 128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Lesser General Public License for more details. 148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * You should have received a copy of the GNU Lesser General Public 168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * License along with this library; if not, write to the Free Software 178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * USA 198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */ 218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h" 238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "NumberPrototype.h" 248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Error.h" 265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "JSFunction.h" 278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "JSString.h" 28d0825bca7fe65beaee391d30da42e937db621564Steve Block#include "Operations.h" 295ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen#include "dtoa.h" 308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/Assertions.h> 31e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#include <wtf/DecimalNumber.h> 328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/MathExtras.h> 338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <wtf/Vector.h> 348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace JSC { 368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectASSERT_CLASS_FITS_IN_CELL(NumberPrototype); 388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 39545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*); 40545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState*); 41545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState*); 42545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState*); 43545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState*); 44545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochstatic EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*); 458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ECMA 15.7.4 478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben MurdochNumberPrototype::NumberPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, Structure* functionStructure) 492fc2651226baac27029e38c9d6ef883fa32084dbSteve Block : NumberObject(exec->globalData(), structure) 508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 512fc2651226baac27029e38c9d6ef883fa32084dbSteve Block setInternalValue(exec->globalData(), jsNumber(0)); 528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // The constructor will be added later, after NumberConstructor has been constructed 548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 5581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toString, numberProtoFuncToString), DontEnum); 5681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toLocaleString, numberProtoFuncToLocaleString), DontEnum); 5781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().valueOf, numberProtoFuncValueOf), DontEnum); 5881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toFixed, numberProtoFuncToFixed), DontEnum); 5981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toExponential, numberProtoFuncToExponential), DontEnum); 6081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().toPrecision, numberProtoFuncToPrecision), DontEnum); 618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ------------------------------ Functions --------------------------- 648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ECMA 15.7.4.2 - 15.7.4.7 668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 67e8b154fd68f9b33be40a3590e58347f353835f5cSteve Blockstatic ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double &x) 688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 69e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block JSValue v = thisValue.getJSNumber(); 70e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (UNLIKELY(!v)) 71e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return false; 72e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block x = v.uncheckedGetNumber(); 73e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return true; 74e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block} 75e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 76e8b154fd68f9b33be40a3590e58347f353835f5cSteve Blockstatic ALWAYS_INLINE bool getIntegerArgumentInRange(ExecState* exec, int low, int high, int& result, bool& isUndefined) 77e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{ 78e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block result = 0; 79e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block isUndefined = false; 80e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 81e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block JSValue argument0 = exec->argument(0); 82e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (argument0.isUndefined()) { 83e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block isUndefined = true; 84e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return true; 858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 87e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block double asDouble = argument0.toInteger(exec); 88e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (asDouble < low || asDouble > high) 89e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return false; 90e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 91e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block result = static_cast<int>(asDouble); 92e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return true; 938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 95e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// toExponential converts a number to a string, always formatting as an expoential. 96e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// This method takes an optional argument specifying a number of *decimal places* 97e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// to round the significand to (or, put another way, this method optionally rounds 98e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// to argument-plus-one significant figures). 99e8b154fd68f9b33be40a3590e58347f353835f5cSteve BlockEncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec) 1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 101e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // Get x (the double value of this, which should be a Number). 102e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block double x; 103e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (!toThisNumber(exec->hostThisValue(), x)) 104e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return throwVMTypeError(exec); 105e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 106e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // Get the argument. 107e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block int decimalPlacesInExponent; 108e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block bool isUndefined; 109e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined)) 110e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return throwVMError(exec, createRangeError(exec, "toExponential() argument must be between 0 and 20")); 1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 112e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // Handle NaN and Infinity. 113e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (isnan(x) || isinf(x)) 114e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return JSValue::encode(jsString(exec, UString::number(x))); 115e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 116e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // Round if the argument is not undefined, always format as exponential. 117e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block NumberToStringBuffer buffer; 118e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block unsigned length = isUndefined 119a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ? DecimalNumber(x).toStringExponential(buffer, WTF::NumberToStringBufferLength) 120a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch : DecimalNumber(x, RoundingSignificantFigures, decimalPlacesInExponent + 1).toStringExponential(buffer, WTF::NumberToStringBufferLength); 121e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 122e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return JSValue::encode(jsString(exec, UString(buffer, length))); 1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 125e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// toFixed converts a number to a string, always formatting as an a decimal fraction. 126e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// This method takes an argument specifying a number of decimal places to round the 127e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// significand to. However when converting large values (1e+21 and above) this 128e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// method will instead fallback to calling ToString. 129e8b154fd68f9b33be40a3590e58347f353835f5cSteve BlockEncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec) 1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 131e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // Get x (the double value of this, which should be a Number). 132e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block JSValue thisValue = exec->hostThisValue(); 133e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block JSValue v = thisValue.getJSNumber(); 134e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (!v) 135e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return throwVMTypeError(exec); 136e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block double x = v.uncheckedGetNumber(); 137e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 138e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // Get the argument. 139e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block int decimalPlaces; 140e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block bool isUndefined; // This is ignored; undefined treated as 0. 141e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined)) 142e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return throwVMError(exec, createRangeError(exec, "toFixed() argument must be between 0 and 20")); 143e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 144e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)" 145e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // This also covers Ininity, and structure the check so that NaN 146e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // values are also handled by numberToString 147e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (!(fabs(x) < 1e+21)) 148e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return JSValue::encode(jsString(exec, UString::number(x))); 149e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 150e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // The check above will return false for NaN or Infinity, these will be 151e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // handled by numberToString. 152e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block ASSERT(!isnan(x) && !isinf(x)); 153e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 154e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // Convert to decimal with rounding, and format as decimal. 155e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block NumberToStringBuffer buffer; 156a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch unsigned length = DecimalNumber(x, RoundingDecimalPlaces, decimalPlaces).toStringDecimal(buffer, WTF::NumberToStringBufferLength); 157e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return JSValue::encode(jsString(exec, UString(buffer, length))); 158e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block} 1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 160e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// toPrecision converts a number to a string, takeing an argument specifying a 161e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// number of significant figures to round the significand to. For positive 162e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// exponent, all values that can be represented using a decimal fraction will 163e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a 164e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// decimal, whilst 1000 is converted to the exponential representation 1.00e+3. 165e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// For negative exponents values >= 1e-6 are formated as decimal fractions, 166e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block// with smaller values converted to exponential representation. 167e8b154fd68f9b33be40a3590e58347f353835f5cSteve BlockEncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec) 168e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block{ 169e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // Get x (the double value of this, which should be a Number). 170e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block JSValue thisValue = exec->hostThisValue(); 171e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block JSValue v = thisValue.getJSNumber(); 172e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (!v) 173e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return throwVMTypeError(exec); 174e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block double x = v.uncheckedGetNumber(); 175e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 176e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // Get the argument. 177e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block int significantFigures; 178e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block bool isUndefined; 179e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined)) 180e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21")); 181e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 182e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // To precision called with no argument is treated as ToString. 183e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (isUndefined) 184e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return JSValue::encode(jsString(exec, UString::number(x))); 185e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 186e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // Handle NaN and Infinity. 187e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (isnan(x) || isinf(x)) 188e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return JSValue::encode(jsString(exec, UString::number(x))); 189e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 190e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // Convert to decimal with rounding. 191e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block DecimalNumber number(x, RoundingSignificantFigures, significantFigures); 192e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // If number is in the range 1e-6 <= x < pow(10, significantFigures) then format 193e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // as decimal. Otherwise, format the number as an exponential. Decimal format 194e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // demands a minimum of (exponent + 1) digits to represent a number, for example 195e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // 1234 (1.234e+3) requires 4 digits. (See ECMA-262 15.7.4.7.10.c) 196e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block NumberToStringBuffer buffer; 197e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block unsigned length = number.exponent() >= -6 && number.exponent() < significantFigures 198a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch ? number.toStringDecimal(buffer, WTF::NumberToStringBufferLength) 199a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch : number.toStringExponential(buffer, WTF::NumberToStringBufferLength); 200e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return JSValue::encode(jsString(exec, UString(buffer, length))); 2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 203545e470e52f0ac6a3a072bf559c796b42c6066b6Ben MurdochEncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec) 2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 2055af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke JSValue thisValue = exec->hostThisValue(); 2065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian JSValue v = thisValue.getJSNumber(); 2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!v) 208545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return throwVMTypeError(exec); 2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2105af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke JSValue radixValue = exec->argument(0); 2116c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen int radix; 2126c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if (radixValue.isInt32()) 2136c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen radix = radixValue.asInt32(); 2146c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen else if (radixValue.isUndefined()) 2156c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen radix = 10; 2166c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen else 2176c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0 2186c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 2196c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if (radix == 10) 220545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return JSValue::encode(jsString(exec, v.toString(exec))); 2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2226c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen static const char* const digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 2236c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 2246c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen // Fast path for number to character conversion. 2256c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if (radix == 36) { 2266c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if (v.isInt32()) { 2276c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen int x = v.asInt32(); 2286c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if (static_cast<unsigned>(x) < 36) { // Exclude negatives 2296c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen JSGlobalData* globalData = &exec->globalData(); 230545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, digits[x])); 2316c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen } 2326c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen } 2336c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen } 2346c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 2356c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if (radix < 2 || radix > 36) 236545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return throwVMError(exec, createRangeError(exec, "toString() radix argument must be between 2 and 36")); 2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // INT_MAX results in 1024 characters left of the dot with radix 2 2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // give the same space on the right side. safety checks are in place 2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // unless someone finds a precise rule. 2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project char s[2048 + 3]; 2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project const char* lastCharInString = s + sizeof(s) - 1; 243635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project double x = v.uncheckedGetNumber(); 2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (isnan(x) || isinf(x)) 245f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick return JSValue::encode(jsString(exec, UString::number(x))); 2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project bool isNegative = x < 0.0; 2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (isNegative) 2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project x = -x; 2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project double integerPart = floor(x); 2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project char* decimalPoint = s + sizeof(s) / 2; 2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // convert integer portion 2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project char* p = decimalPoint; 2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project double d = integerPart; 2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project do { 2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int remainderDigit = static_cast<int>(fmod(d, radix)); 2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *--p = digits[remainderDigit]; 2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project d /= radix; 2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } while ((d <= -1.0 || d >= 1.0) && s < p); 2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (isNegative) 2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *--p = '-'; 2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project char* startOfResultString = p; 2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ASSERT(s <= startOfResultString); 2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project d = x - integerPart; 2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project p = decimalPoint; 2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project const double epsilon = 0.001; // TODO: guessed. base on radix ? 2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project bool hasFractionalPart = (d < -epsilon || d > epsilon); 2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (hasFractionalPart) { 2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *p++ = '.'; 2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project do { 2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project d *= radix; 2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project const int digit = static_cast<int>(d); 2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *p++ = digits[digit]; 2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project d -= digit; 2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } while ((d < -epsilon || d > epsilon) && p < lastCharInString); 2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *p = '\0'; 2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ASSERT(p < s + sizeof(s)); 2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 284545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return JSValue::encode(jsString(exec, startOfResultString)); 2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 287545e470e52f0ac6a3a072bf559c796b42c6066b6Ben MurdochEncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec) 2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 2895af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke JSValue thisValue = exec->hostThisValue(); 2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // FIXME: Not implemented yet. 2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian JSValue v = thisValue.getJSNumber(); 2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!v) 294545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return throwVMTypeError(exec); 2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 296545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return JSValue::encode(jsString(exec, v.toString(exec))); 2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 299545e470e52f0ac6a3a072bf559c796b42c6066b6Ben MurdochEncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec) 3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 3015af96e2c7b73ebc627c6894727826a7576d31758Leon Clarke JSValue thisValue = exec->hostThisValue(); 3025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian JSValue v = thisValue.getJSNumber(); 3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!v) 304545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return throwVMTypeError(exec); 3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 306545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return JSValue::encode(v); 3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace JSC 310