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