Fixed build error.
[WebKit-https.git] / JavaScriptCore / kjs / object.cpp
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 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., 59 Temple Place - Suite 330,
21  *  Boston, MA 02111-1307, 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
47 static bool _traceJavaScript = false;
48
49 extern "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
62 namespace KJS {
63
64 // ------------------------------ Object ---------------------------------------
65
66 Object 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
75 Value 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
126 ObjectImp::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
132 ObjectImp::ObjectImp(ObjectImp *proto)
133   : _proto(proto), _internalValue(0L)
134 {
135   //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
136 }
137
138 ObjectImp::ObjectImp()
139 {
140   //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
141   _proto = NullImp::staticNull;
142   _internalValue = 0L;
143 }
144
145 ObjectImp::~ObjectImp()
146 {
147   //fprintf(stderr,"ObjectImp::~ObjectImp %p\n",(void*)this);
148 }
149
150 void 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
166 const ClassInfo *ObjectImp::classInfo() const
167 {
168   return 0;
169 }
170
171 bool 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
186 Type ObjectImp::type() const
187 {
188   return ObjectType;
189 }
190
191 Value ObjectImp::prototype() const
192 {
193   return Value(_proto);
194 }
195
196 void ObjectImp::setPrototype(const Value &proto)
197 {
198   _proto = proto.imp();
199 }
200
201 UString ObjectImp::className() const
202 {
203   const ClassInfo *ci = classInfo();
204   if ( ci )
205     return ci->className;
206   return "Object";
207 }
208
209 Value 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
226 Value ObjectImp::get(ExecState *exec, unsigned propertyName) const
227 {
228   return get(exec, Identifier::from(propertyName));
229 }
230
231 // ECMA 8.6.2.2
232 void 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
258 void 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
265 bool 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
283 bool ObjectImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
284 {
285   if (_prop.get(propertyName))
286     return true;
287
288   // Look in the static hashtable of properties
289   if (findPropertyHashEntry(propertyName))
290       return true;
291
292   // non-standard netscape extension
293   if (propertyName == specialPrototypePropertyName)
294     return true;
295
296   if (_proto->dispatchType() != ObjectType) {
297     return false;
298   }
299
300   // Look in the prototype
301   return static_cast<ObjectImp *>(_proto)->hasProperty(exec, propertyName);
302 }
303
304 bool ObjectImp::hasProperty(ExecState *exec, unsigned propertyName) const
305 {
306   return hasProperty(exec, Identifier::from(propertyName));
307 }
308
309 // ECMA 8.6.2.5
310 bool ObjectImp::deleteProperty(ExecState */*exec*/, const Identifier &propertyName)
311 {
312   int attributes;
313   ValueImp *v = _prop.get(propertyName, attributes);
314   if (v) {
315     if ((attributes & DontDelete))
316       return false;
317     _prop.remove(propertyName);
318     return true;
319   }
320
321   // Look in the static hashtable of properties
322   const HashEntry* entry = findPropertyHashEntry(propertyName);
323   if (entry && entry->attr & DontDelete)
324     return false; // this builtin property can't be deleted
325   return true;
326 }
327
328 bool ObjectImp::deleteProperty(ExecState *exec, unsigned propertyName)
329 {
330   return deleteProperty(exec, Identifier::from(propertyName));
331 }
332
333 void ObjectImp::deleteAllProperties( ExecState * )
334 {
335   _prop.clear();
336 }
337
338 // ECMA 8.6.2.6
339 Value ObjectImp::defaultValue(ExecState *exec, Type hint) const
340 {
341   if (hint != StringType && hint != NumberType) {
342     /* Prefer String for Date objects */
343     if (_proto == exec->lexicalInterpreter()->builtinDatePrototype().imp())
344       hint = StringType;
345     else
346       hint = NumberType;
347   }
348
349   Value v;
350   if (hint == StringType)
351     v = get(exec,toStringPropertyName);
352   else
353     v = get(exec,valueOfPropertyName);
354
355   if (v.type() == ObjectType) {
356     Object o = Object(static_cast<ObjectImp*>(v.imp()));
357     if (o.implementsCall()) { // spec says "not primitive type" but ...
358       Object thisObj = Object(const_cast<ObjectImp*>(this));
359       Value def = o.call(exec,thisObj,List::empty());
360       Type defType = def.type();
361       if (defType == UnspecifiedType || defType == UndefinedType ||
362           defType == NullType || defType == BooleanType ||
363           defType == StringType || defType == NumberType) {
364         return def;
365       }
366     }
367   }
368
369   if (hint == StringType)
370     v = get(exec,valueOfPropertyName);
371   else
372     v = get(exec,toStringPropertyName);
373
374   if (v.type() == ObjectType) {
375     Object o = Object(static_cast<ObjectImp*>(v.imp()));
376     if (o.implementsCall()) { // spec says "not primitive type" but ...
377       Object thisObj = Object(const_cast<ObjectImp*>(this));
378       Value def = o.call(exec,thisObj,List::empty());
379       Type defType = def.type();
380       if (defType == UnspecifiedType || defType == UndefinedType ||
381           defType == NullType || defType == BooleanType ||
382           defType == StringType || defType == NumberType) {
383         return def;
384       }
385     }
386   }
387
388   Object err = Error::create(exec, TypeError, I18N_NOOP("No default value"));
389   exec->setException(err);
390   return err;
391 }
392
393 const HashEntry* ObjectImp::findPropertyHashEntry( const Identifier& propertyName ) const
394 {
395   const ClassInfo *info = classInfo();
396   while (info) {
397     if (info->propHashTable) {
398       const HashEntry *e = Lookup::findEntry(info->propHashTable, propertyName);
399       if (e)
400         return e;
401     }
402     info = info->parentClass;
403   }
404   return 0L;
405 }
406
407 bool ObjectImp::implementsConstruct() const
408 {
409   return false;
410 }
411
412 Object ObjectImp::construct(ExecState */*exec*/, const List &/*args*/)
413 {
414   assert(false);
415   return Object(0);
416 }
417
418 Object ObjectImp::construct(ExecState *exec, const List &args, const UString &/*sourceURL*/, int /*lineNumber*/)
419 {
420   return construct(exec, args);
421 }
422
423 bool ObjectImp::implementsCall() const
424 {
425   return false;
426 }
427
428 Value ObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/)
429 {
430   assert(false);
431   return Object(0);
432 }
433
434 bool ObjectImp::implementsHasInstance() const
435 {
436   return false;
437 }
438
439 Boolean ObjectImp::hasInstance(ExecState */*exec*/, const Value &/*value*/)
440 {
441   assert(false);
442   return Boolean(false);
443 }
444
445 ReferenceList ObjectImp::propList(ExecState *exec, bool recursive)
446 {
447   ReferenceList list;
448   if (_proto && _proto->dispatchType() == ObjectType && recursive)
449     list = static_cast<ObjectImp*>(_proto)->propList(exec,recursive);
450
451   _prop.addEnumerablesToReferenceList(list, Object(this));
452
453   // Add properties from the static hashtable of properties
454   const ClassInfo *info = classInfo();
455   while (info) {
456     if (info->propHashTable) {
457       int size = info->propHashTable->size;
458       const HashEntry *e = info->propHashTable->entries;
459       for (int i = 0; i < size; ++i, ++e) {
460         if ( e->s && !(e->attr & DontEnum) )
461           list.append(Reference(this, e->s)); /// ######### check for duplicates with the propertymap
462       }
463     }
464     info = info->parentClass;
465   }
466
467   return list;
468 }
469
470 Value ObjectImp::internalValue() const
471 {
472   return Value(_internalValue);
473 }
474
475 void ObjectImp::setInternalValue(const Value &v)
476 {
477   _internalValue = v.imp();
478 }
479
480 void ObjectImp::setInternalValue(ValueImp *v)
481 {
482 #if !USE_CONSERVATIVE_GC
483   v->setGcAllowed();
484 #endif
485   _internalValue = v;
486 }
487
488 Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const
489 {
490   return defaultValue(exec,preferredType);
491 }
492
493 bool ObjectImp::toBoolean(ExecState */*exec*/) const
494 {
495   return true;
496 }
497
498 double ObjectImp::toNumber(ExecState *exec) const
499 {
500   Value prim = toPrimitive(exec,NumberType);
501   if (exec->hadException()) // should be picked up soon in nodes.cpp
502     return 0.0;
503   return prim.toNumber(exec);
504 }
505
506 UString ObjectImp::toString(ExecState *exec) const
507 {
508   Value prim = toPrimitive(exec,StringType);
509   if (exec->hadException()) // should be picked up soon in nodes.cpp
510     return "";
511   return prim.toString(exec);
512 }
513
514 Object ObjectImp::toObject(ExecState */*exec*/) const
515 {
516   return Object(const_cast<ObjectImp*>(this));
517 }
518
519 void ObjectImp::putDirect(const Identifier &propertyName, ValueImp *value, int attr)
520 {
521 #if !USE_CONSERVATIVE_GC
522     value->setGcAllowed();
523 #endif
524     _prop.put(propertyName, value, attr);
525 }
526
527 void ObjectImp::putDirect(const Identifier &propertyName, int value, int attr)
528 {
529     _prop.put(propertyName, NumberImp::create(value), attr);
530 }
531
532 // ------------------------------ Error ----------------------------------------
533
534 const char * const errorNamesArr[] = {
535   I18N_NOOP("Error"), // GeneralError
536   I18N_NOOP("Evaluation error"), // EvalError
537   I18N_NOOP("Range error"), // RangeError
538   I18N_NOOP("Reference error"), // ReferenceError
539   I18N_NOOP("Syntax error"), // SyntaxError
540   I18N_NOOP("Type error"), // TypeError
541   I18N_NOOP("URI error"), // URIError
542 };
543
544 const char * const * const Error::errorNames = errorNamesArr;
545
546 Object Error::create(ExecState *exec, ErrorType errtype, const char *message,
547                      int lineno, int sourceId, const UString *sourceURL)
548 {
549   Object cons;
550   switch (errtype) {
551   case EvalError:
552     cons = exec->lexicalInterpreter()->builtinEvalError();
553     break;
554   case RangeError:
555     cons = exec->lexicalInterpreter()->builtinRangeError();
556     break;
557   case ReferenceError:
558     cons = exec->lexicalInterpreter()->builtinReferenceError();
559     break;
560   case SyntaxError:
561     cons = exec->lexicalInterpreter()->builtinSyntaxError();
562     break;
563   case TypeError:
564     cons = exec->lexicalInterpreter()->builtinTypeError();
565     break;
566   case URIError:
567     cons = exec->lexicalInterpreter()->builtinURIError();
568     break;
569   default:
570     cons = exec->lexicalInterpreter()->builtinError();
571     break;
572   }
573
574   if (!message)
575     message = errorNames[errtype];
576   List args;
577   args.append(String(message));
578   Object err = Object::dynamicCast(cons.construct(exec,args));
579
580   if (lineno != -1)
581     err.put(exec, "line", Number(lineno));
582   if (sourceId != -1)
583     err.put(exec, "sourceId", Number(sourceId));
584
585   if(sourceURL)
586    err.put(exec,"sourceURL", String(*sourceURL));
587  
588   return err;
589
590 /*
591 #ifndef NDEBUG
592   const char *msg = err.get("message").toString().value().ascii();
593   if (l >= 0)
594       fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
595   else
596       fprintf(stderr, "KJS: %s. %s\n", estr, msg);
597 #endif
598
599   return err;
600 */
601 }
602
603 } // namespace KJS