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