diff --git a/jstalk.xcodeproj/project.pbxproj b/jstalk.xcodeproj/project.pbxproj index 118f4ee..e0e26d8 100644 --- a/jstalk.xcodeproj/project.pbxproj +++ b/jstalk.xcodeproj/project.pbxproj @@ -217,6 +217,10 @@ CC69B5831245536600E735F6 /* JSTRuntimeInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = CC09CB521242C91F00B41D15 /* JSTRuntimeInfo.m */; }; CC725EB91238026D00EA83BF /* TETextUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = CC725EB71238026D00EA83BF /* TETextUtils.h */; }; CC725EBA1238026D00EA83BF /* TETextUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = CC725EB81238026D00EA83BF /* TETextUtils.m */; }; + CC7528F3124FE64D005546B0 /* JSTFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = CC7528F1124FE64D005546B0 /* JSTFunction.h */; }; + CC7528F4124FE64D005546B0 /* JSTFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7528F2124FE64D005546B0 /* JSTFunction.m */; }; + CC75296E1250066F005546B0 /* JSTTests.h in Headers */ = {isa = PBXBuildFile; fileRef = CC75296C1250066F005546B0 /* JSTTests.h */; }; + CC75296F1250066F005546B0 /* JSTTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC75296D1250066F005546B0 /* JSTTests.m */; }; CC7576B40F6DF3B7003AE279 /* JSTFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7576B30F6DF3B7003AE279 /* JSTFileWatcher.m */; }; CC8CF98F0F46521000C32090 /* JSTExtras.m in Sources */ = {isa = PBXBuildFile; fileRef = CC4143C00F2529F200E46669 /* JSTExtras.m */; }; CC94E0520F4A616300208BE0 /* JSTalk.icns in Resources */ = {isa = PBXBuildFile; fileRef = CC94E0510F4A616300208BE0 /* JSTalk.icns */; }; @@ -238,8 +242,8 @@ CCC5B8CD0F1EFAAA00126722 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CCC5B8CC0F1EFAAA00126722 /* main.m */; }; CCC5B8D00F1EFABA00126722 /* JSTDocument.m in Sources */ = {isa = PBXBuildFile; fileRef = CCC5B8CE0F1EFABA00126722 /* JSTDocument.m */; }; CCC5B94E0F1EFC4500126722 /* JSTAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CCC5B94D0F1EFC4500126722 /* JSTAppDelegate.m */; }; - CCD7C530124D674A00657984 /* JSTClosure.h in Headers */ = {isa = PBXBuildFile; fileRef = CCD7C52E124D674A00657984 /* JSTClosure.h */; }; - CCD7C531124D674A00657984 /* JSTClosure.m in Sources */ = {isa = PBXBuildFile; fileRef = CCD7C52F124D674A00657984 /* JSTClosure.m */; }; + CCCA67A11250422700522EFA /* JSTFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = CC7528F2124FE64D005546B0 /* JSTFunction.m */; }; + CCCA67A31250422900522EFA /* JSTUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = CCB5EB0F124D922E0052BCD9 /* JSTUtils.m */; }; CCE16C3E12188AE500F6D312 /* JSTPluginMover.m in Sources */ = {isa = PBXBuildFile; fileRef = CCE16C3D12188AE500F6D312 /* JSTPluginMover.m */; }; CCE16C8312188F5000F6D312 /* JSTDocumentController.m in Sources */ = {isa = PBXBuildFile; fileRef = CCE16C8212188F5000F6D312 /* JSTDocumentController.m */; }; CCF68F1E0F4E3E4F00925FCA /* JSTalkDocument.icns in Resources */ = {isa = PBXBuildFile; fileRef = CCF68F1D0F4E3E4F00925FCA /* JSTalkDocument.icns */; }; @@ -465,6 +469,10 @@ CC5FB7D70F1FDDE900F4ECC2 /* JSTalk.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = JSTalk.m; path = src/JSTalk.m; sourceTree = ""; }; CC725EB71238026D00EA83BF /* TETextUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TETextUtils.h; path = src/TETextUtils.h; sourceTree = ""; }; CC725EB81238026D00EA83BF /* TETextUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TETextUtils.m; path = src/TETextUtils.m; sourceTree = ""; }; + CC7528F1124FE64D005546B0 /* JSTFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSTFunction.h; path = src/JSTFunction.h; sourceTree = ""; }; + CC7528F2124FE64D005546B0 /* JSTFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = JSTFunction.m; path = src/JSTFunction.m; sourceTree = ""; }; + CC75296C1250066F005546B0 /* JSTTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSTTests.h; path = src/JSTTests.h; sourceTree = ""; }; + CC75296D1250066F005546B0 /* JSTTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = JSTTests.m; path = src/JSTTests.m; sourceTree = ""; }; CC7576B20F6DF3B7003AE279 /* JSTFileWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSTFileWatcher.h; path = src/JSTFileWatcher.h; sourceTree = ""; }; CC7576B30F6DF3B7003AE279 /* JSTFileWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = JSTFileWatcher.m; path = src/JSTFileWatcher.m; sourceTree = ""; }; CC94E0510F4A616300208BE0 /* JSTalk.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = JSTalk.icns; path = res/images/JSTalk.icns; sourceTree = ""; }; @@ -489,8 +497,6 @@ CCC5B94D0F1EFC4500126722 /* JSTAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = JSTAppDelegate.m; path = src/JSTAppDelegate.m; sourceTree = ""; }; CCC5B95A0F1EFCFE00126722 /* JSTListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSTListener.h; path = src/JSTListener.h; sourceTree = ""; }; CCC5B95B0F1EFCFE00126722 /* JSTListener.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = JSTListener.m; path = src/JSTListener.m; sourceTree = ""; }; - CCD7C52E124D674A00657984 /* JSTClosure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSTClosure.h; path = src/JSTClosure.h; sourceTree = ""; }; - CCD7C52F124D674A00657984 /* JSTClosure.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = JSTClosure.m; path = src/JSTClosure.m; sourceTree = ""; }; CCE16C3C12188AE500F6D312 /* JSTPluginMover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSTPluginMover.h; path = src/JSTPluginMover.h; sourceTree = ""; }; CCE16C3D12188AE500F6D312 /* JSTPluginMover.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = JSTPluginMover.m; path = src/JSTPluginMover.m; sourceTree = ""; }; CCE16C8112188F5000F6D312 /* JSTDocumentController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSTDocumentController.h; path = src/JSTDocumentController.h; sourceTree = ""; }; @@ -629,19 +635,21 @@ children = ( CCC5B92C0F1EFB5900126722 /* JSCocoa */, CC5FB7D60F1FDDE900F4ECC2 /* JSTalk.h */, - CCB5EB0E124D922E0052BCD9 /* JSTUtils.h */, - CCB5EB0F124D922E0052BCD9 /* JSTUtils.m */, CC5FB7D70F1FDDE900F4ECC2 /* JSTalk.m */, CC3CC7F1124C3406001A349E /* JSTBridge.h */, CC3CC7F2124C3406001A349E /* JSTBridge.m */, - CCD7C52E124D674A00657984 /* JSTClosure.h */, - CCD7C52F124D674A00657984 /* JSTClosure.m */, CC4143C10F2529F200E46669 /* JSTExtras.h */, CC4143C00F2529F200E46669 /* JSTExtras.m */, + CC7528F1124FE64D005546B0 /* JSTFunction.h */, + CC7528F2124FE64D005546B0 /* JSTFunction.m */, CCC5B95A0F1EFCFE00126722 /* JSTListener.h */, CCC5B95B0F1EFCFE00126722 /* JSTListener.m */, CC975BC60F47E5BD00097108 /* JSTPreprocessor.h */, CC975BC70F47E5BD00097108 /* JSTPreprocessor.m */, + CC75296C1250066F005546B0 /* JSTTests.h */, + CC75296D1250066F005546B0 /* JSTTests.m */, + CCB5EB0E124D922E0052BCD9 /* JSTUtils.h */, + CCB5EB0F124D922E0052BCD9 /* JSTUtils.m */, CC4184501244773A004144B7 /* MA */, CC1C7D200F48BB2C007A2941 /* todparsekit */, CC5064DE0F4A155000F4A952 /* UIWidgets */, @@ -922,8 +930,9 @@ CC41845F12447743004144B7 /* RTUnregisteredClass.h in Headers */, CC41857112448360004144B7 /* MABlockClosure.h in Headers */, CC3CC7F3124C3406001A349E /* JSTBridge.h in Headers */, - CCD7C530124D674A00657984 /* JSTClosure.h in Headers */, CCB5EB10124D922E0052BCD9 /* JSTUtils.h in Headers */, + CC7528F3124FE64D005546B0 /* JSTFunction.h in Headers */, + CC75296E1250066F005546B0 /* JSTTests.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1156,8 +1165,9 @@ CC41846012447743004144B7 /* RTUnregisteredClass.m in Sources */, CC41857212448360004144B7 /* MABlockClosure.m in Sources */, CC3CC7F4124C3406001A349E /* JSTBridge.m in Sources */, - CCD7C531124D674A00657984 /* JSTClosure.m in Sources */, CCB5EB11124D922E0052BCD9 /* JSTUtils.m in Sources */, + CC7528F4124FE64D005546B0 /* JSTFunction.m in Sources */, + CC75296F1250066F005546B0 /* JSTTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1232,6 +1242,8 @@ CCA9C2261241D7E5003EB4C5 /* JSTBridgedObject.m in Sources */, CC69B5831245536600E735F6 /* JSTRuntimeInfo.m in Sources */, CC3CC7FB124C3416001A349E /* JSTBridge.m in Sources */, + CCCA67A11250422700522EFA /* JSTFunction.m in Sources */, + CCCA67A31250422900522EFA /* JSTUtils.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/res/JSTalk.bridgesupport b/res/JSTalk.bridgesupport index c8d1880..8d50614 100644 --- a/res/JSTalk.bridgesupport +++ b/res/JSTalk.bridgesupport @@ -2,65 +2,38 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + - - - + + + - - - - + + + - - - - + + + + + + + + + + + diff --git a/src/JSCocoaController.m b/src/JSCocoaController.m index b49dc40..e1d0ea8 100644 --- a/src/JSCocoaController.m +++ b/src/JSCocoaController.m @@ -2654,7 +2654,7 @@ JSValueRef OSXObject_getProperty(JSContextRef ctx, JSObjectRef object, JSStringR // Let's see if it's a function - if ([bridgedObjectInfo objectType] == JSTFunction) { + if ([bridgedObjectInfo jstType] == JSTTypeFunction) { JSObjectRef jsRef = [JSCocoaController jsCocoaPrivateFunctionInContext:ctx]; JSTBridgedObject* private = JSObjectGetPrivate(jsRef); //private.type = @"function"; @@ -2667,7 +2667,7 @@ JSValueRef OSXObject_getProperty(JSContextRef ctx, JSObjectRef object, JSStringR } // ok, is it a struct maybe? - else if ([bridgedObjectInfo objectType] == JSTStruct) { + else if ([bridgedObjectInfo jstType] == JSTTypeStruct) { JSObjectRef jsRef = [JSCocoaController jsCocoaPrivateObjectInContext:ctx]; JSTBridgedObject* private = JSObjectGetPrivate(jsRef); //private.type = @"struct"; @@ -2677,7 +2677,7 @@ JSValueRef OSXObject_getProperty(JSContextRef ctx, JSObjectRef object, JSStringR } // How about a constant? - else if (([bridgedObjectInfo objectType] == JSTConstant)) { + else if (([bridgedObjectInfo jstType] == JSTTypeConstant)) { debug(@"[bridgedObjectInfo typeEncoding]: '%@'", [bridgedObjectInfo typeEncoding]); @@ -2721,7 +2721,7 @@ JSValueRef OSXObject_getProperty(JSContextRef ctx, JSObjectRef object, JSStringR id o = *(id*)symbol; return [JSCocoaController boxedJSObject:o inContext:ctx]; } - else if ([constInfo objectType] == JSTStruct) { + else if ([constInfo jstType] == JSTTypeStruct) { debug(@"ok, it's a struct, so I'm doing that thing."); @@ -2767,7 +2767,7 @@ JSValueRef OSXObject_getProperty(JSContextRef ctx, JSObjectRef object, JSStringR } // Enum - else if ([bridgedObjectInfo objectType] == JSTEnum) { + else if ([bridgedObjectInfo jstType] == JSTTypeEnum) { debug(@"[bridgedObjectInfo enumValue]: %d", [bridgedObjectInfo enumValue]); return JSValueMakeNumber(ctx, [bridgedObjectInfo enumValue]); } @@ -3082,7 +3082,7 @@ JSValueRef valueOfCallback(JSContextRef ctx, JSObjectRef function, JSObjectRef t } // Struct - if ([[thisPrivateObject runtimeInfo] objectType] == JSTStruct)// .type isEqualToString:@"struct"]) + if ([[thisPrivateObject runtimeInfo] jstType] == JSTTypeStruct)// .type isEqualToString:@"struct"]) { id structDescription = nil; id self = [JSCocoaController controllerFromContext:ctx]; @@ -3223,7 +3223,7 @@ static JSValueRef jsCocoaObject_getProperty(JSContextRef ctx, JSObjectRef object JSCocoaController* jsc = [JSCocoaController controllerFromContext:ctx]; id delegate = jsc.delegate; - if ([runtimeInfo objectType] == JSTStruct) { + if ([runtimeInfo jstType] == JSTTypeStruct) { debug(@"IT'S A FUCKING STRUCT!"); @@ -4009,7 +4009,7 @@ static bool jsCocoaObject_setProperty(JSContextRef ctx, JSObjectRef object, JSSt if ([bridgedObject.type isEqualToString:@"struct"]) { debug(@"bridgedObject: '%@'", bridgedObject); //assert([bridgedObject runtimeInfo]); - //if ([[bridgedObject runtimeInfo] objectType] == JSTStruct) { + //if ([[bridgedObject runtimeInfo] jstType] == JSTTypeStruct) { //assert(NO); return NO; } diff --git a/src/JSTBridge.m b/src/JSTBridge.m index 7228d79..aaea932 100644 --- a/src/JSTBridge.m +++ b/src/JSTBridge.m @@ -7,15 +7,18 @@ // #import "JSTBridge.h" -#import "JSTClosure.h" +#import "JSTFunction.h" #import "JSTUtils.h" // JSObjectGetPropertyCallback JSValueRef JSTBridge_getProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyNameJS, JSValueRef* exception); JSValueRef JSTBridge_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); -void JSTBridge_objectInitialize(JSContextRef ctx, JSObjectRef object); // JSObjectInitializeCallback -void JSTBridge_objectFinalize(JSObjectRef object); // JSObjectFinalizeCallback + +void JSTClass_initialize(JSContextRef ctx, JSObjectRef object); // JSObjectInitializeCallback +void JSTClass_finalize(JSObjectRef object); // JSObjectFinalizeCallback +JSValueRef JSTClass_convertToType(JSContextRef ctx, JSObjectRef object, JSType type, JSValueRef* exception); +JSValueRef JSTClass_getProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyNameJS, JSValueRef* exception); static const char * JSTRuntimeAssociatedInfoKey = "jstri"; @@ -37,10 +40,13 @@ - (id)init { JSObjectSetPrivate(JSContextGetGlobalObject(_jsContext), self); JSClassDefinition bridgedObjectDefinition = kJSClassDefinitionEmpty; - bridgedObjectDefinition.className = "JSTBridgedObject"; + bridgedObjectDefinition.className = "id"; + + bridgedObjectDefinition.initialize = JSTClass_initialize; + bridgedObjectDefinition.finalize = JSTClass_finalize; + bridgedObjectDefinition.convertToType = JSTClass_convertToType; + bridgedObjectDefinition.getProperty = JSTClass_getProperty; - bridgedObjectDefinition.initialize = JSTBridge_objectInitialize; - bridgedObjectDefinition.finalize = JSTBridge_objectFinalize; /* // jsCocoaObjectDefinition.hasProperty = jsCocoaObject_hasProperty; @@ -58,7 +64,7 @@ - (id)init { JSClassDefinition bridgedFunctionDefinition = kJSClassDefinitionEmpty; - bridgedFunctionDefinition.className = "JSCocoa box"; + bridgedFunctionDefinition.className = "JSTFunction"; bridgedFunctionDefinition.parentClass = _bridgedObjectClass; bridgedFunctionDefinition.callAsFunction = JSTBridge_callAsFunction; @@ -110,6 +116,11 @@ - (JSValueRef)evalJSString:(NSString*)script withPath:(NSString*)path { } - (JSObjectRef)makeJSObjectWithNSObject:(id)obj runtimeInfo:(JSTRuntimeInfo*)info { + + if (!obj) { + return nil; + } + objc_setAssociatedObject(obj, &JSTRuntimeAssociatedInfoKey, info, OBJC_ASSOCIATION_ASSIGN); [obj retain]; return JSObjectMake(_jsContext, _bridgedObjectClass, obj); @@ -123,11 +134,9 @@ - (JSObjectRef)makeJSObjectWithNSObject:(id*)bridgedObject runtimeInfo:(JSTRunti */ - (JSObjectRef)makeBridgedFunctionWithRuntimeInfo:(JSTRuntimeInfo*)info name:(NSString*)functionName { - - JSTClosure *closure = [[JSTClosure alloc] initWithFunctionName:functionName bridge:self runtimeInfo:info]; - objc_setAssociatedObject(closure, &JSTRuntimeAssociatedInfoKey, info, OBJC_ASSOCIATION_ASSIGN); - return JSObjectMake(_jsContext, _bridgedFunctionClass, closure); - + JSTFunction *function = [[JSTFunction alloc] initWithFunctionName:functionName bridge:self runtimeInfo:info]; + objc_setAssociatedObject(function, &JSTRuntimeAssociatedInfoKey, info, OBJC_ASSOCIATION_ASSIGN); + return JSObjectMake(_jsContext, _bridgedFunctionClass, function); } - (JSTRuntimeInfo*)runtimeInfoForObject:(id)obj { @@ -139,8 +148,8 @@ - (id)NSObjectForJSObject:(JSObjectRef)jsObj { } -- (JSTClosure*)closureForJSFunction:(JSObjectRef)jsObj { - return (id)JSObjectGetPrivate(jsObj); +- (JSTFunction*)functionForJSFunction:(JSObjectRef)jsObj { + return (JSTFunction*)JSObjectGetPrivate(jsObj); } @@ -152,6 +161,30 @@ - (void)pushObject:(id)obj withName:(NSString*)name { JSStringRelease(propName); } +- (JSValueRef)internalFunctionForJSObject:(JSObjectRef)object functionName:(NSString*)functionName outException:(JSValueRef*)exception { + + id target = [self NSObjectForJSObject:object]; + + if (!target) { + return nil; + } + + JSTFunction *function = 0x00; + + if ([@"valueOf" isEqualToString:functionName]) { + function = [[JSTValueOfFunction alloc] initWithTarget:target bridge:self]; + } + else if ([@"toString" isEqualToString:functionName]) { + function = [[JSTToStringFunction alloc] initWithTarget:target bridge:self]; + } + else { + NSLog(@"Unknown internal function name '%@'", functionName); + JSTAssert(false); + } + + return JSObjectMake(_jsContext, _bridgedFunctionClass, function); +} + - (JSValueRef)propertyForObject:(JSObjectRef)object named:(JSStringRef)jsPropertyName outException:(JSValueRef*)exception { NSString *propertyName = (NSString*)JSStringCopyCFString(kCFAllocatorDefault, jsPropertyName); @@ -159,23 +192,26 @@ - (JSValueRef)propertyForObject:(JSObjectRef)object named:(JSStringRef)jsPropert id returnNSObject = 0x00; JSTRuntimeInfo *info = [JSTBridgeSupportLoader runtimeInfoForSymbol:propertyName]; - //debug(@"Trying to find info on %@", propertyName); + + if ([propertyName isEqualToString:@"valueOf"] || [propertyName isEqualToString:@"toString"]) { + return [self internalFunctionForJSObject:object functionName:propertyName outException:exception]; + } + if (info) { - if ([info objectType] == JSTClass) { + if ([info jstType] == JSTTypeClass) { returnNSObject = NSClassFromString(propertyName); returnJSObject = [self makeJSObjectWithNSObject:returnNSObject runtimeInfo:info]; } - else if ([info objectType] == JSTFunction) { + else if ([info jstType] == JSTTypeFunction) { returnJSObject = [self makeBridgedFunctionWithRuntimeInfo:info name:propertyName]; returnNSObject = [self NSObjectForJSObject:(JSObjectRef)returnJSObject]; } - else if ([info objectType] == JSTStruct) { - + else if ([info jstType] == JSTTypeStruct) { } - else if (([info objectType] == JSTConstant)) { + else if (([info jstType] == JSTTypeConstant)) { // in the case of NSBundleDidLoadNotification, it's declaredType is NSString*, so we need to trim it up to find the symbol info NSString *fixedDeclaredType = [info declaredType]; @@ -196,7 +232,7 @@ - (JSValueRef)propertyForObject:(JSObjectRef)object named:(JSStringRef)jsPropert return nil; } - if ([constInfo objectType] == JSTClass) { + if ([constInfo jstType] == JSTTypeClass) { id obj = *(id*)symbol; returnJSObject = [self makeJSObjectWithNSObject:obj runtimeInfo:constInfo]; } @@ -204,7 +240,7 @@ - (JSValueRef)propertyForObject:(JSObjectRef)object named:(JSStringRef)jsPropert returnJSObject = JSValueMakeBoolean(_jsContext, *(bool*)symbol); } } - else if ([info objectType] == JSTEnum) { + else if ([info jstType] == JSTTypeEnum) { returnJSObject = JSValueMakeNumber(_jsContext, [info enumValue]); } } @@ -232,24 +268,24 @@ - (JSValueRef)propertyForObject:(JSObjectRef)object named:(JSStringRef)jsPropert } -- (JSValueRef)callFunction:(JSObjectRef)function onObject:(JSObjectRef)thisObject argCount:(size_t)argumentCount arguments:(const JSValueRef*)arguments outException:(JSValueRef*)exception { +- (JSValueRef)callFunction:(JSObjectRef)jsFunction onObject:(JSObjectRef)thisObject argCount:(size_t)argumentCount arguments:(const JSValueRef*)arguments outException:(JSValueRef*)exception { - JSTClosure *closure = [self closureForJSFunction:function]; - JSTRuntimeInfo *runtimeInfo = [self runtimeInfoForObject:closure]; - NSString *functionName = [closure functionName]; + JSTFunction *function = [self functionForJSFunction:jsFunction]; + JSTRuntimeInfo *runtimeInfo = [self runtimeInfoForObject:function]; + NSString *functionName = [function functionName]; JSTAssert(functionName); - JSTAssert(closure); + JSTAssert(function); - debug(@"functionName: '%@'", functionName); + //debug(@"functionName: '%@'", functionName); - if (!closure) { + if (!function) { // FIXME: throw a JS exception, saying we couldn't find the function. return nil; } if (runtimeInfo) { - assert([runtimeInfo objectType] == JSTFunction); + assert([runtimeInfo jstType] == JSTTypeFunction); if (![runtimeInfo isVariadic] && ([[runtimeInfo arguments] count] != argumentCount)) { // FIXME: blow up and throw an exception about the wrong number of args. @@ -258,14 +294,19 @@ - (JSValueRef)callFunction:(JSObjectRef)function onObject:(JSObjectRef)thisObjec } } - [closure setArguments:arguments withCount:argumentCount]; + [function setArguments:arguments withCount:argumentCount]; - return [closure call]; + return [function call:exception]; } - (void)initializeObject:(JSObjectRef)jsObject { - //JSTBridgedObject *bridgedObject = [self bridgedObjectForJSObject:jsObject]; + +} + +- (JSValueRef)convertObject:(JSObjectRef)object toType:(JSType)type outException:(JSValueRef*)exception { + debug(@"%s:%d", __FUNCTION__, __LINE__); + return nil; } @end @@ -276,13 +317,23 @@ JSValueRef JSTBridge_getProperty(JSContextRef ctx, JSObjectRef object, JSStringR return [(JSTBridge*)JSObjectGetPrivate(object) propertyForObject:object named:propertyName outException:exception]; } -void JSTBridge_objectInitialize(JSContextRef ctx, JSObjectRef object) { +void JSTClass_initialize(JSContextRef ctx, JSObjectRef object) { return [(JSTBridge*)JSObjectGetPrivate(JSContextGetGlobalObject(ctx)) initializeObject:object]; } +JSValueRef JSTClass_convertToType(JSContextRef ctx, JSObjectRef object, JSType type, JSValueRef* exception) { + assert(false); + return [(JSTBridge*)JSObjectGetPrivate(JSContextGetGlobalObject(ctx)) convertObject:object toType:type outException:exception]; + +} + +JSValueRef JSTClass_getProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) { + return [(JSTBridge*)JSObjectGetPrivate(JSContextGetGlobalObject(ctx)) propertyForObject:object named:propertyName outException:exception]; +} + // @abstract The callback invoked when an object is finalized (prepared for garbage collection). An object may be finalized on any thread. // So yea, don't do much here thank you very much. -void JSTBridge_objectFinalize(JSObjectRef object) { +void JSTClass_finalize(JSObjectRef object) { id o = JSObjectGetPrivate(object); debug(@"releasing: %@", o); [o release]; diff --git a/src/JSTBridgeSupportLoader.m b/src/JSTBridgeSupportLoader.m index c84608c..bbbdee0 100644 --- a/src/JSTBridgeSupportLoader.m +++ b/src/JSTBridgeSupportLoader.m @@ -62,21 +62,21 @@ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)tagName namespa if ([tagName isEqualToString:@"struct"]) { nextObject = [[JSTRuntimeInfo alloc] init]; - [nextObject setObjectType:JSTStruct]; + [nextObject setJSTType:JSTTypeStruct]; } else if ([tagName isEqualToString:@"constant"]) { nextObject = [[JSTRuntimeInfo alloc] init]; - [nextObject setObjectType:JSTConstant]; + [nextObject setJSTType:JSTTypeConstant]; [nextObject setDeclaredType:[atts objectForKey:@"declared_type"]]; } else if ([tagName isEqualToString:@"enum"]) { nextObject = [[JSTRuntimeInfo alloc] init]; - [nextObject setObjectType:JSTEnum]; + [nextObject setJSTType:JSTTypeEnum]; [nextObject grabEnumValueFromAttributes:atts]; } else if ([tagName isEqualToString:@"function"]) { nextObject = [[JSTRuntimeInfo alloc] init]; - [nextObject setObjectType:JSTFunction]; + [nextObject setJSTType:JSTTypeFunction]; [nextObject setIsVariadic:[[atts objectForKey:@"variadic"] isEqualToString:@"true"]]; } else if ([tagName isEqualToString:@"class"]) { @@ -85,12 +85,12 @@ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)tagName namespa nextObject = [_symbolLookup objectForKey:[atts objectForKey:@"name"]]; nextObject = nextObject ? [nextObject retain] : [[JSTRuntimeInfo alloc] init]; - [nextObject setObjectType:JSTClass]; + [nextObject setJSTType:JSTTypeClass]; _currentBridgeClass = nextObject; } else if (_currentBridgeClass && [tagName isEqualToString:@"method"]) { nextObject = [[JSTRuntimeInfo alloc] init]; - [nextObject setObjectType:JSTMethod]; + [nextObject setJSTType:JSTTypeMethod]; [nextObject setMethodSelector:[atts objectForKey:@"selector"]]; if ([[atts objectForKey:@"class_method"] boolValue]) { @@ -100,10 +100,10 @@ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)tagName namespa [_currentBridgeClass addInstanceMethod:nextObject]; } } - else if ([_currentBridgeObject objectType] == JSTStruct && [tagName isEqualToString:@"field"]) { + else if ([_currentBridgeObject jstType] == JSTTypeStruct && [tagName isEqualToString:@"field"]) { [_currentBridgeObject addStructField:[atts objectForKey:@"name"]]; } - else if ([_currentBridgeObject objectType] == JSTFunction && ([tagName isEqualToString:@"arg"] || [tagName isEqualToString:@"retval"])) { + else if ([_currentBridgeObject jstType] == JSTTypeFunction && ([tagName isEqualToString:@"arg"] || [tagName isEqualToString:@"retval"])) { JSTRuntimeInfo *arg = [[JSTRuntimeInfo alloc] init]; [arg setDeclaredType:[atts objectForKey:@"declared_type"]]; @@ -119,7 +119,7 @@ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)tagName namespa [arg release]; } // is it an arg or a ret for a method on a class? - else if (_currentBridgeClass && [_currentBridgeObject objectType] == JSTMethod && ([tagName isEqualToString:@"arg"] || [tagName isEqualToString:@"retval"])) { + else if (_currentBridgeClass && [_currentBridgeObject jstType] == JSTTypeMethod && ([tagName isEqualToString:@"arg"] || [tagName isEqualToString:@"retval"])) { @@ -156,9 +156,9 @@ - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)tagName namespa _currentBridgeObject = nextObject; - if ([nextObject objectType] == JSTStruct || [nextObject objectType] == JSTConstant || - [nextObject objectType] == JSTEnum || [nextObject objectType] == JSTFunction || - [nextObject objectType] == JSTClass) { + if ([nextObject jstType] == JSTTypeStruct || [nextObject jstType] == JSTTypeConstant || + [nextObject jstType] == JSTTypeEnum || [nextObject jstType] == JSTTypeFunction || + [nextObject jstType] == JSTTypeClass) { //debug(@"Adding: %@ - %@", [nextObject name], [nextObject type]); diff --git a/src/JSTDocument.m b/src/JSTDocument.m index 1615a02..93858dd 100644 --- a/src/JSTDocument.m +++ b/src/JSTDocument.m @@ -185,6 +185,8 @@ - (void)runScript:(NSString*)s { [jstalk.env setObject:[[self fileURL] URLByDeletingLastPathComponent] forKey:@"scriptDirectoryURL"]; } + debug(@"jstalk.env: '%@'", jstalk.env); + if ([JSTPrefs boolForKey:@"clearConsoleOnRun"]) { [self clearConsole:nil]; } diff --git a/src/JSTClosure.h b/src/JSTFunction.h similarity index 65% rename from src/JSTClosure.h rename to src/JSTFunction.h index 6bf7108..a71efc6 100644 --- a/src/JSTClosure.h +++ b/src/JSTFunction.h @@ -1,10 +1,10 @@ -#import #import #import #import "JSTRuntimeInfo.h" +#import "JSTUtils.h" @class JSTBridge; -@interface JSTClosure : NSObject +@interface JSTFunction : NSObject { NSMutableArray *_allocations; ffi_cif _closureCIF; @@ -21,7 +21,7 @@ size_t _argumentCount; JSValueRef *_jsArguments; JSTBridge *_bridge; - //void **argValues; + Method _objcMethod; } - (id)initWithFunctionName:(NSString*)name bridge:(JSTBridge*)bridge runtimeInfo:(JSTRuntimeInfo*)runtimeInfo; @@ -30,8 +30,24 @@ - (void)setArguments:(const JSValueRef *)args withCount:(size_t)count; -- (JSValueRef)call; +- (JSValueRef)call:(JSValueRef*)exception; @property (retain) NSString *functionName; @end + +@interface JSTValueOfFunction : JSTFunction { + id _target; +} +@property (retain) id target; +- (id)initWithTarget:(id)target bridge:(JSTBridge*)bridge; + +@end + +@interface JSTToStringFunction : JSTFunction { + id _target; +} +@property (retain) id target; +- (id)initWithTarget:(id)target bridge:(JSTBridge*)bridge; + +@end \ No newline at end of file diff --git a/src/JSTClosure.m b/src/JSTFunction.m similarity index 61% rename from src/JSTClosure.m rename to src/JSTFunction.m index c290dee..fc586a8 100644 --- a/src/JSTClosure.m +++ b/src/JSTFunction.m @@ -1,14 +1,15 @@ -#import "JSTClosure.h" -#import "JSTUtils.h" - +#import "JSTFunction.h" +@interface JSTFunction () +- (Method)objcMethod; +@end -@implementation JSTClosure +@implementation JSTFunction @synthesize functionName=_functionName; static void BlockClosure(ffi_cif *cif, void *ret, void **args, void *userdata) { - JSTClosure *self = userdata; + JSTFunction *self = userdata; debug(@"self: '%@'", self); /* @@ -228,7 +229,7 @@ - (void)setArguments:(const JSValueRef *)args withCount:(size_t)count { _argumentCount = count; } -void JSTClosureFunction(ffi_cif* cif, void* resp, void** args, void* userdata) { +void JSTFunctionFunction(ffi_cif* cif, void* resp, void** args, void* userdata) { debug(@"%s:%d", __FUNCTION__, __LINE__); //[(id)userdata calledByClosureWithArgs:args returnValue:resp]; } @@ -236,15 +237,19 @@ void JSTClosureFunction(ffi_cif* cif, void* resp, void** args, void* userdata) { - (void)checkForMsgSendMethodRuntimeInfo { if ((_callAddress != &objc_msgSend) || (_argumentCount < 2)) { + debug(@"Can't possibly be objc_msgSend"); return; } - id target = JSTNSObjectFromValue(_bridge, _jsArguments[0]); - NSString *sel = JSTNSObjectFromValue(_bridge, _jsArguments[1]); + id target = JSTNSObjectFromValue(_bridge, _jsArguments[0]); + NSString *sel = JSTNSObjectFromValue(_bridge, _jsArguments[1]); + BOOL isClassMethod = class_isMetaClass(object_getClass(target)); JSTRuntimeInfo *instanceInfo = [_bridge runtimeInfoForObject:target]; - - BOOL isClassMethod = class_isMetaClass(object_getClass(target)); + if (!instanceInfo) { + NSString *classString = NSStringFromClass(isClassMethod ? target :[target class]); + instanceInfo = [JSTBridgeSupportLoader runtimeInfoForSymbol:classString]; + } if (isClassMethod) { // are we dealing with an Class method? _msgSendMethodRuntimeInfo = [instanceInfo runtimeInfoForClassMethodName:sel]; @@ -253,8 +258,17 @@ - (void)checkForMsgSendMethodRuntimeInfo { _msgSendMethodRuntimeInfo = [instanceInfo runtimeInfoForInstanceMethodName:sel]; } - debug(@"Setup to call: %c[%@ %@]", isClassMethod ? '+' : '-', NSStringFromClass(isClassMethod ? target : [target class]), sel); + if (!_msgSendMethodRuntimeInfo) { + [self objcMethod]; // go ahead and cache that guy. + + if (!_objcMethod) { + debug(@"Can't find runtime info for: %c[%@ %@]", isClassMethod ? '+' : '-', target, sel); + } + } + else { + debug(@"Setup to call: %c[%@ %@]", isClassMethod ? '+' : '-', NSStringFromClass(isClassMethod ? target : [target class]), sel); + } } @@ -283,6 +297,28 @@ void setterFor4(ffi_type **arg_types, void **arg_values, int index) { */ +- (Method)objcMethod { + + if (_objcMethod) { + return _objcMethod; + } + + JSTAssert((_callAddress == &objc_msgSend)); + JSTAssert(_argumentCount > 1); + + id target = JSTNSObjectFromValue(_bridge, _jsArguments[0]); + SEL sel = JSTSelectorFromValue(_bridge, _jsArguments[1]); + + if (class_isMetaClass(object_getClass(target))) { // are we dealing with an Class method? + _objcMethod = class_getClassMethod(target, sel); + } + else { + _objcMethod = class_getInstanceMethod(object_getClass(target), sel); + } + + return _objcMethod; +} + -(ffi_type*)setValue:(void**)argVals atIndex:(int)idx { JSValueRef argument = _jsArguments[idx]; @@ -291,12 +327,18 @@ -(ffi_type*)setValue:(void**)argVals atIndex:(int)idx { if (idx < 0) { - if (!_msgSendMethodRuntimeInfo) { - // FIXME: look up the return type in the runtime - return &ffi_type_pointer; // we always assume it's a pointer to id here if we can't find the interface + if (_msgSendMethodRuntimeInfo) { + return JSTFFITypeForTypeEncoding([[_msgSendMethodRuntimeInfo returnValue] typeEncoding]); + } + + const char *c = method_getTypeEncoding([self objcMethod]); + if (c) { + return [self _ffiArgForEncode:c]; } - return JSTFFITypeForTypeEncoding([[_msgSendMethodRuntimeInfo returnValue] typeEncoding]); + JSTAssert(false); // wtf really? + + return &ffi_type_pointer; } void **foo = [self _allocate:(sizeof(void*))]; @@ -312,20 +354,37 @@ -(ffi_type*)setValue:(void**)argVals atIndex:(int)idx { return &ffi_type_pointer; } - if (!_msgSendMethodRuntimeInfo) { - // we're going to assume everything is an id right now. - *foo = JSTNSObjectFromValue(_bridge, argument); - argVals[idx] = foo; + if (_msgSendMethodRuntimeInfo) { - return &ffi_type_pointer; + *foo = [_bridge NSObjectForJSObject:(JSObjectRef)argument]; + JSTRuntimeInfo *ri = [[_msgSendMethodRuntimeInfo arguments] objectAtIndex:idx-2]; + + return JSTFFITypeForTypeEncoding([ri typeEncoding]); } - *foo = [_bridge NSObjectForJSObject:(JSObjectRef)argument]; - JSTRuntimeInfo *ri = [[_msgSendMethodRuntimeInfo arguments] objectAtIndex:idx-2]; - return JSTFFITypeForTypeEncoding([ri typeEncoding]); + + // we're going to assume everything is an id right now. + *foo = JSTNSObjectFromValue(_bridge, argument); + argVals[idx] = foo; + + return &ffi_type_pointer; } else { + + if (idx < 0) { + + JSTRuntimeInfo *info = [JSTBridgeSupportLoader runtimeInfoForSymbol:_functionName]; + + if ([info returnValue]) { // sometimes, we have info, but not the return value. Like for NSBeep() + return JSTFFITypeForTypeEncoding([[info returnValue] typeEncoding]); + } + + return &ffi_type_void; + + } + + JSTAssert(false); } @@ -333,12 +392,12 @@ -(ffi_type*)setValue:(void**)argVals atIndex:(int)idx { } -- (JSValueRef)call { +- (JSValueRef)call:(JSValueRef*)exception { [self checkForMsgSendMethodRuntimeInfo]; - - ffi_type **argTypes = _argumentCount ? malloc(_argumentCount * sizeof(ffi_type*)) : 0x00; - void **argVals = _argumentCount ? malloc(_argumentCount * sizeof(void*)) : 0x00; + BOOL success = YES; + ffi_type **argTypes = _argumentCount ? malloc(_argumentCount * sizeof(ffi_type*)) : 0x00; + void **argVals = _argumentCount ? malloc(_argumentCount * sizeof(void*)) : 0x00; for (int j = 0; j < _argumentCount; j++) { argTypes[j] = [self setValue:*(void**)&argVals atIndex:j]; @@ -359,7 +418,8 @@ - (JSValueRef)call { ffi_call(&cif, _callAddress, &result, argVals); } @catch (NSException * e) { - NSLog(@"Exception: %@", e); + success = NO; + JSTAssignException(_bridge, exception, [e description]); } if (argTypes) { @@ -372,20 +432,15 @@ - (JSValueRef)call { [_allocations release]; - if (returnFIIType == &ffi_type_void) { - return JSValueMakeNull([_bridge jsContext]); - } - else if (returnFIIType == &ffi_type_pointer) { - return [_bridge makeJSObjectWithNSObject:(id)result runtimeInfo:nil]; - } - else if (returnFIIType == &ffi_type_sint8) { - // well, it's a bool or a char or a ... hrm. - return JSValueMakeBoolean([_bridge jsContext], (bool)result); + if (!success) { + return nil; } - JSTAssert(false); + JSValueRef retJS = JSTMakeJSValueWithFFITypeAndValue(returnFIIType, result, _bridge); + + JSTAssert(retJS); - return nil; + return retJS; } @@ -429,58 +484,107 @@ - (void *)fptr { @end +@implementation JSTValueOfFunction -@implementation JSTClosure (TestExtras) +@synthesize target=_target; -- (BOOL)testBoolValue { - debug(@"%s:%d", __FUNCTION__, __LINE__); - return YES; +- (id)initWithTarget:(id)target bridge:(JSTBridge*)bridge { + self = [super init]; + if (self != nil) { + _target = [target retain]; + _bridge = [bridge retain]; + _functionName = [@" enum { - JSTUnknown, - JSTStruct, - JSTConstant, - JSTEnum, - JSTFunction, - JSTMethod, - JSTClass, + JSTTypeUnknown, + JSTTypeStruct, + JSTTypeConstant, + JSTTypeEnum, + JSTTypeFunction, + JSTTypeMethod, + JSTTypeClass, }; @interface JSTRuntimeInfo : NSObject { - int _objectType; + int _jstType; NSString *_symbolName; NSString *_typeEncoding; @@ -40,7 +40,8 @@ enum { BOOL _isVariadic; } -@property (assign) int objectType; + +@property (assign, setter=setJSTType:) int jstType; @property (retain) NSString *symbolName; @property (retain) NSString *typeEncoding; @property (retain) NSString *declaredType; diff --git a/src/JSTRuntimeInfo.m b/src/JSTRuntimeInfo.m index be5c257..ecd07e9 100644 --- a/src/JSTRuntimeInfo.m +++ b/src/JSTRuntimeInfo.m @@ -13,7 +13,7 @@ @implementation JSTRuntimeInfo -@synthesize objectType=_objectType; +@synthesize jstType=_jstType; @synthesize symbolName=_symbolName; @synthesize typeEncoding=_typeEncoding; @synthesize declaredType=_declaredType; @@ -95,7 +95,6 @@ - (JSTRuntimeInfo*)runtimeInfoForClassMethodName:(NSString*)name { Class s = class_getSuperclass(NSClassFromString(_symbolName)); if (!s) { - NSLog(@"Can't find superclass for %@", _symbolName); return nil; } @@ -115,7 +114,6 @@ - (JSTRuntimeInfo*)runtimeInfoForInstanceMethodName:(NSString*)name { Class s = class_getSuperclass(NSClassFromString(_symbolName)); if (!s) { - NSLog(@"Can't find superclass for %@", _symbolName); return nil; } @@ -217,10 +215,10 @@ - (NSString*)description { NSString *prefix = [super description]; - if (_objectType == JSTClass) { + if (_jstType == JSTTypeClass) { return [NSString stringWithFormat:@"%@ class '%@'", prefix, _symbolName]; } - else if (_objectType == JSTFunction) { + else if (_jstType == JSTTypeFunction) { return [NSString stringWithFormat:@"%@ function '%@'",prefix, _symbolName]; } diff --git a/src/JSTTests.h b/src/JSTTests.h new file mode 100644 index 0000000..330c033 --- /dev/null +++ b/src/JSTTests.h @@ -0,0 +1,16 @@ +// +// JSTTests.h +// jstalk +// +// Created by August Mueller on 9/26/10. +// Copyright 2010 Flying Meat Inc. All rights reserved. +// + +#import + + +@interface JSTTests : NSObject { + +} + +@end diff --git a/src/JSTTests.m b/src/JSTTests.m new file mode 100644 index 0000000..3c23dfe --- /dev/null +++ b/src/JSTTests.m @@ -0,0 +1,77 @@ +// +// JSTTests.m +// jstalk +// +// Created by August Mueller on 9/26/10. +// Copyright 2010 Flying Meat Inc. All rights reserved. +// + +#import "JSTTests.h" + + +@implementation JSTTests + + +- (BOOL)testBoolValue { + debug(@"%s:%d", __FUNCTION__, __LINE__); + return YES; +} + +- (BOOL)testClassBoolValue { + // this should never be called. + assert(false); +} + ++ (BOOL)testClassBoolValue { + debug(@"%s:%d", __FUNCTION__, __LINE__); + return YES; +} + +- (NSString*)testStringValue { + debug(@"%s:%d", __FUNCTION__, __LINE__); + return @"String from testStringValue"; +} + ++ (NSString*)testClassStringValue { + debug(@"%s:%d", __FUNCTION__, __LINE__); + return @"String from testClassStringValue"; +} + +- (NSString*)testAppendString:(NSString*)string { + debug(@"%s:%d", __FUNCTION__, __LINE__); + return [NSString stringWithFormat:@"String from testAppendString: %@", string]; +} + +- (NSString*)testClassAppendString:(NSString*)string { + debug(@"%s:%d", __FUNCTION__, __LINE__); + return [NSString stringWithFormat:@"String from testClassAppendString: %@", string]; +} + ++ (NSString*)nonBridgedClassMethodReturnString { + debug(@"%s:%d", __FUNCTION__, __LINE__); + return @"String from nonBridgedClassMethodReturnString"; +} + +- (NSString*)nonBridgedInstanceMethodReturnString { + debug(@"%s:%d", __FUNCTION__, __LINE__); + return @"String from nonBridgedInstanceMethodReturnString"; +} + ++ (int)nonBridgedClassMethodReturnInt { + return 34; +} + +- (int)nonBridgedInstanceMethodReturnInt { + return 36; +} + + ++ (int)nonBridgedClassMethodAddIntTo34:(int)val { + return 34 + val; +} + +- (int)nonBridgedInstanceMethodAddIntTo34:(int)val { + return 34 + val; +} + +@end diff --git a/src/JSTUtils.h b/src/JSTUtils.h index 0977893..8138315 100644 --- a/src/JSTUtils.h +++ b/src/JSTUtils.h @@ -11,9 +11,11 @@ #import "JSTBridge.h" #include +void JSTAssignException(JSTBridge *bridge, JSValueRef *exception, NSString *reason); id JSTNSObjectFromValue(JSTBridge *bridge, JSValueRef value); SEL JSTSelectorFromValue(JSTBridge *bridge, JSValueRef value); ffi_type* JSTFFITypeForTypeEncoding(NSString *encoding); int JSTSizeOfTypeEncoding(NSString *encoding); NSString *JSTStringForFFIType(ffi_type* type); ffi_type* JSTFFITypeForBridgeDeclaredType(NSString *type); +JSValueRef JSTMakeJSValueWithFFITypeAndValue(ffi_type *type, ffi_arg value, JSTBridge *bridge); diff --git a/src/JSTUtils.m b/src/JSTUtils.m index 1c5fd81..8916262 100644 --- a/src/JSTUtils.m +++ b/src/JSTUtils.m @@ -9,6 +9,42 @@ #import "JSTUtils.h" +void JSTAssignException(JSTBridge *bridge, JSValueRef *exception, NSString *reason) { + + JSContextRef ctx = [bridge jsContext]; + /* + // Gather call stack + JSValueRef callStackException = nil; + JSStringRef scriptJS = JSStringCreateWithUTF8CString("return dumpCallStack()"); + JSObjectRef fn = JSObjectMakeFunction(ctx, nil, 0, nil, scriptJS, nil, 0, nil); + JSValueRef result = JSObjectCallAsFunction(ctx, fn, nil, 0, nil, &callStackException); + JSStringRelease(scriptJS); + + if (!callStackException) { + + // Convert call stack to string + JSStringRef resultStringJS = JSValueToStringCopy(ctx, result, nil); + NSString* callStack = (NSString*)JSStringCopyCFString(kCFAllocatorDefault, resultStringJS); + JSStringRelease(resultStringJS); + [NSMakeCollectable(callStack) autorelease]; + + // Append call stack to exception + if ([callStack length]) { + reason = [NSString stringWithFormat:@"%@\n%@", reason, callStack]; + } + } + */ + + // Convert exception to string + JSStringRef jsName = JSStringCreateWithUTF8CString([reason UTF8String]); + JSValueRef jsString = JSValueMakeString(ctx, jsName); + JSStringRelease(jsName); + + // Convert to object to allow JavascriptCore to add line and sourceURL + *exception = JSValueToObject(ctx, jsString, nil); +} + + id JSTNSObjectFromValue(JSTBridge *bridge, JSValueRef value) { JSContextRef ctx = [bridge jsContext]; @@ -59,7 +95,6 @@ SEL JSTSelectorFromValue(JSTBridge *bridge, JSValueRef value) { } return nil; - } ffi_type* JSTFFITypeForBridgeDeclaredType(NSString *type) { @@ -227,3 +262,62 @@ int JSTSizeOfTypeEncoding(NSString *encoding) { return @"unknown ffi type"; } + + + +JSValueRef JSTMakeJSValueWithFFITypeAndValue(ffi_type *type, ffi_arg value, JSTBridge *bridge) { + + if (type == &ffi_type_void) { + return JSValueMakeNull([bridge jsContext]); + } + else if (type == &ffi_type_pointer) { + return [bridge makeJSObjectWithNSObject:(id)value runtimeInfo:nil]; + } + else if (type == &ffi_type_float) { + return JSValueMakeNumber([bridge jsContext], (float)value); + } + else if (type == &ffi_type_double) { + return JSValueMakeNumber([bridge jsContext], (double)value); + } + else if (type == &ffi_type_longdouble) { + return JSValueMakeNumber([bridge jsContext], (long double)value); + } + else if (type == &ffi_type_uint8) { + return JSValueMakeNumber([bridge jsContext], (uint8_t)value); + } + else if (type == &ffi_type_sint8) { + // well, it's a bool or a char or a ... hrm. Let's just say it's a bool. + return JSValueMakeBoolean([bridge jsContext], (bool)value); + } + else if (type == &ffi_type_sint32) { + return JSValueMakeNumber([bridge jsContext], (int32_t)value); + } + else if (type == &ffi_type_uint32) { + return JSValueMakeNumber([bridge jsContext], (uint32_t)value); + } + else if (type == &ffi_type_sint16) { + return JSValueMakeNumber([bridge jsContext], (int16_t)value); + } + else if (type == &ffi_type_uint16) { + return JSValueMakeNumber([bridge jsContext], (uint16_t)value); + } + else if (type == &ffi_type_sint64) { + return JSValueMakeNumber([bridge jsContext], (int64_t)value); + } + else if (type == &ffi_type_uint64) { + return JSValueMakeNumber([bridge jsContext], (uint64_t)value); + } + + return 0x00; +} + + + + + + + + + + + diff --git a/src/JSTalk.h b/src/JSTalk.h index 017008e..eea1208 100644 --- a/src/JSTalk.h +++ b/src/JSTalk.h @@ -24,7 +24,7 @@ @property (retain) JSTBridge *bridge; @property (retain) NSMutableDictionary *env; -- (id)executeString:(NSString*) str; +- (id)executeString:(NSString*)str; //- (void)pushObject:(id)obj withName:(NSString*)name; - (void)deleteObjectWithName:(NSString*)name; diff --git a/src/JSTalk.m b/src/JSTalk.m index 471b487..8df311b 100644 --- a/src/JSTalk.m +++ b/src/JSTalk.m @@ -206,7 +206,7 @@ - (void)deleteObjectWithName:(NSString*)name { } -- (id)executeString:(NSString*) str { +- (id)executeString:(NSString*)str { if (!JSTalkPluginList && JSTalkShouldLoadJSTPlugins) { [self loadPlugins]; @@ -290,7 +290,7 @@ - (void)include:(NSString*)fileName { str = [JSTPreprocessor preprocessCode:str]; - if (![[self jsController] evalJSString:str withScriptPath:[scriptURL path]]) { + if (![_bridge evalJSString:str withPath:[scriptURL path]]) { NSLog(@"Could not include '%@'", fileName); } } diff --git a/tests/B.jstalk b/tests/B.jstalk index 2070e5d..178e35d 100644 --- a/tests/B.jstalk +++ b/tests/B.jstalk @@ -1,27 +1,41 @@ -var b = [JSTClosure testClassBoolValue]; +[jstalk include:"testsetup.jstalk"]; -if (b) { - print("\nHurray motherfucker!\n\n"); -} +var ti = [[JSTTests alloc] init]; -//b = [[JSTClosure alloc] init]; +jsassert([ti testBoolValue], "[ti testBoolValue] failed"); +jsassert([JSTTests testClassBoolValue], "[JSTTests testClassBoolValue] failed"); -/* -var b = [[[JSTClosure alloc] init] testBoolValue]; -var b = [JSTClosure testBoolValue]; -var b = [JSTClosure testBoolValue]; -*/ -//var s = [NSString string]; +jsassert([ti testStringValue] == "String from testStringValue", "[ti testStringValue] failed"); + +jsassert([JSTTests nonBridgedClassMethodReturnString] == "String from nonBridgedClassMethodReturnString", + "[JSTTests nonBridgedClassMethodReturnString] failed"); + +jsassert([ti nonBridgedInstanceMethodReturnString] == "String from nonBridgedInstanceMethodReturnString", + "[ti nonBridgedInstanceMethodReturnString] failed"); + + +var name = NSFullUserName(); +jsassert(name, "NSFullUserName failed"); +jsassert((name + "").toLowerCase() == [name lowercaseString], "Lowercase stuff failed"); + + +jsassert(([JSTTests nonBridgedClassMethodReturnInt] == 34), "nonBridgedClassMethodReturnInt failed"); +jsassert(([ti nonBridgedInstanceMethodReturnInt] == 36), "nonBridgedInstanceMethodReturnInt failed"); + +jsassert(([JSTTests nonBridgedClassMethodAddIntTo34:2] == 36), "nonBridgedClassMethodAddIntTo34 failed"); + +jsassert(([ti nonBridgedInstanceMethodAddIntTo34:4] == 36), "nonBridgedInstanceMethodAddIntTo34 failed"); + +var nilValue = nil; +jsassert(!nilValue, "nilValue is not nil"); -/* -var nilValue = nil; var randomConst = NSBundleDidLoadNotification; -var boolVal = NSZombieEnabled; -var enumVal = NSMinYEdge; -var ri = [[[JSTRuntimeInfo alloc] init] autorelease]; +jsassert(randomConst == "NSBundleDidLoadNotification", "Can't find the NSBundleDidLoadNotification const"); + +var boolVal = NSZombieEnabled; +jsassert(!boolVal, "Why would NSZombieEnabled be enabled?"); -print(s); -print(ri); +jsassert(NSMinYEdge == 1, "Can't find NSMinYEdge"); +jsassert(CGRectMinYEdge == 1, "Can't find NSMinYEdge"); -[jstalk print:s]; -*/ \ No newline at end of file +//print("Done with " + [jstalk env]); \ No newline at end of file