- Changed JSObjectMakeConstructor to JSObjectMakeConstructorWithCallback,
to match JSObjectMakeFunctionWithCallback.
- Added prototype parameter, so the generated constructor
automatically works with hasInstance / instanceof
- Moved hasInstance implementation from InternalFunctionImp to JSObject
so that subclasses can inherit it without inheriting function-related baggage.
More refactoring here would be good, but this seems like a good short-term
solution.
(KJS::JSCallbackFunction::implementsHasInstance): override and return false,
because callback functions aren't constructors.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@15482
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
{
}
+bool JSCallbackConstructor::implementsHasInstance() const
+{
+ return true;
+}
+
bool JSCallbackConstructor::implementsConstruct() const
{
return true;
#define JSCallbackConstructor_h
#include "JSObjectRef.h"
-#include "object.h"
+#include <kjs/object.h>
namespace KJS {
-
+
class JSCallbackConstructor : public JSObject
{
public:
JSCallbackConstructor(ExecState* exec, JSObjectCallAsConstructorCallback callback);
+ virtual bool implementsHasInstance() const;
+
virtual bool implementsConstruct() const;
virtual JSObject* construct(ExecState*, const List &args);
-
+
virtual const ClassInfo *classInfo() const { return &info; }
static const ClassInfo info;
{
}
+// InternalFunctionImp mish-mashes constructor and function behavior -- we should
+// refactor the code so this override isn't necessary
+bool JSCallbackFunction::implementsHasInstance() const {
+ return false;
+}
+
JSValue* JSCallbackFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List &args)
{
JSContextRef execRef = toRef(exec);
public:
JSCallbackFunction(ExecState* exec, JSObjectCallAsFunctionCallback callback, const Identifier& name);
+ virtual bool implementsHasInstance() const;
virtual JSValue* callAsFunction(ExecState*, JSObject* thisObj, const List &args);
virtual const ClassInfo *classInfo() const { return &info; }
return jsClass;
}
-static JSObjectRef JSNode_prototype(JSContextRef context)
+JSObjectRef JSNode_prototype(JSContextRef context)
{
static JSObjectRef prototype;
if (!prototype) {
#include "Node.h"
extern JSObjectRef JSNode_new(JSContextRef context, Node* node);
+extern JSObjectRef JSNode_prototype(JSContextRef context);
extern JSObjectRef JSNode_construct(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
#endif // JSNode_h
return toRef(new JSCallbackFunction(exec, callAsFunction, nameID));
}
-JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSObjectCallAsConstructorCallback callAsConstructor)
+JSObjectRef JSObjectMakeConstructorWithCallback(JSContextRef ctx, JSValueRef prototype, JSObjectCallAsConstructorCallback callAsConstructor)
{
JSLock lock;
ExecState* exec = toJS(ctx);
- return toRef(new JSCallbackConstructor(exec, callAsConstructor));
+ JSValue* jsPrototype = toJS(prototype);
+
+ if (!jsPrototype)
+ jsPrototype = exec->dynamicInterpreter()->builtinObjectPrototype();
+
+ JSObject* constructor = new JSCallbackConstructor(exec, callAsConstructor);
+ constructor->put(exec, prototypePropertyName, jsPrototype, DontEnum|DontDelete|ReadOnly);
+ return toRef(constructor);
}
JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
@param ctx The execution context to use.
@param name A JSString containing the function's name. This will be used when converting the function to string. Pass NULL to create an anonymous function.
@param callAsFunction The JSObjectCallAsFunctionCallback to invoke when the function is called.
-@result A JSObject that is an anonymous function. The object's prototype will be the default function prototype.
+@result A JSObject that is a function. The object's prototype will be the default function prototype.
*/
JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction);
+
/*!
@function
@abstract Convenience method for creating a JavaScript constructor with a given callback as its implementation.
@param ctx The execution context to use.
+@param prototype A JSValue to use as the constructor's .prototype property. This should be the same value your constructor will set as the prototype of the objects it constructs.
@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 ctx, JSObjectCallAsConstructorCallback callAsConstructor);
+JSObjectRef JSObjectMakeConstructorWithCallback(JSContextRef ctx, JSValueRef prototype, JSObjectCallAsConstructorCallback callAsConstructor);
/*!
@function
JSStringRelease(printIString);
JSStringRef node = JSStringCreateWithUTF8CString("Node");
- JSObjectSetProperty(context, globalObject, node, JSObjectMakeConstructor(context, JSNode_construct), kJSPropertyAttributeNone, NULL);
+ JSObjectSetProperty(context, globalObject, node, JSObjectMakeConstructorWithCallback(context, JSNode_prototype(context), JSNode_construct), kJSPropertyAttributeNone, NULL);
JSStringRelease(node);
char* scriptUTF8 = createStringWithContentsOfFile("minidom.js");
oldNodeType = node.nodeType;
node.nodeType = 1;
shouldBe("node.nodeType", oldNodeType);
+
+ shouldBe("node instanceof Node", true);
+ shouldBe("new Object() instanceof Node", false);
+
+ print(Node);
/*
var element, name, weapon;
assert(!JSObjectGetPrivate(printFunction));
JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor");
- JSObjectRef myConstructor = JSObjectMakeConstructor(context, myConstructor_callAsConstructor);
+ JSObjectRef myConstructor = JSObjectMakeConstructorWithCallback(context, NULL, myConstructor_callAsConstructor);
JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL);
JSStringRelease(myConstructorIString);
+2006-07-17 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej.
+
+ - Changed JSObjectMakeConstructor to JSObjectMakeConstructorWithCallback,
+ to match JSObjectMakeFunctionWithCallback.
+
+ - Added prototype parameter, so the generated constructor
+ automatically works with hasInstance / instanceof
+
+ - Moved hasInstance implementation from InternalFunctionImp to JSObject
+ so that subclasses can inherit it without inheriting function-related baggage.
+ More refactoring here would be good, but this seems like a good short-term
+ solution.
+
+ (KJS::JSCallbackFunction::implementsHasInstance): override and return false,
+ because callback functions aren't constructors.
+
2006-07-17 Maciej Stachowiak <mjs@apple.com>
Reviewed by Geoff.
_JSObjectIsConstructor
_JSObjectIsFunction
_JSObjectMake
-_JSObjectMakeConstructor
+_JSObjectMakeConstructorWithCallback
_JSObjectMakeFunctionWithCallback
_JSObjectMakeFunction
_JSObjectSetPrivate
__ZN3KJS16RuntimeObjectImpC1EPNS_8Bindings8InstanceE
__ZN3KJS17PropertyNameArray3addERKNS_10IdentifierE
__ZN3KJS18lengthPropertyNameE
-__ZN3KJS19InternalFunctionImp11hasInstanceEPNS_9ExecStateEPNS_7JSValueE
__ZN3KJS19InternalFunctionImp4infoE
__ZN3KJS19InternalFunctionImpC2EPNS_17FunctionPrototypeERKNS_10IdentifierE
__ZN3KJS19messagePropertyNameE
return true;
}
-bool InternalFunctionImp::hasInstance(ExecState *exec, JSValue *value)
-{
- if (!value->isObject())
- return false;
-
- JSValue *prot = get(exec,prototypePropertyName);
- if (!prot->isObject() && !prot->isNull()) {
- throwError(exec, TypeError, "Invalid prototype encountered in instanceof operation.");
- return false;
- }
-
- JSObject *v = static_cast<JSObject *>(value);
- while ((v = v->prototype()->getObject())) {
- if (v == prot)
- return true;
- }
- return false;
-}
-
// ------------------------------ global functions -----------------------------
double roundValue(ExecState *exec, JSValue *v)
virtual bool implementsCall() const;
virtual JSValue* callAsFunction(ExecState*, JSObject* thisObjec, const List& args) = 0;
virtual bool implementsHasInstance() const;
- virtual bool hasInstance(ExecState*, JSValue*);
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
return false;
}
-bool JSObject::hasInstance(ExecState *, JSValue *)
+bool JSObject::hasInstance(ExecState* exec, JSValue* value)
{
- assert(false);
- return false;
+ JSValue* proto = get(exec, prototypePropertyName);
+ if (!proto->isObject()) {
+ throwError(exec, TypeError, "intanceof called on an object with an invalid prototype property.");
+ return false;
+ }
+
+ if (!value->isObject())
+ return false;
+
+ JSObject* o = static_cast<JSObject*>(value);
+ while ((o = o->prototype()->getObject())) {
+ if (o == proto)
+ return true;
+ }
+ return false;
}
bool JSObject::propertyIsEnumerable(ExecState*, const Identifier& propertyName) const