📄 object.cpp
字号:
// -*- c-basic-offset: 2 -*-/* * This file is part of the KDE libraries * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2003 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * */#include "value.h"#include "object.h"#include "types.h"#include "interpreter.h"#include "lookup.h"#include "reference_list.h"#include <assert.h>#include <math.h>#include <stdio.h>#include "internal.h"#include "collector.h"#include "operations.h"#include "error_object.h"#include "nodes.h"namespace KJS {// ------------------------------ Object ---------------------------------------Object Object::dynamicCast(const Value &v){ if (v.isNull() || v.type() != ObjectType) return Object(0); return Object(static_cast<ObjectImp*>(v.imp()));}Value Object::call(ExecState *exec, Object &thisObj, const List &args){ #if KJS_MAX_STACK > 0 static int depth = 0; // sum of all concurrent interpreters if (++depth > KJS_MAX_STACK) { --depth; Object err = Error::create(exec, RangeError, "Maximum call stack size exceeded."); exec->setException(err); return err; }#endif Value ret = imp()->call(exec,thisObj,args); #if KJS_MAX_STACK > 0 --depth;#endif return ret;}// ------------------------------ ObjectImp ------------------------------------ObjectImp::ObjectImp(const Object &proto) : _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L){ //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);}ObjectImp::ObjectImp(ObjectImp *proto) : _proto(proto), _internalValue(0L){ //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this);}ObjectImp::ObjectImp(){ //fprintf(stderr,"ObjectImp::ObjectImp %p\n",(void*)this); _proto = NullImp::staticNull; _internalValue = 0L;}ObjectImp::~ObjectImp(){ //fprintf(stderr,"ObjectImp::~ObjectImp %p\n",(void*)this);}void ObjectImp::mark(){ //fprintf(stderr,"ObjectImp::mark() %p\n",(void*)this); ValueImp::mark(); if (_proto && !_proto->marked()) _proto->mark(); _prop.mark(); if (_internalValue && !_internalValue->marked()) _internalValue->mark(); _scope.mark();}const ClassInfo *ObjectImp::classInfo() const{ return 0;}bool ObjectImp::inherits(const ClassInfo *info) const{ if (!info) return false; const ClassInfo *ci = classInfo(); if (!ci) return false; while (ci && ci != info) ci = ci->parentClass; return (ci == info);}Type ObjectImp::type() const{ return ObjectType;}Value ObjectImp::prototype() const{ return Value(_proto);}void ObjectImp::setPrototype(const Value &proto){ _proto = proto.imp();}UString ObjectImp::className() const{ const ClassInfo *ci = classInfo(); if ( ci ) return ci->className; return "Object";}Value ObjectImp::get(ExecState *exec, const Identifier &propertyName) const{ ValueImp *imp = getDirect(propertyName); if (imp) return Value(imp); // non-standard netscape extension if (propertyName == specialPrototypePropertyName) return Value(_proto); if (_proto->dispatchType() != ObjectType) { return Undefined(); } return static_cast<ObjectImp *>(_proto)->get(exec, propertyName);}Value ObjectImp::get(ExecState *exec, unsigned propertyName) const{ return get(exec, Identifier::from(propertyName));}// ECMA 8.6.2.2void ObjectImp::put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr){ assert(!value.isNull()); // non-standard netscape extension if (propertyName == specialPrototypePropertyName) { setPrototype(value); return; } /* TODO: check for write permissions directly w/o this call */ /* Doesn't look very easy with the PropertyMap API - David */ // 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 || attr == DontDelete) && !canPut(exec,propertyName)) {#ifdef KJS_VERBOSE fprintf( stderr, "WARNING: canPut %s said NO\n", propertyName.ascii() );#endif return; } _prop.put(propertyName,value.imp(),attr);}void ObjectImp::put(ExecState *exec, unsigned propertyName, const Value &value, int attr){ put(exec, Identifier::from(propertyName), value, attr);}// ECMA 8.6.2.3bool ObjectImp::canPut(ExecState *, const Identifier &propertyName) const{ int attributes; ValueImp *v = _prop.get(propertyName, attributes); if (v) return!(attributes & ReadOnly); // Look in the static hashtable of properties const HashEntry* e = findPropertyHashEntry(propertyName); if (e) return !(e->attr & ReadOnly); // Don't look in the prototype here. We can always put an override // in the object, even if the prototype has a ReadOnly property. return true;}// ECMA 8.6.2.4bool ObjectImp::hasProperty(ExecState *exec, const Identifier &propertyName) const{ if (_prop.get(propertyName)) return true; // Look in the static hashtable of properties if (findPropertyHashEntry(propertyName)) return true; // non-standard netscape extension if (propertyName == specialPrototypePropertyName) return true; if (_proto->dispatchType() != ObjectType) { return false; } // Look in the prototype return static_cast<ObjectImp *>(_proto)->hasProperty(exec, propertyName);}bool ObjectImp::hasProperty(ExecState *exec, unsigned propertyName) const{ return hasProperty(exec, Identifier::from(propertyName));}// ECMA 8.6.2.5bool ObjectImp::deleteProperty(ExecState */*exec*/, const Identifier &propertyName){ int attributes; ValueImp *v = _prop.get(propertyName, attributes); if (v) { if ((attributes & DontDelete)) return false; _prop.remove(propertyName); return true; } // Look in the static hashtable of properties const HashEntry* entry = findPropertyHashEntry(propertyName); if (entry && entry->attr & DontDelete) return false; // this builtin property can't be deleted return true;}bool ObjectImp::deleteProperty(ExecState *exec, unsigned propertyName){ return deleteProperty(exec, Identifier::from(propertyName));}void ObjectImp::deleteAllProperties( ExecState * ){ _prop.clear();}// ECMA 8.6.2.6Value ObjectImp::defaultValue(ExecState *exec, Type hint) const{ if (hint != StringType && hint != NumberType) { /* Prefer String for Date objects */ if (_proto == exec->lexicalInterpreter()->builtinDatePrototype().imp()) hint = StringType; else hint = NumberType; } Value v; if (hint == StringType) v = get(exec,toStringPropertyName); else v = get(exec,valueOfPropertyName); if (v.type() == ObjectType) { Object o = Object(static_cast<ObjectImp*>(v.imp())); if (o.implementsCall()) { // spec says "not primitive type" but ... Object thisObj = Object(const_cast<ObjectImp*>(this)); Value def = o.call(exec,thisObj,List::empty()); Type defType = def.type(); if (defType == UnspecifiedType || defType == UndefinedType || defType == NullType || defType == BooleanType || defType == StringType || defType == NumberType) { return def; } } } if (hint == StringType) v = get(exec,valueOfPropertyName); else v = get(exec,toStringPropertyName); if (v.type() == ObjectType) { Object o = Object(static_cast<ObjectImp*>(v.imp())); if (o.implementsCall()) { // spec says "not primitive type" but ... Object thisObj = Object(const_cast<ObjectImp*>(this)); Value def = o.call(exec,thisObj,List::empty()); Type defType = def.type(); if (defType == UnspecifiedType || defType == UndefinedType || defType == NullType || defType == BooleanType || defType == StringType || defType == NumberType) { return def; } } } Object err = Error::create(exec, TypeError, I18N_NOOP("No default value")); exec->setException(err); return err;}const HashEntry* ObjectImp::findPropertyHashEntry( const Identifier& propertyName ) const{ const ClassInfo *info = classInfo(); while (info) { if (info->propHashTable) { const HashEntry *e = Lookup::findEntry(info->propHashTable, propertyName); if (e) return e; } info = info->parentClass; } return 0L;}bool ObjectImp::implementsConstruct() const{ return false;}Object ObjectImp::construct(ExecState */*exec*/, const List &/*args*/){ assert(false); return Object(0);}bool ObjectImp::implementsCall() const{ return false;}Value ObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/){ assert(false); return Object(0);}bool ObjectImp::implementsHasInstance() const{ return false;}Boolean ObjectImp::hasInstance(ExecState */*exec*/, const Value &/*value*/){ assert(false); return Boolean(false);}ReferenceList ObjectImp::propList(ExecState *exec, bool recursive){ ReferenceList list; if (_proto && _proto->dispatchType() == ObjectType && recursive) list = static_cast<ObjectImp*>(_proto)->propList(exec,recursive); _prop.addEnumerablesToReferenceList(list, Object(this)); // Add properties from the static hashtable of properties const ClassInfo *info = classInfo(); while (info) { if (info->propHashTable) { int size = info->propHashTable->size; const HashEntry *e = info->propHashTable->entries; for (int i = 0; i < size; ++i, ++e) { if ( e->s && !(e->attr & DontEnum) ) list.append(Reference(this, e->s)); /// ######### check for duplicates with the propertymap } } info = info->parentClass; } return list;}Value ObjectImp::internalValue() const{ return Value(_internalValue);}void ObjectImp::setInternalValue(const Value &v){ _internalValue = v.imp();}void ObjectImp::setInternalValue(ValueImp *v){ v->setGcAllowed(); _internalValue = v;}Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const{ return defaultValue(exec,preferredType);}bool ObjectImp::toBoolean(ExecState */*exec*/) const{ return true;}double ObjectImp::toNumber(ExecState *exec) const{ Value prim = toPrimitive(exec,NumberType); if (exec->hadException()) // should be picked up soon in nodes.cpp return 0.0; return prim.toNumber(exec);}UString ObjectImp::toString(ExecState *exec) const{ Value prim = toPrimitive(exec,StringType); if (exec->hadException()) // should be picked up soon in nodes.cpp return ""; return prim.toString(exec);}Object ObjectImp::toObject(ExecState */*exec*/) const{ return Object(const_cast<ObjectImp*>(this));}void ObjectImp::putDirect(const Identifier &propertyName, ValueImp *value, int attr){ value->setGcAllowed(); _prop.put(propertyName, value, attr);}void ObjectImp::putDirect(const Identifier &propertyName, int value, int attr){ _prop.put(propertyName, NumberImp::create(value), attr);}// ------------------------------ Error ----------------------------------------const char * const errorNamesArr[] = { I18N_NOOP("Error"), // GeneralError I18N_NOOP("Evaluation error"), // EvalError I18N_NOOP("Range error"), // RangeError I18N_NOOP("Reference error"), // ReferenceError I18N_NOOP("Syntax error"), // SyntaxError I18N_NOOP("Type error"), // TypeError I18N_NOOP("URI error"), // URIError};const char * const * const Error::errorNames = errorNamesArr;Object Error::create(ExecState *exec, ErrorType errtype, const char *message, int lineno, int sourceId, const UString *sourceURL){ Object cons; switch (errtype) { case EvalError: cons = exec->lexicalInterpreter()->builtinEvalError(); break; case RangeError: cons = exec->lexicalInterpreter()->builtinRangeError(); break; case ReferenceError: cons = exec->lexicalInterpreter()->builtinReferenceError(); break; case SyntaxError: cons = exec->lexicalInterpreter()->builtinSyntaxError(); break; case TypeError: cons = exec->lexicalInterpreter()->builtinTypeError(); break; case URIError: cons = exec->lexicalInterpreter()->builtinURIError(); break; default: cons = exec->lexicalInterpreter()->builtinError(); break; } if (!message) message = errorNames[errtype]; List args; args.append(String(message)); Object err = Object::dynamicCast(cons.construct(exec,args)); if (lineno != -1) err.put(exec, "line", Number(lineno)); if (sourceId != -1) err.put(exec, "sourceId", Number(sourceId)); if(sourceURL) err.put(exec,"sourceURL", String(*sourceURL)); return err;/*#ifndef NDEBUG const char *msg = err.get("message").toString().value().ascii(); if (l >= 0) fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg); else fprintf(stderr, "KJS: %s. %s\n", estr, msg);#endif return err;*/}} // namespace KJS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -