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

Last change on this file since 1852 was 1852, checked in by darin, 23 years ago

Fix the Development build.

  • kjs/object.cpp: Take out a use of ReferenceType.
  • kjs/ustring.h: Added a bit more inlining.
  • kjs/ustring.cpp: Moved the function out of here.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.7 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 */
23
24#include "value.h"
25#include "object.h"
26#include "types.h"
27#include "interpreter.h"
28#include "lookup.h"
29#include "reference_list.h"
30
31#include <assert.h>
32#include <math.h>
33#include <stdio.h>
34
35#include "internal.h"
36#include "collector.h"
37#include "operations.h"
38#include "error_object.h"
39#include "nodes.h"
40#include "property_map.h"
41
42namespace KJS {
43
44extern const UString lengthPropertyName("length");
45extern const UString prototypePropertyName("prototype");
46extern const UString toStringPropertyName("toString");
47extern const UString valueOfPropertyName("valueOf");
48
49// ------------------------------ Object ---------------------------------------
50
51Object Object::dynamicCast(const Value &v)
52{
53 if (v.isNull() || v.type() != ObjectType)
54 return Object(0);
55
56 return Object(static_cast<ObjectImp*>(v.imp()));
57}
58
59// ------------------------------ ObjectImp ------------------------------------
60
61ObjectImp::ObjectImp(const Object &proto)
62 : _prop(0), _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L), _scope(0)
63{
64 //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
65 _scope = ListImp::empty();
66 _prop = new PropertyMap();
67}
68
69ObjectImp::ObjectImp()
70{
71 //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
72 _prop = 0;
73 _proto = NullImp::staticNull;
74 _internalValue = 0L;
75 _scope = ListImp::empty();
76 _prop = new PropertyMap();
77}
78
79ObjectImp::~ObjectImp()
80{
81 //fprintf(stderr,"ObjectImp::~ObjectImp %p\n",(void*)this);
82 if (_proto)
83 _proto->setGcAllowed();
84 if (_internalValue)
85 _internalValue->setGcAllowed();
86 if (_scope)
87 _scope->setGcAllowed();
88 delete _prop;
89}
90
91void ObjectImp::mark()
92{
93 //fprintf(stderr,"ObjectImp::mark() %p\n",(void*)this);
94 ValueImp::mark();
95
96 if (_proto && !_proto->marked())
97 _proto->mark();
98
99 PropertyMapNode *node = _prop->first();
100 while (node) {
101 if (!node->value->marked())
102 node->value->mark();
103 node = node->next();
104 }
105
106 if (_internalValue && !_internalValue->marked())
107 _internalValue->mark();
108 if (_scope && !_scope->marked())
109 _scope->mark();
110}
111
112const ClassInfo *ObjectImp::classInfo() const
113{
114 return 0;
115}
116
117bool ObjectImp::inherits(const ClassInfo *info) const
118{
119 if (!info)
120 return false;
121
122 const ClassInfo *ci = classInfo();
123 if (!ci)
124 return false;
125
126 while (ci && ci != info)
127 ci = ci->parentClass;
128
129 return (ci == info);
130}
131
132Type ObjectImp::type() const
133{
134 return ObjectType;
135}
136
137Value ObjectImp::prototype() const
138{
139 return Value(_proto);
140}
141
142void ObjectImp::setPrototype(const Value &proto)
143{
144 _proto = proto.imp();
145}
146
147UString ObjectImp::className() const
148{
149 const ClassInfo *ci = classInfo();
150 if ( ci )
151 return ci->className;
152 return "Object";
153}
154
155Value ObjectImp::get(ExecState *exec, const UString &propertyName) const
156{
157 if (propertyName == "__proto__") {
158 Object proto = Object::dynamicCast(prototype());
159 // non-standard netscape extension
160 if (proto.isNull())
161 return Null();
162 else
163 return proto;
164 }
165
166 ValueImp *imp = getDirect(propertyName);
167 if ( imp )
168 return Value(imp);
169
170 Object proto = Object::dynamicCast(prototype());
171 if (proto.isNull())
172 return Undefined();
173
174 return proto.get(exec,propertyName);
175}
176
177Value ObjectImp::get(ExecState *exec, unsigned propertyName) const
178{
179 return get(exec, UString::from(propertyName));
180}
181
182// This get method only looks at the property map.
183// A bit like hasProperty(recursive=false), this doesn't go to the prototype.
184// This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
185// to look up in the prototype, it might already exist there)
186ValueImp* ObjectImp::getDirect(const UString& propertyName) const
187{
188 return _prop->get(propertyName);
189}
190
191// ECMA 8.6.2.2
192void ObjectImp::put(ExecState *exec, const UString &propertyName,
193 const Value &value, int attr)
194{
195 assert(!value.isNull());
196 assert(value.type() != CompletionType);
197 assert(value.type() != ListType);
198
199 /* TODO: check for write permissions directly w/o this call */
200 /* Doesn't look very easy with the PropertyMap API - David */
201 // putValue() is used for JS assignemnts. It passes no attribute.
202 // Assume that a C++ implementation knows what it is doing
203 // and let it override the canPut() check.
204 if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) {
205#ifdef KJS_VERBOSE
206 fprintf( stderr, "WARNING: canPut %s said NO\n", propertyName.ascii() );
207#endif
208 return;
209 }
210
211 if (propertyName == "__proto__") {
212 // non-standard netscape extension
213 setPrototype(value);
214 return;
215 }
216
217 _prop->put(propertyName,value.imp(),attr);
218}
219
220void ObjectImp::put(ExecState *exec, unsigned propertyName,
221 const Value &value, int attr)
222{
223 put(exec, UString::from(propertyName), value, attr);
224}
225
226// ECMA 8.6.2.3
227bool ObjectImp::canPut(ExecState *, const UString &propertyName) const
228{
229 PropertyMapNode *node = _prop->getNode(propertyName);
230 if (node)
231 return!(node->attr & ReadOnly);
232
233 // Look in the static hashtable of properties
234 const HashEntry* e = findPropertyHashEntry(propertyName);
235 if (e)
236 return !(e->attr & ReadOnly);
237
238 // Don't look in the prototype here. We can always put an override
239 // in the object, even if the prototype has a ReadOnly property.
240 return true;
241}
242
243// ECMA 8.6.2.4
244bool ObjectImp::hasProperty(ExecState *exec, const UString &propertyName) const
245{
246 if (propertyName == "__proto__")
247 return true;
248 if (_prop->get(propertyName))
249 return true;
250
251 // Look in the static hashtable of properties
252 if (findPropertyHashEntry(propertyName))
253 return true;
254
255 // Look in the prototype
256 Object proto = Object::dynamicCast(prototype());
257 return !proto.isNull() && proto.hasProperty(exec,propertyName);
258}
259
260bool ObjectImp::hasProperty(ExecState *exec, unsigned propertyName) const
261{
262 return hasProperty(exec, UString::from(propertyName));
263}
264
265// ECMA 8.6.2.5
266bool ObjectImp::deleteProperty(ExecState */*exec*/, const UString &propertyName)
267{
268 PropertyMapNode *node = _prop->getNode(propertyName);
269 if (node) {
270 if ((node->attr & DontDelete))
271 return false;
272 _prop->remove(propertyName);
273 return true;
274 }
275
276 // Look in the static hashtable of properties
277 const HashEntry* entry = findPropertyHashEntry(propertyName);
278 if (entry && entry->attr & DontDelete)
279 return false; // this builtin property can't be deleted
280 return true;
281}
282
283bool ObjectImp::deleteProperty(ExecState *exec, unsigned propertyName)
284{
285 return deleteProperty(exec, UString::from(propertyName));
286}
287
288void ObjectImp::deleteAllProperties( ExecState * )
289{
290 _prop->clear();
291}
292
293// ECMA 8.6.2.6
294Value ObjectImp::defaultValue(ExecState *exec, Type hint) const
295{
296 if (hint != StringType && hint != NumberType) {
297 /* Prefer String for Date objects */
298 if (_proto == exec->interpreter()->builtinDatePrototype().imp())
299 hint = StringType;
300 else
301 hint = NumberType;
302 }
303
304 Value v;
305 if (hint == StringType)
306 v = get(exec,toStringPropertyName);
307 else
308 v = get(exec,valueOfPropertyName);
309
310 if (v.type() == ObjectType) {
311 Object o = Object(static_cast<ObjectImp*>(v.imp()));
312 if (o.implementsCall()) { // spec says "not primitive type" but ...
313 Object thisObj = Object(const_cast<ObjectImp*>(this));
314 Value def = o.call(exec,thisObj,List::empty());
315 Type defType = def.type();
316 if (defType == UnspecifiedType || defType == UndefinedType ||
317 defType == NullType || defType == BooleanType ||
318 defType == StringType || defType == NumberType) {
319 return def;
320 }
321 }
322 }
323
324 if (hint == StringType)
325 v = get(exec,valueOfPropertyName);
326 else
327 v = get(exec,toStringPropertyName);
328
329 if (v.type() == ObjectType) {
330 Object o = Object(static_cast<ObjectImp*>(v.imp()));
331 if (o.implementsCall()) { // spec says "not primitive type" but ...
332 Object thisObj = Object(const_cast<ObjectImp*>(this));
333 Value def = o.call(exec,thisObj,List::empty());
334 Type defType = def.type();
335 if (defType == UnspecifiedType || defType == UndefinedType ||
336 defType == NullType || defType == BooleanType ||
337 defType == StringType || defType == NumberType) {
338 return def;
339 }
340 }
341 }
342
343 Object err = Error::create(exec, TypeError, I18N_NOOP("No default value"));
344 exec->setException(err);
345 return err;
346}
347
348const HashEntry* ObjectImp::findPropertyHashEntry( const UString& propertyName ) const
349{
350 const ClassInfo *info = classInfo();
351 while (info) {
352 if (info->propHashTable) {
353 const HashEntry *e = Lookup::findEntry(info->propHashTable, propertyName);
354 if (e)
355 return e;
356 }
357 info = info->parentClass;
358 }
359 return 0L;
360}
361
362bool ObjectImp::implementsConstruct() const
363{
364 return false;
365}
366
367Object ObjectImp::construct(ExecState */*exec*/, const List &/*args*/)
368{
369 assert(false);
370 return Object(0);
371}
372
373bool ObjectImp::implementsCall() const
374{
375 return false;
376}
377
378Value ObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/)
379{
380 assert(false);
381 return Object(0);
382}
383
384bool ObjectImp::implementsHasInstance() const
385{
386 return false;
387}
388
389Boolean ObjectImp::hasInstance(ExecState */*exec*/, const Value &/*value*/)
390{
391 assert(false);
392 return Boolean(false);
393}
394
395const List ObjectImp::scope() const
396{
397 return _scope;
398}
399
400void ObjectImp::setScope(const List &s)
401{
402 if (_scope) _scope->setGcAllowed();
403 _scope = static_cast<ListImp*>(s.imp());
404}
405
406ReferenceList ObjectImp::propList(ExecState *exec, bool recursive)
407{
408 ReferenceList list;
409 if (_proto && _proto->dispatchType() == ObjectType && recursive)
410 list = static_cast<ObjectImp*>(_proto)->propList(exec,recursive);
411
412
413 PropertyMapNode *node = _prop->first();
414 while (node) {
415 if (!(node->attr & DontEnum))
416 list.append(Reference(Object(this), node->name));
417 node = node->next();
418 }
419
420 // Add properties from the static hashtable of properties
421 const ClassInfo *info = classInfo();
422 while (info) {
423 if (info->propHashTable) {
424 int size = info->propHashTable->size;
425 const HashEntry *e = info->propHashTable->entries;
426 for (int i = 0; i < size; ++i, ++e) {
427 if ( e->s && !(e->attr & DontEnum) )
428 list.append(Reference(Object(this), e->s)); /// ######### check for duplicates with the propertymap
429 }
430 }
431 info = info->parentClass;
432 }
433
434 return list;
435}
436
437Value ObjectImp::internalValue() const
438{
439 return Value(_internalValue);
440}
441
442void ObjectImp::setInternalValue(const Value &v)
443{
444 _internalValue = v.imp();
445}
446
447Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const
448{
449 return defaultValue(exec,preferredType);
450}
451
452bool ObjectImp::toBoolean(ExecState */*exec*/) const
453{
454 return true;
455}
456
457double ObjectImp::toNumber(ExecState *exec) const
458{
459 Value prim = toPrimitive(exec,NumberType);
460 if (exec->hadException()) // should be picked up soon in nodes.cpp
461 return 0.0;
462 return prim.toNumber(exec);
463}
464
465UString ObjectImp::toString(ExecState *exec) const
466{
467 Value prim = toPrimitive(exec,StringType);
468 if (exec->hadException()) // should be picked up soon in nodes.cpp
469 return "";
470 return prim.toString(exec);
471}
472
473Object ObjectImp::toObject(ExecState */*exec*/) const
474{
475 return Object(const_cast<ObjectImp*>(this));
476}
477
478
479// ------------------------------ Error ----------------------------------------
480
481const char * const errorNamesArr[] = {
482 I18N_NOOP("Error"), // GeneralError
483 I18N_NOOP("Evaluation error"), // EvalError
484 I18N_NOOP("Range error"), // RangeError
485 I18N_NOOP("Reference error"), // ReferenceError
486 I18N_NOOP("Syntax error"), // SyntaxError
487 I18N_NOOP("Type error"), // TypeError
488 I18N_NOOP("URI error"), // URIError
489};
490
491const char * const * const Error::errorNames = errorNamesArr;
492
493Object Error::create(ExecState *exec, ErrorType errtype, const char *message,
494 int lineno, int sourceId)
495{
496 Object cons;
497
498 switch (errtype) {
499 case EvalError:
500 cons = exec->interpreter()->builtinEvalError();
501 break;
502 case RangeError:
503 cons = exec->interpreter()->builtinRangeError();
504 break;
505 case ReferenceError:
506 cons = exec->interpreter()->builtinReferenceError();
507 break;
508 case SyntaxError:
509 cons = exec->interpreter()->builtinSyntaxError();
510 break;
511 case TypeError:
512 cons = exec->interpreter()->builtinTypeError();
513 break;
514 case URIError:
515 cons = exec->interpreter()->builtinURIError();
516 break;
517 default:
518 cons = exec->interpreter()->builtinError();
519 break;
520 }
521
522 if (!message)
523 message = errorNames[errtype];
524 List args;
525 args.append(String(message));
526 Object err = Object::dynamicCast(cons.construct(exec,args));
527
528 if (lineno != -1)
529 err.put(exec, "line", Number(lineno));
530 if (sourceId != -1)
531 err.put(exec, "sourceId", Number(sourceId));
532
533 return err;
534
535/*
536#ifndef NDEBUG
537 const char *msg = err.get("message").toString().value().ascii();
538 if (l >= 0)
539 fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
540 else
541 fprintf(stderr, "KJS: %s. %s\n", estr, msg);
542#endif
543
544 return err;
545*/
546}
547
548} // namespace KJS
Note: See TracBrowser for help on using the repository browser.