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

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

JavaScriptCore:

  • kjs/object.cpp: Make the same change Maciej just did, but to the other constructor right next to the one he changed.

WebFoundation:

  • English.lproj/StringsNotToBeLocalized.txt: Update for recent changes.

WebKit:

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