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

kjs

  • kjs
object.cpp
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
4  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
5  * Copyright (C) 2003 Apple Computer, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB. If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23 
24 #include "value.h"
25 #include "object.h"
26 #include "types.h"
27 #include "interpreter.h"
28 #include "lookup.h"
29 #include "reference_list.h"
30 
31 #include <assert.h>
32 #include <math.h>
33 #include <stdio.h>
34 
35 #include "internal.h"
36 #include "collector.h"
37 #include "operations.h"
38 #include "error_object.h"
39 #include "nodes.h"
40 
41 using namespace KJS;
42 
43 // ------------------------------ Object ---------------------------------------
44 
45 Object Object::dynamicCast(const Value &v)
46 {
47  if (!v.isValid() || v.type() != ObjectType)
48  return Object(0);
49 
50  return Object(static_cast<ObjectImp*>(v.imp()));
51 }
52 
53 Value Object::call(ExecState *exec, Object &thisObj, const List &args)
54 {
55 #if KJS_MAX_STACK > 0
56  static int depth = 0; // sum of all concurrent interpreters
57  if (++depth > KJS_MAX_STACK) {
58 #ifndef NDEBUG
59  fprintf(stderr, "Exceeded maximum function call depth\n");
60 #endif
61  int saveDepth = depth - 1;
62  Object err = Error::create(exec, RangeError,
63  "Exceeded maximum function call depth.");
64  depth = depth - 10; //Give some room for the debugger to operate,
65  //so if it tries to examine things we don't get here again
66  exec->setException(err);
67  depth = saveDepth;
68  return err;
69  }
70 #endif
71 
72  Value ret = static_cast<ObjectImp*>(rep)->call(exec,thisObj,args);
73 
74 #if KJS_MAX_STACK > 0
75  --depth;
76 #endif
77 
78  return ret;
79 }
80 
81 // ------------------------------ ObjectImp ------------------------------------
82 
83 ObjectImp::ObjectImp(const Object &proto)
84  : _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L)
85 {
86  //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
87 }
88 
89 ObjectImp::ObjectImp(ObjectImp *proto)
90  : _proto(proto), _internalValue(0L)
91 {
92 }
93 
94 ObjectImp::ObjectImp()
95 {
96  //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
97  _proto = NullImp::staticNull;
98  _internalValue = 0L;
99 }
100 
101 ObjectImp::~ObjectImp()
102 {
103  //fprintf(stderr,"ObjectImp::~ObjectImp %p\n",(void*)this);
104 }
105 
106 void ObjectImp::mark()
107 {
108  //fprintf(stderr,"ObjectImp::mark() %p\n",(void*)this);
109  ValueImp::mark();
110 
111  if (_proto && !_proto->marked())
112  _proto->mark();
113 
114  _prop.mark();
115 
116  if (_internalValue && !_internalValue->marked())
117  _internalValue->mark();
118 
119  _scope.mark();
120 }
121 
122 const ClassInfo *ObjectImp::classInfo() const
123 {
124  return 0;
125 }
126 
127 bool ObjectImp::inherits(const ClassInfo *info) const
128 {
129  if (!info)
130  return false;
131 
132  const ClassInfo *ci = classInfo();
133  if (!ci)
134  return false;
135 
136  while (ci && ci != info)
137  ci = ci->parentClass;
138 
139  return (ci == info);
140 }
141 
142 Type ObjectImp::type() const
143 {
144  return ObjectType;
145 }
146 
147 Value ObjectImp::prototype() const
148 {
149  return Value(_proto);
150 }
151 
152 void ObjectImp::setPrototype(const Value &proto)
153 {
154  _proto = proto.imp();
155 }
156 
157 UString ObjectImp::className() const
158 {
159  const ClassInfo *ci = classInfo();
160  if ( ci )
161  return ci->className;
162  return "Object";
163 }
164 
165 Value ObjectImp::get(ExecState *exec, const Identifier &propertyName) const
166 {
167  ValueImp *imp = getDirect(propertyName);
168  if (imp)
169  return Value(imp);
170 
171  Object proto = Object::dynamicCast(prototype());
172 
173  // non-standard netscape extension
174  if (propertyName == specialPrototypePropertyName) {
175  if (!proto.isValid())
176  return Null();
177  else
178  return Value(proto);
179  }
180 
181  if (!proto.isValid())
182  return Undefined();
183 
184  return proto.get(exec,propertyName);
185 }
186 
187 Value ObjectImp::getPropertyByIndex(ExecState *exec,
188  unsigned propertyName) const
189 {
190  return get(exec, Identifier::from(propertyName));
191 }
192 
193 // ECMA 8.6.2.2
194 void ObjectImp::put(ExecState *exec, const Identifier &propertyName,
195  const Value &value, int attr)
196 {
197  assert(value.isValid());
198 
199  // non-standard netscape extension
200  if (propertyName == specialPrototypePropertyName) {
201  setPrototype(value);
202  return;
203  }
204 
205  /* TODO: check for write permissions directly w/o this call */
206  /* Doesn't look very easy with the PropertyMap API - David */
207  // putValue() is used for JS assignemnts. It passes no attribute.
208  // Assume that a C++ implementation knows what it is doing
209  // and let it override the canPut() check.
210  if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) {
211 #ifdef KJS_VERBOSE
212  fprintf( stderr, "[kjs-object] WARNING: canPut %s said NO\n", propertyName.ascii() );
213 #endif
214  return;
215  }
216 
217  _prop.put(propertyName,value.imp(),attr);
218 }
219 
220 // delme
221 void ObjectImp::putPropertyByIndex(ExecState *exec, unsigned propertyName,
222  const Value &value, int attr)
223 {
224  put(exec, Identifier::from(propertyName), value, attr);
225 }
226 
227 // ECMA 8.6.2.3
228 bool ObjectImp::canPut(ExecState *, const Identifier &propertyName) const
229 {
230  int attributes;
231  ValueImp *v = _prop.get(propertyName, attributes);
232  if (v)
233  return!(attributes & ReadOnly);
234 
235  // Look in the static hashtable of properties
236  const HashEntry* e = findPropertyHashEntry(propertyName);
237  if (e)
238  return !(e->attr & ReadOnly);
239 
240  // Don't look in the prototype here. We can always put an override
241  // in the object, even if the prototype has a ReadOnly property.
242  return true;
243 }
244 
245 // ECMA 8.6.2.4
246 bool ObjectImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
247 {
248  if (_prop.get(propertyName))
249  return true;
250 
251  // Look in the static hashtable of properties
252  if (findPropertyHashEntry(propertyName))
253  return true;
254 
255  // non-standard netscape extension
256  if (propertyName == specialPrototypePropertyName)
257  return true;
258 
259  // Look in the prototype
260  Object proto = Object::dynamicCast(prototype());
261  return proto.isValid() && proto.hasProperty(exec,propertyName);
262 }
263 
264 bool ObjectImp::hasPropertyByIndex(ExecState *exec, unsigned propertyName) const
265 {
266  return hasProperty(exec, Identifier::from(propertyName));
267 }
268 
269 // ECMA 8.6.2.5
270 bool ObjectImp::deleteProperty(ExecState * /*exec*/, const Identifier &propertyName)
271 {
272  int attributes;
273  ValueImp *v = _prop.get(propertyName, attributes);
274  if (v) {
275  if ((attributes & DontDelete))
276  return false;
277  _prop.remove(propertyName);
278  return true;
279  }
280 
281  // Look in the static hashtable of properties
282  const HashEntry* entry = findPropertyHashEntry(propertyName);
283  if (entry && entry->attr & DontDelete)
284  return false; // this builtin property can't be deleted
285  return true;
286 }
287 
288 bool ObjectImp::deletePropertyByIndex(ExecState *exec, unsigned propertyName)
289 {
290  return deleteProperty(exec, Identifier::from(propertyName));
291 }
292 
293 void ObjectImp::deleteAllProperties( ExecState * )
294 {
295  _prop.clear();
296 }
297 
298 // ECMA 8.6.2.6
299 Value ObjectImp::defaultValue(ExecState *exec, Type hint) const
300 {
301  if (hint != StringType && hint != NumberType) {
302  /* Prefer String for Date objects */
303  if (_proto == exec->lexicalInterpreter()->builtinDatePrototype().imp())
304  hint = StringType;
305  else
306  hint = NumberType;
307  }
308 
309  Value v;
310  if (hint == StringType)
311  v = get(exec,toStringPropertyName);
312  else
313  v = get(exec,valueOfPropertyName);
314 
315  if (v.type() == ObjectType) {
316  Object o = Object(static_cast<ObjectImp*>(v.imp()));
317  if (o.implementsCall()) { // spec says "not primitive type" but ...
318  Object thisObj = Object(const_cast<ObjectImp*>(this));
319  Value def = o.call(exec,thisObj,List::empty());
320  Type defType = def.type();
321  if (defType == UnspecifiedType || defType == UndefinedType ||
322  defType == NullType || defType == BooleanType ||
323  defType == StringType || defType == NumberType) {
324  return def;
325  }
326  }
327  }
328 
329  if (hint == StringType)
330  v = get(exec,valueOfPropertyName);
331  else
332  v = get(exec,toStringPropertyName);
333 
334  if (v.type() == ObjectType) {
335  Object o = Object(static_cast<ObjectImp*>(v.imp()));
336  if (o.implementsCall()) { // spec says "not primitive type" but ...
337  Object thisObj = Object(const_cast<ObjectImp*>(this));
338  Value def = o.call(exec,thisObj,List::empty());
339  Type defType = def.type();
340  if (defType == UnspecifiedType || defType == UndefinedType ||
341  defType == NullType || defType == BooleanType ||
342  defType == StringType || defType == NumberType) {
343  return def;
344  }
345  }
346  }
347 
348  Object err = Error::create(exec, TypeError, I18N_NOOP("No default value"));
349  exec->setException(err);
350  return err;
351 }
352 
353 const HashEntry* ObjectImp::findPropertyHashEntry( const Identifier& propertyName ) const
354 {
355  const ClassInfo *info = classInfo();
356  while (info) {
357  if (info->propHashTable) {
358  const HashEntry *e = Lookup::findEntry(info->propHashTable, propertyName);
359  if (e)
360  return e;
361  }
362  info = info->parentClass;
363  }
364  return 0L;
365 }
366 
367 bool ObjectImp::implementsConstruct() const
368 {
369  return false;
370 }
371 
372 Object ObjectImp::construct(ExecState* /*exec*/, const List &/*args*/)
373 {
374  assert(false);
375  return Object(0);
376 }
377 
378 bool ObjectImp::implementsCall() const
379 {
380  return false;
381 }
382 
383 Value ObjectImp::call(ExecState* /*exec*/, Object &/*thisObj*/, const List &/*args*/)
384 {
385  assert(false);
386  return Object(0);
387 }
388 
389 bool ObjectImp::implementsHasInstance() const
390 {
391  return false;
392 }
393 
394 Boolean ObjectImp::hasInstance(ExecState* /*exec*/, const Value &/*value*/)
395 {
396  assert(false);
397  return Boolean(false);
398 }
399 
400 ReferenceList ObjectImp::propList(ExecState *exec, bool recursive)
401 {
402  ReferenceList list;
403  if (_proto && _proto->dispatchType() == ObjectType && recursive)
404  list = static_cast<ObjectImp*>(_proto)->propList(exec,recursive);
405 
406  _prop.addEnumerablesToReferenceList(list, Object(this));
407 
408  // Add properties from the static hashtable of properties
409  const ClassInfo *info = classInfo();
410  while (info) {
411  if (info->propHashTable) {
412  int size = info->propHashTable->size;
413  const HashEntry *e = info->propHashTable->entries;
414  for (int i = 0; i < size; ++i, ++e) {
415  if ( e->soffset && !(e->attr & DontEnum) )
416  list.append(Reference(this, &info->propHashTable->sbase[e->soffset]));
417  }
418  }
419  info = info->parentClass;
420  }
421 
422  return list;
423 }
424 
425 Value ObjectImp::internalValue() const
426 {
427  return Value(_internalValue);
428 }
429 
430 void ObjectImp::setInternalValue(const Value &v)
431 {
432  _internalValue = v.imp();
433 }
434 
435 void ObjectImp::setInternalValue(ValueImp *v)
436 {
437  v->setGcAllowed();
438  _internalValue = v;
439 }
440 
441 Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const
442 {
443  return defaultValue(exec,preferredType);
444 }
445 
446 bool ObjectImp::toBoolean(ExecState* /*exec*/) const
447 {
448  return true;
449 }
450 
451 double ObjectImp::toNumber(ExecState *exec) const
452 {
453  Value prim = toPrimitive(exec,NumberType);
454  if (exec->hadException()) // should be picked up soon in nodes.cpp
455  return 0.0;
456  return prim.toNumber(exec);
457 }
458 
459 UString ObjectImp::toString(ExecState *exec) const
460 {
461  Value prim = toPrimitive(exec,StringType);
462  if (exec->hadException()) // should be picked up soon in nodes.cpp
463  return "";
464  return prim.toString(exec);
465 }
466 
467 Object ObjectImp::toObject(ExecState * /*exec*/) const
468 {
469  return Object(const_cast<ObjectImp*>(this));
470 }
471 
472 void ObjectImp::putDirect(const Identifier &propertyName, ValueImp *value, int attr)
473 {
474  value->setGcAllowed();
475  _prop.put(propertyName, value, attr);
476 }
477 
478 void ObjectImp::putDirect(const Identifier &propertyName, int value, int attr)
479 {
480  _prop.put(propertyName, NumberImp::create(value), attr);
481 }
482 
483 void ObjectImp::setFunctionName(const Identifier &propertyName)
484 {
485  if (inherits(&InternalFunctionImp::info))
486  static_cast<InternalFunctionImp*>(this)->setName(propertyName);
487 }
488 
489 // ------------------------------ Error ----------------------------------------
490 
491 const char * const errorNamesArr[] = {
492  I18N_NOOP("Error"), // GeneralError
493  I18N_NOOP("Evaluation error"), // EvalError
494  I18N_NOOP("Range error"), // RangeError
495  I18N_NOOP("Reference error"), // ReferenceError
496  I18N_NOOP("Syntax error"), // SyntaxError
497  I18N_NOOP("Type error"), // TypeError
498  I18N_NOOP("URI error"), // URIError
499 };
500 
501 const char * const * const Error::errorNames = errorNamesArr;
502 
503 Object Error::create(ExecState *exec, ErrorType errtype, const char *message,
504  int lineno, int sourceId)
505 {
506 #ifdef KJS_VERBOSE
507  // message could be 0L. Don't enable this on Solaris ;)
508  fprintf(stderr, "WARNING: KJS %s: %s\n", errorNames[errtype], message);
509 #endif
510 
511  Object cons;
512 
513  switch (errtype) {
514  case EvalError:
515  cons = exec->lexicalInterpreter()->builtinEvalError();
516  break;
517  case RangeError:
518  cons = exec->lexicalInterpreter()->builtinRangeError();
519  break;
520  case ReferenceError:
521  cons = exec->lexicalInterpreter()->builtinReferenceError();
522  break;
523  case SyntaxError:
524  cons = exec->lexicalInterpreter()->builtinSyntaxError();
525  break;
526  case TypeError:
527  cons = exec->lexicalInterpreter()->builtinTypeError();
528  break;
529  case URIError:
530  cons = exec->lexicalInterpreter()->builtinURIError();
531  break;
532  default:
533  cons = exec->lexicalInterpreter()->builtinError();
534  break;
535  }
536 
537  if (!message)
538  message = errorNames[errtype];
539  List args;
540  args.append(String(message));
541  Object err = Object::dynamicCast(cons.construct(exec,args));
542 
543  if (lineno != -1)
544  err.put(exec, "line", Number(lineno));
545  if (sourceId != -1)
546  err.put(exec, "sourceId", Number(sourceId));
547 
548  return err;
549 
550 /*
551 #ifndef NDEBUG
552  const char *msg = err.get(messagePropertyName).toString().value().ascii();
553  if (l >= 0)
554  fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
555  else
556  fprintf(stderr, "KJS: %s. %s\n", estr, msg);
557 #endif
558 
559  return err;
560 */
561 }
562 
KJS::Value
Value objects are act as wrappers ("smart pointers") around ValueImp objects and their descendents...
Definition: value.h:167
KJS::Value::type
Type type() const
Returns the type of value.
Definition: value.h:195
KJS::ClassInfo::parentClass
const ClassInfo * parentClass
Pointer to the class information of the base class.
Definition: object.h:67
KJS::InternalFunctionImp
Base class for all function objects.
Definition: function.h:40
KJS::HashTable::sbase
const char *const sbase
pointer to the string table.
Definition: lookup.h:95
KJS::Object::get
Value get(ExecState *exec, const Identifier &propertyName) const
Retrieves the specified property from the object.
Definition: object.h:663
KJS::Object::construct
Object construct(ExecState *exec, const List &args)
Creates a new object based on this object.
Definition: object.h:696
KJS::HashTable::size
int size
size is the total number of entries in the hashtable, including the null entries, i...
Definition: lookup.h:81
KJS::Number
Represents an primitive Number value.
Definition: value.h:367
KJS::List::append
void append(const Value &val)
Append an object to the end of the list.
Definition: list.h:66
KJS::Null
Represents an primitive Null value.
Definition: value.h:294
KJS::ExecState::lexicalInterpreter
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope's global object.
Definition: interpreter.cpp:394
KJS::Object::hasProperty
bool hasProperty(ExecState *exec, const Identifier &propertyName) const
Checks to see whether the object (or any object in it's prototype chain) has a property with the spec...
Definition: object.h:678
KJS::Interpreter::builtinDatePrototype
Object builtinDatePrototype() const
Returns the builtin "Date.prototype" object.
Definition: interpreter.cpp:248
KJS::HashEntry
An entry in a hash table.
Definition: lookup.h:36
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:503
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::Object
Represents an Object.
Definition: object.h:81
KJS::HashEntry::attr
unsigned char attr
attr is a set for flags (e.g.
Definition: lookup.h:48
KJS::HashEntry::soffset
unsigned short soffset
s is the offset to the string key (e.g.
Definition: lookup.h:40
KJS::Undefined
Represents an primitive Undefined value.
Definition: value.h:269
KJS::ClassInfo::className
const char * className
A string denoting the class name.
Definition: object.h:62
KJS::Interpreter::builtinError
Object builtinError() const
Returns the builtin "Error" object.
Definition: interpreter.cpp:213
KJS::Identifier::ascii
const char * ascii() const
Char * of the identifier's string.
Definition: identifier.h:71
KJS::Object::implementsCall
bool implementsCall() const
Whether or not the object implements the call() method.
Definition: object.h:699
KJS::UString
Unicode string class.
Definition: ustring.h:189
KJS::String
Represents an primitive String value.
Definition: value.h:340
KJS::Reference
Defines a Javascript reference.
Definition: reference.h:34
KJS::Object::dynamicCast
static Object dynamicCast(const Value &v)
Converts a Value into an Object.
Definition: object.cpp:45
KJS::Error::errorNames
static const char *const *const errorNames
Array of error names corresponding to ErrorType.
Definition: object.h:644
KJS
Definition: array_instance.h:27
KJS::ValueImp
ValueImp is the base type for all primitives (Undefined, Null, Boolean, String, Number) and objects i...
Definition: value.h:78
KJS::Interpreter::builtinEvalError
Object builtinEvalError() const
The initial value of "Error" global property.
Definition: interpreter.cpp:263
KJS::Lookup::findEntry
static const HashEntry * findEntry(const struct HashTable *table, const Identifier &s)
Find an entry in the table, and return the entry This variant gives access to the other attributes of...
Definition: lookup.cpp:71
KJS::ClassInfo::propHashTable
const HashTable * propHashTable
Static hash-table of properties.
Definition: object.h:71
KJS::List::empty
static const List & empty()
Returns a pointer to a static instance of an empty list.
Definition: list.cpp:322
KJS::ReferenceList
A list of Reference objects.
Definition: reference_list.h:53
KJS::HashTable::entries
const HashEntry *const entries
pointer to the array of entries Mind that some entries in the array are null (0,0,0,0).
Definition: lookup.h:86
KJS::Object::put
void put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr=None)
Sets the specified property.
Definition: object.h:669
KJS::List
Native list type.
Definition: list.h:48
KJS::Boolean
Represents an primitive Boolean value.
Definition: value.h:316
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::ClassInfo
Class Information.
Definition: object.h:58
KJS::Object::call
Value call(ExecState *exec, Object &thisObj, const List &args)
Calls this object as if it is a function.
Definition: object.cpp:53
KJS::Value::isValid
bool isValid() const
Returns whether or not this is a valid value.
Definition: value.h:181
KJS::ExecState
Represents the current state of script execution.
Definition: interpreter.h:438
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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kjs by doxygen 1.8.8
This website is maintained by Timothy Pearson.