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

kjs

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

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
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kjs by doxygen 1.9.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |