00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "value.h"
00024 #include "object.h"
00025 #include "types.h"
00026 #include "interpreter.h"
00027 #include "operations.h"
00028 #include "number_object.h"
00029 #include "error_object.h"
00030 #include "dtoa.h"
00031
00032 #include "number_object.lut.h"
00033
00034 #include <assert.h>
00035 #include <math.h>
00036
00037 using namespace KJS;
00038
00039
00040
00041 const ClassInfo NumberInstanceImp::info = {"Number", 0, 0, 0};
00042
00043 NumberInstanceImp::NumberInstanceImp(ObjectImp *proto)
00044 : ObjectImp(proto)
00045 {
00046 }
00047
00048
00049
00050
00051 NumberPrototypeImp::NumberPrototypeImp(ExecState *exec,
00052 ObjectPrototypeImp *objProto,
00053 FunctionPrototypeImp *funcProto)
00054 : NumberInstanceImp(objProto)
00055 {
00056 Value protect(this);
00057 setInternalValue(NumberImp::zero());
00058
00059
00060
00061 putDirect(toStringPropertyName,new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToString,
00062 1,toStringPropertyName),DontEnum);
00063 putDirect(toLocaleStringPropertyName,new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToLocaleString,
00064 0,toLocaleStringPropertyName),DontEnum);
00065 putDirect(valueOfPropertyName,new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ValueOf,
00066 0,valueOfPropertyName),DontEnum);
00067 putDirect("toFixed", new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToFixed,
00068 1,"toFixed"),DontEnum);
00069 putDirect("toExponential",new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToExponential,
00070 1,"toExponential"),DontEnum);
00071 putDirect("toPrecision",new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToPrecision,
00072 1,"toPrecision"),DontEnum);
00073 }
00074
00075
00076
00077
00078 NumberProtoFuncImp::NumberProtoFuncImp(ExecState * , FunctionPrototypeImp *funcProto,
00079 int i, int len, const Identifier &_ident)
00080 : InternalFunctionImp(funcProto), id(i)
00081 {
00082 Value protect(this);
00083 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
00084 ident = _ident;
00085 }
00086
00087
00088 bool NumberProtoFuncImp::implementsCall() const
00089 {
00090 return true;
00091 }
00092
00093 static UString integer_part_noexp(double d)
00094 {
00095 int decimalPoint;
00096 int sign;
00097 char *result = kjs_dtoa(d, 0, 0, &decimalPoint, &sign, NULL);
00098 int length = strlen(result);
00099
00100 UString str = sign ? "-" : "";
00101 if (decimalPoint == 9999) {
00102 str += UString(result);
00103 } else if (decimalPoint <= 0) {
00104 str += UString("0");
00105 } else {
00106 char *buf;
00107
00108 if (length <= decimalPoint) {
00109 buf = (char*)malloc(decimalPoint+1);
00110 strcpy(buf,result);
00111 memset(buf+length,'0',decimalPoint-length);
00112 } else {
00113 buf = (char*)malloc(decimalPoint+1);
00114 strncpy(buf,result,decimalPoint);
00115 }
00116
00117 buf[decimalPoint] = '\0';
00118 str += UString(buf);
00119 free(buf);
00120 }
00121
00122 kjs_freedtoa(result);
00123
00124 return str;
00125 }
00126
00127 static UString char_sequence(char c, int count)
00128 {
00129 char *buf = (char*)malloc(count+1);
00130 memset(buf,c,count);
00131 buf[count] = '\0';
00132 UString s(buf);
00133 free(buf);
00134 return s;
00135 }
00136
00137
00138 Value NumberProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
00139 {
00140 Value result;
00141
00142
00143 KJS_CHECK_THIS( NumberInstanceImp, thisObj );
00144
00145
00146 Value v = thisObj.internalValue();
00147 switch (id) {
00148 case ToString: {
00149 int radix = 10;
00150 if (!args.isEmpty() && args[0].type() != UndefinedType)
00151 radix = args[0].toInteger(exec);
00152 if (radix < 2 || radix > 36 || radix == 10)
00153 result = String(v.toString(exec));
00154 else {
00155 const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
00156
00157
00158
00159 char s[2048 + 3];
00160 double x = v.toNumber(exec);
00161 if (isNaN(x) || isInf(x))
00162 return String(UString::from(x));
00163
00164 bool neg = false;
00165 if (x < 0.0) {
00166 neg = true;
00167 x = -x;
00168 }
00169
00170 double f = floor(x);
00171 double d = f;
00172 char *dot = s + sizeof(s) / 2;
00173 char *p = dot;
00174 *p = '\0';
00175 do {
00176 *--p = digits[int(fmod(d, double(radix)))];
00177 d /= radix;
00178 } while ((d <= -1.0 || d >= 1.0) && p > s);
00179
00180 d = x - f;
00181 const double eps = 0.001;
00182 if (d < -eps || d > eps) {
00183 *dot++ = '.';
00184 do {
00185 d *= radix;
00186 *dot++ = digits[int(d)];
00187 d -= int(d);
00188 } while ((d < -eps || d > eps) && dot - s < int(sizeof(s)) - 1);
00189 *dot = '\0';
00190 }
00191
00192 if (neg)
00193 *--p = '-';
00194 result = String(p);
00195 }
00196 break;
00197 }
00198 case ToLocaleString:
00199 result = String(v.toString(exec));
00200 break;
00201 case ValueOf:
00202 result = Number(v.toNumber(exec));
00203 break;
00204 case ToFixed:
00205 {
00206
00207
00208
00209 Value fractionDigits = args[0];
00210 int f = -1;
00211 double fd = fractionDigits.toNumber(exec);
00212 if (isNaN(fd)) {
00213 f = 0;
00214 } else if (!isInf(fd)) {
00215 f = int(fd);
00216 }
00217 if (f < 0 || f > 20) {
00218 Object err = Error::create(exec,RangeError);
00219 exec->setException(err);
00220 return err;
00221 }
00222
00223 double x = v.toNumber(exec);
00224 if (isNaN(x))
00225 return String("NaN");
00226
00227 UString s = "";
00228 if (x < 0) {
00229 s += "-";
00230 x = -x;
00231 }
00232
00233 if (x >= 1e21)
00234 return String(s+UString::from(x));
00235
00236 double n = floor(x*pow(10.0,f));
00237 if (fabs(n/pow(10.0,f)-x) > fabs((n+1)/pow(10.0,f)-x))
00238 n++;
00239
00240 UString m = integer_part_noexp(n);
00241
00242 int k = m.size();
00243 if (m.size() < f) {
00244 UString z = "";
00245 for (int i = 0; i < f+1-k; i++)
00246 z += "0";
00247 m = z + m;
00248 k = f + 1;
00249 assert(k == m.size());
00250 }
00251 if (k-f < m.size())
00252 return String(s+m.substr(0,k-f)+"."+m.substr(k-f));
00253 else
00254 return String(s+m.substr(0,k-f));
00255 }
00256 case ToExponential: {
00257 double x = v.toNumber(exec);
00258
00259 if (isNaN(x) || isInf(x))
00260 return String(UString::from(x));
00261
00262 int f = 1;
00263 Value fractionDigits = args[0];
00264 if (args.size() > 0) {
00265 f = fractionDigits.toInteger(exec);
00266 if (f < 0 || f > 20) {
00267 Object err = Error::create(exec,RangeError);
00268 exec->setException(err);
00269 return err;
00270 }
00271 }
00272
00273 int decimalAdjust = 0;
00274 if (!fractionDigits.isA(UndefinedType)) {
00275 double logx = floor(log10(x));
00276 x /= pow(10.0,logx);
00277 double fx = floor(x*pow(10.0,f))/pow(10.0,f);
00278 double cx = ceil(x*pow(10.0,f))/pow(10.0,f);
00279
00280 if (fabs(fx-x) < fabs(cx-x))
00281 x = fx;
00282 else
00283 x = cx;
00284
00285 decimalAdjust = int(logx);
00286 }
00287
00288 char buf[80];
00289 int decimalPoint;
00290 int sign;
00291
00292 if (isNaN(x))
00293 return String("NaN");
00294
00295 char *result = kjs_dtoa(x, 0, 0, &decimalPoint, &sign, NULL);
00296 int length = strlen(result);
00297 decimalPoint += decimalAdjust;
00298
00299 int i = 0;
00300 if (sign) {
00301 buf[i++] = '-';
00302 }
00303
00304 if (decimalPoint == 999) {
00305 strcpy(buf + i, result);
00306 } else {
00307 buf[i++] = result[0];
00308
00309 if (fractionDigits.isA(UndefinedType))
00310 f = length-1;
00311
00312 if (length > 1 && f > 0) {
00313 buf[i++] = '.';
00314 int haveFDigits = length-1;
00315 if (f < haveFDigits) {
00316 strncpy(buf+i,result+1, f);
00317 i += f;
00318 }
00319 else {
00320 strcpy(buf+i,result+1);
00321 i += length-1;
00322 for (int j = 0; j < f-haveFDigits; j++)
00323 buf[i++] = '0';
00324 }
00325 }
00326
00327 buf[i++] = 'e';
00328 buf[i++] = (decimalPoint >= 0) ? '+' : '-';
00329
00330
00331 int exponential = decimalPoint - 1;
00332 if (exponential < 0) {
00333 exponential = exponential * -1;
00334 }
00335 if (exponential >= 100) {
00336 buf[i++] = '0' + exponential / 100;
00337 }
00338 if (exponential >= 10) {
00339 buf[i++] = '0' + (exponential % 100) / 10;
00340 }
00341 buf[i++] = '0' + exponential % 10;
00342 buf[i++] = '\0';
00343 }
00344
00345 assert(i <= 80);
00346
00347 kjs_freedtoa(result);
00348
00349 return String(UString(buf));
00350 }
00351 case ToPrecision:
00352 {
00353 int e = 0;
00354 UString m;
00355
00356 int p = args[0].toInteger(exec);
00357 double x = v.toNumber(exec);
00358 if (args[0].isA(UndefinedType) || isNaN(x) || isInf(x))
00359 return String(v.toString(exec));
00360
00361 UString s = "";
00362 if (x < 0) {
00363 s = "-";
00364 x = -x;
00365 }
00366
00367 if (p < 1 || p > 21) {
00368 Object err = Error::create(exec, RangeError,
00369 "toPrecision() argument must be between 1 and 21");
00370 exec->setException(err);
00371 return err;
00372 }
00373
00374 if (x != 0) {
00375 e = int(log10(x));
00376 double n = floor(x/pow(10.0,e-p+1));
00377 if (n < pow(10.0,p-1)) {
00378 e = e - 1;
00379 n = floor(x/pow(10.0,e-p+1));
00380 }
00381
00382 if (fabs((n+1)*pow(10.0,e-p+1)-x) < fabs(n*pow(10.0,e-p+1)-x))
00383 n++;
00384 assert(pow(10.0,p-1) <= n);
00385 assert(n < pow(10.0,p));
00386
00387 m = integer_part_noexp(n);
00388 if (e < -6 || e >= p) {
00389 if (m.size() > 1)
00390 m = m.substr(0,1)+"."+m.substr(1);
00391 if (e >= 0)
00392 return String(s+m+"e+"+UString::from(e));
00393 else
00394 return String(s+m+"e-"+UString::from(-e));
00395 }
00396 }
00397 else {
00398 m = char_sequence('0',p);
00399 e = 0;
00400 }
00401
00402 if (e == p-1) {
00403 return String(s+m);
00404 }
00405 else if (e >= 0) {
00406 if (e+1 < m.size())
00407 return String(s+m.substr(0,e+1)+"."+m.substr(e+1));
00408 else
00409 return String(s+m.substr(0,e+1));
00410 }
00411 else {
00412 return String(s+"0."+char_sequence('0',-(e+1))+m);
00413 }
00414 }
00415 }
00416
00417 return result;
00418 }
00419
00420
00421
00422 const ClassInfo NumberObjectImp::info = {"Function", &InternalFunctionImp::info, &numberTable, 0};
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433 NumberObjectImp::NumberObjectImp(ExecState * ,
00434 FunctionPrototypeImp *funcProto,
00435 NumberPrototypeImp *numberProto)
00436 : InternalFunctionImp(funcProto)
00437 {
00438 Value protect(this);
00439
00440 putDirect(prototypePropertyName, numberProto, DontEnum|DontDelete|ReadOnly);
00441
00442
00443 putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum);
00444 }
00445
00446 Value NumberObjectImp::get(ExecState *exec, const Identifier &propertyName) const
00447 {
00448 return lookupGetValue<NumberObjectImp, InternalFunctionImp>( exec, propertyName, &numberTable, this );
00449 }
00450
00451 Value NumberObjectImp::getValueProperty(ExecState *, int token) const
00452 {
00453
00454 switch(token) {
00455 case NaNValue:
00456 return Number(NaN);
00457 case NegInfinity:
00458 return Number(-Inf);
00459 case PosInfinity:
00460 return Number(Inf);
00461 case MaxValue:
00462 return Number(1.7976931348623157E+308);
00463 case MinValue:
00464 return Number(5E-324);
00465 }
00466 return Null();
00467 }
00468
00469 bool NumberObjectImp::implementsConstruct() const
00470 {
00471 return true;
00472 }
00473
00474
00475
00476 Object NumberObjectImp::construct(ExecState *exec, const List &args)
00477 {
00478 ObjectImp *proto = exec->lexicalInterpreter()->builtinNumberPrototype().imp();
00479 Object obj(new NumberInstanceImp(proto));
00480
00481 Number n;
00482 if (args.isEmpty())
00483 n = Number(0);
00484 else
00485 n = args[0].toNumber(exec);
00486
00487 obj.setInternalValue(n);
00488
00489 return obj;
00490 }
00491
00492 bool NumberObjectImp::implementsCall() const
00493 {
00494 return true;
00495 }
00496
00497
00498 Value NumberObjectImp::call(ExecState *exec, Object &, const List &args)
00499 {
00500 if (args.isEmpty())
00501 return Number(0);
00502 else
00503 return Number(args[0].toNumber(exec));
00504 }