+2004-08-05 Richard Williamson <rjw@apple.com>
+
+ Fixed part of 3674747. The QT guys need this for feature freeze.
+
+ This patch implements support for the
+
+ - (id)invokeUndefinedMethodFromWebScript:(NSString *)name withArguments:(NSArray *)args
+
+ method of objects bound to JavaScript.
+
+ Reviewed by John.
+
+ * ChangeLog:
+ * bindings/objc/objc_class.mm:
+ (ObjcClass::methodsNamed):
+ (ObjcClass::fieldNamed):
+ * bindings/objc/objc_instance.mm:
+ (ObjcInstance::invokeMethod):
+ * bindings/objc/objc_runtime.h:
+ (KJS::Bindings::ObjcMethod::~ObjcMethod):
+ (KJS::Bindings::ObjcMethod::isFallbackMethod):
+ (KJS::Bindings::ObjcMethod::javaScriptName):
+ * bindings/objc/objc_runtime.mm:
+ (ObjcMethod::ObjcMethod):
+ (ObjcMethod::getMethodSignature):
+ (ObjcMethod::setJavaScriptName):
+ * bindings/testbindings.mm:
+
2004-08-04 Vicki Murley <vicki@apple.com>
Reviewed by mjs.
NSString *mappedName = 0;
// See if the class wants to exclude the selector from visibility in JavaScript.
- if ([(id)thisClass isSelectorExcludedFromWebScript:objcMethod->method_name]) {
- continue;
+ if ([(id)thisClass respondsToSelector:@selector(isSelectorExcludedFromWebScript:)]){
+ if ([(id)thisClass isSelectorExcludedFromWebScript:objcMethod->method_name]) {
+ continue;
+ }
}
// See if the class want to provide a different name for the selector in JavaScript.
thisClass = thisClass->super_class;
}
- CFRelease (methodName);
+ if (methodList.length() == 0) {
+ thisClass = _isa;
+ if ([(id)thisClass instancesRespondToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)]){
+ // Fallback methods are created for one-shot use. They are created here
+ // and deleted in ObjcInstance::invokeMethod().
+ ObjcMethod *fallbackMethod = new ObjcMethod (thisClass, (const char *)@selector(invokeUndefinedMethodFromWebScript:withArguments:));
+ fallbackMethod->setJavaScriptName(methodName);
+ methodList.addMethod ((Method *)fallbackMethod);
+ }
+ }
+ CFRelease (methodName);
+
return methodList;
}
return aField;
}
+ // FIX ME. See if the instance implement attributeKeys. Will need to
+ // change fieldNamed() signature to take a Bindings::Instance.
while (thisClass != 0) {
struct objc_ivar_list *fieldsInClass = thisClass->ivars;
if (fieldsInClass) {
NSString *mappedName = 0;
// See if the class wants to exclude the selector from visibility in JavaScript.
- if ([(id)thisClass isKeyExcludedFromWebScript:objcIVar->ivar_name]) {
- continue;
+ if ([(id)thisClass respondsToSelector:@selector(isKeyExcludedFromWebScript:)]) {
+ if ([(id)thisClass isKeyExcludedFromWebScript:objcIVar->ivar_name]) {
+ continue;
+ }
}
// See if the class want to provide a different name for the selector in JavaScript.
[invocation setTarget:_instance];
unsigned i, count = args.size();
- if (count != [signature numberOfArguments] - 2){
- return Undefined();
- }
-
- for (i = 2; i < count+2; i++) {
- const char *type = [signature getArgumentTypeAtIndex:i];
- ObjcValueType objcValueType = objcValueTypeForType (type);
-
- // Must have a valid argument type. This method signature should have
- // been filtered already to ensure that it has acceptable argument
- // types.
- assert (objcValueType != ObjcInvalidType && objcValueType != ObjcVoidType);
+ if (method->isFallbackMethod()) {
+ // invokeUndefinedMethodFromWebScript:withArguments: implementation must return an
+ // object.
+ if (strcmp ([signature methodReturnType], "@") != 0) {
+ OBJC_LOG ("incorrect signature for invokeUndefinedMethodFromWebScript:withArguments:, expected object return type");
+ delete method;
+ return Undefined();
+ }
- ObjcValue value = convertValueToObjcValue (exec, args.at(i-2), objcValueType);
+ // Invoke invokeUndefinedMethodFromWebScript:withArguments:, pass JavaScript function
+ // name as first (actually at 2) argument and array of args as second.
+ NSString *jsName = (NSString *)method->javaScriptName();
+ [invocation setArgument:&jsName atIndex:2];
- switch (objcValueType) {
- case ObjcObjectType:
- [invocation setArgument:&value.objectValue atIndex:i];
- break;
- case ObjcCharType:
- [invocation setArgument:&value.charValue atIndex:i];
- break;
- case ObjcShortType:
- [invocation setArgument:&value.shortValue atIndex:i];
- break;
- case ObjcIntType:
- [invocation setArgument:&value.intValue atIndex:i];
- break;
- case ObjcLongType:
- [invocation setArgument:&value.longValue atIndex:i];
- break;
- case ObjcFloatType:
- [invocation setArgument:&value.floatValue atIndex:i];
- break;
- case ObjcDoubleType:
- [invocation setArgument:&value.doubleValue atIndex:i];
- break;
- default:
- // Should never get here. Argument types are filtered (and
- // the assert above should have fired in the impossible case
- // of an invalid type anyway).
- fprintf (stderr, "%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)objcValueType);
- assert (true);
+ NSMutableArray *objcArgs = [NSMutableArray array];
+ for (i = 0; i < count; i++) {
+ ObjcValue value = convertValueToObjcValue (exec, args.at(i), ObjcObjectType);
+ [objcArgs addObject:value.objectValue];
}
+ [invocation setArgument:&objcArgs atIndex:3];
}
+ else {
+ if (count != [signature numberOfArguments] - 2){
+ return Undefined();
+ }
+
+ for (i = 2; i < count+2; i++) {
+ const char *type = [signature getArgumentTypeAtIndex:i];
+ ObjcValueType objcValueType = objcValueTypeForType (type);
+ // Must have a valid argument type. This method signature should have
+ // been filtered already to ensure that it has acceptable argument
+ // types.
+ assert (objcValueType != ObjcInvalidType && objcValueType != ObjcVoidType);
+
+ ObjcValue value = convertValueToObjcValue (exec, args.at(i-2), objcValueType);
+
+ switch (objcValueType) {
+ case ObjcObjectType:
+ [invocation setArgument:&value.objectValue atIndex:i];
+ break;
+ case ObjcCharType:
+ [invocation setArgument:&value.charValue atIndex:i];
+ break;
+ case ObjcShortType:
+ [invocation setArgument:&value.shortValue atIndex:i];
+ break;
+ case ObjcIntType:
+ [invocation setArgument:&value.intValue atIndex:i];
+ break;
+ case ObjcLongType:
+ [invocation setArgument:&value.longValue atIndex:i];
+ break;
+ case ObjcFloatType:
+ [invocation setArgument:&value.floatValue atIndex:i];
+ break;
+ case ObjcDoubleType:
+ [invocation setArgument:&value.doubleValue atIndex:i];
+ break;
+ default:
+ // Should never get here. Argument types are filtered (and
+ // the assert above should have fired in the impossible case
+ // of an invalid type anyway).
+ fprintf (stderr, "%s: invalid type (%d)\n", __PRETTY_FUNCTION__, (int)objcValueType);
+ assert (true);
+ }
+ }
+ }
+
// Invoke the ObjectiveC method.
[invocation invoke];
[invocation getReturnValue:buffer];
resultValue = convertObjcValueToValue (exec, buffer, objcValueType);
}
+
+ // Fallback methods are created for one-shot use. They are created in
+ // ObjcClass::methodsNamed() and deleted here.
+ if (method->isFallbackMethod())
+ delete method;
NS_HANDLER