diff options
Diffstat (limited to 'kjs/object.h')
-rw-r--r-- | kjs/object.h | 726 |
1 files changed, 726 insertions, 0 deletions
diff --git a/kjs/object.h b/kjs/object.h new file mode 100644 index 000000000..ca795460c --- /dev/null +++ b/kjs/object.h @@ -0,0 +1,726 @@ +// -*- 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + + +#ifndef _KJS_OBJECT_H_ +#define _KJS_OBJECT_H_ + +// Objects + +#include "value.h" +#include "types.h" +#include "reference_list.h" +#include "identifier.h" +#include "property_map.h" +#include "scope_chain.h" + +namespace KJS { + + class ObjectImpPrivate; + class PropertyMap; + class HashTable; + struct HashEntry; + class ListImp; + + /** Attributes (only applicable to the Object type). + * See ECMA 262-3 8.6.1 + */ + enum Attribute { None = 0, + ReadOnly = 1 << 1, ///< property can be only read, not written + DontEnum = 1 << 2, ///< property doesn't appear in (for .. in ..) + DontDelete = 1 << 3, ///< property can't be deleted + Internal = 1 << 4, ///< an internal property, set to by pass checks + Function = 1 << 5 }; ///< property is a function - only used by static hashtables + + /** + * Class Information + */ + struct ClassInfo { + /** + * A string denoting the class name. Example: "Window". + */ + const char* className; + /** + * Pointer to the class information of the base class. + * 0L if there is none. + */ + const ClassInfo *parentClass; + /** + * Static hash-table of properties. + */ + const HashTable *propHashTable; + /** + * Reserved for future extension. + */ + void *dummy; + }; + + /** + * Represents an Object. This is a wrapper for ObjectImp + */ + class KJS_EXPORT Object : public Value { + public: + Object() { } + explicit Object(ObjectImp *v); + + ObjectImp *imp() const; + + const ClassInfo *classInfo() const; + bool inherits(const ClassInfo *cinfo) const; + + /** + * Converts a Value into an Object. If the value's type is not ObjectType, + * a null object will be returned (i.e. one with it's internal pointer set + * to 0). If you do not know for sure whether the value is of type + * ObjectType, you should check the isValid() methods afterwards before + * calling any methods on the Object. + * + * @return The value converted to an object + */ + static Object dynamicCast(const Value &v); + + /** + * Returns the prototype of this object. Note that this is not the same as + * the "prototype" property. + * + * See ECMA 8.6.2 + * + * @return The object's prototype + */ + Value prototype() const; + + /** + * Returns the class name of the object + * + * See ECMA 8.6.2 + * + * @return The object's class name + */ + UString className() const; + + /** + * Retrieves the specified property from the object. If neither the object + * or any other object in it's prototype chain have the property, this + * function will return Undefined. + * + * See ECMA 8.6.2.1 + * + * @param exec The current execution state + * @param propertyName The name of the property to retrieve + * + * @return The specified property, or Undefined + */ + Value get(ExecState *exec, const Identifier &propertyName) const; + Value get(ExecState *exec, unsigned propertyName) const; + + /** + * Sets the specified property. + * + * See ECMA 8.6.2.2 + * + * @param exec The current execution state + * @param propertyName The name of the property to set + * @param value The value to set + * @param attr The Attribute value for the property + */ + void put(ExecState *exec, const Identifier &propertyName, + const Value &value, int attr = None); + void put(ExecState *exec, unsigned propertyName, + const Value &value, int attr = None); + + /** + * Used to check whether or not a particular property is allowed to be set + * on an object + * + * See ECMA 8.6.2.3 + * + * @param exec The current execution state + * @param propertyName The name of the property + * @return true if the property can be set, otherwise false + */ + bool canPut(ExecState *exec, const Identifier &propertyName) const; + + /** + * Checks to see whether the object (or any object in it's prototype chain) + * has a property with the specified name. + * + * See ECMA 8.6.2.4 + * + * @param exec The current execution state + * @param propertyName The name of the property to check for + * @return true if the object has the property, otherwise false + */ + bool hasProperty(ExecState *exec, const Identifier &propertyName) const; + bool hasProperty(ExecState *exec, unsigned propertyName) const; + + /** + * Removes the specified property from the object. + * + * See ECMA 8.6.2.5 + * + * @param exec The current execution state + * @param propertyName The name of the property to delete + * @return true if the property was successfully deleted or did not + * exist on the object. false if deleting the specified property is not + * allowed. + */ + bool deleteProperty(ExecState *exec, const Identifier &propertyName); + bool deleteProperty(ExecState *exec, unsigned propertyName); + + /** + * Converts the object into a primitive value. The value return may differ + * depending on the supplied hint + * + * See ECMA 8.6.2.6 + * + * @param exec The current execution state + * @param hint The desired primitive type to convert to + * @return A primitive value converted from the objetc. Note that the + * type of primitive value returned may not be the same as the requested + * hint. + */ + Value defaultValue(ExecState *exec, Type hint) const; + + /** + * Whether or not the object implements the construct() method. If this + * returns false you should not call the construct() method on this + * object (typically, an assertion will fail to indicate this). + * + * @return true if this object implements the construct() method, otherwise + * false + */ + bool implementsConstruct() const; + + /** + * Creates a new object based on this object. Typically this means the + * following: + * 1. A new object is created + * 2. The prototype of the new object is set to the value of this object's + * "prototype" property + * 3. The call() method of this object is called, with the new object + * passed as the this value + * 4. The new object is returned + * + * In some cases, Host objects may differ from these semantics, although + * this is discouraged. + * + * If an error occurs during construction, the execution state's exception + * will be set. This can be tested for with ExecState::hadException(). + * Under some circumstances, the exception object may also be returned. + * + * Note: This function should not be called if implementsConstruct() returns + * false, in which case it will result in an assertion failure. + * + * @param exec The current execution state + * @param args The arguments to be passed to call() once the new object has + * been created + * @return The newly created & initialized object + */ + Object construct(ExecState *exec, const List &args); + + /** + * Whether or not the object implements the call() method. If this returns + * false you should not call the call() method on this object (typically, + * an assertion will fail to indicate this). + * + * @return true if this object implements the call() method, otherwise + * false + */ + bool implementsCall() const; + + + /** + * Calls this object as if it is a function. + * + * Note: This function should not be called if implementsCall() returns + * false, in which case it will result in an assertion failure. + * + * See ECMA 8.6.2.3 + * + * @param exec The current execution state + * @param thisObj The obj to be used as "this" within function execution. + * Note that in most cases this will be different from the C++ "this" + * object. For example, if the ECMAScript code "window.location.toString()" + * is executed, call() will be invoked on the C++ object which implements + * the toString method, with the thisObj being window.location + * @param args List of arguments to be passed to the function + * @return The return value from the function + */ + Value call(ExecState *exec, Object &thisObj, const List &args); + + /** + * Whether or not the object implements the hasInstance() method. If this + * returns false you should not call the hasInstance() method on this + * object (typically, an assertion will fail to indicate this). + * + * @return true if this object implements the hasInstance() method, + * otherwise false + */ + bool implementsHasInstance() const; + + /** + * Checks whether value delegates behavior to this object. Used by the + * instanceof operator. + * + * @param exec The current execution state + * @param value The value to check + * @return true if value delegates behavior to this object, otherwise + * false + */ + Boolean hasInstance(ExecState *exec, const Value &value); + + /** + * Returns the scope of this object. This is used when execution declared + * functions - the execution context for the function is initialized with + * extra object in it's scope. An example of this is functions declared + * inside other functions: + * + * \code + * function f() { + * + * function b() { + * return prototype; + * } + * + * var x = 4; + * // do some stuff + * } + * f.prototype = new String(); + * \endcode + * + * When the function f.b is executed, its scope will include properties of + * f. So in the example above the return value of f.b() would be the new + * String object that was assigned to f.prototype. + * + * @return The function's scope + */ + const ScopeChain &scope() const; + void setScope(const ScopeChain &s); + + /** + * Returns a List of References to all the properties of the object. Used + * in "for x in y" statements. The list is created new, so it can be freely + * modified without affecting the object's properties. It should be deleted + * by the caller. + * + * Subclasses can override this method in ObjectImpl to provide the + * appearance of + * having extra properties other than those set specifically with put(). + * + * @param exec The current execution state + * @param recursive Whether or not properties in the object's prototype + * chain should be + * included in the list. + * @return A List of References to properties of the object. + **/ + ReferenceList propList(ExecState *exec, bool recursive = true); + + /** + * Returns the internal value of the object. This is used for objects such + * as String and Boolean which are wrappers for native types. The interal + * value is the actual value represented by the wrapper objects. + * + * @see ECMA 8.6.2 + * @return The internal value of the object + */ + Value internalValue() const; + + /** + * Sets the internal value of the object + * + * @see internalValue() + * + * @param v The new internal value + */ + void setInternalValue(const Value &v); + }; + + inline Object Value::toObject(ExecState *exec) const { return rep->dispatchToObject(exec); } + + class KJS_EXPORT ObjectImp : public ValueImp { + friend class ObjectProtoFuncImp; + public: + /** + * Creates a new ObjectImp with the specified prototype + * + * @param proto The prototype + */ + ObjectImp(const Object &proto); + ObjectImp(ObjectImp *proto); + + /** + * Creates a new ObjectImp with a prototype of Null() + * (that is, the ECMAScript "null" value, not a null Object). + * + */ + ObjectImp(); + + virtual ~ObjectImp(); + + virtual void mark(); + + Type type() const; + + /** + * A pointer to a ClassInfo struct for this class. This provides a basic + * facility for run-time type information, and can be used to check an + * object's class an inheritance (see inherits()). This should + * always return a statically declared pointer, or 0 to indicate that + * there is no class information. + * + * This is primarily useful if you have application-defined classes that you + * wish to check against for casting purposes. + * + * For example, to specify the class info for classes FooImp and BarImp, + * where FooImp inherits from BarImp, you would add the following in your + * class declarations: + * + * \code + * class BarImp : public ObjectImp { + * virtual const ClassInfo *classInfo() const { return &info; } + * static const ClassInfo info; + * // ... + * }; + * + * class FooImp : public ObjectImp { + * virtual const ClassInfo *classInfo() const { return &info; } + * static const ClassInfo info; + * // ... + * }; + * \endcode + * + * And in your source file: + * + * \code + * const ClassInfo BarImp::info = {0, 0, 0}; // no parent class + * const ClassInfo FooImp::info = {&BarImp::info, 0, 0}; + * \endcode + * + * @see inherits() + */ + virtual const ClassInfo *classInfo() const; + + /** + * Checks whether this object inherits from the class with the specified + * classInfo() pointer. This requires that both this class and the other + * class return a non-NULL pointer for their classInfo() methods (otherwise + * it will return false). + * + * For example, for two ObjectImp pointers obj1 and obj2, you can check + * if obj1's class inherits from obj2's class using the following: + * + * if (obj1->inherits(obj2->classInfo())) { + * // ... + * } + * + * If you have a handle to a statically declared ClassInfo, such as in the + * classInfo() example, you can check for inheritance without needing + * an instance of the other class: + * + * if (obj1->inherits(FooImp::info)) { + * // ... + * } + * + * @param cinfo The ClassInfo pointer for the class you want to check + * inheritance against. + * @return true if this object's class inherits from class with the + * ClassInfo pointer specified in cinfo + */ + bool inherits(const ClassInfo *cinfo) const; + + // internal properties (ECMA 262-3 8.6.2) + + /** + * Implementation of the [[Prototype]] internal property (implemented by + * all Objects) + * + * @see Object::prototype() + */ + Value prototype() const; + void setPrototype(const Value &proto); + + /** + * Implementation of the [[Class]] internal property (implemented by all + * Objects) + * + * The default implementation uses classInfo(). + * You should either implement classInfo(), or + * if you simply need a classname, you can reimplement className() + * instead. + * + * @see Object::className() + */ + virtual UString className() const; + + /** + * Implementation of the [[Get]] internal property (implemented by all + * Objects) + * + * @see Object::get() + */ + // [[Get]] - must be implemented by all Objects + virtual Value get(ExecState *exec, const Identifier &propertyName) const; + virtual Value getPropertyByIndex(ExecState *exec, + unsigned propertyName) const; + + /** + * Implementation of the [[Put]] internal property (implemented by all + * Objects) + * + * @see Object::put() + */ + virtual void put(ExecState *exec, const Identifier &propertyName, + const Value &value, int attr = None); + virtual void putPropertyByIndex(ExecState *exec, unsigned propertyName, + const Value &value, int attr = None); + + /** + * Implementation of the [[CanPut]] internal property (implemented by all + * Objects) + * + * @see Object::canPut() + */ + virtual bool canPut(ExecState *exec, const Identifier &propertyName) const; + + /** + * Implementation of the [[HasProperty]] internal property (implemented by + * all Objects) + * + * @see Object::hasProperty() + */ + virtual bool hasProperty(ExecState *exec, + const Identifier &propertyName) const; + virtual bool hasPropertyByIndex(ExecState *exec, unsigned propertyName) const; + + /** + * Implementation of the [[Delete]] internal property (implemented by all + * Objects) + * + * @see Object::deleteProperty() + */ + virtual bool deleteProperty(ExecState *exec, + const Identifier &propertyName); + virtual bool deletePropertyByIndex(ExecState *exec, unsigned propertyName); + + /** + * Remove all properties from this object. + * This doesn't take DontDelete into account, and isn't in the ECMA spec. + * It's simply a quick way to remove everything before destroying. + */ + void deleteAllProperties(ExecState *); + + /** + * Implementation of the [[DefaultValue]] internal property (implemented by + * all Objects) + * + * @see Object::defaultValue() + */ + virtual Value defaultValue(ExecState *exec, Type hint) const; + + virtual bool implementsConstruct() const; + /** + * Implementation of the [[Construct]] internal property + * + * @see Object::construct() + */ + virtual Object construct(ExecState *exec, const List &args); + + virtual bool implementsCall() const; + /** + * Implementation of the [[Call]] internal property + * + * @see Object::call() + */ + virtual Value call(ExecState *exec, Object &thisObj, + const List &args); + + virtual bool implementsHasInstance() const; + /** + * Implementation of the [[HasInstance]] internal property + * + * @see Object::hasInstance() + */ + virtual Boolean hasInstance(ExecState *exec, const Value &value); + + /** + * Implementation of the [[Scope]] internal property + * + * @see Object::scope() + */ + const ScopeChain &scope() const { return _scope; } + void setScope(const ScopeChain &s) { _scope = s; } + + virtual ReferenceList propList(ExecState *exec, bool recursive = true); + + Value internalValue() const; + void setInternalValue(const Value &v); + void setInternalValue(ValueImp *v); + + Value toPrimitive(ExecState *exec, + Type preferredType = UnspecifiedType) const; + bool toBoolean(ExecState *exec) const; + double toNumber(ExecState *exec) const; + UString toString(ExecState *exec) const; + Object toObject(ExecState *exec) const; + + // This get method only looks at the property map. + // A bit like hasProperty(recursive=false), this doesn't go to the prototype. + // This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want + // to look up in the prototype, it might already exist there) + ValueImp *getDirect(const Identifier& propertyName) const + { return _prop.get(propertyName); } + void putDirect(const Identifier &propertyName, ValueImp *value, int attr = 0); + void putDirect(const Identifier &propertyName, int value, int attr = 0); + + /** + * Sets the name of the function, if this is an InternalFunctionImp object. + * (calling InternalFunctionImp::setName) + */ + void setFunctionName(const Identifier &propertyName); + + protected: + PropertyMap _prop; + private: + const HashEntry* findPropertyHashEntry( const Identifier& propertyName ) const; + ObjectImpPrivate *_od; + ValueImp *_proto; + ValueImp *_internalValue; + ScopeChain _scope; + }; + + /** + * Types of Native Errors available. For custom errors, GeneralError + * should be used. + */ + enum ErrorType { GeneralError = 0, + EvalError = 1, + RangeError = 2, + ReferenceError = 3, + SyntaxError = 4, + TypeError = 5, + URIError = 6}; + + /** + * @short Factory methods for error objects. + */ + class KJS_EXPORT Error { + public: + /** + * Factory method for error objects. + * + * @param exec The current execution state + * @param errtype Type of error. + * @param message Optional error message. + * @param lineno Optional line number. + * @param sourceId Optional source id. + */ + static Object create(ExecState *exec, ErrorType errtype = GeneralError, + const char *message = 0, int lineno = -1, + int sourceId = -1); + + /** + * Array of error names corresponding to ErrorType + */ + static const char * const * const errorNames; + }; + + inline Object::Object(ObjectImp *v) : Value(v) { } + + inline ObjectImp *Object::imp() const { return static_cast<ObjectImp*>(rep); } + + inline const ClassInfo *Object::classInfo() const + { return imp()->classInfo(); } + + inline bool Object::inherits(const ClassInfo *cinfo) const + { return imp()->inherits(cinfo); } + + inline Value Object::prototype() const + { return Value(imp()->prototype()); } + + inline UString Object::className() const + { return imp()->className(); } + + inline Value Object::get(ExecState *exec, const Identifier &propertyName) const + { return imp()->get(exec,propertyName); } + + inline Value Object::get(ExecState *exec, unsigned propertyName) const + { return imp()->getPropertyByIndex(exec, propertyName); } + + inline void Object::put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr) + { imp()->put(exec,propertyName,value,attr); } + + inline void Object::put(ExecState *exec, unsigned propertyName, const Value &value, int attr) + { imp()->putPropertyByIndex(exec, propertyName, value, attr); } + + inline bool Object::canPut(ExecState *exec, const Identifier &propertyName) const + { return imp()->canPut(exec,propertyName); } + + inline bool Object::hasProperty(ExecState *exec, const Identifier &propertyName) const + { return imp()->hasProperty(exec, propertyName); } + + inline bool Object::hasProperty(ExecState *exec, unsigned propertyName) const + { return imp()->hasPropertyByIndex(exec, propertyName); } + + inline bool Object::deleteProperty(ExecState *exec, const Identifier &propertyName) + { return imp()->deleteProperty(exec,propertyName); } + + inline bool Object::deleteProperty(ExecState *exec, unsigned propertyName) + { return imp()->deletePropertyByIndex(exec, propertyName); } + + inline Value Object::defaultValue(ExecState *exec, Type hint) const + { return imp()->defaultValue(exec,hint); } + + inline bool Object::implementsConstruct() const + { return imp()->implementsConstruct(); } + + inline Object Object::construct(ExecState *exec, const List &args) + { return imp()->construct(exec,args); } + + inline bool Object::implementsCall() const + { return imp()->implementsCall(); } + + inline bool Object::implementsHasInstance() const + { return imp()->implementsHasInstance(); } + + inline Boolean Object::hasInstance(ExecState *exec, const Value &value) + { return imp()->hasInstance(exec,value); } + + inline const ScopeChain &Object::scope() const + { return imp()->scope(); } + + inline void Object::setScope(const ScopeChain &s) + { imp()->setScope(s); } + + inline ReferenceList Object::propList(ExecState *exec, bool recursive) + { return imp()->propList(exec,recursive); } + + inline Value Object::internalValue() const + { return imp()->internalValue(); } + + inline void Object::setInternalValue(const Value &v) + { imp()->setInternalValue(v); } + +} // namespace + +#endif // _KJS_OBJECT_H_ |