📄 object.cpp
字号:
obj.setPrototype(prot); return obj;}Object Object::create(Class c, const KJSO& val, const Object& p){ Global global(Global::current()); Object obj = Object(); Object prot; obj.setClass(c); obj.setInternalValue(val); prot = p; obj.setPrototype(prot); return obj;}Object Object::dynamicCast(const KJSO &obj){ // return null object on type mismatch if (!obj.isA(ObjectType)) return Object(0L); return Object(obj.imp());}#ifdef KJS_DEBUG_MEMint KJSO::count = 0;int Imp::count = 0;int List::count = 0;#endifImp::Imp() : refcount(0), prop(0), proto(0){ setCreated(true);#ifdef KJS_DEBUG_MEM count++;#endif}Imp::~Imp(){#ifdef KJS_DEBUG_MEM assert(Collector::collecting); count--;#endif// dangling pointer during garbage collection !// if (proto)// proto->deref(); // delete attached properties Property *tmp, *p = prop; while (p) { tmp = p; p = p->next; delete tmp; }}KJSO Imp::toPrimitive(Type preferred) const{ return defaultValue(preferred); /* TODO: is there still any need to throw a runtime error _here_ ? */}Boolean Imp::toBoolean() const{ return Boolean();}Number Imp::toNumber() const{ return Number();}String Imp::toString() const{ return String();}Object Imp::toObject() const{ return Object(Error::create(TypeError).imp());}PropList* Imp::propList(PropList *first, PropList *last, bool recursive) const{ Property *pr = prop; while(pr) { if (!(pr->attribute & DontEnum) && !first->contains(pr->name)) { if(last) { last->next = new PropList(); last = last->next; } else { first = new PropList(); last = first; } last->name = pr->name; } pr = pr->next; } if (proto && recursive) proto->propList(first, last); return first;}KJSO Imp::get(const UString &p) const{ Property *pr = prop; while (pr) { if (pr->name == p) { return pr->object; } pr = pr->next; } if (!proto) return Undefined(); return proto->get(p);}// may be overridenvoid Imp::put(const UString &p, const KJSO& v){ put(p, v, None);}// ECMA 8.6.2.2void Imp::put(const UString &p, const KJSO& v, int attr){ /* TODO: check for write permissions directly w/o this call */ // putValue() is used for JS assignemnts. It passes no attribute. // Assume that a C++ implementation knows what it is doing // and let it override the canPut() check. if (attr == None && !canPut(p)) return; Property *pr; if (prop) { pr = prop; while (pr) { if (pr->name == p) { // replace old value pr->object = v.imp(); pr->attribute = attr; return; } pr = pr->next; } } // add new property pr = new Property; pr->name = p; pr->object = v.imp(); pr->attribute = attr; pr->next = prop; prop = pr;}// ECMA 8.6.2.3bool Imp::canPut(const UString &p) const{ if (prop) { const Property *pr = prop; while (pr) { if (pr->name == p) return !(pr->attribute & ReadOnly); pr = pr->next; } } if (!proto) return true; return proto->canPut(p);}// ECMA 8.6.2.4bool Imp::hasProperty(const UString &p, bool recursive) const{ const Property *pr = prop; while (pr) { if (pr->name == p) return true; pr = pr->next; } if (!proto || !recursive) return false; return proto->hasProperty(p);}// ECMA 8.6.2.5bool Imp::deleteProperty(const UString &p){ Property *pr = prop; Property **prev = ∝ while (pr) { if (pr->name == p) { if ((pr->attribute & DontDelete)) return false; *prev = pr->next; delete pr; return true; } prev = &(pr->next); pr = pr->next; } return true;}// ECMA 15.4.5.1void Imp::putArrayElement(const UString &p, const KJSO& v){ if (!canPut(p)) return; if (hasProperty(p)) { if (p == "length") { KJSO len = get("length"); unsigned int oldLen = len.toUInt32(); unsigned int newLen = v.toUInt32(); // shrink array for (unsigned int u = newLen; u < oldLen; u++) { UString p = UString::from(u); if (hasProperty(p, false)) deleteProperty(p); } put("length", Number(newLen), DontEnum | DontDelete); return; } // put(p, v); } // } else put(p, v); // array index ? unsigned int idx; if (!sscanf(p.cstring().c_str(), "%u", &idx)) /* TODO */ return; // do we need to update/create the length property ? if (hasProperty("length", false)) { KJSO len = get("length"); if (idx < len.toUInt32()) return; } put("length", Number(idx+1), DontDelete | DontEnum);}bool Imp::implementsCall() const{ return (type() == FunctionType || type() == InternalFunctionType || type() == ConstructorType || type() == DeclaredFunctionType || type() == AnonymousFunctionType);}// ECMA 8.6.2.6 (new draft)KJSO Imp::defaultValue(Type hint) const{ KJSO o; /* TODO String on Date object */ if (hint != StringType && hint != NumberType) hint = NumberType; if (hint == StringType) o = get("toString"); else o = get("valueOf"); Imp *that = const_cast<Imp*>(this); if (o.implementsCall()) { // spec says "not primitive type" but ... FunctionImp *f = static_cast<FunctionImp*>(o.imp()); KJSO s = f->executeCall(that, 0L); if (!s.isObject()) return s; } if (hint == StringType) o = get("valueOf"); else o = get("toString"); if (o.implementsCall()) { FunctionImp *f = static_cast<FunctionImp*>(o.imp()); KJSO s = f->executeCall(that, 0L); if (!s.isObject()) return s; } return Error::create(TypeError, I18N_NOOP("No default value"));}void Imp::mark(Imp*){ setMarked(true); if (proto && !proto->marked()) proto->mark(); struct Property *p = prop; while (p) { if (p->object && !p->object->marked()) p->object->mark(); p = p->next; }}bool Imp::marked() const{ return prev;}void Imp::setPrototype(const KJSO& p){ if (proto) proto->deref(); proto = p.imp(); if (proto) proto->ref();}void Imp::setPrototypeProperty(const KJSO &p){ put("prototype", p, DontEnum | DontDelete | ReadOnly);}void Imp::setConstructor(const KJSO& c){ put("constructor", c, DontEnum | DontDelete | ReadOnly);}void* Imp::operator new(size_t s){ return Collector::allocate(s);}void Imp::operator delete(void*, size_t){ // deprecated. a mistake.}void Imp::operator delete(void*){ // Do nothing. So far.}void Imp::setMarked(bool m){ prev = m ? this : 0L;}void Imp::setGcAllowed(bool a){ next = this; if (a) next++;}bool Imp::gcAllowed() const{ return (next && next != this);}void Imp::setCreated(bool c){ next = c ? this : 0L;}bool Imp::created() const{ return next;}ObjectImp::ObjectImp(Class c) : cl(c), val(0L) { }ObjectImp::ObjectImp(Class c, const KJSO &v) : cl(c), val(v.imp()) { }ObjectImp::ObjectImp(Class c, const KJSO &v, const KJSO &p) : cl(c), val(v.imp()){ setPrototype(p);}ObjectImp::~ObjectImp() { }Boolean ObjectImp::toBoolean() const{ return Boolean(true);}Number ObjectImp::toNumber() const{ return toPrimitive(NumberType).toNumber();}String ObjectImp::toString() const{ KJSO tmp; String res; if (hasProperty("toString") && (tmp = get("toString")).implementsCall()) { // TODO live w/o hack res = tmp.executeCall(KJSO(const_cast<ObjectImp*>(this)), 0L).toString(); } else { tmp = toPrimitive(StringType); res = tmp.toString(); } return res;}const TypeInfo ObjectImp::info = { "Object", ObjectType, 0, 0, 0 };Object ObjectImp::toObject() const{ return Object(const_cast<ObjectImp*>(this));}KJSO ObjectImp::toPrimitive(Type preferred) const{ // ### Imp already does that now. Remove in KDE 3.0. return defaultValue(preferred); /* TODO: is there still any need to throw a runtime error _here_ ? */}void ObjectImp::mark(Imp*){ // mark objects from the base Imp::mark(); // mark internal value, if any and it has not been visited yet if (val && !val->marked()) val->mark();}HostImp::HostImp(){ setPrototype(Global::current().objectPrototype()); //printf("HostImp::HostImp() %p\n",this);}HostImp::~HostImp() { }Boolean HostImp::toBoolean() const{ return Boolean(true);}String HostImp::toString() const{ // Exact copy of ObjectImp::toString.... KJSO tmp; String res; if (hasProperty("toString") && (tmp = get("toString")).implementsCall()) { // TODO live w/o hack res = tmp.executeCall(KJSO(const_cast<HostImp*>(this)), 0L).toString(); } else { tmp = toPrimitive(StringType); res = tmp.toString(); } return res;}const TypeInfo HostImp::info = { "HostObject", HostType, 0, 0, 0 };Object Error::createObject(ErrorType e, const char *m, int l){ Context *context = Context::current(); if (!context) return Object(); Object err = ErrorObject::create(e, m, l); if (!KJScriptImp::hadException()) KJScriptImp::setException(err.imp()); const struct ErrorStruct { ErrorType e; const char *s; } errtab[] = { { GeneralError, I18N_NOOP("General error") }, { EvalError, I18N_NOOP("Evaluation error") }, { RangeError, I18N_NOOP("Range error") }, { ReferenceError, I18N_NOOP("Reference error") }, { SyntaxError, I18N_NOOP("Syntax error") }, { TypeError, I18N_NOOP("Type error") }, { URIError, I18N_NOOP("URI error") }, { (ErrorType)0, 0 } }; const char *estr = I18N_NOOP("Unknown error"); const ErrorStruct *estruct = errtab; while (estruct->e) { if (estruct->e == e) { estr = estruct->s; break; } estruct++; }#ifndef NDEBUG const char *msg = err.get("message").toString().value().ascii(); if (l >= 0) fprintf(stderr, "JS: %s at line %d. %s\n", estr, l, msg); else fprintf(stderr, "JS: %s. %s\n", estr, msg);#endif return err;}KJSO Error::create(ErrorType e, const char *m, int l){ return KJSO(createObject(e, m, l).imp());}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -