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 * 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
KDE Logo
This file is part of the documentation for kjs Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:43:40 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003