• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kjs
 

kjs

  • kjs
number_object.cpp
1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
4 * Copyright (C) 2003 Peter Kelly (pmk@post.com)
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22#include "value.h"
23#include "object.h"
24#include "types.h"
25#include "interpreter.h"
26#include "operations.h"
27#include "number_object.h"
28#include "error_object.h"
29#include "dtoa.h"
30
31#include "number_object.lut.h"
32
33#include <assert.h>
34#include <math.h>
35
36using namespace KJS;
37
38// ------------------------------ NumberInstanceImp ----------------------------
39
40const ClassInfo NumberInstanceImp::info = {"Number", 0, 0, 0};
41
42NumberInstanceImp::NumberInstanceImp(ObjectImp *proto)
43 : ObjectImp(proto)
44{
45}
46// ------------------------------ NumberPrototypeImp ---------------------------
47
48// ECMA 15.7.4
49
50NumberPrototypeImp::NumberPrototypeImp(ExecState *exec,
51 ObjectPrototypeImp *objProto,
52 FunctionPrototypeImp *funcProto)
53 : NumberInstanceImp(objProto)
54{
55 Value protect(this);
56 setInternalValue(NumberImp::zero());
57
58 // The constructor will be added later, after NumberObjectImp has been constructed
59
60 putDirect(toStringPropertyName,new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToString,
61 1,toStringPropertyName),DontEnum);
62 putDirect(toLocaleStringPropertyName,new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToLocaleString,
63 0,toLocaleStringPropertyName),DontEnum);
64 putDirect(valueOfPropertyName,new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ValueOf,
65 0,valueOfPropertyName),DontEnum);
66 putDirect("toFixed", new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToFixed,
67 1,"toFixed"),DontEnum);
68 putDirect("toExponential",new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToExponential,
69 1,"toExponential"),DontEnum);
70 putDirect("toPrecision",new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToPrecision,
71 1,"toPrecision"),DontEnum);
72}
73
74
75// ------------------------------ NumberProtoFuncImp ---------------------------
76
77NumberProtoFuncImp::NumberProtoFuncImp(ExecState * /*exec*/, FunctionPrototypeImp *funcProto,
78 int i, int len, const Identifier &_ident)
79 : InternalFunctionImp(funcProto), id(i)
80{
81 Value protect(this);
82 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
83 ident = _ident;
84}
85
86
87bool NumberProtoFuncImp::implementsCall() const
88{
89 return true;
90}
91
92static UString integer_part_noexp(double d)
93{
94 int decimalPoint;
95 int signDummy;
96 char *result = kjs_dtoa(d, 0, 0, &decimalPoint, &signDummy, NULL);
97 int length = strlen(result);
98
99 // sign for non-zero, negative numbers
100 UString str = d < 0 ? "-" : "";
101 if (decimalPoint == 9999) {
102 str += UString(result);
103 } else if (decimalPoint <= 0) {
104 str += UString("0");
105 } else {
106 char *buf;
107
108 if (length <= decimalPoint) {
109 buf = (char*)malloc(decimalPoint+1);
110 strcpy(buf,result);
111 memset(buf+length,'0',decimalPoint-length);
112 } else {
113 buf = (char*)malloc(decimalPoint+1);
114 strncpy(buf,result,decimalPoint);
115 }
116
117 buf[decimalPoint] = '\0';
118 str += UString(buf);
119 free(buf);
120 }
121
122 kjs_freedtoa(result);
123
124 return str;
125}
126
127static UString char_sequence(char c, int count)
128{
129 char *buf = (char*)malloc(count+1);
130 memset(buf,c,count);
131 buf[count] = '\0';
132 UString s(buf);
133 free(buf);
134 return s;
135}
136
137// ECMA 15.7.4.2 - 15.7.4.7
138Value NumberProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
139{
140 Value result;
141
142 // no generic function. "this" has to be a Number object
143 KJS_CHECK_THIS( NumberInstanceImp, thisObj );
144
145 // execute "toString()" or "valueOf()", respectively
146 Value v = thisObj.internalValue();
147 switch (id) {
148 case ToString: {
149 int radix = 10;
150 if (!args.isEmpty() && args[0].type() != UndefinedType)
151 radix = args[0].toInteger(exec);
152 if (radix < 2 || radix > 36 || radix == 10)
153 result = String(v.toString(exec));
154 else {
155 const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
156 // INT_MAX results in 1024 characters left of the dot with radix 2
157 // give the same space on the right side. safety checks are in place
158 // unless someone finds a precise rule.
159 char s[2048 + 3];
160 double x = v.toNumber(exec);
161 if (isNaN(x) || isInf(x))
162 return String(UString::from(x));
163 // apply algorithm on absolute value. add sign later.
164 bool neg = false;
165 if (x < 0.0) {
166 neg = true;
167 x = -x;
168 }
169 // convert integer portion
170 double f = floor(x);
171 double d = f;
172 char *dot = s + sizeof(s) / 2;
173 char *p = dot;
174 *p = '\0';
175 do {
176 *--p = digits[int(fmod(d, double(radix)))];
177 d /= radix;
178 } while ((d <= -1.0 || d >= 1.0) && p > s);
179 // any decimal fraction ?
180 d = x - f;
181 const double eps = 0.001; // TODO: guessed. base on radix ?
182 if (d < -eps || d > eps) {
183 *dot++ = '.';
184 do {
185 d *= radix;
186 *dot++ = digits[int(d)];
187 d -= int(d);
188 } while ((d < -eps || d > eps) && dot - s < int(sizeof(s)) - 1);
189 *dot = '\0';
190 }
191 // add sign if negative
192 if (neg)
193 *--p = '-';
194 result = String(p);
195 }
196 break;
197 }
198 case ToLocaleString: /* TODO */
199 result = String(v.toString(exec));
200 break;
201 case ValueOf:
202 result = Number(v.toNumber(exec));
203 break;
204 case ToFixed:
205 {
206 // FIXME: firefox works for all values, not just 0..20. This includes
207 // NaN, infinity, undefined, etc. This is just a hack to pass our regression
208 // suite.
209 Value fractionDigits = args[0];
210 int f = -1;
211 double fd = fractionDigits.toNumber(exec);
212 if (isNaN(fd)) {
213 f = 0;
214 } else if (!isInf(fd)) {
215 f = int(fd);
216 }
217 if (f < 0 || f > 20) {
218 Object err = Error::create(exec,RangeError);
219 exec->setException(err);
220 return err;
221 }
222
223 double x = v.toNumber(exec);
224 if (isNaN(x))
225 return String("NaN");
226
227 UString s = "";
228 if (x < 0) {
229 s += "-";
230 x = -x;
231 }
232
233 if (x >= 1e21)
234 return String(s+UString::from(x));
235
236 double n = floor(x*pow(10.0,f));
237 if (fabs(n/pow(10.0,f)-x) > fabs((n+1)/pow(10.0,f)-x))
238 n++;
239
240 UString m = integer_part_noexp(n);
241
242 int k = m.size();
243 if (k <= f) {
244 UString z = "";
245 for (int i = 0; i < f+1-k; i++)
246 z += "0";
247 m = z + m;
248 k = f + 1;
249 assert(k == m.size());
250 }
251 if (k-f < m.size())
252 return String(s+m.substr(0,k-f)+"."+m.substr(k-f));
253 else
254 return String(s+m.substr(0,k-f));
255 }
256 case ToExponential: {
257 double x = v.toNumber(exec);
258
259 if (isNaN(x) || isInf(x))
260 return String(UString::from(x));
261
262 int f = 1;
263 Value fractionDigits = args[0];
264 if (args.size() > 0) {
265 f = fractionDigits.toInteger(exec);
266 if (f < 0 || f > 20) {
267 Object err = Error::create(exec,RangeError);
268 exec->setException(err);
269 return err;
270 }
271 }
272
273 int decimalAdjust = 0;
274 if (!fractionDigits.isA(UndefinedType)) {
275 double logx = floor(log10(fabs(x)));
276 x /= pow(10.0,logx);
277 double fx = floor(x*pow(10.0,f))/pow(10.0,f);
278 double cx = ceil(x*pow(10.0,f))/pow(10.0,f);
279
280 if (fabs(fx-x) < fabs(cx-x))
281 x = fx;
282 else
283 x = cx;
284
285 decimalAdjust = int(logx);
286 }
287
288 char buf[80];
289 int decimalPoint;
290 int sign;
291
292 if (isNaN(x))
293 return String("NaN");
294
295 char *result = kjs_dtoa(x, 0, 0, &decimalPoint, &sign, NULL);
296 int length = strlen(result);
297 decimalPoint += decimalAdjust;
298
299 int i = 0;
300 if (sign) {
301 buf[i++] = '-';
302 }
303
304 if (decimalPoint == 999) {
305 strcpy(buf + i, result);
306 } else {
307 buf[i++] = result[0];
308
309 if (fractionDigits.isA(UndefinedType))
310 f = length-1;
311
312 if (length > 1 && f > 0) {
313 buf[i++] = '.';
314 int haveFDigits = length-1;
315 if (f < haveFDigits) {
316 strncpy(buf+i,result+1, f);
317 i += f;
318 }
319 else {
320 strcpy(buf+i,result+1);
321 i += length-1;
322 for (int j = 0; j < f-haveFDigits; j++)
323 buf[i++] = '0';
324 }
325 }
326
327 buf[i++] = 'e';
328 buf[i++] = (decimalPoint >= 0) ? '+' : '-';
329 // decimalPoint can't be more than 3 digits decimal given the
330 // nature of float representation
331 int exponential = decimalPoint - 1;
332 if (exponential < 0) {
333 exponential = exponential * -1;
334 }
335 if (exponential >= 100) {
336 buf[i++] = '0' + exponential / 100;
337 }
338 if (exponential >= 10) {
339 buf[i++] = '0' + (exponential % 100) / 10;
340 }
341 buf[i++] = '0' + exponential % 10;
342 buf[i++] = '\0';
343 }
344
345 assert(i <= 80);
346
347 kjs_freedtoa(result);
348
349 return String(UString(buf));
350 }
351 case ToPrecision:
352 {
353 int e = 0;
354 UString m;
355
356 int p = args[0].toInteger(exec);
357 double x = v.toNumber(exec);
358 if (args[0].isA(UndefinedType) || isNaN(x) || isInf(x))
359 return String(v.toString(exec));
360
361 UString s = "";
362 if (x < 0) {
363 s = "-";
364 x = -x;
365 }
366
367 if (p < 1 || p > 21) {
368 Object err = Error::create(exec, RangeError,
369 "toPrecision() argument must be between 1 and 21");
370 exec->setException(err);
371 return err;
372 }
373
374 if (x != 0) {
375 // suggestions for a better algorithm welcome!
376 e = int(log10(x));
377 double n = floor(x/pow(10.0,e-p+1));
378 if (n < pow(10.0,p-1)) {
379 // first guess was not good
380 e = e - 1;
381 n = floor(x/pow(10.0,e-p+1));
382 if (n >= pow(10.0,p)) {
383 // violated constraint. try something else.
384 n = pow(10.0,p-1);
385 e = int(log10(x/n)) + p - 1;
386 }
387 }
388
389 if (fabs((n+1)*pow(10.0,e-p+1)-x) < fabs(n*pow(10.0,e-p+1)-x))
390 n++;
391 assert(pow(10.0,p-1) <= n);
392 assert(n < pow(10.0,p));
393
394 m = integer_part_noexp(n);
395 if (e < -6 || e >= p) {
396 if (m.size() > 1)
397 m = m.substr(0,1)+"."+m.substr(1);
398 if (e >= 0)
399 return String(s+m+"e+"+UString::from(e));
400 else
401 return String(s+m+"e-"+UString::from(-e));
402 }
403 }
404 else {
405 m = char_sequence('0',p);
406 e = 0;
407 }
408
409 if (e == p-1) {
410 return String(s+m);
411 }
412 else if (e >= 0) {
413 if (e+1 < m.size())
414 return String(s+m.substr(0,e+1)+"."+m.substr(e+1));
415 else
416 return String(s+m.substr(0,e+1));
417 }
418 else {
419 return String(s+"0."+char_sequence('0',-(e+1))+m);
420 }
421 }
422 }
423
424 return result;
425}
426
427// ------------------------------ NumberObjectImp ------------------------------
428
429const ClassInfo NumberObjectImp::info = {"Function", &InternalFunctionImp::info, &numberTable, 0};
430
431/* Source for number_object.lut.h
432@begin numberTable 5
433 NaN NumberObjectImp::NaNValue DontEnum|DontDelete|ReadOnly
434 NEGATIVE_INFINITY NumberObjectImp::NegInfinity DontEnum|DontDelete|ReadOnly
435 POSITIVE_INFINITY NumberObjectImp::PosInfinity DontEnum|DontDelete|ReadOnly
436 MAX_VALUE NumberObjectImp::MaxValue DontEnum|DontDelete|ReadOnly
437 MIN_VALUE NumberObjectImp::MinValue DontEnum|DontDelete|ReadOnly
438@end
439*/
440NumberObjectImp::NumberObjectImp(ExecState * /*exec*/,
441 FunctionPrototypeImp *funcProto,
442 NumberPrototypeImp *numberProto)
443 : InternalFunctionImp(funcProto)
444{
445 Value protect(this);
446 // Number.Prototype
447 putDirect(prototypePropertyName, numberProto, DontEnum|DontDelete|ReadOnly);
448
449 // no. of arguments for constructor
450 putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum);
451}
452
453Value NumberObjectImp::get(ExecState *exec, const Identifier &propertyName) const
454{
455 return lookupGetValue<NumberObjectImp, InternalFunctionImp>( exec, propertyName, &numberTable, this );
456}
457
458Value NumberObjectImp::getValueProperty(ExecState *, int token) const
459{
460 // ECMA 15.7.3
461 switch(token) {
462 case NaNValue:
463 return Number(NaN);
464 case NegInfinity:
465 return Number(-Inf);
466 case PosInfinity:
467 return Number(Inf);
468 case MaxValue:
469 return Number(1.7976931348623157E+308);
470 case MinValue:
471 return Number(5E-324);
472 }
473 return Null();
474}
475
476bool NumberObjectImp::implementsConstruct() const
477{
478 return true;
479}
480
481
482// ECMA 15.7.1
483Object NumberObjectImp::construct(ExecState *exec, const List &args)
484{
485 ObjectImp *proto = exec->lexicalInterpreter()->builtinNumberPrototype().imp();
486 Object obj(new NumberInstanceImp(proto));
487
488 Number n;
489 if (args.isEmpty())
490 n = Number(0);
491 else
492 n = args[0].toNumber(exec);
493
494 obj.setInternalValue(n);
495
496 return obj;
497}
498
499bool NumberObjectImp::implementsCall() const
500{
501 return true;
502}
503
504// ECMA 15.7.2
505Value NumberObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
506{
507 if (args.isEmpty())
508 return Number(0);
509 else
510 return Number(args[0].toNumber(exec));
511}
KJS::ExecState
Represents the current state of script execution.
Definition: interpreter.h:438
KJS::ExecState::lexicalInterpreter
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope's global object.
Definition: interpreter.cpp:394
KJS::FunctionPrototypeImp
The initial value of Function.prototype (and thus all objects created with the Function constructor)
Definition: function_object.h:34
KJS::Identifier
Represents an Identifier for a Javascript object.
Definition: identifier.h:32
KJS::InternalFunctionImp
Base class for all function objects.
Definition: function.h:40
KJS::Interpreter::builtinNumberPrototype
Object builtinNumberPrototype() const
Returns the builtin "Number.prototype" object.
Definition: interpreter.cpp:243
KJS::List
Native list type.
Definition: list.h:48
KJS::List::isEmpty
bool isEmpty() const
Definition: list.h:86
KJS::List::size
int size() const
Definition: list.h:90
KJS::Null
Represents an primitive Null value.
Definition: value.h:294
KJS::Number
Represents an primitive Number value.
Definition: value.h:367
KJS::Object
Represents an Object.
Definition: object.h:81
KJS::Object::internalValue
Value internalValue() const
Returns the internal value of the object.
Definition: object.h:717
KJS::String
Represents an primitive String value.
Definition: value.h:340
KJS::UString
Unicode string class.
Definition: ustring.h:189
KJS::UString::size
int size() const
Definition: ustring.h:359
KJS::UString::substr
UString substr(int pos=0, int len=-1) const
Definition: ustring.cpp:868
KJS::Value
Value objects are act as wrappers ("smart pointers") around ValueImp objects and their descendents.
Definition: value.h:167
KJS::Value::toString
UString toString(ExecState *exec) const
Performs the ToString type conversion operation on this value (ECMA 9.8)
Definition: value.h:246
KJS::Value::isA
bool isA(Type t) const
Checks whether or not the value is of a particular tpye.
Definition: value.h:203
KJS::Value::toInteger
int toInteger(ExecState *exec) const
Performs the ToInteger type conversion operation on this value (ECMA 9.4)
Definition: value.h:226
KJS::Value::toNumber
double toNumber(ExecState *exec) const
Performs the ToNumber type conversion operation on this value (ECMA 9.3)
Definition: value.h:221
KJS::ClassInfo
Class Information.
Definition: object.h:58

kjs

Skip menu "kjs"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kjs

Skip menu "kjs"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kjs by doxygen 1.9.4
This website is maintained by Timothy Pearson.