return 0;
}
+bool JSCallbackObject::implementsHasInstance() const
+{
+ for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
+ if (jsClass->callbacks.hasInstance)
+ return true;
+
+ return false;
+}
+
+bool JSCallbackObject::hasInstance(ExecState *exec, JSValue *value)
+{
+ JSContextRef execRef = toRef(exec);
+ JSObjectRef thisRef = toRef(this);
+
+ for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
+ if (JSObjectHasInstanceCallback hasInstance = jsClass->callbacks.hasInstance)
+ return hasInstance(execRef, thisRef, toRef(value), toRef(exec->exceptionSlot()));
+
+ ASSERT(0); // implementsHasInstance should prevent us from reaching here
+ return 0;
+}
+
+
bool JSCallbackObject::implementsCall() const
{
for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
virtual bool implementsConstruct() const;
virtual JSObject* construct(ExecState*, const List& args);
+ virtual bool implementsHasInstance() const;
+ virtual bool hasInstance(ExecState *exec, JSValue *value);
+
virtual bool implementsCall() const;
virtual JSValue* callAsFunction(ExecState*, JSObject* thisObj, const List &args);
using namespace KJS;
-const JSObjectCallbacks kJSObjectCallbacksNone = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+const JSObjectCallbacks kJSObjectCallbacksNone = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
JSClassRef JSClassCreate(JSStaticValue* staticValues, JSStaticFunction* staticFunctions, const JSObjectCallbacks* callbacks, JSClassRef parentClass)
{
/*!
@typedef JSObjectCallAsConstructorCallback
-@abstract The callback invoked when an object is used as a constructor in a 'new' statement.
+@abstract The callback invoked when an object is used as a constructor in a 'new' expression.
@param context The current execution context.
@param constructor A JSObject that is the constructor being called.
@param argc An integer count of the number of arguments in argv.
If your callback were invoked by the JavaScript expression 'new myConstructorFunction()', constructor would be set to myConstructorFunction.
-If this callback is NULL, using your object as a constructor in a 'new' statement will throw an exception.
+If this callback is NULL, using your object as a constructor in a 'new' expression will throw an exception.
*/
typedef JSObjectRef
(*JSObjectCallAsConstructorCallback) (JSContextRef context, JSObjectRef constructor, size_t argc, JSValueRef argv[], JSValueRef* exception);
+/*!
+@typedef JSObjectHasInstanceCallback
+@abstract The callback invoked when an object is used in an 'instanceof' expression.
+@param context The current execution context.
+@param constructor The JSObject receiving the hasInstance request
+@param possibleInstance The JSValue being tested to determine if it is an instance of constructor.
+@param exception A pointer to a JSValueRef in which to return an exception, if any.
+@result true if possibleInstance is an instance of constructor, otherwise false
+
+@discussion If you named your function HasInstance, you would declare it like this:
+
+bool HasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleInstance, JSValueRef* exception);
+
+If your callback were invoked by the JavaScript expression 'someValue instanceof myObject', constructor would be set to myObject and possibleInstance would be set to someValue..
+
+If this callback is NULL, using your object in an 'instanceof' will always return false.
+
+Standard JavaScript practice calls for objects that implement the callAsConstructor callback to implement the hasInstance callback as well.
+*/
+typedef bool
+(*JSObjectHasInstanceCallback) (JSContextRef context, JSObjectRef constructor, JSValueRef possibleInstance, JSValueRef* exception);
+
/*!
@typedef JSObjectConvertToTypeCallback
@abstract The callback invoked when converting an object to a particular JavaScript type.
@field deleteProperty The callback invoked when deleting a given property.
@field getPropertyList The callback invoked when adding an object's properties to a property list.
@field callAsFunction The callback invoked when an object is called as a function.
-@field callAsConstructor The callback invoked when an object is used as a constructor in a 'new' statement.
+@field hasInstance The callback invoked when an object is used in an 'instanceof' expression.
+@field callAsConstructor The callback invoked when an object is used as a constructor in a 'new' expression.
@field convertToType The callback invoked when converting an object to a particular JavaScript type.
*/
typedef struct {
JSObjectAddPropertiesToListCallback addPropertiesToList;
JSObjectCallAsFunctionCallback callAsFunction;
JSObjectCallAsConstructorCallback callAsConstructor;
+ JSObjectHasInstanceCallback hasInstance;
JSObjectConvertToTypeCallback convertToType;
} JSObjectCallbacks;
@function
@abstract Convenience method for creating a JavaScript constructor with a given callback as its implementation.
@param context The execution context to use.
-@param callAsConstructor The JSObjectCallAsConstructorCallback to invoke when the constructor is used in a 'new' statement.
+@param callAsConstructor The JSObjectCallAsConstructorCallback to invoke when the constructor is used in a 'new' expression.
@result A JSObject that is a constructor. The object's prototype will be the default object prototype.
*/
JSObjectRef JSObjectMakeConstructor(JSContextRef context, JSObjectCallAsConstructorCallback callAsConstructor);
return JSValueToObject(context, JSValueMakeNumber(0));
}
+static bool MyObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
+{
+ UNUSED_PARAM(context);
+
+ JSStringRef numberString = JSStringCreateWithUTF8CString("Number");
+ JSObjectRef numberConstructor = JSValueToObject(context, JSObjectGetProperty(context, JSContextGetGlobalObject(context), numberString));
+ JSStringRelease(numberString);
+
+ return JSValueIsInstanceOfConstructor(context, possibleValue, numberConstructor);
+}
+
static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception)
{
UNUSED_PARAM(context);
JSObjectCallbacks MyObject_callbacks = {
0,
- &MyObject_initialize,
- &MyObject_finalize,
- &MyObject_hasProperty,
- &MyObject_getProperty,
- &MyObject_setProperty,
- &MyObject_deleteProperty,
- &MyObject_getPropertyList,
- &MyObject_callAsFunction,
- &MyObject_callAsConstructor,
- &MyObject_convertToType,
+ MyObject_initialize,
+ MyObject_finalize,
+ MyObject_hasProperty,
+ MyObject_getProperty,
+ MyObject_setProperty,
+ MyObject_deleteProperty,
+ MyObject_getPropertyList,
+ MyObject_callAsFunction,
+ MyObject_callAsConstructor,
+ MyObject_hasInstance,
+ MyObject_convertToType,
};
static JSClassRef MyObject_class(JSContextRef context)
constructedObject = new MyConstructor(1);
shouldBe("typeof constructedObject", "object");
shouldBe("constructedObject.value", 1);
+shouldBe("(new MyObject()) instanceof MyObject", true);
+shouldBe("(new Object()) instanceof MyObject", false);
+2006-07-12 Maciej Stachowiak <mjs@apple.com>
+
+ 4eviewed by Geoff.
+
+ - add handling of hasInstance callback for API objects
+
+ * API/JSCallbackObject.cpp:
+ (KJS::JSCallbackObject::implementsHasInstance): Check if callback is present.
+ (KJS::JSCallbackObject::hasInstance): Invoke appropriate callback.
+ * API/JSCallbackObject.h:
+ * API/JSClassRef.cpp:
+ * API/JSObjectRef.h:
+ * API/testapi.c:
+ (MyObject_hasInstance): Test case; should match what construct would do.
+ * API/testapi.js:
+
2006-07-11 Geoffrey Garen <ggaren@apple.com>
Reviewed by Maciej.