00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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;
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
00200
00201 ObjectImp::ObjectImp(const Object &proto)
00202 : _prop(0), _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L), _scope(0)
00203 {
00204
00205 _scope = ListImp::empty();
00206 _prop = new PropertyMap();
00207 }
00208
00209 ObjectImp::ObjectImp()
00210 {
00211
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
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
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
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
00318
00319
00320
00321 ValueImp* ObjectImp::getDirect(const UString& propertyName) const
00322 {
00323 return _prop->get(propertyName);
00324 }
00325
00326
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
00336
00337
00338
00339
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
00349 setPrototype(value);
00350 return;
00351 }
00352
00353 _prop->put(propertyName,value.imp(),attr);
00354 }
00355
00356
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
00364 const HashEntry* e = findPropertyHashEntry(propertyName);
00365 if (e)
00366 return !(e->attr & ReadOnly);
00367
00368
00369
00370 return true;
00371 }
00372
00373
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
00382 if (findPropertyHashEntry(propertyName))
00383 return true;
00384
00385
00386 Object proto = Object::dynamicCast(prototype());
00387 return !proto.isNull() && proto.hasProperty(exec,propertyName);
00388 }
00389
00390
00391 bool ObjectImp::deleteProperty(ExecState *, 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
00402 const HashEntry* entry = findPropertyHashEntry(propertyName);
00403 if (entry && entry->attr & DontDelete)
00404 return false;
00405 return true;
00406 }
00407
00408 void ObjectImp::deleteAllProperties( ExecState * )
00409 {
00410 _prop->clear();
00411 }
00412
00413
00414 Value ObjectImp::defaultValue(ExecState *exec, Type hint) const
00415 {
00416 if (hint != StringType && hint != NumberType) {
00417
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()) {
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()) {
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 *, const List &)
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 *, Object &, const List &)
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 *, const 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
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
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
00570
00571
00572 Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const
00573 {
00574 return defaultValue(exec,preferredType);
00575 }
00576
00577 bool ObjectImp::toBoolean(ExecState *) 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())
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())
00614 return "";
00615 return prim.toString(exec);
00616 }
00617
00618 Object ObjectImp::toObject(ExecState *) const
00619 {
00620 return Object(const_cast<ObjectImp*>(this));
00621 }
00622
00623
00624
00625
00626 const char * const errorNamesArr[] = {
00627 I18N_NOOP("Error"),
00628 I18N_NOOP("Evaluation error"),
00629 I18N_NOOP("Range error"),
00630 I18N_NOOP("Reference error"),
00631 I18N_NOOP("Syntax error"),
00632 I18N_NOOP("Type error"),
00633 I18N_NOOP("URI error"),
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
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
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696 }
00697