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
Value fractionDigits = args[0];
00206
int f = fractionDigits.
toInteger(exec);
00207
if (f < 0 || f > 20) {
00208
Object err =
Error::create(exec,RangeError);
00209 exec->
setException(err);
00210
return err;
00211 }
00212
00213
double x = v.
toNumber(exec);
00214
if (isNaN(x))
00215
return String(
"NaN");
00216
00217
UString s =
"";
00218
if (x < 0) {
00219 s +=
"-";
00220 x = -x;
00221 }
00222
00223
if (x >= 1e21)
00224
return String(s+UString::from(x));
00225
00226
double n = floor(x*pow(10.0,f));
00227
if (fabs(n/pow(10.0,f)-x) > fabs((n+1)/pow(10.0,f)-x))
00228 n++;
00229
00230
UString m = integer_part_noexp(n);
00231
00232
int k = m.
size();
00233
if (m.
size() < f) {
00234
UString z =
"";
00235
for (
int i = 0; i < f+1-k; i++)
00236 z +=
"0";
00237 m = z + m;
00238 k = f + 1;
00239 assert(k == m.size());
00240 }
00241
if (k-f < m.
size())
00242
return String(s+m.
substr(0,k-f)+
"."+m.
substr(k-f));
00243
else
00244
return String(s+m.
substr(0,k-f));
00245 }
00246
case ToExponential: {
00247
double x = v.
toNumber(exec);
00248
00249
if (isNaN(x) || isInf(x))
00250
return String(UString::from(x));
00251
00252
Value fractionDigits = args[0];
00253
int f = fractionDigits.
toInteger(exec);
00254
if (f < 0 || f > 20) {
00255
Object err =
Error::create(exec,RangeError);
00256 exec->
setException(err);
00257
return err;
00258 }
00259
00260
int decimalAdjust = 0;
00261
if (!fractionDigits.
isA(UndefinedType)) {
00262
double logx = floor(log10(x));
00263 x /= pow(10.0,logx);
00264
double fx = floor(x*pow(10.0,f))/pow(10.0,f);
00265
double cx = ceil(x*pow(10.0,f))/pow(10.0,f);
00266
00267
if (fabs(fx-x) < fabs(cx-x))
00268 x = fx;
00269
else
00270 x = cx;
00271
00272 decimalAdjust = int(logx);
00273 }
00274
00275
char buf[80];
00276
int decimalPoint;
00277
int sign;
00278
00279
if (isNaN(x))
00280
return String(
"NaN");
00281
00282
char *result = kjs_dtoa(x, 0, 0, &decimalPoint, &sign, NULL);
00283
int length = strlen(result);
00284 decimalPoint += decimalAdjust;
00285
00286
int i = 0;
00287
if (sign) {
00288 buf[i++] =
'-';
00289 }
00290
00291
if (decimalPoint == 999) {
00292 strcpy(buf + i, result);
00293 }
else {
00294 buf[i++] = result[0];
00295
00296
if (fractionDigits.
isA(UndefinedType))
00297 f = length-1;
00298
00299
if (length > 1 && f > 0) {
00300 buf[i++] =
'.';
00301
int haveFDigits = length-1;
00302
if (f < haveFDigits) {
00303 strncpy(buf+i,result+1, f);
00304 i += f;
00305 }
00306
else {
00307 strcpy(buf+i,result+1);
00308 i += length-1;
00309
for (
int j = 0; j < f-haveFDigits; j++)
00310 buf[i++] =
'0';
00311 }
00312 }
00313
00314 buf[i++] =
'e';
00315 buf[i++] = (decimalPoint >= 0) ?
'+' :
'-';
00316
00317
00318
int exponential = decimalPoint - 1;
00319
if (exponential < 0) {
00320 exponential = exponential * -1;
00321 }
00322
if (exponential >= 100) {
00323 buf[i++] =
'0' + exponential / 100;
00324 }
00325
if (exponential >= 10) {
00326 buf[i++] =
'0' + (exponential % 100) / 10;
00327 }
00328 buf[i++] =
'0' + exponential % 10;
00329 buf[i++] =
'\0';
00330 }
00331
00332 assert(i <= 80);
00333
00334 kjs_freedtoa(result);
00335
00336
return String(
UString(buf));
00337 }
00338
case ToPrecision: {
00339
int e = 0;
00340
UString m;
00341
00342
int p = args[0].
toInteger(exec);
00343
double x = v.
toNumber(exec);
00344
if (args[0].isA(UndefinedType) || isNaN(x) || isInf(x))
00345
return String(v.
toString(exec));
00346
00347
UString s =
"";
00348
if (x < 0) {
00349 s =
"-";
00350 x = -x;
00351 }
00352
00353
if (p < 1 || p > 21) {
00354
Object err =
Error::create(exec,RangeError);
00355 exec->
setException(err);
00356
return err;
00357 }
00358
00359
if (x != 0) {
00360 e = int(log10(x));
00361
double n = floor(x/pow(10.0,e-p+1));
00362
if (n < pow(10.0,p-1)) {
00363 e = e - 1;
00364 n = floor(x/pow(10.0,e-p+1));
00365 }
00366
00367
if (fabs((n+1)*pow(10.0,e-p+1)-x) < fabs(n*pow(10.0,e-p+1)-x))
00368 n++;
00369 assert(pow(10.0,p-1) <= n);
00370 assert(n < pow(10.0,p));
00371
00372 m = integer_part_noexp(n);
00373
if (e < -6 || e >= p) {
00374
if (m.
size() > 1)
00375 m = m.
substr(0,1)+
"."+m.
substr(1);
00376
if (e >= 0)
00377
return String(s+m+
"e+"+UString::from(e));
00378
else
00379
return String(s+m+
"e-"+UString::from(-e));
00380 }
00381 }
00382
else {
00383 m = char_sequence(
'0',p);
00384 e = 0;
00385 }
00386
00387
if (e == p-1) {
00388
return String(s+m);
00389 }
00390
else if (e >= 0) {
00391
if (e+1 < m.
size())
00392
return String(s+m.
substr(0,e+1)+
"."+m.
substr(e+1));
00393
else
00394
return String(s+m.
substr(0,e+1));
00395 }
00396
else {
00397
return String(s+
"0."+char_sequence(
'0',-(e+1))+m);
00398 }
00399 }
00400 }
00401
00402
return result;
00403 }
00404
00405
00406
00407
const ClassInfo NumberObjectImp::info = {
"Function", &InternalFunctionImp::info, &numberTable, 0};
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 NumberObjectImp::NumberObjectImp(
ExecState *,
00419
FunctionPrototypeImp *funcProto,
00420 NumberPrototypeImp *numberProto)
00421 :
InternalFunctionImp(funcProto)
00422 {
00423
Value protect(
this);
00424
00425 putDirect(prototypePropertyName, numberProto, DontEnum|DontDelete|ReadOnly);
00426
00427
00428 putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum);
00429 }
00430
00431
Value NumberObjectImp::get(
ExecState *exec,
const Identifier &propertyName)
const
00432
{
00433
return lookupGetValue<NumberObjectImp, InternalFunctionImp>( exec, propertyName, &numberTable,
this );
00434 }
00435
00436
Value NumberObjectImp::getValueProperty(
ExecState *,
int token)
const
00437
{
00438
00439
switch(token) {
00440
case NaNValue:
00441
return Number(NaN);
00442
case NegInfinity:
00443
return Number(-Inf);
00444
case PosInfinity:
00445
return Number(Inf);
00446
case MaxValue:
00447
return Number(1.7976931348623157E+308);
00448
case MinValue:
00449
return Number(5E-324);
00450 }
00451
return Null();
00452 }
00453
00454
bool NumberObjectImp::implementsConstruct()
const
00455
{
00456
return true;
00457 }
00458
00459
00460
00461
Object NumberObjectImp::construct(
ExecState *exec,
const List &args)
00462 {
00463 ObjectImp *proto = exec->
interpreter()->
builtinNumberPrototype().
imp();
00464
Object obj(
new NumberInstanceImp(proto));
00465
00466
Number n;
00467
if (args.
isEmpty())
00468 n =
Number(0);
00469
else
00470 n = args[0].toNumber(exec);
00471
00472 obj.setInternalValue(n);
00473
00474
return obj;
00475 }
00476
00477
bool NumberObjectImp::implementsCall()
const
00478
{
00479
return true;
00480 }
00481
00482
00483
Value NumberObjectImp::call(
ExecState *exec,
Object &,
const List &args)
00484 {
00485
if (args.
isEmpty())
00486
return Number(0);
00487
else
00488
return Number(args[0].toNumber(exec));
00489 }