# kjs Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# object.cpp

    00001 // -*- c-basic-offset: 2 -*-
    00002 /*
    00003  *  This file is part of the KDE libraries
    00004  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
    00005  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
    00006  *
    00007  *  This library is free software; you can redistribute it and/or
    00008  *  modify it under the terms of the GNU Lesser General Public
    00009  *  License as published by the Free Software Foundation; either
    00010  *  version 2 of the License, or (at your option) any later version.
    00011  *
    00012  *  This library is distributed in the hope that it will be useful,
    00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00015  *  Lesser General Public License for more details.
    00016  *
    00017  *  You should have received a copy of the GNU Lesser General Public License
    00018  *  along with this library; see the file COPYING.LIB.  If not, write to
    00019  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00020  *  Boston, MA 02111-1307, USA.
    00021  *
    00022  */
    00023
    00024 #include "value.h"
    00025 #include "object.h"
    00026 #include "types.h"
    00027 #include "interpreter.h"
    00028 #include "lookup.h"
    00029
    00030 #include <assert.h>
    00031 #include <math.h>
    00032 #include <stdio.h>
    00033
    00034 #include "internal.h"
    00035 #include "collector.h"
    00036 #include "operations.h"
    00037 #include "error_object.h"
    00038 #include "nodes.h"
    00039 #include "property_map.h"
    00040
    00041 using namespace KJS;
    00042
    00043 // ------------------------------ Object ---------------------------------------
    00044
    00045 Object::Object() : Value()
    00046 {
    00047 }
    00048
    00049 Object::Object(ObjectImp *v) : Value(v)
    00050 {
    00051 }
    00052
    00053 Object::Object(const Object &v) : Value(v)
    00054 {
    00055 }
    00056
    00057 Object::~Object()
    00058 {
    00059 }
    00060
    00061 Object& Object::operator=(const Object &v)
    00062 {
    00063   Value::operator=(v);
    00064   return *this;
    00065 }
    00066
    00067 const ClassInfo *Object::classInfo() const
    00068 {
    00069   return static_cast<ObjectImp*>(rep)->classInfo();
    00070 }
    00071
    00072 bool Object::inherits(const ClassInfo *cinfo) const
    00073 {
    00074   return static_cast<ObjectImp*>(rep)->inherits(cinfo);
    00075 }
    00076
    00077 Object Object::dynamicCast(const Value &v)
    00078 {
    00079   if (v.isNull() || v.type() != ObjectType)
    00080     return Object(0);
    00081
    00082   return Object(static_cast<ObjectImp*>(v.imp()));
    00083 }
    00084
    00085 Value Object::prototype() const
    00086 {
    00087   return Value(static_cast<ObjectImp*>(rep)->prototype());
    00088 }
    00089
    00090 UString Object::className() const
    00091 {
    00092   return static_cast<ObjectImp*>(rep)->className();
    00093 }
    00094
    00095 Value Object::get(ExecState *exec, const UString &propertyName) const
    00096 {
    00097   return static_cast<ObjectImp*>(rep)->get(exec,propertyName);
    00098 }
    00099
    00100 void Object::put(ExecState *exec, const UString &propertyName, const Value &value, int attr)
    00101 {
    00102   static_cast<ObjectImp*>(rep)->put(exec,propertyName,value,attr);
    00103 }
    00104
    00105 bool Object::canPut(ExecState *exec, const UString &propertyName) const
    00106 {
    00107   return static_cast<ObjectImp*>(rep)->canPut(exec,propertyName);
    00108 }
    00109
    00110 bool Object::hasProperty(ExecState *exec, const UString &propertyName) const
    00111 {
    00112   return static_cast<ObjectImp*>(rep)->hasProperty(exec, propertyName);
    00113 }
    00114
    00115 bool Object::deleteProperty(ExecState *exec, const UString &propertyName)
    00116 {
    00117   return static_cast<ObjectImp*>(rep)->deleteProperty(exec,propertyName);
    00118 }
    00119
    00120 Value Object::defaultValue(ExecState *exec, Type hint) const
    00121 {
    00122   return static_cast<ObjectImp*>(rep)->defaultValue(exec,hint);
    00123 }
    00124
    00125 bool Object::implementsConstruct() const
    00126 {
    00127   return static_cast<ObjectImp*>(rep)->implementsConstruct();
    00128 }
    00129
    00130 Object Object::construct(ExecState *exec, const List &args)
    00131 {
    00132   return static_cast<ObjectImp*>(rep)->construct(exec,args);
    00133 }
    00134
    00135 bool Object::implementsCall() const
    00136 {
    00137   return static_cast<ObjectImp*>(rep)->implementsCall();
    00138 }
    00139
    00140 Value Object::call(ExecState *exec, Object &thisObj, const List &args)
    00141 {
    00142 #if KJS_MAX_STACK > 0
    00143   static int depth = 0; // sum of all concurrent interpreters
    00144   if (++depth > KJS_MAX_STACK) {
    00145 #ifndef NDEBUG
    00146     fprintf(stderr, "Exceeded maximum function call depth\n");
    00147 #endif
    00148     Object err = Error::create(exec, RangeError,
    00149                                "Maximum call stack size exceeded.");
    00150     exec->setException(err);
    00151     return err;
    00152   }
    00153 #endif
    00154
    00155   Value ret = static_cast<ObjectImp*>(rep)->call(exec,thisObj,args);
    00156
    00157 #if KJS_MAX_STACK > 0
    00158   --depth;
    00159 #endif
    00160
    00161   return ret;
    00162 }
    00163
    00164 bool Object::implementsHasInstance() const
    00165 {
    00166   return static_cast<ObjectImp*>(rep)->implementsHasInstance();
    00167 }
    00168
    00169 Boolean Object::hasInstance(ExecState *exec, const Value &value)
    00170 {
    00171   return static_cast<ObjectImp*>(rep)->hasInstance(exec,value);
    00172 }
    00173
    00174 const List Object::scope() const
    00175 {
    00176   return static_cast<ObjectImp*>(rep)->scope();
    00177 }
    00178
    00179 void Object::setScope(const List &s)
    00180 {
    00181   static_cast<ObjectImp*>(rep)->setScope(s);
    00182 }
    00183
    00184 List Object::propList(ExecState *exec, bool recursive)
    00185 {
    00186   return static_cast<ObjectImp*>(rep)->propList(exec,recursive);
    00187 }
    00188
    00189 Value Object::internalValue() const
    00190 {
    00191   return static_cast<ObjectImp*>(rep)->internalValue();
    00192 }
    00193
    00194 void Object::setInternalValue(const Value &v)
    00195 {
    00196   static_cast<ObjectImp*>(rep)->setInternalValue(v);
    00197 }
    00198
    00199 // ------------------------------ ObjectImp ------------------------------------
    00200
    00201 ObjectImp::ObjectImp(const Object &proto)
    00202   : _prop(0), _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L), _scope(0)
    00203 {
    00204   //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
    00205   _scope = ListImp::empty();
    00206   _prop = new PropertyMap();
    00207 }
    00208
    00209 ObjectImp::ObjectImp()
    00210 {
    00211   //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
    00212   _prop = 0;
    00213   _proto = NullImp::staticNull;
    00214   _internalValue = 0L;
    00215   _scope = ListImp::empty();
    00216   _prop = new PropertyMap();
    00217 }
    00218
    00219 ObjectImp::~ObjectImp()
    00220 {
    00221   //fprintf(stderr,"ObjectImp::~ObjectImp %p\n",(void*)this);
    00222   if (_proto)
    00223     _proto->inlinedSetGcAllowed();
    00224   if (_internalValue)
    00225     _internalValue->inlinedSetGcAllowed();
    00226   if (_scope)
    00227     _scope->inlinedSetGcAllowed();
    00228   delete _prop;
    00229 }
    00230
    00231 void ObjectImp::mark()
    00232 {
    00233   //fprintf(stderr,"ObjectImp::mark() %p\n",(void*)this);
    00234   ValueImp::mark();
    00235
    00236   if (_proto && !_proto->marked())
    00237     _proto->mark();
    00238
    00239   PropertyMapNode *node = _prop->first();
    00240   while (node) {
    00241     if (!node->value->marked())
    00242       node->value->mark();
    00243     node = node->next();
    00244   }
    00245
    00246   if (_internalValue && !_internalValue->marked())
    00247     _internalValue->mark();
    00248   if (_scope && !_scope->marked())
    00249     _scope->mark();
    00250 }
    00251
    00252 const ClassInfo *ObjectImp::classInfo() const
    00253 {
    00254   return 0;
    00255 }
    00256
    00257 bool ObjectImp::inherits(const ClassInfo *info) const
    00258 {
    00259   if (!info)
    00260     return false;
    00261
    00262   const ClassInfo *ci = classInfo();
    00263   if (!ci)
    00264     return false;
    00265
    00266   while (ci && ci != info)
    00267     ci = ci->parentClass;
    00268
    00269   return (ci == info);
    00270 }
    00271
    00272 Type ObjectImp::type() const
    00273 {
    00274   return ObjectType;
    00275 }
    00276
    00277 Value ObjectImp::prototype() const
    00278 {
    00279   return Value(_proto);
    00280 }
    00281
    00282 void ObjectImp::setPrototype(const Value &proto)
    00283 {
    00284   _proto = proto.imp();
    00285 }
    00286
    00287 UString ObjectImp::className() const
    00288 {
    00289   const ClassInfo *ci = classInfo();
    00290   if ( ci )
    00291     return ci->className;
    00292   return "Object";
    00293 }
    00294
    00295 Value ObjectImp::get(ExecState *exec, const UString &propertyName) const
    00296 {
    00297   if (propertyName == "__proto__") {
    00298     Object proto = Object::dynamicCast(prototype());
    00299     // non-standard netscape extension
    00300     if (proto.isNull())
    00301       return Null();
    00302     else
    00303       return proto;
    00304   }
    00305
    00306   ValueImp *imp = getDirect(propertyName);
    00307   if ( imp )
    00308     return Value(imp);
    00309
    00310   Object proto = Object::dynamicCast(prototype());
    00311   if (proto.isNull())
    00312     return Undefined();
    00313
    00314   return proto.get(exec,propertyName);
    00315 }
    00316
    00317 // This get method only looks at the property map.
    00318 // A bit like hasProperty(recursive=false), this doesn't go to the prototype.
    00319 // This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
    00320 // to look up in the prototype, it might already exist there)
    00321 ValueImp* ObjectImp::getDirect(const UString& propertyName) const
    00322 {
    00323   return _prop->get(propertyName);
    00324 }
    00325
    00326 // ECMA 8.6.2.2
    00327 void ObjectImp::put(ExecState *exec, const UString &propertyName,
    00328                      const Value &value, int attr)
    00329 {
    00330   assert(!value.isNull());
    00331   assert(value.type() != ReferenceType);
    00332   assert(value.type() != CompletionType);
    00333   assert(value.type() != ListType);
    00334
    00335   /* TODO: check for write permissions directly w/o this call */
    00336   /* Doesn't look very easy with the PropertyMap API - David */
    00337   // putValue() is used for JS assignemnts. It passes no attribute.
    00338   // Assume that a C++ implementation knows what it is doing
    00339   // and let it override the canPut() check.
    00340   if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) {
    00341 #ifdef KJS_VERBOSE
    00342     fprintf( stderr, "WARNING: canPut %s said NO\n", propertyName.ascii() );
    00343 #endif
    00344     return;
    00345   }
    00346
    00347   if (propertyName == "__proto__") {
    00348     // non-standard netscape extension
    00349     setPrototype(value);
    00350     return;
    00351   }
    00352
    00353   _prop->put(propertyName,value.imp(),attr);
    00354 }
    00355
    00356 // ECMA 8.6.2.3
    00357 bool ObjectImp::canPut(ExecState *, const UString &propertyName) const
    00358 {
    00359   PropertyMapNode *node = _prop->getNode(propertyName);
    00360   if (node)
    00361     return!(node->attr & ReadOnly);
    00362
    00363   // Look in the static hashtable of properties
    00364   const HashEntry* e = findPropertyHashEntry(propertyName);
    00365   if (e)
    00366     return !(e->attr & ReadOnly);
    00367
    00368   // Don't look in the prototype here. We can always put an override
    00369   // in the object, even if the prototype has a ReadOnly property.
    00370   return true;
    00371 }
    00372
    00373 // ECMA 8.6.2.4
    00374 bool ObjectImp::hasProperty(ExecState *exec, const UString &propertyName) const
    00375 {
    00376   if (propertyName == "__proto__")
    00377     return true;
    00378   if (_prop->get(propertyName))
    00379     return true;
    00380
    00381   // Look in the static hashtable of properties
    00382   if (findPropertyHashEntry(propertyName))
    00383       return true;
    00384
    00385   // Look in the prototype
    00386   Object proto = Object::dynamicCast(prototype());
    00387   return !proto.isNull() && proto.hasProperty(exec,propertyName);
    00388 }
    00389
    00390 // ECMA 8.6.2.5
    00391 bool ObjectImp::deleteProperty(ExecState */*exec*/, const UString &propertyName)
    00392 {
    00393   PropertyMapNode *node = _prop->getNode(propertyName);
    00394   if (node) {
    00395     if ((node->attr & DontDelete))
    00396       return false;
    00397     _prop->remove(propertyName);
    00398     return true;
    00399   }
    00400
    00401   // Look in the static hashtable of properties
    00402   const HashEntry* entry = findPropertyHashEntry(propertyName);
    00403   if (entry && entry->attr & DontDelete)
    00404     return false; // this builtin property can't be deleted
    00405   return true;
    00406 }
    00407
    00408 void ObjectImp::deleteAllProperties( ExecState * )
    00409 {
    00410   _prop->clear();
    00411 }
    00412
    00413 // ECMA 8.6.2.6
    00414 Value ObjectImp::defaultValue(ExecState *exec, Type hint) const
    00415 {
    00416   if (hint != StringType && hint != NumberType) {
    00417     /* Prefer String for Date objects */
    00418     if (_proto == exec->interpreter()->builtinDatePrototype().imp())
    00419       hint = StringType;
    00420     else
    00421       hint = NumberType;
    00422   }
    00423
    00424   Value v;
    00425   if (hint == StringType)
    00426     v = get(exec,"toString");
    00427   else
    00428     v = get(exec,"valueOf");
    00429
    00430   if (v.type() == ObjectType) {
    00431     Object o = Object(static_cast<ObjectImp*>(v.imp()));
    00432     if (o.implementsCall()) { // spec says "not primitive type" but ...
    00433       Object thisObj = Object(const_cast<ObjectImp*>(this));
    00434       Value def = o.call(exec,thisObj,List::empty());
    00435       Type defType = def.type();
    00436       if (defType == UnspecifiedType || defType == UndefinedType ||
    00437           defType == NullType || defType == BooleanType ||
    00438           defType == StringType || defType == NumberType) {
    00439         return def;
    00440       }
    00441     }
    00442   }
    00443
    00444   if (hint == StringType)
    00445     v = get(exec,"valueOf");
    00446   else
    00447     v = get(exec,"toString");
    00448
    00449   if (v.type() == ObjectType) {
    00450     Object o = Object(static_cast<ObjectImp*>(v.imp()));
    00451     if (o.implementsCall()) { // spec says "not primitive type" but ...
    00452       Object thisObj = Object(const_cast<ObjectImp*>(this));
    00453       Value def = o.call(exec,thisObj,List::empty());
    00454       Type defType = def.type();
    00455       if (defType == UnspecifiedType || defType == UndefinedType ||
    00456           defType == NullType || defType == BooleanType ||
    00457           defType == StringType || defType == NumberType) {
    00458         return def;
    00459       }
    00460     }
    00461   }
    00462
    00463   Object err = Error::create(exec, TypeError, I18N_NOOP("No default value"));
    00464   exec->setException(err);
    00465   return err;
    00466 }
    00467
    00468 const HashEntry* ObjectImp::findPropertyHashEntry( const UString& propertyName ) const
    00469 {
    00470   const ClassInfo *info = classInfo();
    00471   while (info) {
    00472     if (info->propHashTable) {
    00473       const HashEntry *e = Lookup::findEntry(info->propHashTable, propertyName);
    00474       if (e)
    00475         return e;
    00476     }
    00477     info = info->parentClass;
    00478   }
    00479   return 0L;
    00480 }
    00481
    00482 bool ObjectImp::implementsConstruct() const
    00483 {
    00484   return false;
    00485 }
    00486
    00487 Object ObjectImp::construct(ExecState */*exec*/, const List &/*args*/)
    00488 {
    00489   assert(false);
    00490   return Object(0);
    00491 }
    00492
    00493 bool ObjectImp::implementsCall() const
    00494 {
    00495   return false;
    00496 }
    00497
    00498 Value ObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/)
    00499 {
    00500   assert(false);
    00501   return Object(0);
    00502 }
    00503
    00504 bool ObjectImp::implementsHasInstance() const
    00505 {
    00506   return false;
    00507 }
    00508
    00509 Boolean ObjectImp::hasInstance(ExecState */*exec*/, const Value &/*value*/)
    00510 {
    00511   assert(false);
    00512   return Boolean(false);
    00513 }
    00514
    00515 const List ObjectImp::scope() const
    00516 {
    00517   return _scope;
    00518 }
    00519
    00520 void ObjectImp::setScope(const List &s)
    00521 {
    00522   if (_scope)
    00523     _scope->inlinedSetGcAllowed();
    00524   _scope = static_cast<ListImp*>(s.imp());
    00525 }
    00526
    00527 List ObjectImp::propList(ExecState *exec, bool recursive)
    00528 {
    00529   // TODO: stop using old Reference class
    00530   List list;
    00531   if (_proto && _proto->type() == ObjectType && recursive)
    00532     list = static_cast<ObjectImp*>(_proto)->propList(exec,recursive);
    00533
    00534
    00535   PropertyMapNode *node = _prop->first();
    00536   while (node) {
    00537     if (!(node->attr & DontEnum))
    00538       list.append(Reference(Object(this), node->name));
    00539     node = node->next();
    00540   }
    00541
    00542   // Add properties from the static hashtable of properties
    00543   const ClassInfo *info = classInfo();
    00544   while (info) {
    00545     if (info->propHashTable) {
    00546       int size = info->propHashTable->size;
    00547       const HashEntry *e = info->propHashTable->entries;
    00548       for (int i = 0; i < size; ++i, ++e) {
    00549         if ( e->s && !(e->attr & DontEnum) )
    00550           list.append(Reference(Object(this), e->s));
    00551       }
    00552     }
    00553     info = info->parentClass;
    00554   }
    00555
    00556   return list;
    00557 }
    00558
    00559 Value ObjectImp::internalValue() const
    00560 {
    00561   return Value(_internalValue);
    00562 }
    00563
    00564 void ObjectImp::setInternalValue(const Value &v)
    00565 {
    00566   _internalValue = v.imp();
    00567 }
    00568
    00569 // The following functions simply call the corresponding functions in ValueImp
    00570 // but are overridden in case of future needs
    00571
    00572 Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const
    00573 {
    00574   return defaultValue(exec,preferredType);
    00575 }
    00576
    00577 bool ObjectImp::toBoolean(ExecState */*exec*/) const
    00578 {
    00579   return true;
    00580 }
    00581
    00582 double ObjectImp::toNumber(ExecState *exec) const
    00583 {
    00584   Value prim = toPrimitive(exec,NumberType);
    00585   if (exec->hadException()) // should be picked up soon in nodes.cpp
    00586     return 0.0;
    00587   return prim.toNumber(exec);
    00588 }
    00589
    00590 int ObjectImp::toInteger(ExecState *exec) const
    00591 {
    00592   return ValueImp::toInteger(exec);
    00593 }
    00594
    00595 int ObjectImp::toInt32(ExecState *exec) const
    00596 {
    00597   return ValueImp::toInt32(exec);
    00598 }
    00599
    00600 unsigned int ObjectImp::toUInt32(ExecState *exec) const
    00601 {
    00602   return ValueImp::toUInt32(exec);
    00603 }
    00604
    00605 unsigned short ObjectImp::toUInt16(ExecState *exec) const
    00606 {
    00607   return ValueImp::toUInt16(exec);
    00608 }
    00609
    00610 UString ObjectImp::toString(ExecState *exec) const
    00611 {
    00612   Value prim = toPrimitive(exec,StringType);
    00613   if (exec->hadException()) // should be picked up soon in nodes.cpp
    00614     return "";
    00615   return prim.toString(exec);
    00616 }
    00617
    00618 Object ObjectImp::toObject(ExecState */*exec*/) const
    00619 {
    00620   return Object(const_cast<ObjectImp*>(this));
    00621 }
    00622
    00623
    00624 // ------------------------------ Error ----------------------------------------
    00625
    00626 const char * const errorNamesArr[] = {
    00627   I18N_NOOP("Error"), // GeneralError
    00628   I18N_NOOP("Evaluation error"), // EvalError
    00629   I18N_NOOP("Range error"), // RangeError
    00630   I18N_NOOP("Reference error"), // ReferenceError
    00631   I18N_NOOP("Syntax error"), // SyntaxError
    00632   I18N_NOOP("Type error"), // TypeError
    00633   I18N_NOOP("URI error"), // URIError
    00634 };
    00635
    00636 const char * const * const Error::errorNames = errorNamesArr;
    00637
    00638 Object Error::create(ExecState *exec, ErrorType errtype, const char *message,
    00639                      int lineno, int sourceId)
    00640 {
    00641 #ifdef KJS_VERBOSE
    00642   // message could be 0L. Don't enable this on Solaris ;)
    00643   fprintf(stderr, "WARNING: KJS %s: %s\n", errorNames[errtype], message);
    00644 #endif
    00645
    00646   Object cons;
    00647
    00648   switch (errtype) {
    00649   case EvalError:
    00650     cons = exec->interpreter()->builtinEvalError();
    00651     break;
    00652   case RangeError:
    00653     cons = exec->interpreter()->builtinRangeError();
    00654     break;
    00655   case ReferenceError:
    00656     cons = exec->interpreter()->builtinReferenceError();
    00657     break;
    00658   case SyntaxError:
    00659     cons = exec->interpreter()->builtinSyntaxError();
    00660     break;
    00661   case TypeError:
    00662     cons = exec->interpreter()->builtinTypeError();
    00663     break;
    00664   case URIError:
    00665     cons = exec->interpreter()->builtinURIError();
    00666     break;
    00667   default:
    00668     cons = exec->interpreter()->builtinError();
    00669     break;
    00670   }
    00671
    00672   if (!message)
    00673     message = errorNames[errtype];
    00674   List args;
    00675   args.append(String(message));
    00676   Object err = Object::dynamicCast(cons.construct(exec,args));
    00677
    00678   if (lineno != -1)
    00679     err.put(exec, "line", Number(lineno));
    00680   if (sourceId != -1)
    00681     err.put(exec, "sourceId", Number(sourceId));
    00682
    00683   return err;
    00684
    00685 /*
    00686 #ifndef NDEBUG
    00687   const char *msg = err.get("message").toString().value().ascii();
    00688   if (l >= 0)
    00689       fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
    00690   else
    00691       fprintf(stderr, "KJS: %s. %s\n", estr, msg);
    00692 #endif
    00693
    00694   return err;
    00695 */
    00696 }
    00697

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:08:33 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001