KJS

object.cpp
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 1999-2001 Harri Porten ([email protected])
4  * Copyright (C) 2001 Peter Kelly ([email protected])
5  * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
6  * Copyright (C) 2007 Eric Seidel ([email protected])
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 "object.h"
26 
27 #include "error_object.h"
28 #include "lookup.h"
29 #include "nodes.h"
30 #include "operations.h"
31 #include "PropertyNameArray.h"
32 #include <math.h>
33 
34 #include <typeinfo>
35 
36 #define JAVASCRIPT_MARK_TRACING 0
37 
38 namespace KJS
39 {
40 
41 // ------------------------------ JSObject ------------------------------------
42 
43 void JSObject::mark()
44 {
45  JSCell::mark();
46 
47 #if JAVASCRIPT_MARK_TRACING
48  static int markStackDepth = 0;
49  markStackDepth++;
50  for (int i = 0; i < markStackDepth; i++) {
51  putchar('-');
52  }
53 
54  printf("%s (%p)\n", className().UTF8String().c_str(), this);
55 #endif
56 
57  JSValue *proto = _proto;
58  if (!JSValue::marked(proto)) {
59  JSValue::mark(proto);
60  }
61 
62  _prop.mark();
63 
64 #if JAVASCRIPT_MARK_TRACING
65  markStackDepth--;
66 #endif
67 }
68 
69 JSType JSObject::type() const
70 {
71  return ObjectType;
72 }
73 
74 const ClassInfo *JSObject::classInfo() const
75 {
76  return nullptr;
77 }
78 
79 UString JSObject::className() const
80 {
81  const ClassInfo *ci = classInfo();
82  return ci ? ci->className : "Object";
83 }
84 
85 JSValue *JSObject::get(ExecState *exec, const Identifier &propertyName) const
86 {
87  PropertySlot slot;
88 
89  if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot)) {
90  JSValue *val = slot.getValue(exec, const_cast<JSObject *>(this), propertyName);
91  assert(val);
92  return val;
93  }
94 
95  return jsUndefined();
96 }
97 
98 JSValue *JSObject::get(ExecState *exec, unsigned propertyName) const
99 {
100  PropertySlot slot;
101  if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot)) {
102  return slot.getValue(exec, const_cast<JSObject *>(this), propertyName);
103  }
104 
105  return jsUndefined();
106 }
107 
108 bool JSObject::getPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot &slot)
109 {
110  JSObject *imp = this;
111 
112  while (true) {
113  if (imp->getOwnPropertySlot(exec, propertyName, slot)) {
114  return true;
115  }
116 
117  JSValue *proto = imp->_proto;
118  if (!JSValue::isObject(proto)) {
119  break;
120  }
121 
122  imp = static_cast<JSObject *>(proto);
123  }
124 
125  return false;
126 }
127 
128 bool JSObject::getPropertyDescriptor(ExecState *exec, const Identifier &propertyName, PropertyDescriptor &desc)
129 {
130  JSObject *object = this;
131  while (true) {
132  if (object->getOwnPropertyDescriptor(exec, propertyName, desc)) {
133  return true;
134  }
135  JSValue *prototype = object->prototype();
136  if (!JSValue::isObject(prototype)) {
137  return false;
138  }
139  object = JSValue::toObject(prototype, exec);
140  }
141 }
142 
143 bool JSObject::getOwnPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot &slot)
144 {
145  return getOwnPropertySlot(exec, Identifier::from(propertyName), slot);
146 }
147 
148 // Ideally, we would like to inline this, since it's ultra-hot, but with the large VM
149 // loop, it seems like the code side gets the g++-4.3.x inliner in the paranoid mode, so not only
150 // does it not inline this, but it also doesn't inline setValueSlot() and hasGetterSetterProperties() (!!!).
151 bool JSObject::getOwnPropertySlot(ExecState *exec, const Identifier &propertyName, PropertySlot &slot)
152 {
153  if (JSValue **location = getDirectLocation(propertyName)) {
154  if (_prop.hasGetterSetterProperties() && JSValue::type(location[0]) == GetterSetterType) {
155  fillGetterPropertySlot(slot, location);
156  } else {
157  slot.setValueSlot(this, location);
158  }
159  return true;
160  }
161 
162  // non-standard Netscape extension
163  if (propertyName == exec->propertyNames().underscoreProto) {
164  slot.setValueSlot(this, &_proto);
165  return true;
166  }
167 
168  return false;
169 }
170 
171 bool JSObject::getOwnPropertyDescriptor(ExecState *exec, const Identifier &identifier, PropertyDescriptor &desc)
172 {
173  JSValue *jsVal = getDirect(identifier);
174 
175  // for classes that do not implement getDirect, like the prototypes,
176  // we have to check if they still do own the property and use the propertyslot
177  if (!jsVal) {
178  PropertySlot slot;
179  if (getOwnPropertySlot(exec, identifier, slot)) {
180  jsVal = slot.getValue(exec, this, identifier);
181  }
182  }
183 
184  if (jsVal) {
185  unsigned attr = 0;
186  getPropertyAttributes(identifier, attr);
187  return desc.setPropertyDescriptorValues(exec, jsVal, attr);
188  }
189  return false;
190 }
191 
192 static void throwSetterError(ExecState *exec)
193 {
194  throwError(exec, TypeError, "setting a property that has only a getter");
195 }
196 
197 // ECMA 8.6.2.2
198 void JSObject::put(ExecState *exec, const Identifier &propertyName, JSValue *value, int attr)
199 {
200  assert(value);
201 
202  // non-standard netscape extension
203  if (propertyName == exec->propertyNames().underscoreProto) {
204  JSObject *proto = JSValue::getObject(value);
205  while (proto) {
206  if (proto == this) {
207  throwError(exec, GeneralError, "cyclic __proto__ value");
208  return;
209  }
210  proto = proto->prototype() ? JSValue::getObject(proto->prototype()) : nullptr;
211  }
212 
213  setPrototype(value);
214  return;
215  }
216 
217  // putValue() is used for JS assignments. It passes no attribute.
218  // Assume that a C++ implementation knows what it is doing
219  // and don't spend time doing a read-only check for it.
220  bool checkRO = (attr == None || attr == DontDelete);
221 
222  if (checkRO) {
223  // Check for static properties that are ReadOnly; the property map will check the dynamic properties.
224  // We don't have to worry about setters being read-only as they can't be added with such an attribute.
225  // We also need to inherit any attributes we have from the entry
226  const HashEntry *entry = findPropertyHashEntry(propertyName);
227  if (entry) {
228  if (entry->attr & ReadOnly) {
229 #ifdef KJS_VERBOSE
230  fprintf(stderr, "WARNING: static property %s is ReadOnly\n", propertyName.ascii());
231 #endif
232  return;
233  }
234  attr = entry->attr;
235  }
236  }
237 
238  // Check if there are any setters or getters in the prototype chain
239  JSObject *obj = this;
240  bool hasGettersOrSetters = false;
241  while (true) {
242  if (obj->_prop.hasGetterSetterProperties()) {
243  hasGettersOrSetters = true;
244  break;
245  }
246 
247  if (!JSValue::isObject(obj->_proto)) {
248  break;
249  }
250 
251  obj = static_cast<JSObject *>(obj->_proto);
252  }
253 
254  if (hasGettersOrSetters) {
255  obj = this;
256  while (true) {
257  unsigned attributes;
258  if (JSValue *gs = obj->_prop.get(propertyName, attributes)) {
259  if (attributes & GetterSetter) {
260  JSObject *setterFunc = static_cast<GetterSetterImp *>(gs)->getSetter();
261 
262  if (!setterFunc) {
263  if (false) { //only throw if strict is set
264  throwSetterError(exec);
265  }
266  return;
267  }
268 
269  List args;
270  args.append(value);
271 
272  setterFunc->call(exec, this, args);
273  return;
274  } else {
275  // If there's an existing property on the object or one of its
276  // prototype it should be replaced, so we just break here.
277  break;
278  }
279  }
280 
281  if (!JSValue::isObject(obj->_proto)) {
282  break;
283  }
284 
285  obj = static_cast<JSObject *>(obj->_proto);
286  }
287  }
288 
289  if (!isExtensible() && !_prop.get(propertyName)) {
290  return;
291  }
292  _prop.put(propertyName, value, attr, checkRO);
293 }
294 
295 void JSObject::put(ExecState *exec, unsigned propertyName,
296  JSValue *value, int attr)
297 {
298  put(exec, Identifier::from(propertyName), value, attr);
299 }
300 
301 // ECMA 8.6.2.3
302 bool JSObject::canPut(ExecState *, const Identifier &propertyName) const
303 {
304  unsigned attributes;
305 
306  // Don't look in the prototype here. We can always put an override
307  // in the object, even if the prototype has a ReadOnly property.
308 
309  if (!getPropertyAttributes(propertyName, attributes)) {
310  return true;
311  } else {
312  return !(attributes & ReadOnly);
313  }
314 }
315 
316 // ECMA 8.6.2.4
317 bool JSObject::hasProperty(ExecState *exec, const Identifier &propertyName) const
318 {
319  PropertySlot slot;
320  return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
321 }
322 
323 bool JSObject::hasProperty(ExecState *exec, unsigned propertyName) const
324 {
325  PropertySlot slot;
326  return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
327 }
328 
329 // ECMA 8.6.2.5
330 bool JSObject::deleteProperty(ExecState * /*exec*/, const Identifier &propertyName)
331 {
332  unsigned attributes;
333  JSValue *v = _prop.get(propertyName, attributes);
334  if (v) {
335  if ((attributes & DontDelete)) {
336  return false;
337  }
338  _prop.remove(propertyName);
339  if (attributes & GetterSetter) {
340  _prop.setHasGetterSetterProperties(_prop.containsGettersOrSetters());
341  }
342  return true;
343  }
344 
345  // Look in the static hashtable of properties
346  const HashEntry *entry = findPropertyHashEntry(propertyName);
347  if (entry && entry->attr & DontDelete) {
348  return false; // this builtin property can't be deleted
349  }
350  return true;
351 }
352 
353 bool JSObject::deleteProperty(ExecState *exec, unsigned propertyName)
354 {
355  return deleteProperty(exec, Identifier::from(propertyName));
356 }
357 
358 static ALWAYS_INLINE JSValue *tryGetAndCallProperty(ExecState *exec, const JSObject *object, const Identifier &propertyName)
359 {
360  JSValue *v = object->get(exec, propertyName);
361  if (JSValue::isObject(v)) {
362  JSObject *o = static_cast<JSObject *>(v);
363  if (o->implementsCall()) { // spec says "not primitive type" but ...
364  JSObject *thisObj = const_cast<JSObject *>(object);
365  JSValue *def = o->call(exec, thisObj, List::empty());
366  JSType defType = JSValue::type(def);
367  ASSERT(defType != GetterSetterType);
368  if (defType != ObjectType) {
369  return def;
370  }
371  }
372  }
373  return nullptr;
374 }
375 
376 bool JSObject::getPrimitiveNumber(ExecState *exec, double &number, JSValue *&result)
377 {
378  result = defaultValue(exec, NumberType);
379  number = JSValue::toNumber(result, exec);
380  return !JSValue::isString(result);
381 }
382 
383 // ECMA 8.6.2.6
384 JSValue *JSObject::defaultValue(ExecState *exec, JSType hint) const
385 {
386  const Identifier *firstPropertyName;
387  const Identifier *secondPropertyName;
388  /* Prefer String for Date objects */
389  if ((hint == StringType) || ((hint != NumberType) && (_proto == exec->lexicalInterpreter()->builtinDatePrototype()))) {
390  firstPropertyName = &exec->propertyNames().toString;
391  secondPropertyName = &exec->propertyNames().valueOf;
392  } else {
393  firstPropertyName = &exec->propertyNames().valueOf;
394  secondPropertyName = &exec->propertyNames().toString;
395  }
396 
397  JSValue *v;
398  if ((v = tryGetAndCallProperty(exec, this, *firstPropertyName))) {
399  return v;
400  }
401  if ((v = tryGetAndCallProperty(exec, this, *secondPropertyName))) {
402  return v;
403  }
404 
405  if (exec->hadException()) {
406  return exec->exception();
407  }
408 
409  return throwError(exec, TypeError, "No default value");
410 }
411 
412 const HashEntry *JSObject::findPropertyHashEntry(const Identifier &propertyName) const
413 {
414  for (const ClassInfo *info = classInfo(); info; info = info->parentClass) {
415  if (const HashTable *propHashTable = info->propHashTable) {
416  if (const HashEntry *e = Lookup::findEntry(propHashTable, propertyName)) {
417  return e;
418  }
419  }
420  }
421  return nullptr;
422 }
423 
424 void JSObject::defineGetter(ExecState *, const Identifier &propertyName, JSObject *getterFunc)
425 {
426  JSValue *o = getDirect(propertyName);
427  GetterSetterImp *gs;
428 
429  if (o && JSValue::type(o) == GetterSetterType) {
430  gs = static_cast<GetterSetterImp *>(o);
431  } else {
432  gs = new GetterSetterImp;
433  putDirect(propertyName, gs, GetterSetter);
434  }
435 
436  _prop.setHasGetterSetterProperties(true);
437  gs->setGetter(getterFunc);
438 }
439 
440 void JSObject::defineSetter(ExecState *, const Identifier &propertyName, JSObject *setterFunc)
441 {
442  JSValue *o = getDirect(propertyName);
443  GetterSetterImp *gs;
444 
445  if (o && JSValue::type(o) == GetterSetterType) {
446  gs = static_cast<GetterSetterImp *>(o);
447  } else {
448  gs = new GetterSetterImp;
449  putDirect(propertyName, gs, GetterSetter);
450  }
451 
452  _prop.setHasGetterSetterProperties(true);
453  gs->setSetter(setterFunc);
454 }
455 
456 //ECMA Edition 5.1r6 - 8.12.9
457 bool JSObject::defineOwnProperty(ExecState *exec, const Identifier &propertyName, PropertyDescriptor &desc, bool shouldThrow)
458 {
459  PropertyDescriptor current;
460 
461  // if Object does not have propertyName as OwnProperty just push it.
462  if (!getOwnPropertyDescriptor(exec, propertyName, current)) {
463  if (!isExtensible()) {
464  if (shouldThrow) {
465  throwError(exec, TypeError, "Object is not extensible \'" + propertyName.ustring() + "\'");
466  }
467  return false;
468  }
469  if (desc.isGenericDescriptor() || desc.isDataDescriptor()) {
470  putDirect(propertyName, desc.value() ? desc.value() : jsUndefined(), desc.attributes());
471  } else if (desc.isAccessorDescriptor()) {
472  GetterSetterImp *gs = new GetterSetterImp();
473  putDirect(propertyName, gs, desc.attributes() | GetterSetter);
474  _prop.setHasGetterSetterProperties(true);
475  if (desc.getter() && !JSValue::isUndefined(desc.getter())) {
476  gs->setGetter(JSValue::toObject(desc.getter(), exec));
477  }
478  if (desc.setter() && !JSValue::isUndefined(desc.setter())) {
479  gs->setSetter(JSValue::toObject(desc.setter(), exec));
480  }
481  }
482  return true;
483  }
484 
485  //Step 5
486  if (desc.isEmpty()) {
487  return true;
488  }
489 
490  //Step 6
491  if (desc.equalTo(exec, current)) {
492  return true;
493  }
494 
495  //Step 7
496  // Filter out invalid unconfigurable configurations
497  if (!current.configurable()) {
498  if (desc.configurable()) {
499  if (shouldThrow) {
500  throwError(exec, TypeError, "can not redefine non-configurable property \'" + propertyName.ustring() + "\'");
501  }
502  return false;
503  }
504  if (desc.enumerableSet() && desc.enumerable() != current.enumerable()) {
505  if (shouldThrow) {
506  throwError(exec, TypeError, "can not change enumerable attribute of unconfigurable property \'" + propertyName.ustring() + "\'");
507  }
508  return false;
509  }
510  }
511 
512  //Step 8.
513  if (!desc.isGenericDescriptor()) {
514  if (current.isDataDescriptor() != desc.isDataDescriptor()) { // Step 9
515  // DataDescriptor updating to AccessorDescriptor, or the other way.
516  if (!current.configurable()) {
517  if (shouldThrow) {
518  throwError(exec, TypeError, "can not change access mechanism for an unconfigurable property \'" + propertyName.ustring() + "\'");
519  }
520  return false;
521  }
522 
523  deleteProperty(exec, propertyName);
524 
525  if (current.isDataDescriptor()) {
526  // Updating from DataDescriptor to AccessorDescriptor
527  GetterSetterImp *gs = new GetterSetterImp();
528  putDirect(propertyName, gs, current.attributesWithOverride(desc) | GetterSetter);
529  _prop.setHasGetterSetterProperties(true);
530 
531  if (desc.getter()) {
532  if (JSValue::isUndefined(desc.getter())) {
533  gs->setGetter(nullptr);
534  } else {
535  gs->setGetter(JSValue::toObject(desc.getter(), exec));
536  }
537  }
538  if (desc.setter()) {
539  if (JSValue::isUndefined(desc.setter())) {
540  gs->setSetter(nullptr);
541  } else {
542  gs->setSetter(JSValue::toObject(desc.setter(), exec));
543  }
544  }
545  } else {
546  // Updating from AccessorDescriptor to DataDescriptor
547  unsigned int newAttr = current.attributesWithOverride(desc);
548  if (!desc.writable()) {
549  newAttr |= ReadOnly;
550  }
551  putDirect(propertyName, desc.value() ? desc.value() : jsUndefined(), newAttr);
552  }
553  return true;
554  } else if (current.isDataDescriptor() && desc.isDataDescriptor()) { //Step 10
555  // Just updating the value here
556  if (!current.configurable()) {
557  if (!current.writable() && desc.writable()) {
558  if (shouldThrow) {
559  throwError(exec, TypeError, "can not change writable attribute of unconfigurable property \'" + propertyName.ustring() + "\'");
560  }
561  return false;
562  }
563  if (!current.writable()) {
564  if (desc.value() && !(current.value() && sameValue(exec, current.value(), desc.value()))) {
565  if (shouldThrow) {
566  throwError(exec, TypeError, "can not change value of a readonly property \'" + propertyName.ustring() + "\'");
567  }
568  return false;
569  }
570  }
571  } else {
572  if (!deleteProperty(exec, propertyName)) {
573  removeDirect(propertyName);
574  }
575 
576  putDirect(propertyName, desc.value() ? desc.value() : current.value(), current.attributesWithOverride(desc));
577  return true;
578  }
579  } else if (current.isAccessorDescriptor() && desc.isAccessorDescriptor()) { // Step 11
580  // Filter out unconfigurable combinations
581  if (!current.configurable()) {
582  if (desc.setter() && !sameValue(exec, desc.setter(), current.setter() ? current.setter() : jsUndefined())) {
583  if (shouldThrow) {
584  throwError(exec, TypeError, "can not change the setter of an unconfigurable property \'" + propertyName.ustring() + "\'");
585  }
586  return false;
587  }
588  if (desc.getter() && !sameValue(exec, desc.getter(), current.getter() ? current.getter() : jsUndefined())) {
589  if (shouldThrow) {
590  throwError(exec, TypeError, "can not change the getter of an unconfigurable property \'" + propertyName.ustring() + "\'");
591  }
592  return false;
593  }
594  }
595  }
596  }
597 
598  //Step 12
599  // Everything is allowed here, updating GetterSetter, storing new value
600  JSValue *jsval = getDirect(propertyName);
601  unsigned int newAttr = current.attributesWithOverride(desc);
602  if (jsval && JSValue::type(jsval) == GetterSetterType) {
603  GetterSetterImp *gs = static_cast<GetterSetterImp *>(jsval);
604  if (desc.getter()) {
605  if (JSValue::isUndefined(desc.getter())) {
606  gs->setGetter(nullptr);
607  } else {
608  gs->setGetter(JSValue::toObject(desc.getter(), exec));
609  }
610  }
611  if (desc.setter()) {
612  if (JSValue::isUndefined(desc.setter())) {
613  gs->setSetter(nullptr);
614  } else {
615  gs->setSetter(JSValue::toObject(desc.setter(), exec));
616  }
617  }
618  } else {
619  jsval = desc.value() ? desc.value() : current.value();
620  }
621 
622  deleteProperty(exec, propertyName);
623  if (JSValue::type(jsval) == GetterSetterType) {
624  putDirect(propertyName, jsval, newAttr | GetterSetter);
625  _prop.setHasGetterSetterProperties(true);
626  } else {
627  put(exec, propertyName, jsval, newAttr);
628  }
629 
630  return true; //Step 13
631 }
632 
633 void JSObject::preventExtensions()
634 {
635  if (isExtensible()) {
636  _prop.setExtensible(false);
637  }
638 }
639 
640 bool JSObject::implementsConstruct() const
641 {
642  return false;
643 }
644 
645 JSObject *JSObject::construct(ExecState *, const List & /*args*/)
646 {
647  assert(false);
648  return nullptr;
649 }
650 
651 JSObject *JSObject::construct(ExecState *exec, const List &args, const Identifier & /*functionName*/, const UString & /*sourceURL*/, int /*lineNumber*/)
652 {
653  return construct(exec, args);
654 }
655 
656 JSObject *JSObject::valueClone(Interpreter * /*targetCtx*/) const
657 {
658  return nullptr;
659 }
660 
661 bool JSObject::isFunctionType() const
662 {
663  return implementsCall();
664 }
665 
666 JSValue *JSObject::callAsFunction(ExecState * /*exec*/, JSObject * /*thisObj*/, const List &/*args*/)
667 {
668  assert(false);
669  return nullptr;
670 }
671 
672 bool JSObject::implementsHasInstance() const
673 {
674  return false;
675 }
676 
677 bool JSObject::hasInstance(ExecState *exec, JSValue *value)
678 {
679  JSValue *proto = get(exec, exec->propertyNames().prototype);
680  if (!JSValue::isObject(proto)) {
681  throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property.");
682  return false;
683  }
684 
685  if (!JSValue::isObject(value)) {
686  return false;
687  }
688 
689  JSObject *o = static_cast<JSObject *>(value);
690  while ((o = JSValue::getObject(o->prototype()))) {
691  if (o == proto) {
692  return true;
693  }
694  }
695  return false;
696 }
697 
698 bool JSObject::propertyIsEnumerable(ExecState *, const Identifier &propertyName) const
699 {
700  unsigned attributes;
701 
702  if (!getPropertyAttributes(propertyName, attributes)) {
703  return false;
704  } else {
705  return !(attributes & DontEnum);
706  }
707 }
708 
709 bool JSObject::getPropertyAttributes(const Identifier &propertyName, unsigned &attributes) const
710 {
711  if (_prop.get(propertyName, attributes)) {
712  return true;
713  }
714 
715  // Look in the static hashtable of properties
716  const HashEntry *e = findPropertyHashEntry(propertyName);
717  if (e) {
718  attributes = e->attr;
719  return true;
720  }
721 
722  return false;
723 }
724 
725 void JSObject::getOwnPropertyNames(ExecState * /*exec*/, PropertyNameArray &propertyNames, PropertyMap::PropertyMode mode)
726 {
727  _prop.getPropertyNames(propertyNames, mode);
728 
729  // Add properties from the static hashtable of properties
730  const ClassInfo *info = classInfo();
731  while (info) {
732  if (info->propHashTable) {
733  int size = info->propHashTable->size;
734  const HashEntry *e = info->propHashTable->entries;
735  for (int i = 0; i < size; ++i, ++e) {
736  if (e->s && PropertyMap::checkEnumerable(e->attr, mode)) {
737  propertyNames.add(e->s);
738  }
739  }
740  }
741  info = info->parentClass;
742  }
743 }
744 
745 bool JSObject::toBoolean(ExecState * /*exec*/) const
746 {
747  return true;
748 }
749 
750 double JSObject::toNumber(ExecState *exec) const
751 {
752  JSValue *prim = toPrimitive(exec, NumberType);
753  if (exec->hadException()) { // should be picked up soon in nodes.cpp
754  return 0.0;
755  }
756  return JSValue::toNumber(prim, exec);
757 }
758 
759 UString JSObject::toString(ExecState *exec) const
760 {
761  JSValue *prim = toPrimitive(exec, StringType);
762  if (exec->hadException()) { // should be picked up soon in nodes.cpp
763  return UString(UString::empty);
764  }
765  return JSValue::toString(prim, exec);
766 }
767 
768 JSObject *JSObject::toObject(ExecState * /*exec*/) const
769 {
770  return const_cast<JSObject *>(this);
771 }
772 
773 void JSObject::putDirect(const Identifier &propertyName, int value, int attr)
774 {
775  _prop.put(propertyName, jsNumber(value), attr);
776 }
777 
778 void JSObject::removeDirect(const Identifier &propertyName)
779 {
780  _prop.remove(propertyName);
781 }
782 
783 void JSObject::putDirectFunction(InternalFunctionImp *func, int attr)
784 {
785  putDirect(func->functionName(), func, attr);
786 }
787 
788 void JSObject::fillGetterPropertySlot(PropertySlot &slot, JSValue **location)
789 {
790  GetterSetterImp *gs = static_cast<GetterSetterImp *>(*location);
791  JSObject *getterFunc = gs->getGetter();
792  if (getterFunc) {
793  slot.setGetterSlot(this, getterFunc);
794  } else {
795  slot.setUndefined(this);
796  }
797 }
798 
799 // ------------------------------ Error ----------------------------------------
800 
801 const char *const errorNamesArr[] = {
802  I18N_NOOP("Error"), // GeneralError
803  I18N_NOOP("Evaluation error"), // EvalError
804  I18N_NOOP("Range error"), // RangeError
805  I18N_NOOP("Reference error"), // ReferenceError
806  I18N_NOOP("Syntax error"), // SyntaxError
807  I18N_NOOP("Type error"), // TypeError
808  I18N_NOOP("URI error"), // URIError
809 };
810 
811 const char *const *const Error::errorNames = errorNamesArr;
812 
813 JSObject *Error::create(ExecState *exec, ErrorType errtype, const UString &message,
814  int lineno, int sourceId, const UString &sourceURL)
815 {
816 #ifdef KJS_VERBOSE
817  // message could be 0L. Don't enable this on Solaris ;)
818  fprintf(stderr, "WARNING: KJS %s: %s\n", errorNamesArr[errtype], message.ascii());
819 #endif
820 
821  Interpreter *interp = exec->lexicalInterpreter();
822  JSObject *cons;
823  switch (errtype) {
824  case EvalError:
825  cons = interp->builtinEvalError();
826  break;
827  case RangeError:
828  cons = interp->builtinRangeError();
829  break;
830  case ReferenceError:
831  cons = interp->builtinReferenceError();
832  break;
833  case SyntaxError:
834  cons = interp->builtinSyntaxError();
835  break;
836  case TypeError:
837  cons = interp->builtinTypeError();
838  break;
839  case URIError:
840  cons = interp->builtinURIError();
841  break;
842  default:
843  cons = interp->builtinError();
844  break;
845  }
846 
847  List args;
848  if (message.isEmpty()) {
849  args.append(jsString(errorNames[errtype]));
850  } else {
851  args.append(jsString(message));
852  }
853  JSObject *err = static_cast<JSObject *>(cons->construct(exec, args));
854 
855  if (lineno != -1) {
856  err->put(exec, "line", jsNumber(lineno));
857  }
858  if (sourceId != -1) {
859  err->put(exec, "sourceId", jsNumber(sourceId));
860  }
861 
862  if (!sourceURL.isNull()) {
863  err->put(exec, "sourceURL", jsString(sourceURL));
864  }
865 
866  return err;
867 
868  /*
869  #ifndef NDEBUG
870  const char *msg = err->get(messagePropertyName)->toString().value().ascii();
871  if (l >= 0)
872  fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
873  else
874  fprintf(stderr, "KJS: %s. %s\n", estr, msg);
875  #endif
876 
877  return err;
878  */
879 }
880 
881 JSObject *Error::create(ExecState *exec, ErrorType type, const char *message)
882 {
883  return create(exec, type, message, -1, -1, nullptr);
884 }
885 
886 JSObject *throwError(ExecState *exec, ErrorType type)
887 {
888  JSObject *error = Error::create(exec, type, UString(), -1, -1, nullptr);
889  exec->setException(error);
890  return error;
891 }
892 
893 JSObject *throwError(ExecState *exec, ErrorType type, const UString &message)
894 {
895  JSObject *error = Error::create(exec, type, message, -1, -1, nullptr);
896  exec->setException(error);
897  return error;
898 }
899 
900 JSObject *throwError(ExecState *exec, ErrorType type, const char *message)
901 {
902  JSObject *error = Error::create(exec, type, message, -1, -1, nullptr);
903  exec->setException(error);
904  return error;
905 }
906 
907 JSObject *throwError(ExecState *exec, ErrorType type, const UString &message, int line, int sourceId, const UString &sourceURL)
908 {
909  JSObject *error = Error::create(exec, type, message, line, sourceId, sourceURL);
910  exec->setException(error);
911  return error;
912 }
913 
914 } // namespace KJS
void append(JSValue *val)
Append an object to the end of the list.
Definition: list.h:186
bool isNull() const
Definition: ustring.h:398
static const char *const *const errorNames
Array of error names corresponding to ErrorType.
Definition: object.h:595
Represents the current state of script execution.
Definition: ExecState.h:53
bool isEmpty() const const
Interpreter objects can be used to evaluate ECMAScript code.
Definition: interpreter.h:56
ObjectType
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
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope's global object.
Definition: ExecState.cpp:35
Native list type.
Definition: list.h:52
static const List & empty()
Returns a pointer to a static instance of an empty list.
Definition: list.cpp:311
static JSObject * create(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL)
Factory method for error objects.
Definition: object.cpp:813
virtual QVariant callAsFunction(ScriptableExtension *callerPrincipal, quint64 objId, const ArgList &args)
KIOCORE_EXPORT QString number(KIO::filesize_t size)
virtual bool hasProperty(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName)
JSObject * builtinError() const
Returns the builtin "Error" object.
virtual bool put(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName, const QVariant &value)
QString message
JSObject * builtinEvalError() const
The initial value of "Error" global property.
virtual QVariant get(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName)
Unicode string class.
Definition: ustring.h:153
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Wed Sep 28 2022 03:51:31 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.