kjs Library API Documentation

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 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:21:15 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001