source: webkit/trunk/JavaScriptCore/kjs/object.cpp@ 798

Last change on this file since 798 was 798, checked in by mjs, 23 years ago

Merged changes from LABYRINTH_KDE_3_MERGE branch.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2001 Harri Porten ([email protected])
5 * Copyright (C) 2001 Peter Kelly ([email protected])
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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 *
22 * $Id: object.cpp 798 2002-03-22 00:31:57Z mjs $
23 */
24
25#include "value.h"
26#include "object.h"
27#include "types.h"
28#include "interpreter.h"
29#include "lookup.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#include "property_map.h"
41
42using namespace KJS;
43
44// ------------------------------ Object ---------------------------------------
45
46Object::Object() : Value()
47{
48}
49
50Object::Object(ObjectImp *v) : Value(v)
51{
52}
53
54Object::Object(const Object &v) : Value(v)
55{
56}
57
58Object::~Object()
59{
60}
61
62Object& Object::operator=(const Object &v)
63{
64 Value::operator=(v);
65 return *this;
66}
67
68const ClassInfo *Object::classInfo() const
69{
70 return static_cast<ObjectImp*>(rep)->classInfo();
71}
72
73bool Object::inherits(const ClassInfo *cinfo) const
74{
75 return static_cast<ObjectImp*>(rep)->inherits(cinfo);
76}
77
78Object Object::dynamicCast(const Value &v)
79{
80 if (v.isNull() || v.type() != ObjectType)
81 return Object(0);
82
83 return Object(static_cast<ObjectImp*>(v.imp()));
84}
85
86Value Object::prototype() const
87{
88 return Value(static_cast<ObjectImp*>(rep)->prototype());
89}
90
91UString Object::className() const
92{
93 return static_cast<ObjectImp*>(rep)->className();
94}
95
96Value Object::get(ExecState *exec, const UString &propertyName) const
97{
98 return static_cast<ObjectImp*>(rep)->get(exec,propertyName);
99}
100
101void Object::put(ExecState *exec, const UString &propertyName, const Value &value, int attr)
102{
103 static_cast<ObjectImp*>(rep)->put(exec,propertyName,value,attr);
104}
105
106bool Object::canPut(ExecState *exec, const UString &propertyName) const
107{
108 return static_cast<ObjectImp*>(rep)->canPut(exec,propertyName);
109}
110
111bool Object::hasProperty(ExecState *exec, const UString &propertyName, bool recursive) const
112{
113 return static_cast<ObjectImp*>(rep)->hasProperty(exec,propertyName,recursive);
114}
115
116bool Object::deleteProperty(ExecState *exec, const UString &propertyName)
117{
118 return static_cast<ObjectImp*>(rep)->deleteProperty(exec,propertyName);
119}
120
121Value Object::defaultValue(ExecState *exec, Type hint) const
122{
123 return static_cast<ObjectImp*>(rep)->defaultValue(exec,hint);
124}
125
126bool Object::implementsConstruct() const
127{
128 return static_cast<ObjectImp*>(rep)->implementsConstruct();
129}
130
131Object Object::construct(ExecState *exec, const List &args)
132{
133 return static_cast<ObjectImp*>(rep)->construct(exec,args);
134}
135
136bool Object::implementsCall() const
137{
138 return static_cast<ObjectImp*>(rep)->implementsCall();
139}
140
141Value Object::call(ExecState *exec, Object &thisObj, const List &args)
142{
143 return static_cast<ObjectImp*>(rep)->call(exec,thisObj,args);
144}
145
146bool Object::implementsHasInstance() const
147{
148 return static_cast<ObjectImp*>(rep)->implementsHasInstance();
149}
150
151Boolean Object::hasInstance(ExecState *exec, const Value &value)
152{
153 return static_cast<ObjectImp*>(rep)->hasInstance(exec,value);
154}
155
156const List Object::scope() const
157{
158 return static_cast<ObjectImp*>(rep)->scope();
159}
160
161void Object::setScope(const List &s)
162{
163 static_cast<ObjectImp*>(rep)->setScope(s);
164}
165
166List Object::propList(ExecState *exec, bool recursive)
167{
168 return static_cast<ObjectImp*>(rep)->propList(exec,recursive);
169}
170
171Value Object::internalValue() const
172{
173 return static_cast<ObjectImp*>(rep)->internalValue();
174}
175
176void Object::setInternalValue(const Value &v)
177{
178 static_cast<ObjectImp*>(rep)->setInternalValue(v);
179}
180
181// ------------------------------ ObjectImp ------------------------------------
182
183ObjectImp::ObjectImp(const Object &proto)
184 : _prop(0), _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L), _scope(0)
185{
186 //fprintf(stderr,"ObjectImp::ObjectImp %p %s\n",(void*)this);
187 _scope = ListImp::empty();
188 _prop = new PropertyMap();
189}
190
191ObjectImp::ObjectImp()
192{
193 //fprintf(stderr,"ObjectImp::ObjectImp %p %s\n",(void*)this);
194 _prop = 0;
195 _proto = NullImp::staticNull;
196 _internalValue = 0L;
197 _scope = ListImp::empty();
198 _prop = new PropertyMap();
199}
200
201ObjectImp::~ObjectImp()
202{
203 //fprintf(stderr,"ObjectImp::~ObjectImp %p\n",(void*)this);
204 if (_proto)
205 _proto->setGcAllowed();
206 if (_internalValue)
207 _internalValue->setGcAllowed();
208 if (_scope)
209 _scope->setGcAllowed();
210 delete _prop;
211}
212
213void ObjectImp::mark()
214{
215 //fprintf(stderr,"ObjectImp::mark() %p\n",(void*)this);
216 ValueImp::mark();
217
218 if (_proto && !_proto->marked())
219 _proto->mark();
220
221 PropertyMapNode *node = _prop->first();
222 while (node) {
223 if (!node->value->marked())
224 node->value->mark();
225 node = node->next();
226 }
227
228 if (_internalValue && !_internalValue->marked())
229 _internalValue->mark();
230 if (_scope && !_scope->marked())
231 _scope->mark();
232}
233
234const ClassInfo *ObjectImp::classInfo() const
235{
236 return 0;
237}
238
239bool ObjectImp::inherits(const ClassInfo *info) const
240{
241 if (!info)
242 return false;
243
244 const ClassInfo *ci = classInfo();
245 if (!ci)
246 return false;
247
248 while (ci && ci != info)
249 ci = ci->parentClass;
250
251 return (ci == info);
252}
253
254Type ObjectImp::type() const
255{
256 return ObjectType;
257}
258
259Value ObjectImp::prototype() const
260{
261 return Value(_proto);
262}
263
264void ObjectImp::setPrototype(const Value &proto)
265{
266 _proto = proto.imp();
267}
268
269UString ObjectImp::className() const
270{
271 const ClassInfo *ci = classInfo();
272 if ( ci )
273 return ci->className;
274 return "Object";
275}
276
277Value ObjectImp::get(ExecState *exec, const UString &propertyName) const
278{
279 if (propertyName == "__proto__") {
280 Object proto = Object::dynamicCast(prototype());
281 // non-standard netscape extension
282 if (proto.isNull())
283 return Null();
284 else
285 return proto;
286 }
287
288 ValueImp *imp = getDirect(propertyName);
289 if ( imp )
290 return Value(imp);
291
292 Object proto = Object::dynamicCast(prototype());
293 if (proto.isNull())
294 return Undefined();
295
296 return proto.get(exec,propertyName);
297}
298
299// This get method only looks at the property map.
300// A bit like hasProperty(recursive=false), this doesn't go to the prototype.
301// This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
302// to look up in the prototype, it might already exist there)
303ValueImp* ObjectImp::getDirect(const UString& propertyName) const
304{
305 return _prop->get(propertyName);
306}
307
308// ECMA 8.6.2.2
309void ObjectImp::put(ExecState *exec, const UString &propertyName,
310 const Value &value, int attr)
311{
312 assert(!value.isNull());
313 assert(value.type() != ReferenceType);
314 assert(value.type() != CompletionType);
315 assert(value.type() != ListType);
316
317 /* TODO: check for write permissions directly w/o this call */
318 /* Doesn't look very easy with the PropertyMap API - David */
319 // putValue() is used for JS assignemnts. It passes no attribute.
320 // Assume that a C++ implementation knows what it is doing
321 // and let it override the canPut() check.
322 if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) {
323#ifdef KJS_VERBOSE
324 fprintf( stderr, "WARNING: canPut %s said NO\n", propertyName.ascii() );
325#endif
326 return;
327 }
328
329 if (propertyName == "__proto__") {
330 // non-standard netscape extension
331 setPrototype(value);
332 return;
333 }
334
335 _prop->put(propertyName,value.imp(),attr);
336}
337
338// ECMA 8.6.2.3
339bool ObjectImp::canPut(ExecState *, const UString &propertyName) const
340{
341 PropertyMapNode *node = _prop->getNode(propertyName);
342 if (node)
343 return!(node->attr & ReadOnly);
344
345 // Look in the static hashtable of properties
346 const HashEntry* e = findPropertyHashEntry(propertyName);
347 if (e)
348 return !(e->attr & ReadOnly);
349
350 // Don't look in the prototype here. We can always put an override
351 // in the object, even if the prototype has a ReadOnly property.
352 return true;
353}
354
355// ECMA 8.6.2.4
356bool ObjectImp::hasProperty(ExecState *exec, const UString &propertyName, bool recursive) const
357{
358 if (propertyName == "__proto__")
359 return true;
360 if (_prop->get(propertyName))
361 return true;
362
363 // Look in the static hashtable of properties
364 if (findPropertyHashEntry(propertyName))
365 return true;
366
367 // Look in the prototype
368 Object proto = Object::dynamicCast(prototype());
369 if (proto.isNull() || !recursive)
370 return false;
371
372 return proto.hasProperty(exec,propertyName);
373}
374
375// ECMA 8.6.2.5
376bool ObjectImp::deleteProperty(ExecState */*exec*/, const UString &propertyName)
377{
378 PropertyMapNode *node = _prop->getNode(propertyName);
379 if (node) {
380 if ((node->attr & DontDelete))
381 return false;
382 _prop->remove(propertyName);
383 return true;
384 }
385
386 // Look in the static hashtable of properties
387 if (findPropertyHashEntry(propertyName))
388 return false; // No builtin property can be deleted
389 return true;
390}
391
392void ObjectImp::deleteAllProperties( ExecState * )
393{
394 _prop->clear();
395}
396
397// ECMA 8.6.2.6
398Value ObjectImp::defaultValue(ExecState *exec, Type hint) const
399{
400 if (hint != StringType && hint != NumberType) {
401 /* Prefer String for Date objects */
402 if (_proto == exec->interpreter()->builtinDatePrototype().imp())
403 hint = StringType;
404 else
405 hint = NumberType;
406 }
407
408 Value v;
409 if (hint == StringType)
410 v = get(exec,"toString");
411 else
412 v = get(exec,"valueOf");
413
414 if (v.type() == ObjectType) {
415 Object o = Object(static_cast<ObjectImp*>(v.imp()));
416 if (o.implementsCall()) { // spec says "not primitive type" but ...
417 Object thisObj = Object(const_cast<ObjectImp*>(this));
418 Value def = o.call(exec,thisObj,List::empty());
419 Type defType = def.type();
420 if (defType == UnspecifiedType || defType == UndefinedType ||
421 defType == NullType || defType == BooleanType ||
422 defType == StringType || defType == NumberType) {
423 return def;
424 }
425 }
426 }
427
428 if (hint == StringType)
429 v = get(exec,"valueOf");
430 else
431 v = get(exec,"toString");
432
433 if (v.type() == ObjectType) {
434 Object o = Object(static_cast<ObjectImp*>(v.imp()));
435 if (o.implementsCall()) { // spec says "not primitive type" but ...
436 Object thisObj = Object(const_cast<ObjectImp*>(this));
437 Value def = o.call(exec,thisObj,List::empty());
438 Type defType = def.type();
439 if (defType == UnspecifiedType || defType == UndefinedType ||
440 defType == NullType || defType == BooleanType ||
441 defType == StringType || defType == NumberType) {
442 return def;
443 }
444 }
445 }
446
447 Object err = Error::create(exec, TypeError, I18N_NOOP("No default value"));
448 exec->setException(err);
449 return err;
450}
451
452const HashEntry* ObjectImp::findPropertyHashEntry( const UString& propertyName ) const
453{
454 const ClassInfo *info = classInfo();
455 while (info) {
456 if (info->propHashTable) {
457 const HashEntry *e = Lookup::findEntry(info->propHashTable, propertyName);
458 if (e)
459 return e;
460 }
461 info = info->parentClass;
462 }
463 return 0L;
464}
465
466bool ObjectImp::implementsConstruct() const
467{
468 return false;
469}
470
471Object ObjectImp::construct(ExecState */*exec*/, const List &/*args*/)
472{
473 assert(false);
474 return Object(0);
475}
476
477bool ObjectImp::implementsCall() const
478{
479 return false;
480}
481
482Value ObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/)
483{
484 assert(false);
485 return Object(0);
486}
487
488bool ObjectImp::implementsHasInstance() const
489{
490 return false;
491}
492
493Boolean ObjectImp::hasInstance(ExecState */*exec*/, const Value &/*value*/)
494{
495 assert(false);
496 return Boolean(false);
497}
498
499const List ObjectImp::scope() const
500{
501 return _scope;
502}
503
504void ObjectImp::setScope(const List &s)
505{
506 if (_scope) _scope->setGcAllowed();
507 _scope = static_cast<ListImp*>(s.imp());
508}
509
510List ObjectImp::propList(ExecState *exec, bool recursive)
511{
512 List list;
513 if (_proto && _proto->type() == ObjectType && recursive)
514 list = static_cast<ObjectImp*>(_proto)->propList(exec,recursive);
515
516
517 PropertyMapNode *node = _prop->first();
518 while (node) {
519 if (!(node->attr & DontEnum))
520 list.append(Reference(Object(this), node->name));
521 node = node->next();
522 }
523
524 // Add properties from the static hashtable of properties
525 const ClassInfo *info = classInfo();
526 while (info) {
527 if (info->propHashTable) {
528 int size = info->propHashTable->size;
529 const HashEntry *e = info->propHashTable->entries;
530 for (int i = 0; i < size; ++i, ++e) {
531 if ( e->s && !(e->attr & DontEnum) )
532 list.append(Reference(Object(this), e->s)); /// ######### check for duplicates with the propertymap
533 }
534 }
535 info = info->parentClass;
536 }
537
538 return list;
539}
540
541Value ObjectImp::internalValue() const
542{
543 return Value(_internalValue);
544}
545
546void ObjectImp::setInternalValue(const Value &v)
547{
548 _internalValue = v.imp();
549}
550
551// The following functions simply call the corresponding functions in ValueImp
552// but are overridden in case of future needs
553
554Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const
555{
556 return defaultValue(exec,preferredType);
557}
558
559bool ObjectImp::toBoolean(ExecState */*exec*/) const
560{
561 return true;
562}
563
564double ObjectImp::toNumber(ExecState *exec) const
565{
566 Value prim = toPrimitive(exec,NumberType);
567 if (exec->hadException()) // should be picked up soon in nodes.cpp
568 return 0.0;
569 return prim.toNumber(exec);
570}
571
572int ObjectImp::toInteger(ExecState *exec) const
573{
574 return ValueImp::toInteger(exec);
575}
576
577int ObjectImp::toInt32(ExecState *exec) const
578{
579 return ValueImp::toInt32(exec);
580}
581
582unsigned int ObjectImp::toUInt32(ExecState *exec) const
583{
584 return ValueImp::toUInt32(exec);
585}
586
587unsigned short ObjectImp::toUInt16(ExecState *exec) const
588{
589 return ValueImp::toUInt16(exec);
590}
591
592UString ObjectImp::toString(ExecState *exec) const
593{
594 Value prim = toPrimitive(exec,StringType);
595 if (exec->hadException()) // should be picked up soon in nodes.cpp
596 return "";
597 return prim.toString(exec);
598}
599
600Object ObjectImp::toObject(ExecState */*exec*/) const
601{
602 return Object(const_cast<ObjectImp*>(this));
603}
604
605
606// ------------------------------ Error ----------------------------------------
607
608const char * const errorNamesArr[] = {
609 I18N_NOOP("Error"), // GeneralError
610 I18N_NOOP("Evaluation error"), // EvalError
611 I18N_NOOP("Range error"), // RangeError
612 I18N_NOOP("Reference error"), // ReferenceError
613 I18N_NOOP("Syntax error"), // SyntaxError
614 I18N_NOOP("Type error"), // TypeError
615 I18N_NOOP("URI error"), // URIError
616};
617
618const char * const * const Error::errorNames = errorNamesArr;
619
620Object Error::create(ExecState *exec, ErrorType errtype, const char *message,
621 int lineno, int sourceId)
622{
623 Object cons;
624
625 switch (errtype) {
626 case EvalError:
627 cons = exec->interpreter()->builtinEvalError();
628 break;
629 case RangeError:
630 cons = exec->interpreter()->builtinRangeError();
631 break;
632 case ReferenceError:
633 cons = exec->interpreter()->builtinReferenceError();
634 break;
635 case SyntaxError:
636 cons = exec->interpreter()->builtinSyntaxError();
637 break;
638 case TypeError:
639 cons = exec->interpreter()->builtinTypeError();
640 break;
641 case URIError:
642 cons = exec->interpreter()->builtinURIError();
643 break;
644 default:
645 cons = exec->interpreter()->builtinError();
646 break;
647 }
648
649 if (!message)
650 message = errorNames[errtype];
651 List args;
652 args.append(String(message));
653 Object err = Object::dynamicCast(cons.construct(exec,args));
654
655 if (lineno != -1)
656 err.put(exec, "line", Number(lineno));
657 if (sourceId != -1)
658 err.put(exec, "sourceId", Number(sourceId));
659
660 return err;
661
662/*
663#ifndef NDEBUG
664 const char *msg = err.get("message").toString().value().ascii();
665 if (l >= 0)
666 fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
667 else
668 fprintf(stderr, "KJS: %s. %s\n", estr, msg);
669#endif
670
671 return err;
672*/
673}
674
Note: See TracBrowser for help on using the repository browser.