/* * 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(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_