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

Last change on this file since 9768 was 9768, checked in by ggaren, 20 years ago

-rolled in patches for http://bugzilla.opendarwin.org/show_bug.cgi?id=3945
[PATCH] Safe merges of comments and other trivialities from KDE's kjs

-patch by Martijn Klingens <[email protected]>

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