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

kjs

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

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.8.11
This website is maintained by Timothy Pearson.