kjs Library: object.cpp Source File (kjs Library)

| # kjs Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | 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  *  Copyright (C) 2003 Apple Computer, Inc.
    00007  *
    00008  *  This library is free software; you can redistribute it and/or
    00009  *  modify it under the terms of the GNU Library General Public
    00010  *  License as published by the Free Software Foundation; either
    00011  *  version 2 of the License, or (at your option) any later version.
    00012  *
    00013  *  This library is distributed in the hope that it will be useful,
    00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00016  *  Library General Public License for more details.
    00017  *
    00018  *  You should have received a copy of the GNU Library General Public License
    00019  *  along with this library; see the file COPYING.LIB.  If not, write to
    00020  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00021  *  Boston, MA 02111-1307, USA.
    00022  *
    00023  */
    00024
    00025 #include "value.h"
    00026 #include "object.h"
    00027 #include "types.h"
    00028 #include "interpreter.h"
    00029 #include "lookup.h"
    00030 #include "reference_list.h"
    00031
    00032 #include <assert.h>
    00033 #include <math.h>
    00034 #include <stdio.h>
    00035
    00036 #include "internal.h"
    00037 #include "collector.h"
    00038 #include "operations.h"
    00039 #include "error_object.h"
    00040 #include "nodes.h"
    00041
    00042 using namespace KJS;
    00043
    00044 // ------------------------------ Object ---------------------------------------
    00045
    00046 Object Object::dynamicCast(const Value &v)
    00047 {
    00048   if (!v.isValid() || v.type() != ObjectType)
    00049     return Object(0);
    00050
    00051   return Object(static_cast<ObjectImp*>(v.imp()));
    00052 }
    00053
    00054 Value Object::call(ExecState *exec, Object &thisObj, const List &args)
    00055 {
    00056 #if KJS_MAX_STACK > 0
    00057   static int depth = 0; // sum of all concurrent interpreters
    00058   if (++depth > KJS_MAX_STACK) {
    00059 #ifndef NDEBUG
    00060     fprintf(stderr, "Exceeded maximum function call depth\n");
    00061 #endif
    00062     --depth;
    00063     Object err = Error::create(exec, RangeError,
    00064                                "Exceeded maximum function call depth.");
    00065     exec->setException(err);
    00066     return err;
    00067   }
    00068 #endif
    00069
    00070   Value ret = static_cast<ObjectImp*>(rep)->call(exec,thisObj,args);
    00071
    00072 #if KJS_MAX_STACK > 0
    00073   --depth;
    00074 #endif
    00075
    00076   return ret;
    00077 }
    00078
    00079 // ------------------------------ ObjectImp ------------------------------------
    00080
    00081 ObjectImp::ObjectImp(const Object &proto)
    00082   : _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L)
    00083 {
    00084   //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
    00085 }
    00086
    00087 ObjectImp::ObjectImp(ObjectImp *proto)
    00088   : _proto(proto), _internalValue(0L)
    00089 {
    00090 }
    00091
    00092 ObjectImp::ObjectImp()
    00093 {
    00094   //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);
    00095   _proto = NullImp::staticNull;
    00096   _internalValue = 0L;
    00097 }
    00098
    00099 ObjectImp::~ObjectImp()
    00100 {
    00101   //fprintf(stderr,"ObjectImp::~ObjectImp %p\n",(void*)this);
    00102 }
    00103
    00104 void ObjectImp::mark()
    00105 {
    00106   //fprintf(stderr,"ObjectImp::mark() %p\n",(void*)this);
    00107   ValueImp::mark();
    00108
    00109   if (_proto && !_proto->marked())
    00110     _proto->mark();
    00111
    00112   _prop.mark();
    00113
    00114   if (_internalValue && !_internalValue->marked())
    00115     _internalValue->mark();
    00116
    00117   _scope.mark();
    00118 }
    00119
    00120 const ClassInfo *ObjectImp::classInfo() const
    00121 {
    00122   return 0;
    00123 }
    00124
    00125 bool ObjectImp::inherits(const ClassInfo *info) const
    00126 {
    00127   if (!info)
    00128     return false;
    00129
    00130   const ClassInfo *ci = classInfo();
    00131   if (!ci)
    00132     return false;
    00133
    00134   while (ci && ci != info)
    00135     ci = ci->parentClass;
    00136
    00137   return (ci == info);
    00138 }
    00139
    00140 Type ObjectImp::type() const
    00141 {
    00142   return ObjectType;
    00143 }
    00144
    00145 Value ObjectImp::prototype() const
    00146 {
    00147   return Value(_proto);
    00148 }
    00149
    00150 void ObjectImp::setPrototype(const Value &proto)
    00151 {
    00152   _proto = proto.imp();
    00153 }
    00154
    00155 UString ObjectImp::className() const
    00156 {
    00157   const ClassInfo *ci = classInfo();
    00158   if ( ci )
    00159     return ci->className;
    00160   return "Object";
    00161 }
    00162
    00163 Value ObjectImp::get(ExecState *exec, const Identifier &propertyName) const
    00164 {
    00165   ValueImp *imp = getDirect(propertyName);
    00166   if (imp)
    00167     return Value(imp);
    00168
    00169   Object proto = Object::dynamicCast(prototype());
    00170
    00171   // non-standard netscape extension
    00172   if (propertyName == specialPrototypePropertyName) {
    00173     if (!proto.isValid())
    00174       return Null();
    00175     else
    00176       return Value(proto);
    00177   }
    00178
    00179   if (proto.isNull())
    00180     return Undefined();
    00181
    00182   return proto.get(exec,propertyName);
    00183 }
    00184
    00185 Value ObjectImp::getPropertyByIndex(ExecState *exec,
    00186                     unsigned propertyName) const
    00187 {
    00188   return get(exec, Identifier::from(propertyName));
    00189 }
    00190
    00191 // ECMA 8.6.2.2
    00192 void ObjectImp::put(ExecState *exec, const Identifier &propertyName,
    00193                      const Value &value, int attr)
    00194 {
    00195   assert(!value.isNull());
    00196
    00197   // non-standard netscape extension
    00198   if (propertyName == specialPrototypePropertyName) {
    00199     setPrototype(value);
    00200     return;
    00201   }
    00202
    00203   /* TODO: check for write permissions directly w/o this call */
    00204   /* Doesn't look very easy with the PropertyMap API - David */
    00205   // putValue() is used for JS assignemnts. It passes no attribute.
    00206   // Assume that a C++ implementation knows what it is doing
    00207   // and let it override the canPut() check.
    00208   if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) {
    00209 #ifdef KJS_VERBOSE
    00210     fprintf( stderr, "WARNING: canPut %s said NO\n", propertyName.ascii() );
    00211 #endif
    00212     return;
    00213   }
    00214
    00215   _prop.put(propertyName,value.imp(),attr);
    00216 }
    00217
    00218 // delme
    00219 void ObjectImp::putPropertyByIndex(ExecState *exec, unsigned propertyName,
    00220                      const Value &value, int attr)
    00221 {
    00222   put(exec, Identifier::from(propertyName), value, attr);
    00223 }
    00224
    00225 // ECMA 8.6.2.3
    00226 bool ObjectImp::canPut(ExecState *, const Identifier &propertyName) const
    00227 {
    00228   int attributes;
    00229   ValueImp *v = _prop.get(propertyName, attributes);
    00230   if (v)
    00231     return!(attributes & ReadOnly);
    00232
    00233   // Look in the static hashtable of properties
    00234   const HashEntry* e = findPropertyHashEntry(propertyName);
    00235   if (e)
    00236     return !(e->attr & ReadOnly);
    00237
    00238   // Don't look in the prototype here. We can always put an override
    00239   // in the object, even if the prototype has a ReadOnly property.
    00240   return true;
    00241 }
    00242
    00243 // ECMA 8.6.2.4
    00244 bool ObjectImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
    00245 {
    00246   if (_prop.get(propertyName))
    00247     return true;
    00248
    00249   // Look in the static hashtable of properties
    00250   if (findPropertyHashEntry(propertyName))
    00251       return true;
    00252
    00253   // non-standard netscape extension
    00254   if (propertyName == specialPrototypePropertyName)
    00255     return true;
    00256
    00257   // Look in the prototype
    00258   Object proto = Object::dynamicCast(prototype());
    00259   return !proto.isNull() && proto.hasProperty(exec,propertyName);
    00260 }
    00261
    00262 bool ObjectImp::hasPropertyByIndex(ExecState *exec, unsigned propertyName) const
    00263 {
    00264   return hasProperty(exec, Identifier::from(propertyName));
    00265 }
    00266
    00267 // ECMA 8.6.2.5
    00268 bool ObjectImp::deleteProperty(ExecState * /*exec*/, const Identifier &propertyName)
    00269 {
    00270   int attributes;
    00271   ValueImp *v = _prop.get(propertyName, attributes);
    00272   if (v) {
    00273     if ((attributes & DontDelete))
    00274       return false;
    00275     _prop.remove(propertyName);
    00276     return true;
    00277   }
    00278
    00279   // Look in the static hashtable of properties
    00280   const HashEntry* entry = findPropertyHashEntry(propertyName);
    00281   if (entry && entry->attr & DontDelete)
    00282     return false; // this builtin property can't be deleted
    00283   return true;
    00284 }
    00285
    00286 bool ObjectImp::deletePropertyByIndex(ExecState *exec, unsigned propertyName)
    00287 {
    00288   return deleteProperty(exec, Identifier::from(propertyName));
    00289 }
    00290
    00291 void ObjectImp::deleteAllProperties( ExecState * )
    00292 {
    00293   _prop.clear();
    00294 }
    00295
    00296 // ECMA 8.6.2.6
    00297 Value ObjectImp::defaultValue(ExecState *exec, Type hint) const
    00298 {
    00299   if (hint != StringType && hint != NumberType) {
    00300     /* Prefer String for Date objects */
    00301     if (_proto == exec->interpreter()->builtinDatePrototype().imp())
    00302       hint = StringType;
    00303     else
    00304       hint = NumberType;
    00305   }
    00306
    00307   Value v;
    00308   if (hint == StringType)
    00309     v = get(exec,toStringPropertyName);
    00310   else
    00311     v = get(exec,valueOfPropertyName);
    00312
    00313   if (v.type() == ObjectType) {
    00314     Object o = Object(static_cast<ObjectImp*>(v.imp()));
    00315     if (o.implementsCall()) { // spec says "not primitive type" but ...
    00316       Object thisObj = Object(const_cast<ObjectImp*>(this));
    00317       Value def = o.call(exec,thisObj,List::empty());
    00318       Type defType = def.type();
    00319       if (defType == UnspecifiedType || defType == UndefinedType ||
    00320           defType == NullType || defType == BooleanType ||
    00321           defType == StringType || defType == NumberType) {
    00322         return def;
    00323       }
    00324     }
    00325   }
    00326
    00327   if (hint == StringType)
    00328     v = get(exec,valueOfPropertyName);
    00329   else
    00330     v = get(exec,toStringPropertyName);
    00331
    00332   if (v.type() == ObjectType) {
    00333     Object o = Object(static_cast<ObjectImp*>(v.imp()));
    00334     if (o.implementsCall()) { // spec says "not primitive type" but ...
    00335       Object thisObj = Object(const_cast<ObjectImp*>(this));
    00336       Value def = o.call(exec,thisObj,List::empty());
    00337       Type defType = def.type();
    00338       if (defType == UnspecifiedType || defType == UndefinedType ||
    00339           defType == NullType || defType == BooleanType ||
    00340           defType == StringType || defType == NumberType) {
    00341         return def;
    00342       }
    00343     }
    00344   }
    00345
    00346   Object err = Error::create(exec, TypeError, I18N_NOOP("No default value"));
    00347   exec->setException(err);
    00348   return err;
    00349 }
    00350
    00351 const HashEntry* ObjectImp::findPropertyHashEntry( const Identifier& propertyName ) const
    00352 {
    00353   const ClassInfo *info = classInfo();
    00354   while (info) {
    00355     if (info->propHashTable) {
    00356       const HashEntry *e = Lookup::findEntry(info->propHashTable, propertyName);
    00357       if (e)
    00358         return e;
    00359     }
    00360     info = info->parentClass;
    00361   }
    00362   return 0L;
    00363 }
    00364
    00365 bool ObjectImp::implementsConstruct() const
    00366 {
    00367   return false;
    00368 }
    00369
    00370 Object ObjectImp::construct(ExecState* /*exec*/, const List &/*args*/)
    00371 {
    00372   assert(false);
    00373   return Object(0);
    00374 }
    00375
    00376 bool ObjectImp::implementsCall() const
    00377 {
    00378   return false;
    00379 }
    00380
    00381 Value ObjectImp::call(ExecState* /*exec*/, Object &/*thisObj*/, const List &/*args*/)
    00382 {
    00383   assert(false);
    00384   return Object(0);
    00385 }
    00386
    00387 bool ObjectImp::implementsHasInstance() const
    00388 {
    00389   return false;
    00390 }
    00391
    00392 Boolean ObjectImp::hasInstance(ExecState* /*exec*/, const Value &/*value*/)
    00393 {
    00394   assert(false);
    00395   return Boolean(false);
    00396 }
    00397
    00398 ReferenceList ObjectImp::propList(ExecState *exec, bool recursive)
    00399 {
    00400   ReferenceList list;
    00401   if (_proto && _proto->dispatchType() == ObjectType && recursive)
    00402     list = static_cast<ObjectImp*>(_proto)->propList(exec,recursive);
    00403
    00404   _prop.addEnumerablesToReferenceList(list, Object(this));
    00405
    00406   // Add properties from the static hashtable of properties
    00407   const ClassInfo *info = classInfo();
    00408   while (info) {
    00409     if (info->propHashTable) {
    00410       int size = info->propHashTable->size;
    00411       const HashEntry *e = info->propHashTable->entries;
    00412       for (int i = 0; i < size; ++i, ++e) {
    00413         if ( e->soffset && !(e->attr & DontEnum) )
    00414           list.append(Reference(this, &info->propHashTable->sbase[e->soffset]));
    00415       }
    00416     }
    00417     info = info->parentClass;
    00418   }
    00419
    00420   return list;
    00421 }
    00422
    00423 Value ObjectImp::internalValue() const
    00424 {
    00425   return Value(_internalValue);
    00426 }
    00427
    00428 void ObjectImp::setInternalValue(const Value &v)
    00429 {
    00430   _internalValue = v.imp();
    00431 }
    00432
    00433 void ObjectImp::setInternalValue(ValueImp *v)
    00434 {
    00435   v->setGcAllowed();
    00436   _internalValue = v;
    00437 }
    00438
    00439 Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const
    00440 {
    00441   return defaultValue(exec,preferredType);
    00442 }
    00443
    00444 bool ObjectImp::toBoolean(ExecState* /*exec*/) const
    00445 {
    00446   return true;
    00447 }
    00448
    00449 double ObjectImp::toNumber(ExecState *exec) const
    00450 {
    00451   Value prim = toPrimitive(exec,NumberType);
    00452   if (exec->hadException()) // should be picked up soon in nodes.cpp
    00453     return 0.0;
    00454   return prim.toNumber(exec);
    00455 }
    00456
    00457 UString ObjectImp::toString(ExecState *exec) const
    00458 {
    00459   Value prim = toPrimitive(exec,StringType);
    00460   if (exec->hadException()) // should be picked up soon in nodes.cpp
    00461     return "";
    00462   return prim.toString(exec);
    00463 }
    00464
    00465 Object ObjectImp::toObject(ExecState * /*exec*/) const
    00466 {
    00467   return Object(const_cast<ObjectImp*>(this));
    00468 }
    00469
    00470 void ObjectImp::putDirect(const Identifier &propertyName, ValueImp *value, int attr)
    00471 {
    00472   value->setGcAllowed();
    00473   _prop.put(propertyName, value, attr);
    00474 }
    00475
    00476 void ObjectImp::putDirect(const Identifier &propertyName, int value, int attr)
    00477 {
    00478   _prop.put(propertyName, NumberImp::create(value), attr);
    00479 }
    00480
    00481 void ObjectImp::setFunctionName(const Identifier &propertyName)
    00482 {
    00483   if (inherits(&InternalFunctionImp::info))
    00484     static_cast<InternalFunctionImp*>(this)->setName(propertyName);
    00485 }
    00486
    00487 // ------------------------------ Error ----------------------------------------
    00488
    00489 const char * const errorNamesArr[] = {
    00490   I18N_NOOP("Error"), // GeneralError
    00491   I18N_NOOP("Evaluation error"), // EvalError
    00492   I18N_NOOP("Range error"), // RangeError
    00493   I18N_NOOP("Reference error"), // ReferenceError
    00494   I18N_NOOP("Syntax error"), // SyntaxError
    00495   I18N_NOOP("Type error"), // TypeError
    00496   I18N_NOOP("URI error"), // URIError
    00497 };
    00498
    00499 const char * const * const Error::errorNames = errorNamesArr;
    00500
    00501 Object Error::create(ExecState *exec, ErrorType errtype, const char *message,
    00502                      int lineno, int sourceId)
    00503 {
    00504 #ifdef KJS_VERBOSE
    00505   // message could be 0L. Don't enable this on Solaris ;)
    00506   fprintf(stderr, "WARNING: KJS %s: %s\n", errorNames[errtype], message);
    00507 #endif
    00508
    00509   Object cons;
    00510
    00511   switch (errtype) {
    00512   case EvalError:
    00513     cons = exec->interpreter()->builtinEvalError();
    00514     break;
    00515   case RangeError:
    00516     cons = exec->interpreter()->builtinRangeError();
    00517     break;
    00518   case ReferenceError:
    00519     cons = exec->interpreter()->builtinReferenceError();
    00520     break;
    00521   case SyntaxError:
    00522     cons = exec->interpreter()->builtinSyntaxError();
    00523     break;
    00524   case TypeError:
    00525     cons = exec->interpreter()->builtinTypeError();
    00526     break;
    00527   case URIError:
    00528     cons = exec->interpreter()->builtinURIError();
    00529     break;
    00530   default:
    00531     cons = exec->interpreter()->builtinError();
    00532     break;
    00533   }
    00534
    00535   if (!message)
    00536     message = errorNames[errtype];
    00537   List args;
    00538   args.append(String(message));
    00539   Object err = Object::dynamicCast(cons.construct(exec,args));
    00540
    00541   if (lineno != -1)
    00542     err.put(exec, "line", Number(lineno));
    00543   if (sourceId != -1)
    00544     err.put(exec, "sourceId", Number(sourceId));
    00545
    00546   return err;
    00547
    00548 /*
    00549 #ifndef NDEBUG
    00550   const char *msg = err.get(messagePropertyName).toString().value().ascii();
    00551   if (l >= 0)
    00552       fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
    00553   else
    00554       fprintf(stderr, "KJS: %s. %s\n", estr, msg);
    00555 #endif
    00556
    00557   return err;
    00558 */
    00559 }
    00560

This file is part of the documentation for kjs Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:23:07 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003