From 76ed3e74255fd95bd286d896a513657d356edf42 Mon Sep 17 00:00:00 2001 From: Tim Burks Date: Sun, 24 Apr 2016 16:09:04 -0700 Subject: [PATCH 01/26] Fix missing rootViewController in iOS demo app. --- Xcode/NuApp/NuAppDelegate.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Xcode/NuApp/NuAppDelegate.m b/Xcode/NuApp/NuAppDelegate.m index 15685a9..3d737b7 100644 --- a/Xcode/NuApp/NuAppDelegate.m +++ b/Xcode/NuApp/NuAppDelegate.m @@ -17,6 +17,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( { self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; self.window.backgroundColor = [UIColor greenColor]; + self.window.rootViewController = [[UIViewController alloc] init]; [self.window makeKeyAndVisible]; NuInit(); From 29d5c137643414eaec3eff071b1330f53ad3bed9 Mon Sep 17 00:00:00 2001 From: Tim Burks Date: Sun, 24 Apr 2016 20:16:57 -0700 Subject: [PATCH 02/26] Expand major classes and categories into separate files. --- Xcode/Nu.xcodeproj/project.pbxproj | 362 + objc/NSArray+Nu.h | 55 + objc/NSArray+Nu.m | 163 + objc/NSBundle+Nu.h | 20 + objc/NSBundle+Nu.m | 73 + objc/NSData+Nu.h | 34 + objc/NSData+Nu.m | 78 + objc/NSDate+Nu.h | 13 + objc/NSDate+Nu.m | 20 + objc/NSDictionary+Nu.h | 39 + objc/NSDictionary+Nu.m | 139 + objc/NSFileManager+Nu.h | 24 + objc/NSFileManager+Nu.m | 81 + objc/NSMethodSignature+Nu.h | 19 + objc/NSMethodSignature+Nu.m | 26 + objc/NSNull+Nu.h | 25 + objc/NSNull+Nu.m | 50 + objc/NSNumber+Nu.h | 34 + objc/NSNumber+Nu.m | 112 + objc/NSObject+Nu.h | 98 + objc/NSObject+Nu.m | 700 ++ objc/NSSet+Nu.h | 31 + objc/NSSet+Nu.m | 57 + objc/NSString+Nu.h | 67 + objc/NSString+Nu.m | 251 + objc/Nu.h | 1242 +-- objc/Nu.m | 11169 +-------------------------- objc/NuBlock.h | 58 + objc/NuBlock.m | 257 + objc/NuBridge.h | 142 + objc/NuBridge.m | 2096 +++++ objc/NuCell.h | 91 + objc/NuCell.m | 538 ++ objc/NuClass.h | 67 + objc/NuClass.m | 289 + objc/NuEnumerable.h | 41 + objc/NuEnumerable.m | 228 + objc/NuException.h | 55 + objc/NuException.m | 201 + objc/NuHandler.h | 35 + objc/NuHandler.m | 284 + objc/NuInternals.h | 149 + objc/NuMacro.h | 105 + objc/NuMacro.m | 635 ++ objc/NuMarkupOperator.h | 36 + objc/NuMarkupOperator.m | 207 + objc/NuMath.h | 43 + objc/NuMath.m | 52 + objc/NuMethod.h | 41 + objc/NuMethod.m | 105 + objc/NuObjCRuntime.h | 10 + objc/NuObjCRuntime.m | 136 + objc/NuOperators.h | 34 + objc/NuOperators.m | 2395 ++++++ objc/NuParser.h | 58 + objc/NuParser.m | 1098 +++ objc/NuPointer.h | 35 + objc/NuPointer.m | 90 + objc/NuProfiler.h | 15 + objc/NuProfiler.m | 142 + objc/NuProperty.h | 25 + objc/NuProperty.m | 39 + objc/NuReference.h | 43 + objc/NuReference.m | 76 + objc/NuRegex.h | 92 + objc/NuRegex.m | 172 + objc/NuStack.h | 25 + objc/NuStack.m | 72 + objc/NuSuper.h | 36 + objc/NuSuper.m | 80 + objc/NuSwizzles.h | 9 + objc/NuSwizzles.m | 80 + objc/NuSymbol.h | 64 + objc/NuSymbol.m | 289 + objc/NuTestHelper.h | 13 + objc/NuTestHelper.m | 150 + 76 files changed, 13622 insertions(+), 12393 deletions(-) create mode 100644 objc/NSArray+Nu.h create mode 100644 objc/NSArray+Nu.m create mode 100644 objc/NSBundle+Nu.h create mode 100644 objc/NSBundle+Nu.m create mode 100644 objc/NSData+Nu.h create mode 100644 objc/NSData+Nu.m create mode 100644 objc/NSDate+Nu.h create mode 100644 objc/NSDate+Nu.m create mode 100644 objc/NSDictionary+Nu.h create mode 100644 objc/NSDictionary+Nu.m create mode 100644 objc/NSFileManager+Nu.h create mode 100644 objc/NSFileManager+Nu.m create mode 100644 objc/NSMethodSignature+Nu.h create mode 100644 objc/NSMethodSignature+Nu.m create mode 100644 objc/NSNull+Nu.h create mode 100644 objc/NSNull+Nu.m create mode 100644 objc/NSNumber+Nu.h create mode 100644 objc/NSNumber+Nu.m create mode 100644 objc/NSObject+Nu.h create mode 100644 objc/NSObject+Nu.m create mode 100644 objc/NSSet+Nu.h create mode 100644 objc/NSSet+Nu.m create mode 100644 objc/NSString+Nu.h create mode 100644 objc/NSString+Nu.m create mode 100644 objc/NuBlock.h create mode 100644 objc/NuBlock.m create mode 100644 objc/NuBridge.h create mode 100644 objc/NuBridge.m create mode 100644 objc/NuCell.h create mode 100644 objc/NuCell.m create mode 100644 objc/NuClass.h create mode 100644 objc/NuClass.m create mode 100644 objc/NuEnumerable.h create mode 100644 objc/NuEnumerable.m create mode 100644 objc/NuException.h create mode 100644 objc/NuException.m create mode 100644 objc/NuHandler.h create mode 100644 objc/NuHandler.m create mode 100644 objc/NuInternals.h create mode 100644 objc/NuMacro.h create mode 100644 objc/NuMacro.m create mode 100644 objc/NuMarkupOperator.h create mode 100644 objc/NuMarkupOperator.m create mode 100644 objc/NuMath.h create mode 100644 objc/NuMath.m create mode 100644 objc/NuMethod.h create mode 100644 objc/NuMethod.m create mode 100644 objc/NuObjCRuntime.h create mode 100644 objc/NuObjCRuntime.m create mode 100644 objc/NuOperators.h create mode 100644 objc/NuOperators.m create mode 100644 objc/NuParser.h create mode 100644 objc/NuParser.m create mode 100644 objc/NuPointer.h create mode 100644 objc/NuPointer.m create mode 100644 objc/NuProfiler.h create mode 100644 objc/NuProfiler.m create mode 100644 objc/NuProperty.h create mode 100644 objc/NuProperty.m create mode 100644 objc/NuReference.h create mode 100644 objc/NuReference.m create mode 100644 objc/NuRegex.h create mode 100644 objc/NuRegex.m create mode 100644 objc/NuStack.h create mode 100644 objc/NuStack.m create mode 100644 objc/NuSuper.h create mode 100644 objc/NuSuper.m create mode 100644 objc/NuSwizzles.h create mode 100644 objc/NuSwizzles.m create mode 100644 objc/NuSymbol.h create mode 100644 objc/NuSymbol.m create mode 100644 objc/NuTestHelper.h create mode 100644 objc/NuTestHelper.m diff --git a/Xcode/Nu.xcodeproj/project.pbxproj b/Xcode/Nu.xcodeproj/project.pbxproj index 1565bbb..d3c1ee1 100644 --- a/Xcode/Nu.xcodeproj/project.pbxproj +++ b/Xcode/Nu.xcodeproj/project.pbxproj @@ -7,6 +7,114 @@ objects = { /* Begin PBXBuildFile section */ + 2217EBB81CCD89E60082837B /* NuMarkupOperator.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBB61CCD89E60082837B /* NuMarkupOperator.h */; }; + 2217EBB91CCD89E60082837B /* NuMarkupOperator.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBB71CCD89E60082837B /* NuMarkupOperator.m */; }; + 2217EBBA1CCD8AAC0082837B /* NuMarkupOperator.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBB71CCD89E60082837B /* NuMarkupOperator.m */; }; + 2217EBBE1CCD8BDF0082837B /* NuSymbol.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBBC1CCD8BDF0082837B /* NuSymbol.h */; }; + 2217EBBF1CCD8BDF0082837B /* NuSymbol.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBBD1CCD8BDF0082837B /* NuSymbol.m */; }; + 2217EBC01CCD8BDF0082837B /* NuSymbol.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBBD1CCD8BDF0082837B /* NuSymbol.m */; }; + 2217EBC31CCD8CE30082837B /* NuTestHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBC11CCD8CE30082837B /* NuTestHelper.h */; }; + 2217EBC41CCD8CE30082837B /* NuTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBC21CCD8CE30082837B /* NuTestHelper.m */; }; + 2217EBC51CCD8CE30082837B /* NuTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBC21CCD8CE30082837B /* NuTestHelper.m */; }; + 2217EBC81CCD8DF00082837B /* NuSwizzles.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBC61CCD8DF00082837B /* NuSwizzles.h */; }; + 2217EBC91CCD8DF00082837B /* NuSwizzles.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBC71CCD8DF00082837B /* NuSwizzles.m */; }; + 2217EBCA1CCD8DF00082837B /* NuSwizzles.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBC71CCD8DF00082837B /* NuSwizzles.m */; }; + 2217EBCD1CCD8E760082837B /* NuSuper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBCB1CCD8E760082837B /* NuSuper.h */; }; + 2217EBCE1CCD8E760082837B /* NuSuper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBCC1CCD8E760082837B /* NuSuper.m */; }; + 2217EBCF1CCD8E760082837B /* NuSuper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBCC1CCD8E760082837B /* NuSuper.m */; }; + 2217EBD21CCD8F960082837B /* NuStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBD01CCD8F960082837B /* NuStack.h */; }; + 2217EBD31CCD8F960082837B /* NuStack.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBD11CCD8F960082837B /* NuStack.m */; }; + 2217EBD41CCD8F960082837B /* NuStack.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBD11CCD8F960082837B /* NuStack.m */; }; + 2217EBD71CCD90310082837B /* NuParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBD51CCD90310082837B /* NuParser.h */; }; + 2217EBD81CCD90310082837B /* NuParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBD61CCD90310082837B /* NuParser.m */; }; + 2217EBD91CCD90310082837B /* NuParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBD61CCD90310082837B /* NuParser.m */; }; + 2217EBDC1CCD915B0082837B /* NuRegex.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBDA1CCD915B0082837B /* NuRegex.h */; }; + 2217EBDD1CCD915B0082837B /* NuRegex.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBDB1CCD915B0082837B /* NuRegex.m */; }; + 2217EBDE1CCD915B0082837B /* NuRegex.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBDB1CCD915B0082837B /* NuRegex.m */; }; + 2217EBE11CCD921B0082837B /* NuReference.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBDF1CCD921B0082837B /* NuReference.h */; }; + 2217EBE21CCD921B0082837B /* NuReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBE01CCD921B0082837B /* NuReference.m */; }; + 2217EBE31CCD921B0082837B /* NuReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBE01CCD921B0082837B /* NuReference.m */; }; + 2217EBE61CCD92AC0082837B /* NuProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBE41CCD92AC0082837B /* NuProperty.h */; }; + 2217EBE71CCD92AC0082837B /* NuProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBE51CCD92AC0082837B /* NuProperty.m */; }; + 2217EBE81CCD92AC0082837B /* NuProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBE51CCD92AC0082837B /* NuProperty.m */; }; + 2217EBEB1CCD9DFE0082837B /* NuProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBE91CCD9DFE0082837B /* NuProfiler.h */; }; + 2217EBEC1CCD9DFE0082837B /* NuProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBEA1CCD9DFE0082837B /* NuProfiler.m */; }; + 2217EBED1CCD9DFE0082837B /* NuProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBEA1CCD9DFE0082837B /* NuProfiler.m */; }; + 2217EBF01CCD9E7F0082837B /* NuPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBEE1CCD9E7F0082837B /* NuPointer.h */; }; + 2217EBF11CCD9E7F0082837B /* NuPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBEF1CCD9E7F0082837B /* NuPointer.m */; }; + 2217EBF21CCD9E7F0082837B /* NuPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBEF1CCD9E7F0082837B /* NuPointer.m */; }; + 2217EBF51CCDA0420082837B /* NuOperators.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBF31CCDA0420082837B /* NuOperators.h */; }; + 2217EBF61CCDA0420082837B /* NuOperators.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBF41CCDA0420082837B /* NuOperators.m */; }; + 2217EBF71CCDA0420082837B /* NuOperators.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBF41CCDA0420082837B /* NuOperators.m */; }; + 2217EBFA1CCDA27A0082837B /* NSObject+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBF81CCDA27A0082837B /* NSObject+Nu.h */; }; + 2217EBFB1CCDA27A0082837B /* NSObject+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBF91CCDA27A0082837B /* NSObject+Nu.m */; }; + 2217EBFC1CCDA27A0082837B /* NSObject+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBF91CCDA27A0082837B /* NSObject+Nu.m */; }; + 2217EBFF1CCDA3300082837B /* NuObjCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBFD1CCDA3300082837B /* NuObjCRuntime.h */; }; + 2217EC001CCDA3300082837B /* NuObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBFE1CCDA3300082837B /* NuObjCRuntime.m */; }; + 2217EC011CCDA3300082837B /* NuObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBFE1CCDA3300082837B /* NuObjCRuntime.m */; }; + 2217EC041CCDA3870082837B /* NuMethod.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC021CCDA3870082837B /* NuMethod.h */; }; + 2217EC051CCDA3870082837B /* NuMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC031CCDA3870082837B /* NuMethod.m */; }; + 2217EC061CCDA3870082837B /* NuMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC031CCDA3870082837B /* NuMethod.m */; }; + 2217EC091CCDA4990082837B /* NuMacro.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC071CCDA4990082837B /* NuMacro.h */; }; + 2217EC0A1CCDA4990082837B /* NuMacro.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC081CCDA4990082837B /* NuMacro.m */; }; + 2217EC0B1CCDA4990082837B /* NuMacro.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC081CCDA4990082837B /* NuMacro.m */; }; + 2217EC0E1CCDA5390082837B /* NuHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC0C1CCDA5390082837B /* NuHandler.h */; }; + 2217EC0F1CCDA5390082837B /* NuHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC0D1CCDA5390082837B /* NuHandler.m */; }; + 2217EC101CCDA5390082837B /* NuHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC0D1CCDA5390082837B /* NuHandler.m */; }; + 2217EC131CCDA65F0082837B /* NuBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC111CCDA65F0082837B /* NuBlock.h */; }; + 2217EC141CCDA65F0082837B /* NuBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC121CCDA65F0082837B /* NuBlock.m */; }; + 2217EC151CCDA65F0082837B /* NuBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC121CCDA65F0082837B /* NuBlock.m */; }; + 2217EC181CCDA7350082837B /* NuCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC161CCDA7350082837B /* NuCell.h */; }; + 2217EC191CCDA7350082837B /* NuCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC171CCDA7350082837B /* NuCell.m */; }; + 2217EC1A1CCDA7350082837B /* NuCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC171CCDA7350082837B /* NuCell.m */; }; + 2217EC1D1CCDA8340082837B /* NuClass.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC1B1CCDA8340082837B /* NuClass.h */; }; + 2217EC1E1CCDA8340082837B /* NuClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC1C1CCDA8340082837B /* NuClass.m */; }; + 2217EC1F1CCDA8340082837B /* NuClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC1C1CCDA8340082837B /* NuClass.m */; }; + 2217EC221CCDA9A00082837B /* NuMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC201CCDA9A00082837B /* NuMath.h */; }; + 2217EC231CCDA9A00082837B /* NuMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC211CCDA9A00082837B /* NuMath.m */; }; + 2217EC241CCDA9A00082837B /* NuMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC211CCDA9A00082837B /* NuMath.m */; }; + 2217EC271CCDAA850082837B /* NSString+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC251CCDAA850082837B /* NSString+Nu.h */; }; + 2217EC281CCDAA850082837B /* NSString+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC261CCDAA850082837B /* NSString+Nu.m */; }; + 2217EC291CCDAA850082837B /* NSString+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC261CCDAA850082837B /* NSString+Nu.m */; }; + 2217EC2C1CCDAB700082837B /* NSDictionary+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC2A1CCDAB700082837B /* NSDictionary+Nu.h */; }; + 2217EC2D1CCDAB700082837B /* NSDictionary+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC2B1CCDAB700082837B /* NSDictionary+Nu.m */; }; + 2217EC2E1CCDAB700082837B /* NSDictionary+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC2B1CCDAB700082837B /* NSDictionary+Nu.m */; }; + 2217EC311CCDAC600082837B /* NSBundle+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC2F1CCDAC600082837B /* NSBundle+Nu.h */; }; + 2217EC321CCDAC600082837B /* NSBundle+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC301CCDAC600082837B /* NSBundle+Nu.m */; }; + 2217EC331CCDAC600082837B /* NSBundle+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC301CCDAC600082837B /* NSBundle+Nu.m */; }; + 2217EC361CCDAD3B0082837B /* NuEnumerable.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC341CCDAD3B0082837B /* NuEnumerable.h */; }; + 2217EC371CCDAD3B0082837B /* NuEnumerable.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC351CCDAD3B0082837B /* NuEnumerable.m */; }; + 2217EC381CCDAD3B0082837B /* NuEnumerable.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC351CCDAD3B0082837B /* NuEnumerable.m */; }; + 2217EC3B1CCDAE010082837B /* NuException.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC391CCDAE010082837B /* NuException.h */; }; + 2217EC3C1CCDAE010082837B /* NuException.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC3A1CCDAE010082837B /* NuException.m */; }; + 2217EC3D1CCDAE010082837B /* NuException.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC3A1CCDAE010082837B /* NuException.m */; }; + 2217EC401CCDAED00082837B /* NSArray+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC3E1CCDAED00082837B /* NSArray+Nu.h */; }; + 2217EC411CCDAED00082837B /* NSArray+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC3F1CCDAED00082837B /* NSArray+Nu.m */; }; + 2217EC421CCDAED00082837B /* NSArray+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC3F1CCDAED00082837B /* NSArray+Nu.m */; }; + 2217EC451CCDAF2A0082837B /* NSSet+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC431CCDAF2A0082837B /* NSSet+Nu.h */; }; + 2217EC461CCDAF2A0082837B /* NSSet+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC441CCDAF2A0082837B /* NSSet+Nu.m */; }; + 2217EC471CCDAF2A0082837B /* NSSet+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC441CCDAF2A0082837B /* NSSet+Nu.m */; }; + 2217EC4A1CCDAFE00082837B /* NSNull+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC481CCDAFE00082837B /* NSNull+Nu.h */; }; + 2217EC4B1CCDAFE00082837B /* NSNull+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC491CCDAFE00082837B /* NSNull+Nu.m */; }; + 2217EC4C1CCDAFE00082837B /* NSNull+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC491CCDAFE00082837B /* NSNull+Nu.m */; }; + 2217EC4F1CCDB0770082837B /* NSNumber+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC4D1CCDB0770082837B /* NSNumber+Nu.h */; }; + 2217EC501CCDB0770082837B /* NSNumber+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC4E1CCDB0770082837B /* NSNumber+Nu.m */; }; + 2217EC511CCDB0770082837B /* NSNumber+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC4E1CCDB0770082837B /* NSNumber+Nu.m */; }; + 2217EC541CCDB0D40082837B /* NSData+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC521CCDB0D40082837B /* NSData+Nu.h */; }; + 2217EC551CCDB0D40082837B /* NSData+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC531CCDB0D40082837B /* NSData+Nu.m */; }; + 2217EC561CCDB0D40082837B /* NSData+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC531CCDB0D40082837B /* NSData+Nu.m */; }; + 2217EC591CCDB1240082837B /* NSDate+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC571CCDB1240082837B /* NSDate+Nu.h */; }; + 2217EC5A1CCDB1240082837B /* NSDate+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC581CCDB1240082837B /* NSDate+Nu.m */; }; + 2217EC5B1CCDB1240082837B /* NSDate+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC581CCDB1240082837B /* NSDate+Nu.m */; }; + 2217EC5E1CCDB19C0082837B /* NSFileManager+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC5C1CCDB19C0082837B /* NSFileManager+Nu.h */; }; + 2217EC5F1CCDB19C0082837B /* NSFileManager+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC5D1CCDB19C0082837B /* NSFileManager+Nu.m */; }; + 2217EC601CCDB19C0082837B /* NSFileManager+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC5D1CCDB19C0082837B /* NSFileManager+Nu.m */; }; + 2217EC631CCDB2610082837B /* NSMethodSignature+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC611CCDB2610082837B /* NSMethodSignature+Nu.h */; }; + 2217EC641CCDB2610082837B /* NSMethodSignature+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC621CCDB2610082837B /* NSMethodSignature+Nu.m */; }; + 2217EC651CCDB2610082837B /* NSMethodSignature+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC621CCDB2610082837B /* NSMethodSignature+Nu.m */; }; + 2217EC681CCDBF390082837B /* NuBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC661CCDBF390082837B /* NuBridge.h */; }; + 2217EC691CCDBF390082837B /* NuBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC671CCDBF390082837B /* NuBridge.m */; }; + 2217EC6A1CCDBF390082837B /* NuBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC671CCDBF390082837B /* NuBridge.m */; }; 225F62CD13B04256002DD16B /* ffi.S in Sources */ = {isa = PBXBuildFile; fileRef = 225F62C413B04256002DD16B /* ffi.S */; }; 225F62D313B04256002DD16B /* ffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 225F62CA13B04256002DD16B /* ffi.c */; }; 2283074411DDBEA700A5C690 /* Nu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Nu.framework */; }; @@ -115,6 +223,79 @@ /* Begin PBXFileReference section */ 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 2217EBB61CCD89E60082837B /* NuMarkupOperator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuMarkupOperator.h; sourceTree = ""; }; + 2217EBB71CCD89E60082837B /* NuMarkupOperator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuMarkupOperator.m; sourceTree = ""; }; + 2217EBBB1CCD8AF30082837B /* NuInternals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NuInternals.h; sourceTree = ""; }; + 2217EBBC1CCD8BDF0082837B /* NuSymbol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuSymbol.h; sourceTree = ""; }; + 2217EBBD1CCD8BDF0082837B /* NuSymbol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuSymbol.m; sourceTree = ""; }; + 2217EBC11CCD8CE30082837B /* NuTestHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuTestHelper.h; sourceTree = ""; }; + 2217EBC21CCD8CE30082837B /* NuTestHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuTestHelper.m; sourceTree = ""; }; + 2217EBC61CCD8DF00082837B /* NuSwizzles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuSwizzles.h; sourceTree = ""; }; + 2217EBC71CCD8DF00082837B /* NuSwizzles.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuSwizzles.m; sourceTree = ""; }; + 2217EBCB1CCD8E760082837B /* NuSuper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuSuper.h; sourceTree = ""; }; + 2217EBCC1CCD8E760082837B /* NuSuper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuSuper.m; sourceTree = ""; }; + 2217EBD01CCD8F960082837B /* NuStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuStack.h; sourceTree = ""; }; + 2217EBD11CCD8F960082837B /* NuStack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuStack.m; sourceTree = ""; }; + 2217EBD51CCD90310082837B /* NuParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuParser.h; sourceTree = ""; }; + 2217EBD61CCD90310082837B /* NuParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuParser.m; sourceTree = ""; }; + 2217EBDA1CCD915B0082837B /* NuRegex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuRegex.h; sourceTree = ""; }; + 2217EBDB1CCD915B0082837B /* NuRegex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuRegex.m; sourceTree = ""; }; + 2217EBDF1CCD921B0082837B /* NuReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuReference.h; sourceTree = ""; }; + 2217EBE01CCD921B0082837B /* NuReference.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuReference.m; sourceTree = ""; }; + 2217EBE41CCD92AC0082837B /* NuProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuProperty.h; sourceTree = ""; }; + 2217EBE51CCD92AC0082837B /* NuProperty.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuProperty.m; sourceTree = ""; }; + 2217EBE91CCD9DFE0082837B /* NuProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuProfiler.h; sourceTree = ""; }; + 2217EBEA1CCD9DFE0082837B /* NuProfiler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuProfiler.m; sourceTree = ""; }; + 2217EBEE1CCD9E7F0082837B /* NuPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuPointer.h; sourceTree = ""; }; + 2217EBEF1CCD9E7F0082837B /* NuPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuPointer.m; sourceTree = ""; }; + 2217EBF31CCDA0420082837B /* NuOperators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuOperators.h; sourceTree = ""; }; + 2217EBF41CCDA0420082837B /* NuOperators.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuOperators.m; sourceTree = ""; }; + 2217EBF81CCDA27A0082837B /* NSObject+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+Nu.h"; sourceTree = ""; }; + 2217EBF91CCDA27A0082837B /* NSObject+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Nu.m"; sourceTree = ""; }; + 2217EBFD1CCDA3300082837B /* NuObjCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuObjCRuntime.h; sourceTree = ""; }; + 2217EBFE1CCDA3300082837B /* NuObjCRuntime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuObjCRuntime.m; sourceTree = ""; }; + 2217EC021CCDA3870082837B /* NuMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuMethod.h; sourceTree = ""; }; + 2217EC031CCDA3870082837B /* NuMethod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuMethod.m; sourceTree = ""; }; + 2217EC071CCDA4990082837B /* NuMacro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuMacro.h; sourceTree = ""; }; + 2217EC081CCDA4990082837B /* NuMacro.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuMacro.m; sourceTree = ""; }; + 2217EC0C1CCDA5390082837B /* NuHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuHandler.h; sourceTree = ""; }; + 2217EC0D1CCDA5390082837B /* NuHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuHandler.m; sourceTree = ""; }; + 2217EC111CCDA65F0082837B /* NuBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuBlock.h; sourceTree = ""; }; + 2217EC121CCDA65F0082837B /* NuBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuBlock.m; sourceTree = ""; }; + 2217EC161CCDA7350082837B /* NuCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuCell.h; sourceTree = ""; }; + 2217EC171CCDA7350082837B /* NuCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuCell.m; sourceTree = ""; }; + 2217EC1B1CCDA8340082837B /* NuClass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuClass.h; sourceTree = ""; }; + 2217EC1C1CCDA8340082837B /* NuClass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuClass.m; sourceTree = ""; }; + 2217EC201CCDA9A00082837B /* NuMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuMath.h; sourceTree = ""; }; + 2217EC211CCDA9A00082837B /* NuMath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuMath.m; sourceTree = ""; }; + 2217EC251CCDAA850082837B /* NSString+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+Nu.h"; sourceTree = ""; }; + 2217EC261CCDAA850082837B /* NSString+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+Nu.m"; sourceTree = ""; }; + 2217EC2A1CCDAB700082837B /* NSDictionary+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Nu.h"; sourceTree = ""; }; + 2217EC2B1CCDAB700082837B /* NSDictionary+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Nu.m"; sourceTree = ""; }; + 2217EC2F1CCDAC600082837B /* NSBundle+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+Nu.h"; sourceTree = ""; }; + 2217EC301CCDAC600082837B /* NSBundle+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+Nu.m"; sourceTree = ""; }; + 2217EC341CCDAD3B0082837B /* NuEnumerable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuEnumerable.h; sourceTree = ""; }; + 2217EC351CCDAD3B0082837B /* NuEnumerable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuEnumerable.m; sourceTree = ""; }; + 2217EC391CCDAE010082837B /* NuException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuException.h; sourceTree = ""; }; + 2217EC3A1CCDAE010082837B /* NuException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuException.m; sourceTree = ""; }; + 2217EC3E1CCDAED00082837B /* NSArray+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+Nu.h"; sourceTree = ""; }; + 2217EC3F1CCDAED00082837B /* NSArray+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+Nu.m"; sourceTree = ""; }; + 2217EC431CCDAF2A0082837B /* NSSet+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSSet+Nu.h"; sourceTree = ""; }; + 2217EC441CCDAF2A0082837B /* NSSet+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSSet+Nu.m"; sourceTree = ""; }; + 2217EC481CCDAFE00082837B /* NSNull+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNull+Nu.h"; sourceTree = ""; }; + 2217EC491CCDAFE00082837B /* NSNull+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSNull+Nu.m"; sourceTree = ""; }; + 2217EC4D1CCDB0770082837B /* NSNumber+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNumber+Nu.h"; sourceTree = ""; }; + 2217EC4E1CCDB0770082837B /* NSNumber+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSNumber+Nu.m"; sourceTree = ""; }; + 2217EC521CCDB0D40082837B /* NSData+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Nu.h"; sourceTree = ""; }; + 2217EC531CCDB0D40082837B /* NSData+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Nu.m"; sourceTree = ""; }; + 2217EC571CCDB1240082837B /* NSDate+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+Nu.h"; sourceTree = ""; }; + 2217EC581CCDB1240082837B /* NSDate+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+Nu.m"; sourceTree = ""; }; + 2217EC5C1CCDB19C0082837B /* NSFileManager+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSFileManager+Nu.h"; sourceTree = ""; }; + 2217EC5D1CCDB19C0082837B /* NSFileManager+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSFileManager+Nu.m"; sourceTree = ""; }; + 2217EC611CCDB2610082837B /* NSMethodSignature+Nu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMethodSignature+Nu.h"; sourceTree = ""; }; + 2217EC621CCDB2610082837B /* NSMethodSignature+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMethodSignature+Nu.m"; sourceTree = ""; }; + 2217EC661CCDBF390082837B /* NuBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuBridge.h; sourceTree = ""; }; + 2217EC671CCDBF390082837B /* NuBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuBridge.m; sourceTree = ""; }; 225F62BE13B04256002DD16B /* ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi.h; sourceTree = ""; }; 225F62C413B04256002DD16B /* ffi.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = ffi.S; sourceTree = ""; }; 225F62CA13B04256002DD16B /* ffi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi.c; sourceTree = ""; }; @@ -384,8 +565,81 @@ 22B3B41C13B0359300B3AB31 /* objc */ = { isa = PBXGroup; children = ( + 2217EC3E1CCDAED00082837B /* NSArray+Nu.h */, + 2217EC3F1CCDAED00082837B /* NSArray+Nu.m */, + 2217EC2F1CCDAC600082837B /* NSBundle+Nu.h */, + 2217EC301CCDAC600082837B /* NSBundle+Nu.m */, + 2217EC521CCDB0D40082837B /* NSData+Nu.h */, + 2217EC531CCDB0D40082837B /* NSData+Nu.m */, + 2217EC571CCDB1240082837B /* NSDate+Nu.h */, + 2217EC581CCDB1240082837B /* NSDate+Nu.m */, + 2217EC2A1CCDAB700082837B /* NSDictionary+Nu.h */, + 2217EC2B1CCDAB700082837B /* NSDictionary+Nu.m */, + 2217EC5C1CCDB19C0082837B /* NSFileManager+Nu.h */, + 2217EC5D1CCDB19C0082837B /* NSFileManager+Nu.m */, + 2217EC611CCDB2610082837B /* NSMethodSignature+Nu.h */, + 2217EC621CCDB2610082837B /* NSMethodSignature+Nu.m */, + 2217EC481CCDAFE00082837B /* NSNull+Nu.h */, + 2217EC491CCDAFE00082837B /* NSNull+Nu.m */, + 2217EC4D1CCDB0770082837B /* NSNumber+Nu.h */, + 2217EC4E1CCDB0770082837B /* NSNumber+Nu.m */, + 2217EBF81CCDA27A0082837B /* NSObject+Nu.h */, + 2217EBF91CCDA27A0082837B /* NSObject+Nu.m */, + 2217EC431CCDAF2A0082837B /* NSSet+Nu.h */, + 2217EC441CCDAF2A0082837B /* NSSet+Nu.m */, + 2217EC251CCDAA850082837B /* NSString+Nu.h */, + 2217EC261CCDAA850082837B /* NSString+Nu.m */, 229FABE113C0129400CEFCF5 /* Nu.h */, 22B3B41D13B0359300B3AB31 /* Nu.m */, + 2217EC111CCDA65F0082837B /* NuBlock.h */, + 2217EC121CCDA65F0082837B /* NuBlock.m */, + 2217EC661CCDBF390082837B /* NuBridge.h */, + 2217EC671CCDBF390082837B /* NuBridge.m */, + 2217EC161CCDA7350082837B /* NuCell.h */, + 2217EC171CCDA7350082837B /* NuCell.m */, + 2217EC1B1CCDA8340082837B /* NuClass.h */, + 2217EC1C1CCDA8340082837B /* NuClass.m */, + 2217EC341CCDAD3B0082837B /* NuEnumerable.h */, + 2217EC351CCDAD3B0082837B /* NuEnumerable.m */, + 2217EC391CCDAE010082837B /* NuException.h */, + 2217EC3A1CCDAE010082837B /* NuException.m */, + 2217EC0C1CCDA5390082837B /* NuHandler.h */, + 2217EC0D1CCDA5390082837B /* NuHandler.m */, + 2217EBBB1CCD8AF30082837B /* NuInternals.h */, + 2217EC071CCDA4990082837B /* NuMacro.h */, + 2217EC081CCDA4990082837B /* NuMacro.m */, + 2217EBB61CCD89E60082837B /* NuMarkupOperator.h */, + 2217EBB71CCD89E60082837B /* NuMarkupOperator.m */, + 2217EC201CCDA9A00082837B /* NuMath.h */, + 2217EC211CCDA9A00082837B /* NuMath.m */, + 2217EC021CCDA3870082837B /* NuMethod.h */, + 2217EC031CCDA3870082837B /* NuMethod.m */, + 2217EBFD1CCDA3300082837B /* NuObjCRuntime.h */, + 2217EBFE1CCDA3300082837B /* NuObjCRuntime.m */, + 2217EBF31CCDA0420082837B /* NuOperators.h */, + 2217EBF41CCDA0420082837B /* NuOperators.m */, + 2217EBD51CCD90310082837B /* NuParser.h */, + 2217EBD61CCD90310082837B /* NuParser.m */, + 2217EBEE1CCD9E7F0082837B /* NuPointer.h */, + 2217EBEF1CCD9E7F0082837B /* NuPointer.m */, + 2217EBE91CCD9DFE0082837B /* NuProfiler.h */, + 2217EBEA1CCD9DFE0082837B /* NuProfiler.m */, + 2217EBE41CCD92AC0082837B /* NuProperty.h */, + 2217EBE51CCD92AC0082837B /* NuProperty.m */, + 2217EBDF1CCD921B0082837B /* NuReference.h */, + 2217EBE01CCD921B0082837B /* NuReference.m */, + 2217EBDA1CCD915B0082837B /* NuRegex.h */, + 2217EBDB1CCD915B0082837B /* NuRegex.m */, + 2217EBD01CCD8F960082837B /* NuStack.h */, + 2217EBD11CCD8F960082837B /* NuStack.m */, + 2217EBCB1CCD8E760082837B /* NuSuper.h */, + 2217EBCC1CCD8E760082837B /* NuSuper.m */, + 2217EBC61CCD8DF00082837B /* NuSwizzles.h */, + 2217EBC71CCD8DF00082837B /* NuSwizzles.m */, + 2217EBBC1CCD8BDF0082837B /* NuSymbol.h */, + 2217EBBD1CCD8BDF0082837B /* NuSymbol.m */, + 2217EBC11CCD8CE30082837B /* NuTestHelper.h */, + 2217EBC21CCD8CE30082837B /* NuTestHelper.m */, ); name = objc; path = ../objc; @@ -438,6 +692,42 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 2217EC681CCDBF390082837B /* NuBridge.h in Headers */, + 2217EC401CCDAED00082837B /* NSArray+Nu.h in Headers */, + 2217EBC81CCD8DF00082837B /* NuSwizzles.h in Headers */, + 2217EBE11CCD921B0082837B /* NuReference.h in Headers */, + 2217EC091CCDA4990082837B /* NuMacro.h in Headers */, + 2217EBCD1CCD8E760082837B /* NuSuper.h in Headers */, + 2217EBC31CCD8CE30082837B /* NuTestHelper.h in Headers */, + 2217EC631CCDB2610082837B /* NSMethodSignature+Nu.h in Headers */, + 2217EC4F1CCDB0770082837B /* NSNumber+Nu.h in Headers */, + 2217EC591CCDB1240082837B /* NSDate+Nu.h in Headers */, + 2217EC361CCDAD3B0082837B /* NuEnumerable.h in Headers */, + 2217EC4A1CCDAFE00082837B /* NSNull+Nu.h in Headers */, + 2217EC5E1CCDB19C0082837B /* NSFileManager+Nu.h in Headers */, + 2217EC041CCDA3870082837B /* NuMethod.h in Headers */, + 2217EC541CCDB0D40082837B /* NSData+Nu.h in Headers */, + 2217EBB81CCD89E60082837B /* NuMarkupOperator.h in Headers */, + 2217EC3B1CCDAE010082837B /* NuException.h in Headers */, + 2217EC221CCDA9A00082837B /* NuMath.h in Headers */, + 2217EC311CCDAC600082837B /* NSBundle+Nu.h in Headers */, + 2217EBFA1CCDA27A0082837B /* NSObject+Nu.h in Headers */, + 2217EC131CCDA65F0082837B /* NuBlock.h in Headers */, + 2217EBFF1CCDA3300082837B /* NuObjCRuntime.h in Headers */, + 2217EBD21CCD8F960082837B /* NuStack.h in Headers */, + 2217EC2C1CCDAB700082837B /* NSDictionary+Nu.h in Headers */, + 2217EBE61CCD92AC0082837B /* NuProperty.h in Headers */, + 2217EBF51CCDA0420082837B /* NuOperators.h in Headers */, + 2217EC181CCDA7350082837B /* NuCell.h in Headers */, + 2217EC0E1CCDA5390082837B /* NuHandler.h in Headers */, + 2217EBDC1CCD915B0082837B /* NuRegex.h in Headers */, + 2217EC451CCDAF2A0082837B /* NSSet+Nu.h in Headers */, + 2217EBBE1CCD8BDF0082837B /* NuSymbol.h in Headers */, + 2217EBF01CCD9E7F0082837B /* NuPointer.h in Headers */, + 2217EC271CCDAA850082837B /* NSString+Nu.h in Headers */, + 2217EBEB1CCD9DFE0082837B /* NuProfiler.h in Headers */, + 2217EC1D1CCDA8340082837B /* NuClass.h in Headers */, + 2217EBD71CCD90310082837B /* NuParser.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -641,11 +931,47 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2217EBFC1CCDA27A0082837B /* NSObject+Nu.m in Sources */, + 2217EBBA1CCD8AAC0082837B /* NuMarkupOperator.m in Sources */, + 2217EBDE1CCD915B0082837B /* NuRegex.m in Sources */, + 2217EC331CCDAC600082837B /* NSBundle+Nu.m in Sources */, + 2217EC561CCDB0D40082837B /* NSData+Nu.m in Sources */, 22EE2C0613A4731600895861 /* main.m in Sources */, + 2217EC061CCDA3870082837B /* NuMethod.m in Sources */, + 2217EBCA1CCD8DF00082837B /* NuSwizzles.m in Sources */, 22EE2C0A13A4731600895861 /* NuAppDelegate.m in Sources */, + 2217EC1F1CCDA8340082837B /* NuClass.m in Sources */, 22B3B47413B0359300B3AB31 /* Nu.m in Sources */, + 2217EC651CCDB2610082837B /* NSMethodSignature+Nu.m in Sources */, + 2217EBE81CCD92AC0082837B /* NuProperty.m in Sources */, + 2217EBC51CCD8CE30082837B /* NuTestHelper.m in Sources */, + 2217EC6A1CCDBF390082837B /* NuBridge.m in Sources */, + 2217EC151CCDA65F0082837B /* NuBlock.m in Sources */, + 2217EC601CCDB19C0082837B /* NSFileManager+Nu.m in Sources */, + 2217EC2E1CCDAB700082837B /* NSDictionary+Nu.m in Sources */, + 2217EC5B1CCDB1240082837B /* NSDate+Nu.m in Sources */, + 2217EC381CCDAD3B0082837B /* NuEnumerable.m in Sources */, + 2217EBCF1CCD8E760082837B /* NuSuper.m in Sources */, + 2217EBF21CCD9E7F0082837B /* NuPointer.m in Sources */, + 2217EC241CCDA9A00082837B /* NuMath.m in Sources */, + 2217EC011CCDA3300082837B /* NuObjCRuntime.m in Sources */, + 2217EBD41CCD8F960082837B /* NuStack.m in Sources */, 225F62CD13B04256002DD16B /* ffi.S in Sources */, + 2217EBE31CCD921B0082837B /* NuReference.m in Sources */, + 2217EC4C1CCDAFE00082837B /* NSNull+Nu.m in Sources */, + 2217EBD91CCD90310082837B /* NuParser.m in Sources */, + 2217EC511CCDB0770082837B /* NSNumber+Nu.m in Sources */, + 2217EC0B1CCDA4990082837B /* NuMacro.m in Sources */, + 2217EBF71CCDA0420082837B /* NuOperators.m in Sources */, + 2217EC291CCDAA850082837B /* NSString+Nu.m in Sources */, + 2217EC3D1CCDAE010082837B /* NuException.m in Sources */, + 2217EBED1CCD9DFE0082837B /* NuProfiler.m in Sources */, + 2217EBC01CCD8BDF0082837B /* NuSymbol.m in Sources */, 225F62D313B04256002DD16B /* ffi.c in Sources */, + 2217EC471CCDAF2A0082837B /* NSSet+Nu.m in Sources */, + 2217EC421CCDAED00082837B /* NSArray+Nu.m in Sources */, + 2217EC1A1CCDA7350082837B /* NuCell.m in Sources */, + 2217EC101CCDA5390082837B /* NuHandler.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -653,7 +979,43 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2217EC691CCDBF390082837B /* NuBridge.m in Sources */, + 2217EC501CCDB0770082837B /* NSNumber+Nu.m in Sources */, + 2217EC411CCDAED00082837B /* NSArray+Nu.m in Sources */, + 2217EC051CCDA3870082837B /* NuMethod.m in Sources */, + 2217EBC41CCD8CE30082837B /* NuTestHelper.m in Sources */, + 2217EBEC1CCD9DFE0082837B /* NuProfiler.m in Sources */, + 2217EC5A1CCDB1240082837B /* NSDate+Nu.m in Sources */, + 2217EBD31CCD8F960082837B /* NuStack.m in Sources */, + 2217EBF11CCD9E7F0082837B /* NuPointer.m in Sources */, + 2217EC321CCDAC600082837B /* NSBundle+Nu.m in Sources */, + 2217EBE71CCD92AC0082837B /* NuProperty.m in Sources */, + 2217EC141CCDA65F0082837B /* NuBlock.m in Sources */, + 2217EC641CCDB2610082837B /* NSMethodSignature+Nu.m in Sources */, + 2217EC551CCDB0D40082837B /* NSData+Nu.m in Sources */, + 2217EBE21CCD921B0082837B /* NuReference.m in Sources */, + 2217EC461CCDAF2A0082837B /* NSSet+Nu.m in Sources */, + 2217EC231CCDA9A00082837B /* NuMath.m in Sources */, + 2217EC3C1CCDAE010082837B /* NuException.m in Sources */, + 2217EC4B1CCDAFE00082837B /* NSNull+Nu.m in Sources */, + 2217EC191CCDA7350082837B /* NuCell.m in Sources */, + 2217EC0A1CCDA4990082837B /* NuMacro.m in Sources */, + 2217EC2D1CCDAB700082837B /* NSDictionary+Nu.m in Sources */, + 2217EBB91CCD89E60082837B /* NuMarkupOperator.m in Sources */, + 2217EC1E1CCDA8340082837B /* NuClass.m in Sources */, + 2217EC371CCDAD3B0082837B /* NuEnumerable.m in Sources */, + 2217EBBF1CCD8BDF0082837B /* NuSymbol.m in Sources */, 22B3B47313B0359300B3AB31 /* Nu.m in Sources */, + 2217EBD81CCD90310082837B /* NuParser.m in Sources */, + 2217EBFB1CCDA27A0082837B /* NSObject+Nu.m in Sources */, + 2217EBF61CCDA0420082837B /* NuOperators.m in Sources */, + 2217EBCE1CCD8E760082837B /* NuSuper.m in Sources */, + 2217EC0F1CCDA5390082837B /* NuHandler.m in Sources */, + 2217EBDD1CCD915B0082837B /* NuRegex.m in Sources */, + 2217EBC91CCD8DF00082837B /* NuSwizzles.m in Sources */, + 2217EC5F1CCDB19C0082837B /* NSFileManager+Nu.m in Sources */, + 2217EC281CCDAA850082837B /* NSString+Nu.m in Sources */, + 2217EC001CCDA3300082837B /* NuObjCRuntime.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/objc/NSArray+Nu.h b/objc/NSArray+Nu.h new file mode 100644 index 0000000..9358b3b --- /dev/null +++ b/objc/NSArray+Nu.h @@ -0,0 +1,55 @@ +// +// NSArray+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +@class NuBlock; +@class NuCell; + +/*! + @category NSArray(Nu) + @abstract NSArray extensions for Nu programming. + */ +@interface NSArray(Nu) +/*! Creates an array that contains the contents of a specified list. */ ++ (NSArray *) arrayWithList:(id) list; + +/*! Sort an array using its elements' compare: method. */ +- (NSArray *) sort; + +/*! Convert an array into a list. */ +- (NuCell *) list; + +/*! Repeatedly apply a function of two arguments to the elements of an array, + working from right to left and beginning with the specified inital value. */ +- (id) reduceLeft:(id)callable from:(id) initial; + +/*! Iterate over each member of an array in reverse order and beginning with the lastObject, evaluating the provided block for each member. */ +- (id) eachInReverse:(id) callable; + +/*! Return a sorted array using the specified block to compare array elements. + The block should return -1, 0, or 1. */ +- (NSArray *) sortedArrayUsingBlock:(NuBlock *) block; + +@end + +/*! + @category NSMutableArray(Nu) + @abstract NSMutableArray extensions for Nu programming. + */ +@interface NSMutableArray(Nu) +/*! Add the objects from the specified list to the array. */ +- (void) addObjectsFromList:(id)list; +/*! Add an object to an array, automatically converting nil into [NSNull null]. */ +- (void) addPossiblyNullObject:(id)anObject; +/*! Insert an object into an array, automatically converting nil into [NSNull null]. */ +- (void) insertPossiblyNullObject:(id)anObject atIndex:(int)index; +/*! Replace an object in an array, automatically converting nil into [NSNull null]. */ +- (void) replaceObjectAtIndex:(int)index withPossiblyNullObject:(id)anObject; +@end + diff --git a/objc/NSArray+Nu.m b/objc/NSArray+Nu.m new file mode 100644 index 0000000..6c72d60 --- /dev/null +++ b/objc/NSArray+Nu.m @@ -0,0 +1,163 @@ +// +// NSArray+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSArray+Nu.h" +#import "NuInternals.h" +#import "NuCell.h" + +@implementation NSArray(Nu) ++ (NSArray *) arrayWithList:(id) list +{ + NSMutableArray *a = [NSMutableArray array]; + id cursor = list; + while (cursor && cursor != Nu__null) { + [a addObject:[cursor car]]; + cursor = [cursor cdr]; + } + return a; +} + +// When an unknown message is received by an array, treat it as a call to objectAtIndex: +- (id) handleUnknownMessage:(NuCell *) method withContext:(NSMutableDictionary *) context +{ + id m = [[method car] evalWithContext:context]; + if ([m isKindOfClass:[NSNumber class]]) { + int mm = [m intValue]; + if (mm < 0) { + // if the index is negative, index from the end of the array + mm += [self count]; + } + if ((mm < [self count]) && (mm >= 0)) { + return [self objectAtIndex:mm]; + } + else { + return Nu__null; + } + } + else { + return [super handleUnknownMessage:method withContext:context]; + } +} + +// This default sort method sorts an array using its elements' compare: method. +- (NSArray *) sort +{ + return [self sortedArrayUsingSelector:@selector(compare:)]; +} + +// Convert an array into a list. +- (NuCell *) list +{ + NSUInteger count = [self count]; + if (count == 0) + return nil; + NuCell *result = [[[NuCell alloc] init] autorelease]; + NuCell *cursor = result; + [result setCar:[self objectAtIndex:0]]; + for (int i = 1; i < count; i++) { + [cursor setCdr:[[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + [cursor setCar:[self objectAtIndex:i]]; + } + return result; +} + +- (id) reduceLeft:(id)callable from:(id) initial +{ + id args = [[NuCell alloc] init]; + [args setCdr:[[[NuCell alloc] init] autorelease]]; + id result = initial; + if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { + for (NSInteger i = [self count] - 1; i >= 0; i--) { + id object = [self objectAtIndex:i]; + [args setCar:result]; + [[args cdr] setCar: object]; + result = [callable evalWithArguments:args context:nil]; + } + } + [args release]; + return result; +} + +- (id) eachInReverse:(id) callable +{ + id args = [[NuCell alloc] init]; + if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { + NSEnumerator *enumerator = [self reverseObjectEnumerator]; + id object; + while ((object = [enumerator nextObject])) { + @try + { + [args setCar:object]; + [callable evalWithArguments:args context:nil]; + } + @catch (NuBreakException *exception) { + break; + } + @catch (NuContinueException *exception) { + // do nothing, just continue with the next loop iteration + } + @catch (id exception) { + @throw(exception); + } + } + } + [args release]; + return self; +} + +static NSComparisonResult sortedArrayUsingBlockHelper(id a, id b, void *context) +{ + id args = [[NuCell alloc] init]; + [args setCdr:[[[NuCell alloc] init] autorelease]]; + [args setCar:a]; + [[args cdr] setCar:b]; + + // cast context as a block + NuBlock *block = (NuBlock *)context; + id result = [block evalWithArguments:args context:nil]; + + [args release]; + return [result intValue]; +} + +- (NSArray *) sortedArrayUsingBlock:(NuBlock *) block +{ + return [self sortedArrayUsingFunction:sortedArrayUsingBlockHelper context:block]; +} + +@end + +@implementation NSMutableArray(Nu) + +- (void) addObjectsFromList:(id)list +{ + [self addObjectsFromArray:[NSArray arrayWithList:list]]; +} + +- (void) addPossiblyNullObject:(id)anObject +{ + [self addObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; +} + +- (void) insertPossiblyNullObject:(id)anObject atIndex:(int)index +{ + [self insertObject:((anObject == nil) ? (id)[NSNull null] : anObject) atIndex:index]; +} + +- (void) replaceObjectAtIndex:(int)index withPossiblyNullObject:(id)anObject +{ + [self replaceObjectAtIndex:index withObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; +} + +- (void) sortUsingBlock:(NuBlock *) block +{ + [self sortUsingFunction:sortedArrayUsingBlockHelper context:block]; +} + +@end \ No newline at end of file diff --git a/objc/NSBundle+Nu.h b/objc/NSBundle+Nu.h new file mode 100644 index 0000000..0a8c813 --- /dev/null +++ b/objc/NSBundle+Nu.h @@ -0,0 +1,20 @@ +// +// NSBundle+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @category NSBundle(Nu) + @abstract NSBundle extensions for Nu programming. + */ +@interface NSBundle (Nu) +/*! Get or load a framework by name. */ ++ (NSBundle *) frameworkWithName:(NSString *) frameworkName; +/*! Load a Nu source file from the framework's resource directory. */ +- (id) loadNuFile:(NSString *) nuFileName withContext:(NSMutableDictionary *) context; +@end \ No newline at end of file diff --git a/objc/NSBundle+Nu.m b/objc/NSBundle+Nu.m new file mode 100644 index 0000000..8660f1c --- /dev/null +++ b/objc/NSBundle+Nu.m @@ -0,0 +1,73 @@ +// +// NSBundle+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSBundle+Nu.h" +#import "NuInternals.h" +#import "NSDictionary+Nu.h" + +@implementation NSBundle(Nu) + ++ (NSBundle *) frameworkWithName:(NSString *) frameworkName +{ + NSBundle *framework = nil; + + // is the framework already loaded? + NSArray *fw = [NSBundle allFrameworks]; + NSEnumerator *frameworkEnumerator = [fw objectEnumerator]; + while ((framework = [frameworkEnumerator nextObject])) { + if ([frameworkName isEqual: [[framework infoDictionary] objectForKey:@"CFBundleName"]]) { + return framework; + } + } + + // first try the current directory + framework = [NSBundle bundleWithPath:[NSString stringWithFormat:@"%@/%@.framework", [[NSFileManager defaultManager] currentDirectoryPath], frameworkName]]; + + // then /Library/Frameworks + if (!framework) + framework = [NSBundle bundleWithPath:[NSString stringWithFormat:@"/Library/Frameworks/%@.framework", frameworkName]]; + + // then /System/Library/Frameworks + if (!framework) + framework = [NSBundle bundleWithPath:[NSString stringWithFormat:@"/System/Library/Frameworks/%@.framework", frameworkName]]; + + // then /usr/frameworks + if (!framework) + framework = [NSBundle bundleWithPath:[NSString stringWithFormat:@"/usr/frameworks/%@.framework", frameworkName]]; + + // then /usr/local/frameworks + if (!framework) + framework = [NSBundle bundleWithPath:[NSString stringWithFormat:@"/usr/local/frameworks/%@.framework", frameworkName]]; + + if (framework) { + if ([framework load]) + return framework; + } + return nil; +} + +- (id) loadNuFile:(NSString *) nuFileName withContext:(NSMutableDictionary *) context +{ + NSString *fileName = [self pathForResource:nuFileName ofType:@"nu"]; + if (fileName) { + NSString *string = [NSString stringWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:NULL]; + if (string) { + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id parser = [context lookupObjectForKey:[symbolTable symbolWithString:@"_parser"]]; + id body = [parser parse:string asIfFromFilename:[fileName cStringUsingEncoding:NSUTF8StringEncoding]]; + [body evalWithContext:context]; + return [symbolTable symbolWithString:@"t"]; + } + return nil; + } + else { + return nil; + } +} + +@end diff --git a/objc/NSData+Nu.h b/objc/NSData+Nu.h new file mode 100644 index 0000000..a7a4225 --- /dev/null +++ b/objc/NSData+Nu.h @@ -0,0 +1,34 @@ +// +// NSData+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + + + +/*! + @category NSData(Nu) + @abstract NSData extensions for Nu programming. + @discussion NSData extensions for Nu programming. + */ +@interface NSData(Nu) + +#if !TARGET_OS_IPHONE +/*! Run a shell command and return the results as data. */ ++ (NSData *) dataWithShellCommand:(NSString *) command; + +/*! Run a shell command with the specified data or string as standard input and return the results as data. */ ++ (NSData *) dataWithShellCommand:(NSString *) command standardInput:(id) input; +#endif + +/*! Return data read from standard input. */ ++ (NSData *) dataWithStandardInput; + +/*! Property list helper. Return the (immutable) property list value of the associated data. */ +- (id) propertyListValue; + +@end diff --git a/objc/NSData+Nu.m b/objc/NSData+Nu.m new file mode 100644 index 0000000..2301334 --- /dev/null +++ b/objc/NSData+Nu.m @@ -0,0 +1,78 @@ +// +// NSData+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSData+Nu.h" + +@implementation NSData(Nu) + +- (const unsigned char) byteAtIndex:(int) i +{ + const unsigned char buffer[2]; + [self getBytes:(void *)&buffer range:NSMakeRange(i,1)]; + return buffer[0]; +} + +#if !TARGET_OS_IPHONE +// Read the output of a shell command into an NSData object and return the object. ++ (NSData *) dataWithShellCommand:(NSString *) command +{ + return [self dataWithShellCommand:command standardInput:nil]; +} + ++ (NSData *) dataWithShellCommand:(NSString *) command standardInput:(id) input +{ + char *input_template = strdup("/tmp/nuXXXXXX"); + char *input_filename = mktemp(input_template); + char *output_template = strdup("/tmp/nuXXXXXX"); + char *output_filename = mktemp(output_template); + id returnValue = nil; + if (input_filename || output_filename) { + NSString *inputFileName = [NSString stringWithCString:input_filename encoding:NSUTF8StringEncoding]; + NSString *outputFileName = [NSString stringWithCString:output_filename encoding:NSUTF8StringEncoding]; + NSString *fullCommand; + if (input) { + if ([input isKindOfClass:[NSData class]]) { + [input writeToFile:inputFileName atomically:NO]; + } else if ([input isKindOfClass:[NSString class]]) { + [input writeToFile:inputFileName atomically:NO encoding:NSUTF8StringEncoding error:NULL]; + } else { + [[input stringValue] writeToFile:inputFileName atomically:NO encoding:NSUTF8StringEncoding error:NULL]; + } + fullCommand = [NSString stringWithFormat:@"%@ < %@ > %@", command, inputFileName, outputFileName]; + } + else { + fullCommand = [NSString stringWithFormat:@"%@ > %@", command, outputFileName]; + } + const char *commandString = [[fullCommand stringValue] cStringUsingEncoding:NSUTF8StringEncoding]; + int result = system(commandString) >> 8; // this needs an explanation + if (!result) + returnValue = [NSData dataWithContentsOfFile:outputFileName]; + system([[NSString stringWithFormat:@"rm -f %@ %@", inputFileName, outputFileName] cStringUsingEncoding:NSUTF8StringEncoding]); + } + free(input_template); + free(output_template); + return returnValue; +} +#endif + +// Read the contents of standard input into a string. ++ (NSData *) dataWithStandardInput +{ + return [[NSFileHandle fileHandleWithStandardInput] readDataToEndOfFile]; +} + +// Helper. Included because it's so useful. +- (id) propertyListValue { + return [NSPropertyListSerialization propertyListWithData:self + options:NSPropertyListImmutable + format:0 + error:NULL]; +} + +@end + diff --git a/objc/NSDate+Nu.h b/objc/NSDate+Nu.h new file mode 100644 index 0000000..eab351e --- /dev/null +++ b/objc/NSDate+Nu.h @@ -0,0 +1,13 @@ +// +// NSDate+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +@interface NSDate(Nu) + +@end diff --git a/objc/NSDate+Nu.m b/objc/NSDate+Nu.m new file mode 100644 index 0000000..1e938cb --- /dev/null +++ b/objc/NSDate+Nu.m @@ -0,0 +1,20 @@ +// +// NSDate+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSDate+Nu.h" + +@implementation NSDate(Nu) + +#ifndef LINUX ++ dateWithTimeIntervalSinceNow:(NSTimeInterval) seconds +{ + return [[[NSDate alloc] initWithTimeIntervalSinceNow:seconds] autorelease]; +} +#endif + +@end diff --git a/objc/NSDictionary+Nu.h b/objc/NSDictionary+Nu.h new file mode 100644 index 0000000..5b95872 --- /dev/null +++ b/objc/NSDictionary+Nu.h @@ -0,0 +1,39 @@ +// +// NSDictionary+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + + +/*! + @category NSDictionary(Nu) + @abstract NSDictionary extensions for Nu programming. + */ +@interface NSDictionary(Nu) +/*! Creates a dictionary that contains the contents of a specified list. + The list should be a sequence of interleaved keys and values. */ ++ (NSDictionary *) dictionaryWithList:(id) list; +/*! Look up an object by key, returning the specified default if no object is found. */ +- (id) objectForKey:(id)key withDefault:(id)defaultValue; +@end + +/*! + @category NSMutableDictionary(Nu) + @abstract NSMutableDictionary extensions for Nu programming. + @discussion In Nu, NSMutableDictionaries are used to represent evaluation contexts. + Context keys are NuSymbols, and the associated objects are the symbols' + assigned values. + */ +@interface NSMutableDictionary(Nu) +/*! Looks up the value associated with a key in the current context. + If no value is found, looks in the context's parent, continuing + upward until no more parent contexts are found. */ +- (id) lookupObjectForKey:(id)key; +/*! Add an object to a dictionary, automatically converting nil into [NSNull null]. */ +- (void) setPossiblyNullObject:(id) anObject forKey:(id) aKey; + +@end \ No newline at end of file diff --git a/objc/NSDictionary+Nu.m b/objc/NSDictionary+Nu.m new file mode 100644 index 0000000..f134ea7 --- /dev/null +++ b/objc/NSDictionary+Nu.m @@ -0,0 +1,139 @@ +// +// NSDictionary+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSDictionary+Nu.h" +#import "NuCell.h" +#import "NuInternals.h" + +@implementation NSDictionary(Nu) + ++ (NSDictionary *) dictionaryWithList:(id) list +{ + NSMutableDictionary *d = [NSMutableDictionary dictionary]; + id cursor = list; + while (cursor && (cursor != Nu__null) && ([cursor cdr]) && ([cursor cdr] != Nu__null)) { + id key = [cursor car]; + if ([key isKindOfClass:[NuSymbol class]] && [key isLabel]) { + key = [key labelName]; + } + id value = [[cursor cdr] car]; + if (!value || [value isEqual:[NSNull null]]) { + [d removeObjectForKey:key]; + } else { + [d setValue:value forKey:key]; + } + cursor = [[cursor cdr] cdr]; + } + return d; +} + +- (id) objectForKey:(id)key withDefault:(id)defaultValue +{ + id value = [self objectForKey:key]; + return value ? value : defaultValue; +} + +// When an unknown message is received by a dictionary, treat it as a call to objectForKey: +- (id) handleUnknownMessage:(NuCell *) method withContext:(NSMutableDictionary *) context +{ + id cursor = method; + while (cursor && (cursor != Nu__null) && ([cursor cdr]) && ([cursor cdr] != Nu__null)) { + id key = [cursor car]; + id value = [[cursor cdr] car]; + if ([key isKindOfClass:[NuSymbol class]] && [key isLabel]) { + id evaluated_key = [key labelName]; + id evaluated_value = [value evalWithContext:context]; + [self setValue:evaluated_value forKey:evaluated_key]; + } + else { + id evaluated_key = [key evalWithContext:context]; + id evaluated_value = [value evalWithContext:context]; + [self setValue:evaluated_value forKey:evaluated_key]; + } + cursor = [[cursor cdr] cdr]; + } + if (cursor && (cursor != Nu__null)) { + // if the method is a label, use its value as the key. + if ([[cursor car] isKindOfClass:[NuSymbol class]] && ([[cursor car] isLabel])) { + id result = [self objectForKey:[[cursor car] labelName]]; + return result ? result : Nu__null; + } + else { + id result = [self objectForKey:[[cursor car] evalWithContext:context]]; + return result ? result : Nu__null; + } + } + else { + return Nu__null; + } +} + +// Iterate over the key-object pairs in a dictionary. Pass it a block with two arguments: (key object). +- (id) each:(id) block +{ + id args = [[NuCell alloc] init]; + [args setCdr:[[[NuCell alloc] init] autorelease]]; + NSEnumerator *keyEnumerator = [[self allKeys] objectEnumerator]; + id key; + while ((key = [keyEnumerator nextObject])) { + @try + { + [args setCar:key]; + [[args cdr] setCar:[self objectForKey:key]]; + [block evalWithArguments:args context:Nu__null]; + } + @catch (NuBreakException *exception) { + break; + } + @catch (NuContinueException *exception) { + // do nothing, just continue with the next loop iteration + } + @catch (id exception) { + @throw(exception); + } + } + [args release]; + return self; +} + +- (NSDictionary *) map: (id) callable +{ + NSMutableDictionary *results = [NSMutableDictionary dictionary]; + id args = [[NuCell alloc] init]; + if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { + NSEnumerator *enumerator = [self keyEnumerator]; + id object; + while ((object = [enumerator nextObject])) { + [args setCar:object]; + [args setCdr:[[[NuCell alloc] init] autorelease]]; + [[args cdr] setCar:[self objectForKey:object]]; + [results setObject:[callable evalWithArguments:args context:nil] forKey:object]; + } + } + [args release]; + return results; +} + +@end + +@implementation NSMutableDictionary(Nu) +- (id) lookupObjectForKey:(id)key +{ + id object = [self objectForKey:key]; + if (object) return object; + id parent = [self objectForKey:PARENT_KEY]; + if (!parent) return nil; + return [parent lookupObjectForKey:key]; +} + +- (void) setPossiblyNullObject:(id) anObject forKey:(id) aKey +{ + [self setObject:((anObject == nil) ? (id)[NSNull null] : anObject) forKey:aKey]; +} + +@end diff --git a/objc/NSFileManager+Nu.h b/objc/NSFileManager+Nu.h new file mode 100644 index 0000000..3561727 --- /dev/null +++ b/objc/NSFileManager+Nu.h @@ -0,0 +1,24 @@ +// +// NSFileManager+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @category NSFileManager(Nu) + @abstract NSFileManager extensions for Nu programming. + */ +@interface NSFileManager (Nu) +/*! Get the creation time for a file. */ ++ (id) creationTimeForFileNamed:(NSString *) filename; +/*! Get the latest modification time for a file. */ ++ (id) modificationTimeForFileNamed:(NSString *) filename; +/*! Test for the existence of a directory. */ ++ (int) directoryExistsNamed:(NSString *) filename; +/*! Test for the existence of a file. */ ++ (int) fileExistsNamed:(NSString *) filename; +@end diff --git a/objc/NSFileManager+Nu.m b/objc/NSFileManager+Nu.m new file mode 100644 index 0000000..040afd1 --- /dev/null +++ b/objc/NSFileManager+Nu.m @@ -0,0 +1,81 @@ +// +// NSFileManager+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSFileManager+Nu.h" +#import "NuInternals.h" +#import + +@implementation NSFileManager(Nu) + +// crashes ++ (id) _timestampForFileNamed:(NSString *) filename +{ + if (filename == Nu__null) return nil; + NSError *error; + NSDictionary *attributes = [[NSFileManager defaultManager] + attributesOfItemAtPath:[filename stringByExpandingTildeInPath] + error:&error]; + return [attributes valueForKey:NSFileModificationDate]; +} + ++ (id) creationTimeForFileNamed:(NSString *) filename +{ + if (!filename) + return nil; + const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; + struct stat sb; + int result = stat(path, &sb); + if (result == -1) { + return nil; + } + // return [NSDate dateWithTimeIntervalSince1970:sb.st_ctimespec.tv_sec]; + return [NSDate dateWithTimeIntervalSince1970:sb.st_ctime]; +} + ++ (id) modificationTimeForFileNamed:(NSString *) filename +{ + if (!filename) + return nil; + const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; + struct stat sb; + int result = stat(path, &sb); + if (result == -1) { + return nil; + } + return [NSDate dateWithTimeIntervalSince1970:sb.st_mtime]; +} + ++ (int) directoryExistsNamed:(NSString *) filename +{ + if (!filename) + return NO; + const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; + struct stat sb; + int result = stat(path, &sb); + if (result == -1) { + return NO; + } + return (S_ISDIR(sb.st_mode) != 0) ? 1 : 0; +} + ++ (int) fileExistsNamed:(NSString *) filename +{ + if (!filename) + return NO; + const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; + struct stat sb; + int result = stat(path, &sb); + if (result == -1) { + return NO; + } + return (S_ISDIR(sb.st_mode) == 0) ? 1 : 0; +} + +@end + + diff --git a/objc/NSMethodSignature+Nu.h b/objc/NSMethodSignature+Nu.h new file mode 100644 index 0000000..eb3dd88 --- /dev/null +++ b/objc/NSMethodSignature+Nu.h @@ -0,0 +1,19 @@ +// +// NSMethodSignature+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @category NSMethodSignature(Nu) + @abstract NSMethodSignature extensions for Nu programming. + */ +@interface NSMethodSignature (Nu) +/*! Get the type string for a method signature. */ +- (NSString *) typeString; +@end + diff --git a/objc/NSMethodSignature+Nu.m b/objc/NSMethodSignature+Nu.m new file mode 100644 index 0000000..3a33703 --- /dev/null +++ b/objc/NSMethodSignature+Nu.m @@ -0,0 +1,26 @@ +// +// NSMethodSignature+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSMethodSignature+Nu.h" + +@implementation NSMethodSignature(Nu) + +- (NSString *) typeString +{ + // in 10.5, we can do this: + // return [self _typeString]; + NSMutableString *result = [NSMutableString stringWithFormat:@"%s", [self methodReturnType]]; + NSInteger i; + NSUInteger max = [self numberOfArguments]; + for (i = 0; i < max; i++) { + [result appendFormat:@"%s", [self getArgumentTypeAtIndex:i]]; + } + return result; +} + +@end \ No newline at end of file diff --git a/objc/NSNull+Nu.h b/objc/NSNull+Nu.h new file mode 100644 index 0000000..e5b8f90 --- /dev/null +++ b/objc/NSNull+Nu.h @@ -0,0 +1,25 @@ +// +// NSNull+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @category NSNull(Nu) + @abstract NSNull extensions for Nu programming. + @discussion In Nu, nil is represented by [NSNull null]. + */ +@interface NSNull(Nu) +/*! Returns false. In Nu, nil is not an atom. */ +- (bool) atom; +/*! The length of nil is zero. */ +- (NSUInteger) length; +/*! count is a synonym for length. */ +- (NSUInteger) count; +/*! nil converts to an empty array. */ +- (NSMutableArray *) array; +@end \ No newline at end of file diff --git a/objc/NSNull+Nu.m b/objc/NSNull+Nu.m new file mode 100644 index 0000000..89b6200 --- /dev/null +++ b/objc/NSNull+Nu.m @@ -0,0 +1,50 @@ +// +// NSNull+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSNull+Nu.h" + + +@implementation NSNull(Nu) + +- (bool) atom +{ + return true; +} + +- (NSUInteger) length +{ + return 0; +} + +- (NSUInteger) count +{ + return 0; +} + +- (NSMutableArray *) array +{ + return [NSMutableArray array]; +} + +- (NSString *) stringValue +{ + return @"()"; +} + +- (BOOL) isEqual:(id) other +{ + return ((self == other) || (other == 0)) ? 1l : 0l; +} + +- (const char *) cStringUsingEncoding:(NSStringEncoding) encoding +{ + return [[self stringValue] cStringUsingEncoding:encoding]; +} + +@end + diff --git a/objc/NSNumber+Nu.h b/objc/NSNumber+Nu.h new file mode 100644 index 0000000..dbe17f7 --- /dev/null +++ b/objc/NSNumber+Nu.h @@ -0,0 +1,34 @@ +// +// NSNumber+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @category NSNumber(Nu) + @abstract NSNumber extensions for Nu programming. + */ +@interface NSNumber(Nu) +/*! + Iterate a number of times corresponding to the message receiver. + On each iteration, evaluate the given block after passing in the iteration count. + Iteration counts begin at zero and end at n-1. + */ +- (id) times:(id) block; +/*! + Iterate from the current value up to a specified limit. + On each iteration, evaluate the given block after passing in the index. + Indices begin at the receiver's value and end at the specified number. + */ +- (id) upTo:(id) number do:(id) block; +/*! + Iterate from the current value down to a specified limit. + On each iteration, evaluate the given block after passing in the index. + Indices begin at the receiver's value and end at the specified number. + */ +- (id) downTo:(id) number do:(id) block; +@end diff --git a/objc/NSNumber+Nu.m b/objc/NSNumber+Nu.m new file mode 100644 index 0000000..b5085f3 --- /dev/null +++ b/objc/NSNumber+Nu.m @@ -0,0 +1,112 @@ +// +// NSNumber+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSNumber+Nu.h" +#import "NuInternals.h" +#import "NuBlock.h" + +@implementation NSNumber(Nu) + +- (id) times:(id) block +{ + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + id args = [[NuCell alloc] init]; + int x = [self intValue]; + int i; + for (i = 0; i < x; i++) { + @try + { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [args setCar:[NSNumber numberWithInt:i]]; + [block evalWithArguments:args context:Nu__null]; + [pool release]; + } + @catch (NuBreakException *exception) { + break; + } + @catch (NuContinueException *exception) { + // do nothing, just continue with the next loop iteration + } + @catch (id exception) { + @throw(exception); + } + } + [args release]; + } + return self; +} + +- (id) downTo:(id) number do:(id) block +{ + int startValue = [self intValue]; + int finalValue = [number intValue]; + if (startValue < finalValue) { + return self; + } + else { + id args = [[NuCell alloc] init]; + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + int i; + for (i = startValue; i >= finalValue; i--) { + @try + { + [args setCar:[NSNumber numberWithInt:i]]; + [block evalWithArguments:args context:Nu__null]; + } + @catch (NuBreakException *exception) { + break; + } + @catch (NuContinueException *exception) { + // do nothing, just continue with the next loop iteration + } + @catch (id exception) { + @throw(exception); + } + } + } + [args release]; + } + return self; +} + +- (id) upTo:(id) number do:(id) block +{ + int startValue = [self intValue]; + int finalValue = [number intValue]; + id args = [[NuCell alloc] init]; + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + int i; + for (i = startValue; i <= finalValue; i++) { + @try + { + [args setCar:[NSNumber numberWithInt:i]]; + [block evalWithArguments:args context:Nu__null]; + } + @catch (NuBreakException *exception) { + break; + } + @catch (NuContinueException *exception) { + // do nothing, just continue with the next loop iteration + } + @catch (id exception) { + @throw(exception); + } + } + } + [args release]; + return self; +} + +- (NSString *) hexValue +{ + int x = [self intValue]; + return [NSString stringWithFormat:@"0x%x", x]; +} + +@end + diff --git a/objc/NSObject+Nu.h b/objc/NSObject+Nu.h new file mode 100644 index 0000000..ab1af90 --- /dev/null +++ b/objc/NSObject+Nu.h @@ -0,0 +1,98 @@ +// +// NSObject+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +@class NuClass; +@class NuCell; + +/*! + @category NSObject(Nu) + @abstract NSObject extensions for Nu programming. + */ +@interface NSObject(Nu) +/*! Returns true. In Nu, virtually all Objective-C classes are considered atoms. */ +- (bool) atom; +/*! + Evaluation operator. The Nu default is for an Objective-C object to evaluate to itself, + but certain subclasses (such as NuSymbol and NSString) behave differently. + */ +- (id) evalWithContext:(NSMutableDictionary *) context; +/*! Gets the value of a specified instance variable. */ +- (id) valueForIvar:(NSString *) name; +/*! Sets the value of a specified instance variable. */ +- (void) setValue:(id) value forIvar:(NSString *) name; +/*! Get an array containing NuMethod representations of the class methods of a class. */ ++ (NSArray *) classMethods; +/*! Get an array containing NuMethod representations of the instance methods of a class. */ ++ (NSArray *) instanceMethods; +/*! Get an array containing the names of the class methods of a class. */ ++ (NSArray *) classMethodNames; +/*! Get an array containing the names of the instance methods of a class. */ ++ (NSArray *) instanceMethodNames; +/*! Get an array containing the names of all instance variables of the class. */ ++ (NSArray *) instanceVariableNames; + +/*! Create a subclass of a class with the specified name. */ ++ (id) createSubclassNamed:(NSString *) subclassName; + +/*! Copy a named instance method from another class to the receiving class. */ ++ (BOOL) copyInstanceMethod:(NSString *) methodName fromClass:(NuClass *) prototypeClass; +/*! Copy all of the instance methods from a specified class to the receiving class. */ ++ (BOOL) include:(NuClass *) prototypeClass; + +/*! Send a message to an object with an execution context */ +- (id) sendMessage:(id)cdr withContext:(NSMutableDictionary *)context; +/*! Evaluate a list with the receiving object at the head. Calls sendMessage:withContext: */ +- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context; + +/*! Handle an unknown message. Override this in subclasses to provide dynamic method handling. */ +- (id) handleUnknownMessage:(id) cdr withContext:(NSMutableDictionary *) context; + +/*! This method is automatically sent to a class whenever Nu code creates a subclass of that class. + Its default implementation does nothing. Override it to track subclassing. */ ++ (id) inheritedByClass:(NuClass *) newClass; + +/*! Get a string providing a helpful description of an object. + This method should be overridden by subclasses to be more helpful. */ +- (NSString *) help; + +/*! Swap a pair of instance methods of the underlying class. */ ++ (BOOL) exchangeInstanceMethod:(SEL)sel1 withMethod:(SEL)sel2; + +/*! Swap a pair of class methods of the underlying class. */ ++ (BOOL) exchangeClassMethod:(SEL)sel1 withMethod:(SEL)sel2; + +/*! Concisely set key-value pairs from a property list. */ +- (id) set:(NuCell *) propertyList; + +/*! Set a retained associated object. */ +- (void) setRetainedAssociatedObject:(id) object forKey:(id) key; + +/*! Set an assigned associated object. */ +- (void) setAssignedAssociatedObject:(id) object forKey:(id) key; + +/*! Set a copied associated object. */ +- (void) setCopiedAssociatedObject:(id) object forKey:(id) key; + +/*! Get the value of an associated object. */ +- (id) associatedObjectForKey:(id) key; + +/*! Remove all associated objects. */ +- (void) removeAssociatedObjects; + +/*! Return true if object has a value for the named instance variable. */ +- (BOOL) hasValueForIvar:(NSString *) name; + +/*! Property list helper. Return the XML property list representation of the object. */ +- (NSData *) XMLPropertyListRepresentation; + +/*! Property list helper. Return the binary property list representation of the object. */ +- (NSData *) binaryPropertyListRepresentation; + +@end diff --git a/objc/NSObject+Nu.m b/objc/NSObject+Nu.m new file mode 100644 index 0000000..09a65cd --- /dev/null +++ b/objc/NSObject+Nu.m @@ -0,0 +1,700 @@ +// +// NSObject+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSObject+Nu.h" +#import "NuInternals.h" +#import "NSDictionary+Nu.h" +#import "NuEnumerable.h" +#import "NuMethod.h" + +@protocol NuCanSetAction +- (void) setAction:(SEL) action; +@end + +// use this to look up selectors with symbols +@interface NuSelectorCache : NSObject +{ + NuSymbol *symbol; + NuSelectorCache *parent; + NSMutableDictionary *children; + SEL selector; +} + +@end + +@implementation NuSelectorCache + ++ (NuSelectorCache *) sharedSelectorCache +{ + static NuSelectorCache *sharedCache = nil; + if (!sharedCache) + sharedCache = [[self alloc] init]; + return sharedCache; +} + +- (NuSelectorCache *) init +{ + if ((self = [super init])) { + symbol = nil; + parent = nil; + children = [[NSMutableDictionary alloc] init]; + selector = NULL; + } + return self; +} + +- (NuSymbol *) symbol {return symbol;} +- (NuSelectorCache *) parent {return parent;} +- (NSMutableDictionary *) children {return children;} + +- (SEL) selector +{ + return selector; +} + +- (void) setSelector:(SEL) s +{ + selector = s; +} + +- (NuSelectorCache *) initWithSymbol:(NuSymbol *)s parent:(NuSelectorCache *)p +{ + if ((self = [super init])) { + symbol = s; + parent = p; + children = [[NSMutableDictionary alloc] init]; + selector = NULL; + } + return self; +} + +- (NSString *) selectorName +{ + NSMutableArray *selectorStrings = [NSMutableArray array]; + [selectorStrings addObject:[[self symbol] stringValue]]; + id p = parent; + while ([p symbol]) { + [selectorStrings addObject:[[p symbol] stringValue]]; + p = [p parent]; + } + NSUInteger max = [selectorStrings count]; + NSInteger i; + for (i = 0; i < max/2; i++) { + [selectorStrings exchangeObjectAtIndex:i withObjectAtIndex:(max - i - 1)]; + } + return [selectorStrings componentsJoinedByString:@""]; +} + +- (NuSelectorCache *) lookupSymbol:(NuSymbol *)childSymbol +{ + NuSelectorCache *child = [children objectForKey:childSymbol]; + if (!child) { + child = [[[NuSelectorCache alloc] initWithSymbol:childSymbol parent:self] autorelease]; + NSString *selectorString = [child selectorName]; + [child setSelector:sel_registerName([selectorString cStringUsingEncoding:NSUTF8StringEncoding])]; + [children setValue:child forKey:(id)childSymbol]; + } + return child; +} + +@end + +@implementation NSObject(Nu) +- (bool) atom +{ + return true; +} + +- (id) evalWithContext:(NSMutableDictionary *) context +{ + return self; +} + +- (NSString *) stringValue +{ + return [NSString stringWithFormat:@"<%s:%lx>", class_getName(object_getClass(self)), (long) self]; +} + +- (id) car +{ + [NSException raise:@"NuCarCalledOnAtom" + format:@"car called on atom for object %@", + self]; + return Nu__null; +} + +- (id) cdr +{ + [NSException raise:@"NuCdrCalledOnAtom" + format:@"cdr called on atom for object %@", + self]; + return Nu__null; +} + + +- (id) sendMessage:(id)cdr withContext:(NSMutableDictionary *)context +{ + // By themselves, Objective-C objects evaluate to themselves. + if (!cdr || (cdr == Nu__null)) + return self; + + // But when they're at the head of a list, that list is converted into a message that is sent to the object. + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + // Collect the method selector and arguments. + // This seems like a bottleneck, and it also lacks flexibility. + // Replacing explicit string building with the selector cache reduced runtimes by around 20%. + // Methods with variadic arguments (NSArray arrayWithObjects:...) are not supported. + NSMutableArray *args = [[NSMutableArray alloc] init]; + id cursor = cdr; + SEL sel = 0; + id nextSymbol = [cursor car]; + if (nu_objectIsKindOfClass(nextSymbol, [NuSymbol class])) { + // The commented out code below was the original approach. + // methods were identified by concatenating symbols and looking up the resulting method -- on every method call + // that was slow but simple + // NSMutableString *selectorString = [NSMutableString stringWithString:[nextSymbol stringValue]]; + NuSelectorCache *selectorCache = [[NuSelectorCache sharedSelectorCache] lookupSymbol:nextSymbol]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + [args addObject:[cursor car]]; + cursor = [cursor cdr]; + if (cursor && (cursor != Nu__null)) { + id nextSymbol = [cursor car]; + if (nu_objectIsKindOfClass(nextSymbol, [NuSymbol class]) && [nextSymbol isLabel]) { + // [selectorString appendString:[nextSymbol stringValue]]; + selectorCache = [selectorCache lookupSymbol:nextSymbol]; + } + cursor = [cursor cdr]; + } + } + // sel = sel_getUid([selectorString cStringUsingEncoding:NSUTF8StringEncoding]); + sel = [selectorCache selector]; + } + + id target = self; + + // Look up the appropriate method to call for the specified selector. + Method m; + // instead of isMemberOfClass:, which may be blocked by an NSProtocolChecker + BOOL isAClass = (object_getClass(self) == [NuClass class]); + if (isAClass) { + // Class wrappers (objects of type NuClass) get special treatment. Instance methods are sent directly to the class wrapper object. + // But when a class method is sent to a class wrapper, the method is instead sent as a class method to the wrapped class. + // This makes it possible to call class methods from Nu, but there is no way to directly call class methods of NuClass from Nu. + id wrappedClass = [((NuClass *) self) wrappedClass]; + m = class_getClassMethod(wrappedClass, sel); + if (m) + target = wrappedClass; + else + m = class_getInstanceMethod(object_getClass(self), sel); + } + else { + m = class_getInstanceMethod(object_getClass(self), sel); + if (!m) m = class_getClassMethod(object_getClass(self), sel); + } + id result = Nu__null; + if (m) { + // We have a method that matches the selector. + // First, evaluate the arguments. + NSMutableArray *argValues = [[NSMutableArray alloc] init]; + NSUInteger i; + NSUInteger imax = [args count]; + for (i = 0; i < imax; i++) { + [argValues addObject:[[args objectAtIndex:i] evalWithContext:context]]; + } + // Then call the method. + result = nu_calling_objc_method_handler(target, m, argValues); + [argValues release]; + } + else { + // If the head of the list is a label, we treat the list as a property list. + // We just evaluate the elements of the list and return the result. + if (nu_objectIsKindOfClass(self, [NuSymbol class]) && [((NuSymbol *)self) isLabel]) { + NuCell *cell = [[[NuCell alloc] init] autorelease]; + [cell setCar: self]; + id cursor = cdr; + id result_cursor = cell; + while (cursor && (cursor != Nu__null)) { + id arg = [[cursor car] evalWithContext:context]; + [result_cursor setCdr:[[[NuCell alloc] init] autorelease]]; + result_cursor = [result_cursor cdr]; + [result_cursor setCar:arg]; + cursor = [cursor cdr]; + } + result = cell; + } + // Messaging null is ok. + else if (self == Nu__null) { + } + // Test if target specifies another object that should receive the message + else if ( (target = [target forwardingTargetForSelector:sel]) ) { + //NSLog(@"found forwarding target: %@ for selector: %@", target, NSStringFromSelector(sel)); + result = [target sendMessage:cdr withContext:context]; + } + // Otherwise, call the overridable handler for unknown messages. + else { + //NSLog(@"calling handle unknown message for %@", [cdr stringValue]); + result = [self handleUnknownMessage:cdr withContext:context]; + //NSLog(@"result is %@", result); + } + } + + [args release]; + [result retain]; + [pool drain]; + [result autorelease]; + return result; +} + +- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + return [self sendMessage:cdr withContext:context]; +} + ++ (id) handleUnknownMessage:(id) cdr withContext:(NSMutableDictionary *) context +{ + [NSException raise:@"NuUnknownMessage" + format:@"unable to find message handler for %@", + [cdr stringValue]]; + return Nu__null; +} + + +- (id) handleUnknownMessage:(id) message withContext:(NSMutableDictionary *) context +{ + // Collect the method selector and arguments. + // This seems like a bottleneck, and it also lacks flexibility. + // Replacing explicit string building with the selector cache reduced runtimes by around 20%. + // Methods with variadic arguments (NSArray arrayWithObjects:...) are not supported. + NSMutableArray *args = [NSMutableArray array]; + id cursor = message; + SEL sel = 0; + id nextSymbol = [cursor car]; + if (nu_objectIsKindOfClass(nextSymbol, [NuSymbol class])) { + // The commented out code below was the original approach. + // methods were identified by concatenating symbols and looking up the resulting method -- on every method call + // that was slow but simple + // NSMutableString *selectorString = [NSMutableString stringWithString:[nextSymbol stringValue]]; + NuSelectorCache *selectorCache = [[NuSelectorCache sharedSelectorCache] lookupSymbol:nextSymbol]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + [args addObject:[cursor car]]; + cursor = [cursor cdr]; + if (cursor && (cursor != Nu__null)) { + id nextSymbol = [cursor car]; + if (nu_objectIsKindOfClass(nextSymbol, [NuSymbol class]) && [nextSymbol isLabel]) { + // [selectorString appendString:[nextSymbol stringValue]]; + selectorCache = [selectorCache lookupSymbol:nextSymbol]; + } + cursor = [cursor cdr]; + } + } + // sel = sel_getUid([selectorString cStringUsingEncoding:NSUTF8StringEncoding]); + sel = [selectorCache selector]; + } + + // If the object responds to methodSignatureForSelector:, we should create and forward an invocation to it. + NSMethodSignature *methodSignature = sel ? [self methodSignatureForSelector:sel] : 0; + if (methodSignature) { + id result = [NSNull null]; + // Create an invocation to forward. + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; + [invocation setTarget:self]; + [invocation setSelector:sel]; + // Set any arguments to the invocation. + NSUInteger i; + NSUInteger imax = [args count]; + for (i = 0; i < imax; i++) { + const char *argument_type = [methodSignature getArgumentTypeAtIndex:i+2]; + char *buffer = value_buffer_for_objc_type(argument_type); + set_objc_value_from_nu_value(buffer, [[args objectAtIndex:i] evalWithContext:context], argument_type); + [invocation setArgument:buffer atIndex:i+2]; + free(buffer); + } + // Forward the invocation. + [self forwardInvocation:invocation]; + // Get the return value from the invocation. + NSUInteger length = [[invocation methodSignature] methodReturnLength]; + if (length > 0) { + char *buffer = (void *)malloc(length); + @try { + // In GNUstep, invocations that have no return values throw exceptions when this is called. + [invocation getReturnValue:buffer]; + result = get_nu_value_from_objc_value(buffer, [methodSignature methodReturnType]); + } @catch (id exception) { + result = [NSNull null]; + } + free(buffer); + } + return result; + } + +#define AUTOMATIC_IVAR_ACCESSORS +#ifdef AUTOMATIC_IVAR_ACCESSORS + //NSLog(@"attempting to access ivar %@", [message stringValue]); + NSInteger message_length = [message length]; + if (message_length == 1) { + // try to automatically get an ivar + NSString *ivarName = [[message car] stringValue]; + if ([self hasValueForIvar:ivarName]) { + id result = [self valueForIvar:ivarName]; + return result; + } + } + else if (message_length == 2) { + // try to automatically set an ivar + if ([[[[message car] stringValue] substringWithRange:NSMakeRange(0,3)] isEqualToString:@"set"]) { + @try + { + id firstArgument = [[message car] stringValue]; + id variableName0 = [[firstArgument substringWithRange:NSMakeRange(3,1)] lowercaseString]; + id variableName1 = [firstArgument substringWithRange:NSMakeRange(4, [firstArgument length] - 5)]; + [self setValue:[[[message cdr] car] evalWithContext:context] + forIvar:[NSString stringWithFormat:@"%@%@", variableName0, variableName1]]; + return Nu__null; + } + @catch (id error) { + // NSLog(@"skipping this error: %@", [error description]); + // no ivar, keep going + } + } + } +#endif + NuCell *cell = [[[NuCell alloc] init] autorelease]; + [cell setCar:self]; + [cell setCdr:message]; + [NSException raise:@"NuUnknownMessage" + format:@"unable to find message handler for %@", + [cell stringValue]]; + return Nu__null; +} + +- (id) valueForIvar:(NSString *) name +{ + Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); + if (!v) { + // look for sparse ivar storage + NSMutableDictionary *sparseIvars = [self associatedObjectForKey:@"__nuivars"]; + if (sparseIvars) { + // NSLog(@"sparse %@", [sparseIvars description]); + id result = [sparseIvars objectForKey:name]; + if (result) { + return result; + } else { + return Nu__null; + } + } + return Nu__null; + } + void *location = (void *)&(((char *)self)[ivar_getOffset(v)]); + id result = get_nu_value_from_objc_value(location, ivar_getTypeEncoding(v)); + return result; +} + +- (BOOL) hasValueForIvar:(NSString *) name +{ + Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); + if (!v) { + // look for sparse ivar storage + NSMutableDictionary *sparseIvars = [self associatedObjectForKey:@"__nuivars"]; + if (sparseIvars) { + // NSLog(@"sparse %@", [sparseIvars description]); + id result = [sparseIvars objectForKey:name]; + if (result) { + return YES; + } else { + return NO; + } + } + return NO; + } + //void *location = (void *)&(((char *)self)[ivar_getOffset(v)]); + //id result = get_nu_value_from_objc_value(location, ivar_getTypeEncoding(v)); + return YES; +} + + +- (void) setValue:(id) value forIvar:(NSString *)name +{ + Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); + if (!v) { + NSMutableDictionary *sparseIvars = [self associatedObjectForKey:@"__nuivars"]; + if (!sparseIvars) { + sparseIvars = [[[NSMutableDictionary alloc] init] autorelease]; + [self setRetainedAssociatedObject:sparseIvars forKey:@"__nuivars"]; + } + [self willChangeValueForKey:name]; + [sparseIvars setPossiblyNullObject:value forKey:name]; + [self didChangeValueForKey:name]; + return; + } + [self willChangeValueForKey:name]; + void *location = (void *)&(((char *)self)[ivar_getOffset(v)]); + const char *encoding = ivar_getTypeEncoding(v); + if (encoding && (strlen(encoding) > 0) && (encoding[0] == '@')) { + [value retain]; + [*((id *)location) release]; + } + set_objc_value_from_nu_value(location, value, ivar_getTypeEncoding(v)); + [self didChangeValueForKey:name]; +} + ++ (NSArray *) classMethods +{ + NSMutableArray *array = [NSMutableArray array]; + unsigned int method_count; + Method *method_list = class_copyMethodList(object_getClass([self class]), &method_count); + int i; + for (i = 0; i < method_count; i++) { + [array addObject:[[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]]; + } + free(method_list); + [array sortUsingSelector:@selector(compare:)]; + return array; +} + ++ (NSArray *) instanceMethods +{ + NSMutableArray *array = [NSMutableArray array]; + unsigned int method_count; + Method *method_list = class_copyMethodList([self class], &method_count); + int i; + for (i = 0; i < method_count; i++) { + [array addObject:[[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]]; + } + free(method_list); + [array sortUsingSelector:@selector(compare:)]; + return array; +} + ++ (NSArray *) classMethodNames +{ + Class c = [self class]; + id methods = [c classMethods]; + return [methods mapSelector:@selector(name)]; + // return [[c classMethods] mapSelector:@selector(name)]; +} + ++ (NSArray *) instanceMethodNames +{ + Class c = [self class]; + id methods = [c instanceMethods]; + return [methods mapSelector:@selector(name)]; + // return [[c instanceMethods] mapSelector:@selector(name)]; +} + ++ (NSArray *) instanceVariableNames +{ + NSMutableArray *array = [NSMutableArray array]; + unsigned int ivar_count; + Ivar *ivar_list = class_copyIvarList([self class], &ivar_count); + int i; + for (i = 0; i < ivar_count; i++) { + [array addObject:[NSString stringWithCString:ivar_getName(ivar_list[i]) encoding:NSUTF8StringEncoding]]; + } + free(ivar_list); + [array sortUsingSelector:@selector(compare:)]; + return array; +} + ++ (NSString *) signatureForIvar:(NSString *)name +{ + Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); + return [NSString stringWithCString:ivar_getTypeEncoding(v) encoding:NSUTF8StringEncoding]; +} + ++ (id) inheritedByClass:(NuClass *) newClass +{ + return nil; +} + ++ (id) createSubclassNamed:(NSString *) subclassName +{ + Class c = [self class]; + const char *name = [subclassName cStringUsingEncoding:NSUTF8StringEncoding]; + + // does the class already exist? + Class s = objc_getClass(name); + if (s) { + // the subclass's superclass must be the current class! + if (c != [s superclass]) { + NSLog(@"Warning: Class %s already exists and is not a subclass of %s", name, class_getName(c)); + } + } + else { + s = objc_allocateClassPair(c, name, 0); + objc_registerClassPair(s); + } + NuClass *newClass = [[[NuClass alloc] initWithClass:s] autorelease]; + + if ([self respondsToSelector:@selector(inheritedByClass:)]) { + [self inheritedByClass:newClass]; + } + + return newClass; +} + +/* + + (id) addInstanceMethod:(NSString *)methodName signature:(NSString *)signature body:(NuBlock *)block + { + Class c = [self class]; + return add_method_to_class(c, methodName, signature, block); + } + + + (id) addClassMethod:(NSString *)methodName signature:(NSString *)signature body:(NuBlock *)block + { + Class c = [self class]->isa; + return add_method_to_class(c, methodName, signature, block); + } + */ ++ (BOOL) copyInstanceMethod:(NSString *) methodName fromClass:(NuClass *)prototypeClass +{ + Class thisClass = [self class]; + Class otherClass = [prototypeClass wrappedClass]; + const char *method_name_str = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; + SEL selector = sel_registerName(method_name_str); + BOOL result = nu_copyInstanceMethod(thisClass, otherClass, selector); + return result; +} + ++ (BOOL) include:(NuClass *)prototypeClass +{ + NSArray *methods = [prototypeClass instanceMethods]; + NSEnumerator *enumerator = [methods objectEnumerator]; + id method; + while ((method = [enumerator nextObject])) { + // NSLog(@"copying method %@", [method name]); + [self copyInstanceMethod:[method name] fromClass:prototypeClass]; + } + return true; +} + ++ (NSString *) help +{ + return [NSString stringWithFormat:@"This is a class named %s.", class_getName([self class])]; +} + +- (NSString *) help +{ + return [NSString stringWithFormat:@"This is an instance of %s.", class_getName([self class])]; +} + +// adapted from the CocoaDev MethodSwizzling page + ++ (BOOL) exchangeInstanceMethod:(SEL)sel1 withMethod:(SEL)sel2 +{ + Class myClass = [self class]; + Method method1 = NULL, method2 = NULL; + + // First, look for the methods + method1 = class_getInstanceMethod(myClass, sel1); + method2 = class_getInstanceMethod(myClass, sel2); + // If both are found, swizzle them + if ((method1 != NULL) && (method2 != NULL)) { + method_exchangeImplementations(method1, method2); + return true; + } + else { + if (method1 == NULL) NSLog(@"swap failed: can't find %s", sel_getName(sel1)); + if (method2 == NULL) NSLog(@"swap failed: can't find %s", sel_getName(sel2)); + return false; + } + + return YES; +} + ++ (BOOL) exchangeClassMethod:(SEL)sel1 withMethod:(SEL)sel2 +{ + Class myClass = [self class]; + Method method1 = NULL, method2 = NULL; + + // First, look for the methods + method1 = class_getClassMethod(myClass, sel1); + method2 = class_getClassMethod(myClass, sel2); + + // If both are found, swizzle them + if ((method1 != NULL) && (method2 != NULL)) { + method_exchangeImplementations(method1, method2); + return true; + } + else { + if (method1 == NULL) NSLog(@"swap failed: can't find %s", sel_getName(sel1)); + if (method2 == NULL) NSLog(@"swap failed: can't find %s", sel_getName(sel2)); + return false; + } + + return YES; +} + +// Concisely set key-value pairs from a property list. + +- (id) set:(NuCell *) propertyList +{ + id cursor = propertyList; + while (cursor && (cursor != Nu__null) && ([cursor cdr]) && ([cursor cdr] != Nu__null)) { + id key = [cursor car]; + id value = [[cursor cdr] car]; + id label = ([key isKindOfClass:[NuSymbol class]] && [key isLabel]) ? [key labelName] : key; + if ([label isEqualToString:@"action"] && [self respondsToSelector:@selector(setAction:)]) { + SEL selector = sel_registerName([value cStringUsingEncoding:NSUTF8StringEncoding]); + [(id) self setAction:selector]; + } + else { + [self setValue:value forKey:label]; + } + cursor = [[cursor cdr] cdr]; + } + return self; +} + +- (void) setRetainedAssociatedObject:(id) object forKey:(id) key { + if ([key isKindOfClass:[NSString class]]) + key = [[NuSymbolTable sharedSymbolTable] symbolWithString:key]; + objc_setAssociatedObject(self, key, object, OBJC_ASSOCIATION_RETAIN); +} + +- (void) setAssignedAssociatedObject:(id) object forKey:(id) key { + if ([key isKindOfClass:[NSString class]]) + key = [[NuSymbolTable sharedSymbolTable] symbolWithString:key]; + objc_setAssociatedObject(self, key, object, OBJC_ASSOCIATION_ASSIGN); +} + +- (void) setCopiedAssociatedObject:(id) object forKey:(id) key { + if ([key isKindOfClass:[NSString class]]) + key = [[NuSymbolTable sharedSymbolTable] symbolWithString:key]; + objc_setAssociatedObject(self, key, object, OBJC_ASSOCIATION_COPY); +} + +- (id) associatedObjectForKey:(id) key { + if ([key isKindOfClass:[NSString class]]) + key = [[NuSymbolTable sharedSymbolTable] symbolWithString:key]; + return objc_getAssociatedObject(self, key); +} + +- (void) removeAssociatedObjects { + objc_removeAssociatedObjects(self); +} + +// Helper. Included because it's so useful. +- (NSData *) XMLPropertyListRepresentation { + return [NSPropertyListSerialization dataWithPropertyList:self + format: NSPropertyListXMLFormat_v1_0 + options:0 + error:NULL]; +} + +// Helper. Included because it's so useful. +- (NSData *) binaryPropertyListRepresentation { + return [NSPropertyListSerialization dataWithPropertyList:self + format: NSPropertyListBinaryFormat_v1_0 + options:0 + error:NULL]; +} + +@end diff --git a/objc/NSSet+Nu.h b/objc/NSSet+Nu.h new file mode 100644 index 0000000..3de3e0a --- /dev/null +++ b/objc/NSSet+Nu.h @@ -0,0 +1,31 @@ +// +// NSSet+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +@class NuCell; + +/*! + @category NSSet(Nu) + @abstract NSSet extensions for Nu programming. + */ +@interface NSSet(Nu) +/*! Creates a set that contains the contents of a specified list. */ ++ (NSSet *) setWithList:(id) list; +/*! Convert a set into a list. */ +- (NuCell *) list; +@end + +/*! + @category NSMutableSet(Nu) + @abstract NSSet extensions for Nu programming. + */ +@interface NSMutableSet(Nu) +/*! Add an object to a set, automatically converting nil into [NSNull null]. */ +- (void) addPossiblyNullObject:(id)anObject; +@end \ No newline at end of file diff --git a/objc/NSSet+Nu.m b/objc/NSSet+Nu.m new file mode 100644 index 0000000..5cd6e91 --- /dev/null +++ b/objc/NSSet+Nu.m @@ -0,0 +1,57 @@ +// +// NSSet+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSSet+Nu.h" +#import "NuCell.h" +#import "NuInternals.h" + + +@implementation NSSet(Nu) ++ (NSSet *) setWithList:(id) list +{ + NSMutableSet *s = [NSMutableSet set]; + id cursor = list; + while (cursor && cursor != Nu__null) { + [s addObject:[cursor car]]; + cursor = [cursor cdr]; + } + return s; +} + +// Convert a set into a list. +- (NuCell *) list +{ + NSEnumerator *setEnumerator = [self objectEnumerator]; + NSObject *anObject = [setEnumerator nextObject]; + + if(!anObject) + return nil; + + NuCell *result = [[[NuCell alloc] init] autorelease]; + NuCell *cursor = result; + [cursor setCar:anObject]; + + while ((anObject = [setEnumerator nextObject])) { + [cursor setCdr:[[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + [cursor setCar:anObject]; + } + return result; +} + +@end + +@implementation NSMutableSet(Nu) + +- (void) addPossiblyNullObject:(id)anObject +{ + [self addObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; +} + +@end + diff --git a/objc/NSString+Nu.h b/objc/NSString+Nu.h new file mode 100644 index 0000000..fea41ef --- /dev/null +++ b/objc/NSString+Nu.h @@ -0,0 +1,67 @@ +// +// NSString+Nu.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @category NSString(Nu) + @abstract NSString extensions for Nu programming. + @discussion NSString extensions for Nu programming. + */ +@interface NSString(Nu) +/*! Get string consisting of a single carriage return character. */ ++ (id) carriageReturn; +/*! + Evaluation operator. In Nu, strings may contain embedded Nu expressions that are evaluated when this method is called. + Expressions are wrapped in #{...} where the ellipses correspond to a Nu expression. + */ +- (id) evalWithContext:(NSMutableDictionary *) context; + +#if !TARGET_OS_IPHONE +/*! Run a shell command and return its results in a string. */ ++ (NSString *) stringWithShellCommand:(NSString *) command; + +/*! Run a shell command with the specified data or string as standard input and return the results in a string. */ ++ (NSString *) stringWithShellCommand:(NSString *) command standardInput:(id) input; +#endif + +/*! Return a string read from standard input. */ ++ (NSString *) stringWithStandardInput; + +/*! If the last character is a newline, return a new string without it. */ +- (NSString *) chomp; + +/*! Create a string from a specified character */ ++ (NSString *) stringWithCharacter:(unichar) c; + +/*! Convert a string into a symbol. */ +- (id) symbolValue; + +/*! Get a representation of the string that can be used in Nu source code. */ +- (NSString *) escapedStringRepresentation; + +/*! Split a string into lines. */ +- (NSArray *) lines; + +/*! Replace a substring with another. */ +- (NSString *) replaceString:(NSString *) target withString:(NSString *) replacement; + +/*! Iterate over each character in a string, evaluating the provided block for each character. */ +- (id) each:(id) block; + +@end + +/*! + @category NSMutableString(Nu) + @abstract NSMutableString extensions for Nu programming. + */ +@interface NSMutableString(Nu) +/*! Append a specified character to a string. */ +- (void) appendCharacter:(unichar) c; +@end + diff --git a/objc/NSString+Nu.m b/objc/NSString+Nu.m new file mode 100644 index 0000000..f414f6d --- /dev/null +++ b/objc/NSString+Nu.m @@ -0,0 +1,251 @@ +// +// NSString+Nu.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NSString+Nu.h" +#import "NuInternals.h" +#import "NSDictionary+Nu.h" +#import "NSData+Nu.h" + +@interface NuStringEnumerator : NSEnumerator +{ + NSString *string; + int index; +} +@end + +@implementation NuStringEnumerator + ++ (NuStringEnumerator *) enumeratorWithString:(NSString *) string +{ + return [[[self alloc] initWithString:string] autorelease]; +} + +- (id) initWithString:(NSString *) s +{ + self = [super init]; + string = [s retain]; + index = 0; + return self; +} + +- (id) nextObject { + if (index < [string length]) { + return [NSNumber numberWithInt:[string characterAtIndex:index++]]; + } else { + return nil; + } +} + +- (void) dealloc { + [string release]; + [super dealloc]; +} + +@end + + +@implementation NSString(Nu) +- (NSString *) stringValue +{ + return self; +} + +- (NSString *) escapedStringRepresentation +{ + NSMutableString *result = [NSMutableString stringWithString:@"\""]; + NSUInteger length = [self length]; + for (int i = 0; i < length; i++) { + unichar c = [self characterAtIndex:i]; + if (c < 32) { + switch (c) { + case 0x07: [result appendString:@"\\a"]; break; + case 0x08: [result appendString:@"\\b"]; break; + case 0x09: [result appendString:@"\\t"]; break; + case 0x0a: [result appendString:@"\\n"]; break; + case 0x0c: [result appendString:@"\\f"]; break; + case 0x0d: [result appendString:@"\\r"]; break; + case 0x1b: [result appendString:@"\\e"]; break; + default: + [result appendFormat:@"\\x%02x", c]; + } + } + else if (c == '"') { + [result appendString:@"\\\""]; + } + else if (c == '\\') { + [result appendString:@"\\\\"]; + } + else if (c < 127) { + [result appendCharacter:c]; + } + else if (c < 256) { + [result appendFormat:@"\\x%02x", c]; + } + else { + [result appendFormat:@"\\u%04x", c]; + } + } + [result appendString:@"\""]; + return result; +} + +- (id) evalWithContext:(NSMutableDictionary *) context +{ + NSMutableString *result; + NSArray *components = [self componentsSeparatedByString:@"#{"]; + if ([components count] == 1) { + result = [NSMutableString stringWithString:self]; + } + else { + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id parser = [context lookupObjectForKey:[symbolTable symbolWithString:@"_parser"]]; + result = [NSMutableString stringWithString:[components objectAtIndex:0]]; + int i; + for (i = 1; i < [components count]; i++) { + NSArray *parts = [[components objectAtIndex:i] componentsSeparatedByString:@"}"]; + NSString *expression = [parts objectAtIndex:0]; + // evaluate each expression + if (expression) { + id body; + @synchronized(parser) { + body = [parser parse:expression]; + } + id value = [body evalWithContext:context]; + NSString *stringValue = [value stringValue]; + [result appendString:stringValue]; + } + [result appendString:[parts objectAtIndex:1]]; + int j = 2; + while (j < [parts count]) { + [result appendString:@"}"]; + [result appendString:[parts objectAtIndex:j]]; + j++; + } + } + } + return result; +} + ++ (id) carriageReturn +{ + return [self stringWithCString:"\n" encoding:NSUTF8StringEncoding]; +} + +#if !TARGET_OS_IPHONE + +// Read the text output of a shell command into a string and return the string. ++ (NSString *) stringWithShellCommand:(NSString *) command +{ + return [self stringWithShellCommand:command standardInput:nil]; +} + ++ (NSString *) stringWithShellCommand:(NSString *) command standardInput:(id) input +{ + NSData *data = [NSData dataWithShellCommand:command standardInput:input]; + return data ? [[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease] chomp] : nil; +} +#endif + ++ (NSString *) stringWithData:(NSData *) data encoding:(int) encoding +{ + return [[[NSString alloc] initWithData:data encoding:encoding] autorelease]; +} + +// Read the contents of standard input into a string. ++ (NSString *) stringWithStandardInput +{ + return [[[NSString alloc] initWithData:[NSData dataWithStandardInput] encoding:NSUTF8StringEncoding] autorelease]; +} + +// If the last character is a newline, delete it. +- (NSString *) chomp +{ + NSInteger lastIndex = [self length] - 1; + if (lastIndex >= 0) { + if ([self characterAtIndex:lastIndex] == 10) { + return [self substringWithRange:NSMakeRange(0, lastIndex)]; + } + else { + return self; + } + } + else { + return self; + } +} + ++ (NSString *) stringWithCharacter:(unichar) c +{ + return [self stringWithFormat:@"%C", c]; +} + +// Convert a string into a symbol. +- (id) symbolValue +{ + return [[NuSymbolTable sharedSymbolTable] symbolWithString:self]; +} + +// Split a string into lines. +- (NSArray *) lines +{ + NSArray *a = [self componentsSeparatedByString:@"\n"]; + if ([[a lastObject] isEqualToString:@""]) { + return [a subarrayWithRange:NSMakeRange(0, [a count]-1)]; + } + else { + return a; + } +} + +// Replace a substring with another. +- (NSString *) replaceString:(NSString *) target withString:(NSString *) replacement +{ + NSMutableString *s = [NSMutableString stringWithString:self]; + [s replaceOccurrencesOfString:target withString:replacement options:0 range:NSMakeRange(0, [self length])]; + return s; +} + +- (id) objectEnumerator +{ + return [NuStringEnumerator enumeratorWithString:self]; +} + +- (id) each:(id) block +{ + id args = [[NuCell alloc] init]; + NSEnumerator *characterEnumerator = [self objectEnumerator]; + id character; + while ((character = [characterEnumerator nextObject])) { + @try + { + [args setCar:character]; + [block evalWithArguments:args context:Nu__null]; + } + @catch (NuBreakException *exception) { + break; + } + @catch (NuContinueException *exception) { + // do nothing, just continue with the next loop iteration + } + @catch (id exception) { + @throw(exception); + } + } + [args release]; + return self; +} + +@end + +@implementation NSMutableString(Nu) +- (void) appendCharacter:(unichar) c +{ + [self appendFormat:@"%C", c]; +} + +@end \ No newline at end of file diff --git a/objc/Nu.h b/objc/Nu.h index 27ca948..1e5dbd3 100644 --- a/objc/Nu.h +++ b/objc/Nu.h @@ -24,1218 +24,8 @@ #import #import -#pragma mark - -#pragma mark Symbol Table - -/*! - @class NuSymbol - @abstract The Nu symbol class. - @discussion Instances of NuSymbol are used to uniquely represent strings in parsed Nu expressions. - NuSymbol objects are used as keys in local evaluation contexts (typically of type NSMutableDictionary) - and each NuSymbol may also have a global value bound to it. - Symbols ending in a colon (':') are considered "labels" which evaluate to themselves without error, - and when a label is found at the head of the list, - the list is considered to be a special type of list called a property list (no relation to ObjC plists). - Each member of a property list is evaluated and the resulting list is returned with no further evaluation. - */ -@interface NuSymbol : NSObject - -/*! Get the global value of a symbol. */ -- (id) value; -/*! Set the global value of a symbol. */ -- (void) setValue:(id)v; -/*! Get an object of type NSString representing the symbol. */ -- (NSString *) stringValue; -/*! Returns true if a symbol is a label. */ -- (bool) isLabel; -/*! Returns true if a symbol is to be replaced by a generated symbol (which only occurs during macro evaluation). */ -- (bool) isGensym; -/*! If a symbol is a label, get a string representing its name. This string omits the final colon (':'). */ -- (NSString *) labelName; -/*! Evaluate a symbol in a specified context. */ -- (id) evalWithContext:(NSMutableDictionary *) context; -/*! Compare a symbol with another symbol by name. This allows arrays of symbols to be easily sorted. */ -- (NSComparisonResult) compare:(NuSymbol *) anotherSymbol; -/*! Get a description of a symbol. This is equivalent to a call to stringValue. */ -- (NSString *) description; - -@end - -/*! - @class NuSymbolTable - @abstract The Nu symbol table class. - @discussion Instances of NuSymbolTable manage collections of NuSymbol objects. - By default, one NuSymbolTable object is shared by all NuParser objects and execution contexts in a process. - */ -@interface NuSymbolTable : NSObject - -/*! Get the shared NuSymbolTable object. */ -+ (NuSymbolTable *) sharedSymbolTable; -/*! Get a symbol with the specified string. */ -- (NuSymbol *) symbolWithString:(NSString *)string; -/*! Lookup a symbol in a symbol table. */ -- (NuSymbol *) lookup:(NSString *) string; -/*! Get an array containing all of the symbols in a symbol table. */ -- (NSArray *) all; -/*! Remove a symbol from the symbol table */ -- (void) removeSymbol:(NuSymbol *) symbol; -@end - -#pragma mark - -#pragma mark List Representation - -/*! - @class NuCell - @abstract The building blocks of lists. - @discussion NuCells are used to build lists and accept several powerful messages for list manipulation. - In Lisp, these are called "cons" cells after the function used to create them. - - Each NuCell contains pointers to two objects, which for historical reasons are called its "car" and "cdr". - These pointers can point to objects of any Objective-C class, - which includes other NuCells. Typically, the car of a NuCell points to a member of a list and - its cdr points to another NuCell that is the head of the remainder of the list. - The cdr of the last element in a list is nil. - In Nu, nil is represented with the [NSNull null] object. - */ -@interface NuCell : NSObject - -/*! Create a new cell with a specifed car and cdr. */ -+ (id) cellWithCar:(id)car cdr:(id)cdr; -/*! Get the car of a NuCell. */ -- (id) car; -/*! Get the cdr of a NuCell. */ -- (id) cdr; -/*! Set the car of a NuCell. */ -- (void) setCar:(id) c; -/*! Set the cdr of a NuCell. */ -- (void) setCdr:(id) c; -/*! Get the last object in a list by traversing the list. Use this carefully. */ -- (id) lastObject; -/*! Get a string representation of a list. In many cases, this can be parsed to produce the original list. */ -- (NSMutableString *) stringValue; -/*! Treat the NuCell as the head of a list of Nu expressions and evaluate those expressions. */ -- (id) evalWithContext:(NSMutableDictionary *)context; -/*! Returns false. NuCells are not atoms. Also, nil is not an atom. But everything else is. */ -- (bool) atom; -/*! Get any comments that were associated with a NuCell in its Nu source file. */ -- (id) comments; -/*! Iterate over each element of the list headed by a NuCell, calling the specified block with the element as an argument. */ -- (id) each:(id) block; -/*! Iterate over each pair of elements of the list headed by a NuCell, calling the specified block with the two elements as arguments. */ -- (id) eachPair:(id) block; -/*! Iterate over each element of the list headed by a NuCell, calling the specified block with the element and its index as arguments. */ -- (id) eachWithIndex:(id) block; -/*! Iterate over each element of the list headed by a NuCell, returning a list containing the elements for which the provided block evaluates non-nil. */ -- (id) select:(id) block; -/*! Iterate over each element of the list headed by a NuCell, returning the first element for which the provided block evaluates non-nil. */ -- (id) find:(id) block; -/*! Iterate over each element of the list headed by a NuCell, applying the provided block to each element, and returning a list of the results. */ -- (id) map:(id) block; -/*! Iterate over each element of the list headed by a NuCell, using the provided block to combine elements into a single return value. */ -- (id) reduce:(id) block from:(id) initial; -/*! Get the length of a list beginning at a NuCell. */ -- (NSUInteger) length; -/*! Get the number of elements in a list. Synonymous with length. */ -- (NSUInteger) count; -/*! Get an array containing the elements of a list. */ -- (NSMutableArray *) array; - -- (void) setFile:(int) f line:(int) l; -- (int) file; -- (int) line; - -- (void)encodeWithCoder:(NSCoder *)coder; -- (id) initWithCoder:(NSCoder *)coder; - -@end - -/*! - @class NuCellWithComments - @abstract A cell with annotated comments. - @discussion To simplify programmatic analysis of Nu code, - the Nu parser can optionally attach the comments preceding a list element to an instance of this subclass of NuCell. - Comments can then be parsed with Nu code, typically to produce documentation. - */ -@interface NuCellWithComments : NuCell - -/*! Get a string containing the comments that preceded a list element. */ -- (id) comments; -/*! Set the comments string for a list element. */ -- (void) setComments:(id) comments; - -@end - -#pragma mark - -#pragma mark Parsing - -/*! - @class NuStack - @abstract A stack class. - @discussion A simple stack class used by the Nu parser. - */ -@interface NuStack : NSObject - -/*! Push an object onto the stack. */ -- (void) push:(id) object; -/*! Pop an object from the top of the stack. Return nil if the stack is empty. */ -- (id) pop; -/*! Return the current stack depth. */ -- (NSUInteger) depth; - -@end - -/*! - @class NuParser - @abstract A Nu language parser. - @discussion Instances of this class are used to parse and evaluate Nu source text. - */ -@interface NuParser : NSObject - -/*! Get the symbol table used by a parser. */ -- (NuSymbolTable *) symbolTable; -/*! Get the top-level evaluation context that a parser uses for evaluation. */ -- (NSMutableDictionary *) context; -/*! Parse Nu source into an expression, returning the NuCell at the top of the resulting expression. - Since parsing may produce multiple expressions, the top-level NuCell is a Nu progn operator. - */ -- (id) parse:(NSString *)string; -/*! Call -parse: while specifying the name of the source file for the string to be parsed. */ -- (id) parse:(NSString *)string asIfFromFilename:(const char *) filename; -/*! Evaluate a parsed Nu expression in the parser's evaluation context. */ -- (id) eval: (id) code; -/*! Parse Nu source text and evaluate it in the parser's evalation context. */ -- (NSString *) parseEval:(NSString *)string; -/*! Get the value of a name or expression in the parser's context. */ -- (id) valueForKey:(NSString *)string; -/*! Set the value of a name in the parser's context. */ -- (void) setValue:(id)value forKey:(NSString *)string; -/*! Returns true if the parser is currently parsing an incomplete Nu expression. - Presumably the rest of the expression will be passed in with a future - invocation of the parse: method. - */ -- (BOOL) incomplete; -/*! Reset the parse set after an error */ -- (void) reset; - -#if !TARGET_OS_IPHONE -/*! Run a parser interactively at the console (Terminal.app). */ -- (int) interact; -/*! Run the main handler for a console(Terminal.app)-oriented Nu shell. */ -+ (int) main; -#endif - -@end - -#pragma mark - -#pragma mark Callables: Functions, Macros, Operators - -/*! - @class NuBlock - @abstract The Nu representation of functions. - @discussion A Nu Block is an anonymous function with a saved execution context. - This is commonly referred to as a closure. - - In Nu programs, blocks may be directly created using the do operator. - Since blocks are objects, they may be passed as method and function arguments and may be assigned to names. - When a block is assigned to a name, the block will be called when a list is evaluated that - contains that name at its head; - the remainder of the list will be evaluated and passed to the block as the block's arguments. - - Blocks are implicitly created by several other operators. - - The Nu function operator uses blocks to create new named functions. - - The Nu macro operator uses blocks to create macros. - Since macros evaluate in their callers' contexts, no context information is kept for blocks used to create macros. - - When used in a class context, the - and + operators - use blocks to create new method implementations. - When a block is called as a method implementation, its context includes the symbols - self and super. This allows method implementations to send messages to - the owning object and its superclass. - */ -@interface NuBlock : NSObject - -/*! Create a block. Requires a list of parameters, the code to be executed, and an execution context. */ -- (id) initWithParameters:(NuCell *)a body:(NuCell *)b context:(NSMutableDictionary *)c; -/*! Get the list of parameters required by the block. */ -- (NuCell *) parameters; -/*! Get the body of code that is evaluated during block evaluation. */ -- (NuCell *) body; -/*! Get the lexical context of the block. - This is a dictionary containing the symbols and associated values at the point - where the block was created. */ -- (NSMutableDictionary *) context; -/*! Evaluate a block using the specified arguments and calling context. */ -- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context; -/*! Evaluate a block using the specified arguments, calling context, and owner. - This is the mechanism used to evaluate blocks as methods. */ -- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context self:(id)object; -/*! Get a string representation of the block. */ -- (NSString *) stringValue; - -@end - -/*! - @class NuMacro_0 - @abstract The Nu implementation of macros. - @discussion Macros allow Nu programmers to arbitrarily extend the Nu language. - - In Nu programs, macros are defined with the macro operator. - - Macros are like functions, but with two important differences: - - First, macro arguments are not evaluated before the macro is called. - It is up to the macro implementation to decide whether and how - many times to evaluate each argument. When a Nu macro is evaluated, - the margs name is defined and is bound to a list of - the arguments of the macro. - - Second, macro evaluation occurs in the context of the caller. - This means that a macro has access to all names defined in the - code that calls it, and that any name assignments made in a macro will - affect the names in the calling code. To avoid unintentional - name conflicts, any names in a macro body that begin with a double - underscore ("__") are replaced with automatically-generated symbols - that are guaranteed to be unique. In Lisp terminology, these generated - symbols are called "gensyms". - */ -@interface NuMacro_0 : NSObject - -/*! Construct a macro. */ -+ (id) macroWithName:(NSString *)name body:(NuCell *)body; -/*! Get the name of a macro. */ -- (NSString *) name; -/*! Get the body of a macro. */ -- (NuCell *) body; -/*! Get any gensyms in a macro. */ -- (NSSet *) gensyms; -/*! Initialize a macro. */ -- (id) initWithName:(NSString *)name body:(NuCell *)body; -/*! Get a string representation of a macro. */ -- (NSString *) stringValue; -/*! Evaluate a macro. */ -- (id) evalWithArguments:(id)margs context:(NSMutableDictionary *)calling_context; -/*! Expand a macro in its context. */ -- (id) expand1:(id)margs context:(NSMutableDictionary *)calling_context; -/*! Insert unique gensym'd variables. */ -- (id) body:(NuCell *) oldBody withGensymPrefix:(NSString *) prefix symbolTable:(NuSymbolTable *) symbolTable; -/*! Expand unquotes in macro body. */ -- (id) expandUnquotes:(id) oldBody withContext:(NSMutableDictionary *) context; - -@end - -/*! - @class NuMacro_1 - @abstract The Nu implementation of a Lisp-like macro operator. - @discussion Macros allow Nu programmers to arbitrarily extend the Nu language. - - The macro operator works similarly to the Nu macro-0 - operator, but differs in the following ways: - - macro accepts a parameter list much like a Nu function. - Nu's macro operator puts all of the parameter list into an - implicit variable named margs, which the body of the macro - must destructure manually. - - macro does not implicitly "quote" the body of the macro. - Instead the backquote (abbreviated as '`') - and bq-comma (abbreviated as ',') operators can be - used to write a macro body that more closely resembles the - generated code. - - For example, the following two macros are equivalent: - - (macro-0 inc! (set (unquote (car margs)) (+ (unquote (car margs)) 1))) - - (macro inc! (n) `(set ,n (+ ,n 1))) - */ -@interface NuMacro_1 : NuMacro_0 - -/*! Construct a macro. */ -+ (id) macroWithName:(NSString *)name parameters:(NuCell*)args body:(NuCell *)body; -/*! Initialize a macro. */ -- (id) initWithName:(NSString *)name parameters:(NuCell *)args body:(NuCell *)body; -/*! Get a string representation of a macro. */ -- (NSString *) stringValue; -/*! Evaluate a macro. */ -- (id) evalWithArguments:(id)margs context:(NSMutableDictionary *)calling_context; -/*! Expand a macro in its context. */ -- (id) expand1:(id)margs context:(NSMutableDictionary *)calling_context; - -@end - -/*! - @class NuOperator - @abstract An abstract class for Nu operators. - @discussion Like everything else in Nu, operators are represented with objects. - Nu operators that are written in Objective-C are implemented with subclasses of this class. - Each operator is intended to have a singleton instance that is bound to a symbol - in a Nu symbol table. An operator is evaluated with a call to - its evalWithArguments:context: method. - When they implement functions, operators evaluate their arguments, - but many special forms exist that evaluate their arguments zero or multiple times. - */ -@interface NuOperator : NSObject - -/*! Evaluate an operator with a list of arguments and an execution context. - This method calls callWithArguments:context: and should not be overridden. - */ -- (id) evalWithArguments:(id) cdr context:(NSMutableDictionary *) context; -/*! Call an operator with a list of arguments and an execution context. - This method should be overridden by implementations of new operators. - */ -- (id) callWithArguments:(id) cdr context:(NSMutableDictionary *) context; - -@end - -#pragma mark - -#pragma mark Bridging C - -/*! - @class NuBridgedFunction - @abstract The Nu wrapper for imported C functions. - @discussion Instances of this class wrap functions imported from C. - - Because NuBridgedFunction is a subclass of NuOperator, Nu expressions that - begin with NuBridgedFunction instances are treated as operator calls. - - In general, operators may or may not evaluate their arguments, - but for NuBridgedFunctions, all arguments are evaluated. - The resulting values are then passed to the bridged C function - using the foreign function interface (libFFI). - - The C function's return value is converted into a Nu object and returned. - - Here is an example showing the use of this class from Nu. - The example imports and calls the C function NSApplicationMain. - -
- - (set NSApplicationMain
-     (NuBridgedFunction
-         functionWithName:"NSApplicationMain"
-         signature:"ii^*"))

- (NSApplicationMain 0 nil) -
-
- - The signature string used to create a NuBridgedFunction must be a valid Objective-C type signature. - In the future, convenience methods may be added to make those signatures easier to generate. - But in practice, this has not been much of a problem. - */ -@interface NuBridgedFunction : NuOperator - -/*! Create a wrapper for a C function with the specified name and signature. - The function is looked up using the dlsym() function and the wrapper is - constructed using libFFI. If the result of this method is assigned to a - symbol, that symbol may be used as the name of the bridged function. - */ -+ (NuBridgedFunction *) functionWithName:(NSString *)name signature:(NSString *)signature; -/*! Initialize a wrapper for a C function with the specified name and signature. - The function is looked up using the dlsym() function and the wrapper is - constructed using libFFI. If the result of this method is assigned to a - symbol, that symbol may be used as the name of the bridged function. - */ -- (NuBridgedFunction *) initWithName:(NSString *)name signature:(NSString *)signature; -/*! Evaluate a bridged function with the specified arguments and context. - Arguments must be in a Nu list. - */ -- (id) evalWithArguments:(id)arguments context:(NSMutableDictionary *)context; -@end - -/*! - @class NuBridgedConstant - @abstract The Nu wrapper for imported C constants. - @discussion This class can be used to import constants defined in C code. - The signature string used to import a constant must be a valid Objective-C type signature. - */ -@interface NuBridgedConstant : NSObject {} -/*! Look up the value of a constant with specified name and type. - The function is looked up using the dlsym() function. - The returned value is of the type specified by the signature argument. - */ -+ (id) constantWithName:(NSString *) name signature:(NSString *) signature; - -@end - -#ifdef __BLOCKS__ -/*! - @class NuBridgedBlock - @abstract Generates a C block that wraps a nu block - @discussion This class makes a C block that wraps a nu block using a supplied - Objective-C-style function signature. This works by copying a dummy c block and - then writing over its function pointer with a libFFI-generated closure function. - */ -@interface NuBridgedBlock : NSObject - -/*! Returns a C block that wraps the supplied nu block using the supplied - Objective-C-style function signature. - */ -+(id)cBlockWithNuBlock:(NuBlock*)nb signature:(NSString*)sig; - -/*! Initializes a NuBridgedBlock object using a NuBlock and an Objective-C-style - function signature. A C block is generated during the initialization. - */ --(id)initWithNuBlock:(NuBlock*)nb signature:(NSString*)sig; - -/*! Returns the NuBlock associated with the NuBridgedBlock object. - */ --(NuBlock*)nuBlock; - -/*! Returns the C block generated by the NuBridgedBlock object. - */ --(id)cBlock; - -@end -#endif //__BLOCKS__ - -#pragma mark - -#pragma mark Wrapping access to items and objects in memory - -/*! - @class NuPointer - @abstract The Nu pointer wrapper. - @discussion The NuPointer class provides a wrapper for pointers to arbitrary locations in memory. - */ -@interface NuPointer : NSObject - -/*! Get the value of the pointer. Don't call this from Nu. */ -- (void *) pointer; -/*! Set the pointer. Used by the bridge to create NuReference objects from pointers. Don't call this from Nu. */ -- (void) setPointer:(void *) pointer; -/*! Set the type of a pointer. This should be an Objective-C type encoding that begins with a "^". */ -- (void) setTypeString:(NSString *) typeString; -/*! Get an Objective-C type string describing the pointer target. */ -- (NSString *) typeString; -/*! Assume the pointer is a pointer to an Objective-C object. Get the object. You had better be right, or this will crash. */ -- (id) object; -/*! Get the value of the pointed-to object, using the typeString to determine the correct type */ -- (id) value; -/*! Helper function, used internally to reserve space for data of a specified type. */ -- (void) allocateSpaceForTypeString:(NSString *) s; -@end - -/*! - @class NuReference - @abstract The Nu object wrapper. - @discussion The NuReference class provides a wrapper for pointers to Objective-C objects. - NuReference objects are used in the Nu language to capture arguments that are returned by value from Objective-C methods. - For example, the following Nu method uses a NuReference to capture a returned-by-reference NSError: - -
- - (- (id) save is
-   (set perror ((NuReference alloc) init))
-   (set result ((self managedObjectContext) save:perror))
-   (unless result
-     (NSLog "error: #{((perror value) localizedDescription)}"))
-   result) -
-
- */ -@interface NuReference : NSObject - -/*! Get the value of the referenced object. */ -- (id) value; -/*! Set the value of the referenced object. */ -- (void) setValue:(id) value; -/*! Set the pointer for a reference. Used by the bridge to create NuReference objects from pointers. Don't call this from Nu. */ -- (void) setPointer:(id *) pointer; -/*! Get a pointer to the referenced object. Used by the bridge to Objective-C to convert NuReference objects to pointers. - Don't call this from Nu. - */ -- (id *) pointerToReferencedObject; -/*! Retain the referenced object. Used by the bridge to Objective-C to retain values returned by reference. */ -- (void) retainReferencedObject; -@end - -#pragma mark - -#pragma mark Interacting with the Objective-C Runtime - -/*! - @class NuMethod - @abstract A Nu wrapper for method representations in the Objective-C runtime. - @discussion NuMethod provides an object wrapper for methods that are represented in the Objective-C runtime. - NuMethod objects are used in the Nu language to manipulate Objective-C methods. - */ -@interface NuMethod : NSObject - -/*! Initialize a NuMethod for a given Objective-C method (used from Objective-C) */ -- (id) initWithMethod:(Method) method; -/*! Get the name of a method. */ -- (NSString *) name; -/*! Get the number of arguments to a method. */ -- (int) argumentCount; -/*! Get the Objective-C type encoding of a method. This includes offset information. */ -- (NSString *) typeEncoding; -/*! Get the Objective-C type signature of a method. */ -- (NSString *) signature; -/*! Get the type encoding of a specified argument of a method. */ -- (NSString *) argumentType:(int) i; -/*! Get the encoded return type of a method. */ -- (NSString *) returnType; -/*! If a method is implemented with Nu, get its block. */ -- (NuBlock *) block; -/*! Compare a method with another method by name. This allows arrays of methods to be easily sorted. */ -- (NSComparisonResult) compare:(NuMethod *) anotherMethod; -@end - -/*! - @class NuClass - @abstract A Nu wrapper for class representations in the Objective-C runtime. - @discussion NuClass provides an object wrapper for classes that are represented in the Objective-C runtime. - NuClass objects are used in the Nu language to manipulate and extend Objective-C classes. - */ -@interface NuClass : NSObject - -/*! Create a class wrapper for the specified class (used from Objective-C). */ -+ (NuClass *) classWithClass:(Class) class; -/*! Create a class wrapper for the named Objective-C class. */ -+ (NuClass *) classWithName:(NSString *)string; -/*! Initialize a class wrapper for the specified class (used from Objective-C). */ -- (id) initWithClass:(Class) class; -/*! Initialize a class wrapper for the named Objective-C class. */ -- (id) initWithClassNamed:(NSString *) name; -/*! Get the class corresponding to the NuClass wrapper (used from Objective-C). */ -- (Class) wrappedClass; -/*! Get an array of all classes known to the Objective-C runtime. - Beware, some of these classes may be deprecated, undocumented, or otherwise unsafe to use. */ -+ (NSArray *) all; -/*! Get the name of a class. */ -- (NSString *) name; -/*! Get an array containing NuMethod representations of the class methods of a class. */ -- (NSArray *) classMethods; -/*! Get an array containing NuMethod representations of the instance methods of a class. */ -- (NSArray *) instanceMethods; -/*! Get an array containing the names of the class methods of a class. */ -- (NSArray *) classMethodNames; -/*! Get an array containing the names of the instance methods of a class. */ -- (NSArray *) instanceMethodNames; -/*! Determine whether a class is derived from another class. */ -- (BOOL) isDerivedFromClass:(Class) parent; -/*! Compare a class with another class by name. This allows arrays of classes to be easily sorted. */ -- (NSComparisonResult) compare:(NuClass *) anotherClass; -/*! Get a class method by name. */ -- (NuMethod *) classMethodWithName:(NSString *) methodName; -/*! Get an instance method by name. */ -- (NuMethod *) instanceMethodWithName:(NSString *) methodName; -/*! Compare two classes for equality. */ -- (BOOL) isEqual:(NuClass *) anotherClass; -/*! Change the superclass of a class. Be careful with this. */ -- (void) setSuperclass:(NuClass *) newSuperclass; -/*! Add an instance method to a class with the specified name, type signature, and body. */ -- (id) addInstanceMethod:(NSString *) methodName signature:(NSString *)signature body:(NuBlock *) block; -/*! Add a class method to a class with the specified name, type signature, and body. */ -- (id) addClassMethod:(NSString *) methodName signature:(NSString *)signature body:(NuBlock *) block; -/*! Add an instance variable to the receiving class. This will cause problems if there are already instances of the receiving class. */ -- (id) addInstanceVariable:(NSString *)variableName signature:(NSString *) signature; - -- (BOOL) isRegistered; -- (void) setRegistered:(BOOL) value; -- (void) registerClass; -@end - -/*! - @class NuSuper - @abstract The Nu superclass proxy, an implementation detail used by Nu methods. - @discussion Instances of this class in Nu methods act as proxies for object superclasses. - Each time a Nu implementation of a method is called, - a NuSuper instance is created and inserted into the method's execution context with the name "super". - This allows method implementations to send messages to superclass implementations. - Typically, there is no need to directly interact with this class from Nu. - */ -@interface NuSuper : NSObject - -/*! Create a NuSuper proxy for an object with a specified class. - Note that the object class must be explicitly specified. - This is necessary to allow proper chaining of message sends - to super when multilevel methods are used (typically for initialization), - each calling the superclass version of itself. */ -+ (NuSuper *) superWithObject:(id) o ofClass:(Class) c; -/*! Initialize a NuSuper proxy for an object with a specified class. */ -- (NuSuper *) initWithObject:(id) o ofClass:(Class) c; -/*! Evalute a list headed by a NuSuper proxy. If non-null, the remainder - of the list is treated as a message that is sent to the object, - but treating the object as if it is an instance of its immediate superclass. - This is equivalent to sending a message to "super" in Objective-C. */ -- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context; - -@end - -/*! - @class NuProperty - @abstract Wrapper for Objective-C properties. - @discussion Preliminary and incomplete. - */ -@interface NuProperty : NSObject - -/*! Create a property wrapper for the specified property (used from Objective-C). */ -+ (NuProperty *) propertyWithProperty:(objc_property_t) property; -/*! Initialize a property wrapper for the specified property (used from Objective-C). */ -- (id) initWithProperty:(objc_property_t) property; - -@end - -#if !TARGET_OS_IPHONE -/*! - @class NuBridgeSupport - @abstract A reader for Apple's BridgeSupport files. - @discussion Methods of this class are used to read Apple's BridgeSupport files. - */ -@interface NuBridgeSupport : NSObject -/*! Import a dynamic library at the specified path. */ -+ (void)importLibrary:(NSString *) libraryPath; -/*! Import a BridgeSupport description of a framework from a specified path. Store the results in the specified dictionary. */ -+ (void)importFramework:(NSString *) framework fromPath:(NSString *) path intoDictionary:(NSMutableDictionary *) BridgeSupport; - -@end -#endif - -#pragma mark - -#pragma mark Error Handling - -/*! - @class NuException - @abstract When something goes wrong in Nu. - @discussion A Nu Exception is a subclass of NSException, representing - errors during execution of Nu code. It has the ability to store trace information. - This information gets added during unwinding the stack by the NuCells. - */ -@interface NuException : NSException - -+ (void)setDefaultExceptionHandler; -+ (void)setVerbose:(BOOL)flag; - -/*! Create a NuException. */ -- (id)initWithName:(NSString *)name reason:(NSString *)reason userInfo:(NSDictionary *)userInfo; - -/*! Get the stack trace. */ -- (NSArray*)stackTrace; - -/*! Add to the stack trace. */ -- (NuException *)addFunction:(NSString *)function lineNumber:(int)line; -- (NuException *)addFunction:(NSString *)function lineNumber:(int)line filename:(NSString*)filename; - -/*! Get a string representation of the exception. */ -- (NSString *)stringValue; - -/*! Dump the exception to stdout. */ -- (NSString*)dump; - -/*! Dump leaving off some of the toplevel */ -- (NSString*)dumpExcludingTopLevelCount:(NSUInteger)count; - -@end - -@interface NuTraceInfo : NSObject - -- (id)initWithFunction:(NSString *)function lineNumber:(int)lineNumber filename:(NSString *)filename; -- (NSString *)filename; -- (int)lineNumber; -- (NSString *)function; - -@end - -#pragma mark - -#pragma mark Mixins - -/*! - @class NuEnumerable - @abstract The NuEnumerable mixin class. - @discussion This class implements methods that act on enumerated collections of objects. - It is designed to be mixed into a class using the include method that Nu adds to NSObject. - The receiving class must have an objectEnumerator method that returns an NSEnumerator. - Some methods in this class take a callable object as an argument; callable objects are those - that have evalWithArguments:context: defined. - */ -@interface NuEnumerable : NSObject - -/*! Iterate over each member of a collection, evaluating the provided callable item for each member. */ -- (id) each:(id) callable; -/*! Iterate over each member of a collection, evaluating the provided block for each member. - The block is expected to take two arguments: the member and its index. */ -- (id) eachWithIndex:(NuBlock *) block; -/*! Iterate over each member of a collection, returning an array containing the elements for which the provided block evaluates non-nil. */ -- (NSArray *) select:(NuBlock *) block; -/*! Iterate over each member of a collection, returning the first element for which the provided block evaluates non-nil. */ -- (id) find:(NuBlock *) block; -/*! Iterate over each member of a collection, applying the provided block to each member, and returning an array of the results. */ -- (NSArray *) map:(id) callable; -/*! Iterate over each member of a collection, using the provided callable to combine members into a single return value. - */ -- (id) reduce:(id) callable from:(id) initial; -/*! Iterate over each member of a collection, applying the provided selector to each member, and returning an array of the results. */ -- (NSArray *) mapSelector:(SEL) selector; - -@end - -#pragma mark - -#pragma mark Class Extensions - -/*! - @category NSObject(Nu) - @abstract NSObject extensions for Nu programming. - */ -@interface NSObject(Nu) -/*! Returns true. In Nu, virtually all Objective-C classes are considered atoms. */ -- (bool) atom; -/*! - Evaluation operator. The Nu default is for an Objective-C object to evaluate to itself, - but certain subclasses (such as NuSymbol and NSString) behave differently. - */ -- (id) evalWithContext:(NSMutableDictionary *) context; -/*! Gets the value of a specified instance variable. */ -- (id) valueForIvar:(NSString *) name; -/*! Sets the value of a specified instance variable. */ -- (void) setValue:(id) value forIvar:(NSString *) name; -/*! Get an array containing NuMethod representations of the class methods of a class. */ -+ (NSArray *) classMethods; -/*! Get an array containing NuMethod representations of the instance methods of a class. */ -+ (NSArray *) instanceMethods; -/*! Get an array containing the names of the class methods of a class. */ -+ (NSArray *) classMethodNames; -/*! Get an array containing the names of the instance methods of a class. */ -+ (NSArray *) instanceMethodNames; -/*! Get an array containing the names of all instance variables of the class. */ -+ (NSArray *) instanceVariableNames; - -/*! Create a subclass of a class with the specified name. */ -+ (id) createSubclassNamed:(NSString *) subclassName; - -/*! Copy a named instance method from another class to the receiving class. */ -+ (BOOL) copyInstanceMethod:(NSString *) methodName fromClass:(NuClass *) prototypeClass; -/*! Copy all of the instance methods from a specified class to the receiving class. */ -+ (BOOL) include:(NuClass *) prototypeClass; - -/*! Send a message to an object with an execution context */ -- (id) sendMessage:(id)cdr withContext:(NSMutableDictionary *)context; -/*! Evaluate a list with the receiving object at the head. Calls sendMessage:withContext: */ -- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context; - -/*! Handle an unknown message. Override this in subclasses to provide dynamic method handling. */ -- (id) handleUnknownMessage:(id) cdr withContext:(NSMutableDictionary *) context; - -/*! This method is automatically sent to a class whenever Nu code creates a subclass of that class. - Its default implementation does nothing. Override it to track subclassing. */ -+ (id) inheritedByClass:(NuClass *) newClass; - -/*! Get a string providing a helpful description of an object. - This method should be overridden by subclasses to be more helpful. */ -- (NSString *) help; - -/*! Swap a pair of instance methods of the underlying class. */ -+ (BOOL) exchangeInstanceMethod:(SEL)sel1 withMethod:(SEL)sel2; - -/*! Swap a pair of class methods of the underlying class. */ -+ (BOOL) exchangeClassMethod:(SEL)sel1 withMethod:(SEL)sel2; - -/*! Concisely set key-value pairs from a property list. */ -- (id) set:(NuCell *) propertyList; - -/*! Set a retained associated object. */ -- (void) setRetainedAssociatedObject:(id) object forKey:(id) key; - -/*! Set an assigned associated object. */ -- (void) setAssignedAssociatedObject:(id) object forKey:(id) key; - -/*! Set a copied associated object. */ -- (void) setCopiedAssociatedObject:(id) object forKey:(id) key; - -/*! Get the value of an associated object. */ -- (id) associatedObjectForKey:(id) key; - -/*! Remove all associated objects. */ -- (void) removeAssociatedObjects; - -/*! Return true if object has a value for the named instance variable. */ -- (BOOL) hasValueForIvar:(NSString *) name; - -/*! Property list helper. Return the XML property list representation of the object. */ -- (NSData *) XMLPropertyListRepresentation; - -/*! Property list helper. Return the binary property list representation of the object. */ -- (NSData *) binaryPropertyListRepresentation; - -@end - -/*! - @category NSNull(Nu) - @abstract NSNull extensions for Nu programming. - @discussion In Nu, nil is represented by [NSNull null]. - */ -@interface NSNull(Nu) -/*! Returns false. In Nu, nil is not an atom. */ -- (bool) atom; -/*! The length of nil is zero. */ -- (NSUInteger) length; -/*! count is a synonym for length. */ -- (NSUInteger) count; -/*! nil converts to an empty array. */ -- (NSMutableArray *) array; -@end - -/*! - @category NSArray(Nu) - @abstract NSArray extensions for Nu programming. - */ -@interface NSArray(Nu) -/*! Creates an array that contains the contents of a specified list. */ -+ (NSArray *) arrayWithList:(id) list; - -/*! Sort an array using its elements' compare: method. */ -- (NSArray *) sort; - -/*! Convert an array into a list. */ -- (NuCell *) list; - -/*! Repeatedly apply a function of two arguments to the elements of an array, - working from right to left and beginning with the specified inital value. */ -- (id) reduceLeft:(id)callable from:(id) initial; - -/*! Iterate over each member of an array in reverse order and beginning with the lastObject, evaluating the provided block for each member. */ -- (id) eachInReverse:(id) callable; - -/*! Return a sorted array using the specified block to compare array elements. - The block should return -1, 0, or 1. */ -- (NSArray *) sortedArrayUsingBlock:(NuBlock *) block; - -@end - -/*! - @category NSMutableArray(Nu) - @abstract NSMutableArray extensions for Nu programming. - */ -@interface NSMutableArray(Nu) -/*! Add the objects from the specified list to the array. */ -- (void) addObjectsFromList:(id)list; -/*! Add an object to an array, automatically converting nil into [NSNull null]. */ -- (void) addPossiblyNullObject:(id)anObject; -/*! Insert an object into an array, automatically converting nil into [NSNull null]. */ -- (void) insertPossiblyNullObject:(id)anObject atIndex:(int)index; -/*! Replace an object in an array, automatically converting nil into [NSNull null]. */ -- (void) replaceObjectAtIndex:(int)index withPossiblyNullObject:(id)anObject; -@end - -/*! - @category NSDictionary(Nu) - @abstract NSDictionary extensions for Nu programming. - */ -@interface NSDictionary(Nu) -/*! Creates a dictionary that contains the contents of a specified list. - The list should be a sequence of interleaved keys and values. */ -+ (NSDictionary *) dictionaryWithList:(id) list; -/*! Look up an object by key, returning the specified default if no object is found. */ -- (id) objectForKey:(id)key withDefault:(id)defaultValue; -@end - -/*! - @category NSMutableDictionary(Nu) - @abstract NSMutableDictionary extensions for Nu programming. - @discussion In Nu, NSMutableDictionaries are used to represent evaluation contexts. - Context keys are NuSymbols, and the associated objects are the symbols' - assigned values. - */ -@interface NSMutableDictionary(Nu) -/*! Looks up the value associated with a key in the current context. - If no value is found, looks in the context's parent, continuing - upward until no more parent contexts are found. */ -- (id) lookupObjectForKey:(id)key; -/*! Add an object to a dictionary, automatically converting nil into [NSNull null]. */ -- (void) setPossiblyNullObject:(id) anObject forKey:(id) aKey; - -@end - -/*! - @category NSSet(Nu) - @abstract NSSet extensions for Nu programming. - */ -@interface NSSet(Nu) -/*! Creates a set that contains the contents of a specified list. */ -+ (NSSet *) setWithList:(id) list; -/*! Convert a set into a list. */ -- (NuCell *) list; -@end - -/*! - @category NSMutableSet(Nu) - @abstract NSSet extensions for Nu programming. - */ -@interface NSMutableSet(Nu) -/*! Add an object to a set, automatically converting nil into [NSNull null]. */ -- (void) addPossiblyNullObject:(id)anObject; -@end - -/*! - @category NSNumber(Nu) - @abstract NSNumber extensions for Nu programming. - */ -@interface NSNumber(Nu) -/*! - Iterate a number of times corresponding to the message receiver. - On each iteration, evaluate the given block after passing in the iteration count. - Iteration counts begin at zero and end at n-1. - */ -- (id) times:(id) block; -/*! - Iterate from the current value up to a specified limit. - On each iteration, evaluate the given block after passing in the index. - Indices begin at the receiver's value and end at the specified number. - */ -- (id) upTo:(id) number do:(id) block; -/*! - Iterate from the current value down to a specified limit. - On each iteration, evaluate the given block after passing in the index. - Indices begin at the receiver's value and end at the specified number. - */ -- (id) downTo:(id) number do:(id) block; -@end - -/*! - @category NSData(Nu) - @abstract NSData extensions for Nu programming. - @discussion NSData extensions for Nu programming. - */ -@interface NSData(Nu) - -#if !TARGET_OS_IPHONE -/*! Run a shell command and return the results as data. */ -+ (NSData *) dataWithShellCommand:(NSString *) command; - -/*! Run a shell command with the specified data or string as standard input and return the results as data. */ -+ (NSData *) dataWithShellCommand:(NSString *) command standardInput:(id) input; -#endif - -/*! Return data read from standard input. */ -+ (NSData *) dataWithStandardInput; - -/*! Property list helper. Return the (immutable) property list value of the associated data. */ -- (id) propertyListValue; - -@end - -/*! - @category NSString(Nu) - @abstract NSString extensions for Nu programming. - @discussion NSString extensions for Nu programming. - */ -@interface NSString(Nu) -/*! Get string consisting of a single carriage return character. */ -+ (id) carriageReturn; -/*! - Evaluation operator. In Nu, strings may contain embedded Nu expressions that are evaluated when this method is called. - Expressions are wrapped in #{...} where the ellipses correspond to a Nu expression. - */ -- (id) evalWithContext:(NSMutableDictionary *) context; - -#if !TARGET_OS_IPHONE -/*! Run a shell command and return its results in a string. */ -+ (NSString *) stringWithShellCommand:(NSString *) command; - -/*! Run a shell command with the specified data or string as standard input and return the results in a string. */ -+ (NSString *) stringWithShellCommand:(NSString *) command standardInput:(id) input; -#endif - -/*! Return a string read from standard input. */ -+ (NSString *) stringWithStandardInput; - -/*! If the last character is a newline, return a new string without it. */ -- (NSString *) chomp; - -/*! Create a string from a specified character */ -+ (NSString *) stringWithCharacter:(unichar) c; - -/*! Convert a string into a symbol. */ -- (id) symbolValue; - -/*! Get a representation of the string that can be used in Nu source code. */ -- (NSString *) escapedStringRepresentation; - -/*! Split a string into lines. */ -- (NSArray *) lines; - -/*! Replace a substring with another. */ -- (NSString *) replaceString:(NSString *) target withString:(NSString *) replacement; - -/*! Iterate over each character in a string, evaluating the provided block for each character. */ -- (id) each:(id) block; - -@end - -/*! - @category NSMutableString(Nu) - @abstract NSMutableString extensions for Nu programming. - */ -@interface NSMutableString(Nu) -/*! Append a specified character to a string. */ -- (void) appendCharacter:(unichar) c; -@end - -/*! - @category NSMethodSignature(Nu) - @abstract NSMethodSignature extensions for Nu programming. - */ -@interface NSMethodSignature (Nu) -/*! Get the type string for a method signature. */ -- (NSString *) typeString; -@end - -/*! - @category NSBundle(Nu) - @abstract NSBundle extensions for Nu programming. - */ -@interface NSBundle (Nu) -/*! Get or load a framework by name. */ -+ (NSBundle *) frameworkWithName:(NSString *) frameworkName; -/*! Load a Nu source file from the framework's resource directory. */ -- (id) loadNuFile:(NSString *) nuFileName withContext:(NSMutableDictionary *) context; -@end - -/*! - @category NSFileManager(Nu) - @abstract NSFileManager extensions for Nu programming. - */ -@interface NSFileManager (Nu) -/*! Get the creation time for a file. */ -+ (id) creationTimeForFileNamed:(NSString *) filename; -/*! Get the latest modification time for a file. */ -+ (id) modificationTimeForFileNamed:(NSString *) filename; -/*! Test for the existence of a directory. */ -+ (int) directoryExistsNamed:(NSString *) filename; -/*! Test for the existence of a file. */ -+ (int) fileExistsNamed:(NSString *) filename; -@end - -#pragma mark - -#pragma mark Regular Expressions - -// Let's make NSRegularExpression and NSTextCheckingResult look like our previous classes, NuRegex and NuRegexMatch - -@interface NSTextCheckingResult (NuRegexMatch) -/*! - @method regex - The regular expression used to make this match. */ -- (NSRegularExpression *)regex; - -/*! - @method count - The number of capturing subpatterns, including the pattern itself. */ -- (NSUInteger)count; - -/*! - @method group - Returns the part of the target string that matched the pattern. */ -- (NSString *)group; - -/*! - @method groupAtIndex: - Returns the part of the target string that matched the subpattern at the given index or nil if it wasn't matched. The subpatterns are indexed in order of their opening parentheses, 0 is the entire pattern, 1 is the first capturing subpattern, and so on. */ -- (NSString *)groupAtIndex:(int)idx; - -/*! - @method string - Returns the target string. */ -- (NSString *)string; - -@end - -@interface NSRegularExpression (NuRegex) - -/*! - @method regexWithPattern: - Creates a new regex using the given pattern string. Returns nil if the pattern string is invalid. */ -+ (id)regexWithPattern:(NSString *)pattern; - -/*! - @method regexWithPattern:options: - Creates a new regex using the given pattern string and option flags. Returns nil if the pattern string is invalid. */ -+ (id)regexWithPattern:(NSString *)pattern options:(int)options; - -/*! - @method initWithPattern: - Initializes the regex using the given pattern string. Returns nil if the pattern string is invalid. */ -- (id)initWithPattern:(NSString *)pattern; - -/*! - @method initWithPattern:options: - Initializes the regex using the given pattern string and option flags. Returns nil if the pattern string is invalid. */ -- (id)initWithPattern:(NSString *)pattern options:(int)options; - -/*! - @method findInString: - Calls findInString:range: using the full range of the target string. */ -- (NSTextCheckingResult *)findInString:(NSString *)string; - -/*! - @method findInString:range: - Returns an NuRegexMatch for the first occurrence of the regex in the given range of the target string or nil if none is found. */ -- (NSTextCheckingResult *)findInString:(NSString *)string range:(NSRange)range; - -/*! - @method findAllInString: - Calls findAllInString:range: using the full range of the target string. */ -- (NSArray *)findAllInString:(NSString *)string; - -/*! - @method findAllInString:range: - Returns an array of all non-overlapping occurrences of the regex in the given range of the target string. The members of the array are NuRegexMatches. */ -- (NSArray *)findAllInString:(NSString *)string range:(NSRange)range; - -/*! - @method replaceWithString:inString: - Calls replaceWithString:inString:limit: with no limit. */ -- (NSString *)replaceWithString:(NSString *)rep inString:(NSString *)str; - -@end - -#pragma mark - -#pragma mark Profiler (Experimental) - -@interface NuProfiler : NSObject - -+ (NuProfiler *) defaultProfiler; - -@end - -#pragma mark - -#pragma mark Utilities (Optional, may disappear) - -/*! - @class NuMath - @abstract A utility class that provides Nu access to common mathematical functions. - @discussion The NuMath class provides a few common mathematical functions as class methods. - */ -@interface NuMath : NSObject -/*! Get the square root of a number. */ -+ (double) sqrt: (double) x; -/*! Get the square of a number. */ -+ (double) square: (double) x; -/*! Get the cubed root of a number. */ -+ (double) cbrt: (double) x; -/*! Get the cosine of an angle. */ -+ (double) cos: (double) x; -/*! Get the sine of an angle. */ -+ (double) sin: (double) x; -/*! Get the largest integral value that is not greater than x.*/ -+ (double) floor: (double) x; -/*! Get the smallest integral value that is greater than or equal to x.*/ -+ (double) ceil: (double) x; -/*! Get the integral value nearest to x by always rounding half-way cases away from zero. */ -+ (double) round: (double) x; -/*! Raise x to the power of y */ -+ (double) raiseNumber: (double) x toPower: (double) y; -/*! Get the qouteint of x divided by y as an integer */ -+ (int) integerDivide:(int) x by:(int) y; -/*! Get the remainder of x divided by y as an integer */ -+ (int) integerMod:(int) x by:(int) y; -/*! Get a random integer. */ -+ (long) random; -/*! Seed the random number generator. */ -+ (void) srandom:(unsigned long) seed; -@end - -#pragma mark - -#pragma mark Top Level Interface +#import "NSObject+Nu.h" +#import "NuParser.h" // call this from main() to run the Nu shell. int NuMain(int argc, const char *argv[]); @@ -1262,7 +52,9 @@ void NuInit(void); Load a Nu source file from a bundle with the specified identifier. Used by bundle (aka framework) initializers. */ -+ (BOOL) loadNuFile:(NSString *) fileName fromBundleWithIdentifier:(NSString *) bundleIdentifier withContext:(NSMutableDictionary *) context; ++ (BOOL) loadNuFile:(NSString *) fileName +fromBundleWithIdentifier:(NSString *) bundleIdentifier + withContext:(NSMutableDictionary *) context; @end // Helpers for programmatic construction of Nu code. Used by nubake. @@ -1279,27 +71,3 @@ id _nuregex_with_length(const unsigned char *pattern, int length, int options); id _nulist(id firstObject,...); id _nudata(const void *bytes, int length); -@interface NuMarkupOperator : NuOperator -{ - NSString *tag; - NSString *prefix; - NSMutableArray *tagIds; - NSMutableArray *tagClasses; - id contents; - BOOL empty; // aka a "void element" -} - -+ (id) operatorWithTag:(NSString *) _tag; -+ (id) operatorWithTag:(NSString *) _tag prefix:(NSString *) _prefix; -+ (id) operatorWithTag:(NSString *) _tag prefix:(NSString *) _prefix contents:(id) _contents; - -- (id) initWithTag:(NSString *) tag; -- (id) initWithTag:(NSString *) tag prefix:(NSString *) prefix contents:(id) contents; -- (void) setEmpty:(BOOL) e; - -- (NSString *) tag; -- (NSString *) prefix; -- (id) contents; -- (BOOL) empty; - -@end diff --git a/objc/Nu.m b/objc/Nu.m index 46d1f01..51cbc21 100644 --- a/objc/Nu.m +++ b/objc/Nu.m @@ -17,15 +17,6 @@ */ #define _GNU_SOURCE 1 -#define NU_VERSION "2.0.1" -#define NU_VERSION_MAJOR 2 -#define NU_VERSION_MINOR 0 -#define NU_VERSION_TWEAK 1 -#define NU_RELEASE_DATE "2011-09-02" -#define NU_RELEASE_YEAR 2011 -#define NU_RELEASE_MONTH 09 -#define NU_RELEASE_DAY 02 - #import #import @@ -72,155 +63,24 @@ #import #import "Nu.h" +#import "NuInternals.h" +#import "NuReference.h" +#import "NuPointer.h" +#import "NSDictionary+Nu.h" +#import "NuEnumerable.h" +#import "NuException.h" +#import "NuBridge.h" + #ifdef LINUX id loadNuLibraryFile(NSString *nuFileName, id parser, id context, id symbolTable); #endif -#define IS_NOT_NULL(xyz) ((xyz) && (((id) (xyz)) != Nu__null)) - -// We'd like for this to be in the ObjC2 API, but it isn't. -static void nu_class_addInstanceVariable_withSignature(Class thisClass, const char *variableName, const char *signature); - -// These are handy. -static IMP nu_class_replaceMethod(Class cls, SEL name, IMP imp, const char *types); -static BOOL nu_copyInstanceMethod(Class destinationClass, Class sourceClass, SEL selector); -static BOOL nu_objectIsKindOfClass(id object, Class class); -static void nu_markEndOfObjCTypeString(char *type, size_t len); - -// This makes it safe to insert nil into container classes -static void nu_swizzleContainerClasses(void); - -static id add_method_to_class(Class c, NSString *methodName, NSString *signature, NuBlock *block); -static id nu_calling_objc_method_handler(id target, Method m, NSMutableArray *args); -static id get_nu_value_from_objc_value(void *objc_value, const char *typeString); -static int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *typeString); -static void *value_buffer_for_objc_type(const char *typeString); -static NSString *signature_for_identifier(NuCell *cell, NuSymbolTable *symbolTable); -static id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *context, BOOL addClassMethod); -static size_t size_of_objc_type(const char *typeString); - -#pragma mark - NuHandler.h - -struct nu_handler_description -{ - IMP handler; - char **description; -}; - -/*! - @class NuHandlerWarehouse - @abstract Internal class used to store and vend method implementations on platforms that don't allow them to be constructed at runtime. - */ -@interface NuHandlerWarehouse : NSObject -+ (void) registerHandlers:(struct nu_handler_description *) description withCount:(int) count forReturnType:(NSString *) returnType; -+ (IMP) handlerWithSelector:(SEL)sel block:(NuBlock *)block signature:(const char *) signature userdata:(char **) userdata; -@end - -static void nu_handler(void *return_value, - struct nu_handler_description *description, - id receiver, - va_list ap); - - -#pragma mark - NuInternals.h - -// Execution contexts are NSMutableDictionaries that are keyed by -// symbols. Here we define two string keys that allow us to store -// some extra information in our contexts. - -// Use this key to get the symbol table from an execution context. -#define SYMBOLS_KEY @"symbols" - -// Use this key to get the parent context of an execution context. -#define PARENT_KEY @"parent" - -/*! - @class NuBreakException - @abstract Internal class used to implement the Nu break operator. - */ -@interface NuBreakException : NSException -@end - -/*! - @class NuContinueException - @abstract Internal class used to implement the Nu continue operator. - */ -@interface NuContinueException : NSException -@end - -/*! - @class NuReturnException - @abstract Internal class used to implement the Nu return operator. - */ -@interface NuReturnException : NSException -{ - id value; - id blockForReturn; -} - -- (id) value; -- (id) blockForReturn; -@end - -// use this to test a value for "truth" -static bool nu_valueIsTrue(id value); - -// use this to get the filename for a NuCell created by the parser -static const char *nu_parsedFilename(int i); - -#pragma mark - DTrace macros - -/* - * Generated by dtrace(1M). - */ - -#ifndef _DTRACE_H -#define _DTRACE_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define NU_STABILITY "___dtrace_stability$nu$v1$5_5_5_1_1_5_1_1_5_5_5_5_5_5_5" - -#define NU_TYPEDEFS "___dtrace_typedefs$nu$v1" - -#define NU_LIST_EVAL_BEGIN(arg0, arg1) \ -{ \ -__asm__ volatile(".reference " NU_TYPEDEFS); \ -__dtrace_probe$nu$list_eval_begin$v1$63686172202a$696e74((char *)arg0, arg1); \ -__asm__ volatile(".reference " NU_STABILITY); \ -} -#define NU_LIST_EVAL_BEGIN_ENABLED() \ -__dtrace_isenabled$nu$list_eval_begin$v1() -#define NU_LIST_EVAL_END(arg0, arg1) \ -{ \ -__asm__ volatile(".reference " NU_TYPEDEFS); \ -__dtrace_probe$nu$list_eval_end$v1$63686172202a$696e74((char *)arg0, arg1); \ -__asm__ volatile(".reference " NU_STABILITY); \ -} -#define NU_LIST_EVAL_END_ENABLED() \ -__dtrace_isenabled$nu$list_eval_end$v1() - - - extern void __dtrace_probe$nu$list_eval_begin$v1$63686172202a$696e74(char *, int); - extern int __dtrace_isenabled$nu$list_eval_begin$v1(void); - extern void __dtrace_probe$nu$list_eval_end$v1$63686172202a$696e74(char *, int); - extern int __dtrace_isenabled$nu$list_eval_end$v1(void); - -#ifdef __cplusplus -} -#endif - -#endif /* _DTRACE_H */ #pragma mark - NuMain -static id Nu__null = 0; +id Nu__null = 0; -static bool nu_valueIsTrue(id value) +bool nu_valueIsTrue(id value) { bool result = value && (value != Nu__null); if (result && nu_objectIsKindOfClass(value, [NSNumber class])) { @@ -429,6 +289,9 @@ void NuInit() } } + +#import "NuRegex.h" + // Helpers for programmatic construction of Nu code. id _nunull() @@ -573,11010 +436,4 @@ + (BOOL) loadNuFile:(NSString *) fileName fromBundleWithIdentifier:(NSString *) @end -#pragma mark - NuBlock.m - -@interface NuBlock () -{ - NuCell *parameters; - NuCell *body; - NSMutableDictionary *context; -} -@end - -@implementation NuBlock - -- (void) dealloc -{ - [parameters release]; - [body release]; - [context release]; - [super dealloc]; -} - -- (id) initWithParameters:(NuCell *)p body:(NuCell *)b context:(NSMutableDictionary *)c -{ - if ((self = [super init])) { - parameters = [p retain]; - body = [b retain]; -#ifdef CLOSE_ON_VALUES - context = [c mutableCopy]; -#else - context = [[NSMutableDictionary alloc] init]; - [context setPossiblyNullObject:c forKey:PARENT_KEY]; - [context setPossiblyNullObject:[c objectForKey:SYMBOLS_KEY] forKey:SYMBOLS_KEY]; -#endif - - // Check for the presence of "*args" in parameter list - id plist = parameters; - - if (!( ([parameters length] == 1) - && ([[[parameters car] stringValue] isEqualToString:@"*args"]))) - { - while (plist && (plist != Nu__null)) - { - id parameter = [plist car]; - - if ([[parameter stringValue] isEqualToString:@"*args"]) - { - printf("Warning: Overriding implicit variable '*args'.\n"); - return self; - } - - plist = [plist cdr]; - } - } - } - return self; -} - -- (NSString *) stringValue -{ - return [NSString stringWithFormat:@"(do %@ %@)", [parameters stringValue], [body stringValue]]; -} - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context -{ - NSUInteger numberOfArguments = [cdr length]; - NSUInteger numberOfParameters = [parameters length]; - - if (numberOfArguments != numberOfParameters) { - // is the last parameter a variable argument? if so, it's ok, and we allow it to have zero elements. - id lastParameter = [parameters lastObject]; - if (lastParameter && ([[lastParameter stringValue] characterAtIndex:0] == '*')) { - if (numberOfArguments < (numberOfParameters - 1)) { - [NSException raise:@"NuIncorrectNumberOfArguments" - format:@"Incorrect number of arguments to block. Received %ld but expected %ld or more: %@", - (unsigned long) numberOfArguments, - (unsigned long) (numberOfParameters - 1), - [parameters stringValue]]; - } - } - else { - [NSException raise:@"NuIncorrectNumberOfArguments" - format:@"Incorrect number of arguments to block. Received %ld but expected %ld: %@", - (unsigned long) numberOfArguments, - (unsigned long) numberOfParameters, - [parameters stringValue]]; - } - } - //NSLog(@"block eval %@", [cdr stringValue]); - // loop over the parameters, looking up their values in the calling_context and copying them into the evaluation_context - id plist = parameters; - id vlist = cdr; - id evaluation_context = [context mutableCopy]; - - // Insert the implicit variable "*args". It contains the entire parameter list. - NuSymbolTable *symbolTable = [evaluation_context objectForKey:SYMBOLS_KEY]; - [evaluation_context setPossiblyNullObject:cdr forKey:[symbolTable symbolWithString:@"*args"]]; - - while (plist && (plist != Nu__null)) { - id parameter = [plist car]; - if ([[parameter stringValue] characterAtIndex:0] == '*') { - id varargs = [[[NuCell alloc] init] autorelease]; - id cursor = varargs; - while (vlist != Nu__null) { - [cursor setCdr:[[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - id value = [vlist car]; - if (calling_context && (calling_context != Nu__null)) - value = [value evalWithContext:calling_context]; - [cursor setCar:value]; - vlist = [vlist cdr]; - } - [evaluation_context setPossiblyNullObject:[varargs cdr] forKey:parameter]; - plist = [plist cdr]; - // this must be the last element in the parameter list - if (plist != Nu__null) { - [NSException raise:@"NuBadParameterList" - format:@"Variable argument list must be the last parameter in the parameter list: %@", - [parameters stringValue]]; - } - } - else { - id value = [vlist car]; - if (calling_context && (calling_context != Nu__null)) - value = [value evalWithContext:calling_context]; - //NSLog(@"setting %@ = %@", parameter, value); - [evaluation_context setPossiblyNullObject:value forKey:parameter]; - plist = [plist cdr]; - vlist = [vlist cdr]; - } - } - // evaluate the body of the block with the saved context (implicit progn) - id value = Nu__null; - id cursor = body; - @try - { - while (cursor && (cursor != Nu__null)) { - value = [[cursor car] evalWithContext:evaluation_context]; - cursor = [cursor cdr]; - } - } - @catch (NuReturnException *exception) { - value = [exception value]; - if ([exception blockForReturn] && ([exception blockForReturn] != self)) { - @throw(exception); - } - } - @catch (id exception) { - @throw(exception); - } - [value retain]; - [value autorelease]; - [evaluation_context release]; - return value; -} - -- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context -{ - return [self callWithArguments:cdr context:calling_context]; -} - -static id getObjectFromContext(id context, id symbol) -{ - while (IS_NOT_NULL(context)) { - id object = [context objectForKey:symbol]; - if (object) - return object; - context = [context objectForKey:PARENT_KEY]; - } - return nil; -} - -- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context self:(id)object -{ - NSUInteger numberOfArguments = [cdr length]; - NSUInteger numberOfParameters = [parameters length]; - if (numberOfArguments != numberOfParameters) { - [NSException raise:@"NuIncorrectNumberOfArguments" - format:@"Incorrect number of arguments to method. Received %ld but expected %ld, %@", - (unsigned long) numberOfArguments, - (unsigned long) numberOfParameters, - [parameters stringValue]]; - } - // NSLog(@"block eval %@", [cdr stringValue]); - // loop over the arguments, looking up their values in the calling_context and copying them into the evaluation_context - id plist = parameters; - id vlist = cdr; - id evaluation_context = [context mutableCopy]; - // NSLog(@"after copying, evaluation context %@ retain count %d", evaluation_context, [evaluation_context retainCount]); - if (object) { - NuSymbolTable *symbolTable = [evaluation_context objectForKey:SYMBOLS_KEY]; - // look up one level for the _class value, but allow for it to be higher (in the perverse case of nested method declarations). - NuClass *c = getObjectFromContext([context objectForKey:PARENT_KEY], [symbolTable symbolWithString:@"_class"]); - [evaluation_context setPossiblyNullObject:object forKey:[symbolTable symbolWithString:@"self"]]; - [evaluation_context setPossiblyNullObject:[NuSuper superWithObject:object ofClass:[c wrappedClass]] forKey:[symbolTable symbolWithString:@"super"]]; - } - while (plist && (plist != Nu__null) && vlist && (vlist != Nu__null)) { - id arg = [plist car]; - // since this message is sent by a method handler (which has already evaluated the block arguments), - // we don't evaluate them here; instead we just copy them - id value = [vlist car]; - // NSLog(@"setting %@ = %@", arg, value); - [evaluation_context setPossiblyNullObject:value forKey:arg]; - plist = [plist cdr]; - vlist = [vlist cdr]; - } - // evaluate the body of the block with the saved context (implicit progn) - id value = Nu__null; - id cursor = body; - @try - { - while (cursor && (cursor != Nu__null)) { - value = [[cursor car] evalWithContext:evaluation_context]; - cursor = [cursor cdr]; - } - } - @catch (NuReturnException *exception) { - value = [exception value]; - if ([exception blockForReturn] && ([exception blockForReturn] != self)) { - @throw(exception); - } - } - @catch (id exception) { - @throw(exception); - } - [value retain]; - [value autorelease]; - [evaluation_context release]; - return value; -} - -- (NSMutableDictionary *) context -{ - return context; -} - -- (NuCell *) parameters -{ - return parameters; -} - -- (NuCell *) body -{ - return body; -} - -@end - -#pragma mark - NuBridge.m - -/* - * types: - * c char - * i int - * s short - * l long - * q long long - * C unsigned char - * I unsigned int - * S unsigned short - * L unsigned long - * Q unsigned long long - * f float - * d double - * B bool (c++) - * v void - * * char * - * @ id - * # Class - * : SEL - * ? unknown - * b4 bit field of 4 bits - * ^type pointer to type - * [type] array - * {name=type...} structure - * (name=type...) union - * - * modifiers: - * r const - * n in - * N inout - * o out - * O bycopy - * R byref - * V oneway - */ - -static NSMutableDictionary *nu_block_table = nil; - -#ifdef __x86_64__ - -#define NSRECT_SIGNATURE0 "{_NSRect={_NSPoint=dd}{_NSSize=dd}}" -#define NSRECT_SIGNATURE1 "{_NSRect=\"origin\"{_NSPoint=\"x\"d\"y\"d}\"size\"{_NSSize=\"width\"d\"height\"d}}" -#define NSRECT_SIGNATURE2 "{_NSRect}" - -#define CGRECT_SIGNATURE0 "{CGRect={CGPoint=dd}{CGSize=dd}}" -#define CGRECT_SIGNATURE1 "{CGRect=\"origin\"{CGPoint=\"x\"d\"y\"d}\"size\"{CGSize=\"width\"d\"height\"d}}" -#define CGRECT_SIGNATURE2 "{CGRect}" - -#define NSRANGE_SIGNATURE "{_NSRange=QQ}" -#define NSRANGE_SIGNATURE1 "{_NSRange}" - -#define NSPOINT_SIGNATURE0 "{_NSPoint=dd}" -#define NSPOINT_SIGNATURE1 "{_NSPoint=\"x\"d\"y\"d}" -#define NSPOINT_SIGNATURE2 "{_NSPoint}" - -#define CGPOINT_SIGNATURE "{CGPoint=dd}" - -#define NSSIZE_SIGNATURE0 "{_NSSize=dd}" -#define NSSIZE_SIGNATURE1 "{_NSSize=\"width\"d\"height\"d}" -#define NSSIZE_SIGNATURE2 "{_NSSize}" - -#define CGSIZE_SIGNATURE "{CGSize=dd}" - -#else - -#define NSRECT_SIGNATURE0 "{_NSRect={_NSPoint=ff}{_NSSize=ff}}" -#define NSRECT_SIGNATURE1 "{_NSRect=\"origin\"{_NSPoint=\"x\"f\"y\"f}\"size\"{_NSSize=\"width\"f\"height\"f}}" -#define NSRECT_SIGNATURE2 "{_NSRect}" - -#define CGRECT_SIGNATURE0 "{CGRect={CGPoint=ff}{CGSize=ff}}" -#define CGRECT_SIGNATURE1 "{CGRect=\"origin\"{CGPoint=\"x\"f\"y\"f}\"size\"{CGSize=\"width\"f\"height\"f}}" -#define CGRECT_SIGNATURE2 "{CGRect}" - -#define NSRANGE_SIGNATURE "{_NSRange=II}" -#define NSRANGE_SIGNATURE1 "{_NSRange}" - -#define NSPOINT_SIGNATURE0 "{_NSPoint=ff}" -#define NSPOINT_SIGNATURE1 "{_NSPoint=\"x\"f\"y\"f}" -#define NSPOINT_SIGNATURE2 "{_NSPoint}" - -#define CGPOINT_SIGNATURE "{CGPoint=ff}" - -#define NSSIZE_SIGNATURE0 "{_NSSize=ff}" -#define NSSIZE_SIGNATURE1 "{_NSSize=\"width\"f\"height\"f}" -#define NSSIZE_SIGNATURE2 "{_NSSize}" - -#define CGSIZE_SIGNATURE "{CGSize=ff}" -#endif - -// private ffi types -static int initialized_ffi_types = false; -static ffi_type ffi_type_nspoint; -static ffi_type ffi_type_nssize; -static ffi_type ffi_type_nsrect; -static ffi_type ffi_type_nsrange; - -static void initialize_ffi_types(void) -{ - if (initialized_ffi_types) return; - initialized_ffi_types = true; - - // It would be better to do this automatically by parsing the ObjC type signatures - ffi_type_nspoint.size = 0; // to be computed automatically - ffi_type_nspoint.alignment = 0; - ffi_type_nspoint.type = FFI_TYPE_STRUCT; - ffi_type_nspoint.elements = malloc(3 * sizeof(ffi_type*)); -#ifdef __x86_64__ - ffi_type_nspoint.elements[0] = &ffi_type_double; - ffi_type_nspoint.elements[1] = &ffi_type_double; -#else - ffi_type_nspoint.elements[0] = &ffi_type_float; - ffi_type_nspoint.elements[1] = &ffi_type_float; -#endif - ffi_type_nspoint.elements[2] = NULL; - - ffi_type_nssize.size = 0; // to be computed automatically - ffi_type_nssize.alignment = 0; - ffi_type_nssize.type = FFI_TYPE_STRUCT; - ffi_type_nssize.elements = malloc(3 * sizeof(ffi_type*)); -#ifdef __x86_64__ - ffi_type_nssize.elements[0] = &ffi_type_double; - ffi_type_nssize.elements[1] = &ffi_type_double; -#else - ffi_type_nssize.elements[0] = &ffi_type_float; - ffi_type_nssize.elements[1] = &ffi_type_float; -#endif - ffi_type_nssize.elements[2] = NULL; - - ffi_type_nsrect.size = 0; // to be computed automatically - ffi_type_nsrect.alignment = 0; - ffi_type_nsrect.type = FFI_TYPE_STRUCT; - ffi_type_nsrect.elements = malloc(3 * sizeof(ffi_type*)); - ffi_type_nsrect.elements[0] = &ffi_type_nspoint; - ffi_type_nsrect.elements[1] = &ffi_type_nssize; - ffi_type_nsrect.elements[2] = NULL; - - ffi_type_nsrange.size = 0; // to be computed automatically - ffi_type_nsrange.alignment = 0; - ffi_type_nsrange.type = FFI_TYPE_STRUCT; - ffi_type_nsrange.elements = malloc(3 * sizeof(ffi_type*)); -#ifdef __x86_64__ - ffi_type_nsrange.elements[0] = &ffi_type_uint64; - ffi_type_nsrange.elements[1] = &ffi_type_uint64; -#else - ffi_type_nsrange.elements[0] = &ffi_type_uint; - ffi_type_nsrange.elements[1] = &ffi_type_uint; -#endif - ffi_type_nsrange.elements[2] = NULL; -} - -static char get_typeChar_from_typeString(const char *typeString) -{ - int i = 0; - char typeChar = typeString[i]; - while ((typeChar == 'r') || (typeChar == 'R') || - (typeChar == 'n') || (typeChar == 'N') || - (typeChar == 'o') || (typeChar == 'O') || - (typeChar == 'V') - ) { - // uncomment the following two lines to complain about unused quantifiers in ObjC type encodings - // if (typeChar != 'r') // don't worry about const - // NSLog(@"ignoring qualifier %c in %s", typeChar, typeString); - typeChar = typeString[++i]; - } - return typeChar; -} - -static ffi_type *ffi_type_for_objc_type(const char *typeString) -{ - char typeChar = get_typeChar_from_typeString(typeString); - switch (typeChar) { - case 'f': return &ffi_type_float; - case 'd': return &ffi_type_double; - case 'v': return &ffi_type_void; - case 'B': return &ffi_type_uchar; - case 'C': return &ffi_type_uchar; - case 'c': return &ffi_type_schar; - case 'S': return &ffi_type_ushort; - case 's': return &ffi_type_sshort; - case 'I': return &ffi_type_uint; - case 'i': return &ffi_type_sint; -#ifdef __x86_64__ - case 'L': return &ffi_type_ulong; - case 'l': return &ffi_type_slong; -#else - case 'L': return &ffi_type_uint; - case 'l': return &ffi_type_sint; -#endif - case 'Q': return &ffi_type_uint64; - case 'q': return &ffi_type_sint64; - case '@': return &ffi_type_pointer; - case '#': return &ffi_type_pointer; - case '*': return &ffi_type_pointer; - case ':': return &ffi_type_pointer; - case '^': return &ffi_type_pointer; - case '{': - { - if (!strcmp(typeString, NSRECT_SIGNATURE0) || - !strcmp(typeString, NSRECT_SIGNATURE1) || - !strcmp(typeString, NSRECT_SIGNATURE2) || - !strcmp(typeString, CGRECT_SIGNATURE0) || - !strcmp(typeString, CGRECT_SIGNATURE1) || - !strcmp(typeString, CGRECT_SIGNATURE2)) { - if (!initialized_ffi_types) initialize_ffi_types(); - return &ffi_type_nsrect; - } - else if ( - !strcmp(typeString, NSRANGE_SIGNATURE) || - !strcmp(typeString, NSRANGE_SIGNATURE1) - ) { - if (!initialized_ffi_types) initialize_ffi_types(); - return &ffi_type_nsrange; - } - else if ( - !strcmp(typeString, NSPOINT_SIGNATURE0) || - !strcmp(typeString, NSPOINT_SIGNATURE1) || - !strcmp(typeString, NSPOINT_SIGNATURE2) || - !strcmp(typeString, CGPOINT_SIGNATURE) - ) { - if (!initialized_ffi_types) initialize_ffi_types(); - return &ffi_type_nspoint; - } - else if ( - !strcmp(typeString, NSSIZE_SIGNATURE0) || - !strcmp(typeString, NSSIZE_SIGNATURE1) || - !strcmp(typeString, NSSIZE_SIGNATURE2) || - !strcmp(typeString, CGSIZE_SIGNATURE) - ) { - if (!initialized_ffi_types) initialize_ffi_types(); - return &ffi_type_nssize; - } - else { - NSLog(@"unknown type identifier %s", typeString); - return &ffi_type_void; - } - } - default: - { - NSLog(@"unknown type identifier %s", typeString); - return &ffi_type_void; // urfkd - } - } -} - -static size_t size_of_objc_type(const char *typeString) -{ - char typeChar = get_typeChar_from_typeString(typeString); - switch (typeChar) { - case 'f': return sizeof(float); - case 'd': return sizeof(double); - case 'v': return sizeof(void *); - case 'B': return sizeof(unsigned int); - case 'C': return sizeof(unsigned int); - case 'c': return sizeof(int); - case 'S': return sizeof(unsigned int); - case 's': return sizeof(int); - case 'I': return sizeof(unsigned int); - case 'i': return sizeof(int); - case 'L': return sizeof(unsigned long); - case 'l': return sizeof(long); - case 'Q': return sizeof(unsigned long long); - case 'q': return sizeof(long long); - case '@': return sizeof(void *); - case '#': return sizeof(void *); - case '*': return sizeof(void *); - case ':': return sizeof(void *); - case '^': return sizeof(void *); - case '{': - { - if (!strcmp(typeString, NSRECT_SIGNATURE0) || - !strcmp(typeString, NSRECT_SIGNATURE1) || - !strcmp(typeString, NSRECT_SIGNATURE2) || - !strcmp(typeString, CGRECT_SIGNATURE0) || - !strcmp(typeString, CGRECT_SIGNATURE1) || - !strcmp(typeString, CGRECT_SIGNATURE2) - ) { - return sizeof(NSRect); - } - else if ( - !strcmp(typeString, NSRANGE_SIGNATURE) || - !strcmp(typeString, NSRANGE_SIGNATURE1) - ) { - return sizeof(NSRange); - } - else if ( - !strcmp(typeString, NSPOINT_SIGNATURE0) || - !strcmp(typeString, NSPOINT_SIGNATURE1) || - !strcmp(typeString, NSPOINT_SIGNATURE2) || - !strcmp(typeString, CGPOINT_SIGNATURE) - ) { - return sizeof(NSPoint); - } - else if ( - !strcmp(typeString, NSSIZE_SIGNATURE0) || - !strcmp(typeString, NSSIZE_SIGNATURE1) || - !strcmp(typeString, NSSIZE_SIGNATURE2) || - !strcmp(typeString, CGSIZE_SIGNATURE) - ) { - return sizeof(NSSize); - } - else { - NSLog(@"unknown type identifier %s", typeString); - return sizeof (void *); - } - } - default: - { - NSLog(@"unknown type identifier %s", typeString); - return sizeof (void *); - } - } -} - -static void *value_buffer_for_objc_type(const char *typeString) -{ - char typeChar = get_typeChar_from_typeString(typeString); - switch (typeChar) { - case 'f': return malloc(sizeof(float)); - case 'd': return malloc(sizeof(double)); - case 'v': return malloc(sizeof(void *)); - case 'B': return malloc(sizeof(unsigned int)); - case 'C': return malloc(sizeof(unsigned int)); - case 'c': return malloc(sizeof(int)); - case 'S': return malloc(sizeof(unsigned int)); - case 's': return malloc(sizeof(int)); - case 'I': return malloc(sizeof(unsigned int)); - case 'i': return malloc(sizeof(int)); - case 'L': return malloc(sizeof(unsigned long)); - case 'l': return malloc(sizeof(long)); - case 'Q': return malloc(sizeof(unsigned long long)); - case 'q': return malloc(sizeof(long long)); - case '@': return malloc(sizeof(void *)); - case '#': return malloc(sizeof(void *)); - case '*': return malloc(sizeof(void *)); - case ':': return malloc(sizeof(void *)); - case '^': return malloc(sizeof(void *)); - case '{': - { - if (!strcmp(typeString, NSRECT_SIGNATURE0) || - !strcmp(typeString, NSRECT_SIGNATURE1) || - !strcmp(typeString, NSRECT_SIGNATURE2) || - !strcmp(typeString, CGRECT_SIGNATURE0) || - !strcmp(typeString, CGRECT_SIGNATURE1) || - !strcmp(typeString, CGRECT_SIGNATURE2) - ) { - return malloc(sizeof(NSRect)); - } - else if ( - !strcmp(typeString, NSRANGE_SIGNATURE) || - !strcmp(typeString, NSRANGE_SIGNATURE1) - ) { - return malloc(sizeof(NSRange)); - } - else if ( - !strcmp(typeString, NSPOINT_SIGNATURE0) || - !strcmp(typeString, NSPOINT_SIGNATURE1) || - !strcmp(typeString, NSPOINT_SIGNATURE2) || - !strcmp(typeString, CGPOINT_SIGNATURE) - ) { - return malloc(sizeof(NSPoint)); - } - else if ( - !strcmp(typeString, NSSIZE_SIGNATURE0) || - !strcmp(typeString, NSSIZE_SIGNATURE1) || - !strcmp(typeString, NSSIZE_SIGNATURE2) || - !strcmp(typeString, CGSIZE_SIGNATURE) - ) { - return malloc(sizeof(NSSize)); - } - else { - NSLog(@"unknown type identifier %s", typeString); - return malloc(sizeof (void *)); - } - } - default: - { - NSLog(@"unknown type identifier %s", typeString); - return malloc(sizeof (void *)); - } - } -} - -static int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *typeString) -{ - // NSLog(@"VALUE => %s", typeString); - char typeChar = get_typeChar_from_typeString(typeString); - switch (typeChar) { - case '@': - { - if (nu_value == Nu__null) { - *((id *) objc_value) = nil; - return NO; - } - *((id *) objc_value) = nu_value; - return NO; - } - case 'I': -#ifndef __ppc__ - case 'S': - case 'C': -#endif - { - if (nu_value == Nu__null) { - *((unsigned int *) objc_value) = 0; - return NO; - } - *((unsigned int *) objc_value) = [nu_value unsignedIntValue]; - return NO; - } -#ifdef __ppc__ - case 'S': - { - if (nu_value == Nu__null) { - *((unsigned short *) objc_value) = 0; - return NO; - } - *((unsigned short *) objc_value) = [nu_value unsignedShortValue]; - return NO; - } - case 'C': - { - if (nu_value == Nu__null) { - *((unsigned char *) objc_value) = 0; - return NO; - } - *((unsigned char *) objc_value) = [nu_value unsignedCharValue]; - return NO; - } -#endif - case 'i': -#ifndef __ppc__ - case 's': - case 'c': -#endif - { - if (nu_value == [NSNull null]) { - *((int *) objc_value) = 0; - return NO; - } - *((int *) objc_value) = [nu_value intValue]; - return NO; - } -#ifdef __ppc__ - case 's': - { - if (nu_value == Nu__null) { - *((short *) objc_value) = 0; - return NO; - } - *((short *) objc_value) = [nu_value shortValue]; - return NO; - } - case 'c': - { - if (nu_value == Nu__null) { - *((char *) objc_value) = 0; - return NO; - } - *((char *) objc_value) = [nu_value charValue]; - return NO; - } -#endif - case 'L': - { - if (nu_value == [NSNull null]) { - *((unsigned long *) objc_value) = 0; - return NO; - } - *((unsigned long *) objc_value) = [nu_value unsignedLongValue]; - return NO; - } - case 'l': - { - if (nu_value == [NSNull null]) { - *((long *) objc_value) = 0; - return NO; - } - *((long *) objc_value) = [nu_value longValue]; - return NO; - } - case 'Q': - { - if (nu_value == [NSNull null]) { - *((unsigned long long *) objc_value) = 0; - return NO; - } - *((unsigned long long *) objc_value) = [nu_value unsignedLongLongValue]; - return NO; - } - case 'q': - { - if (nu_value == [NSNull null]) { - *((long long *) objc_value) = 0; - return NO; - } - *((long long *) objc_value) = [nu_value longLongValue]; - return NO; - } - case 'd': - { - *((double *) objc_value) = [nu_value doubleValue]; - return NO; - } - case 'f': - { - *((float *) objc_value) = (float) [nu_value doubleValue]; - return NO; - } - case 'v': - { - return NO; - } - case ':': - { - // selectors must be strings (symbols could be ok too...) - if (!nu_value || (nu_value == [NSNull null])) { - *((SEL *) objc_value) = 0; - return NO; - } - const char *selectorName = [nu_value cStringUsingEncoding:NSUTF8StringEncoding]; - if (selectorName) { - *((SEL *) objc_value) = sel_registerName(selectorName); - return NO; - } - else { - NSLog(@"can't convert %@ to a selector", nu_value); - return NO; - } - } - case '{': - { - if ( - !strcmp(typeString, NSRECT_SIGNATURE0) || - !strcmp(typeString, NSRECT_SIGNATURE1) || - !strcmp(typeString, NSRECT_SIGNATURE2) || - !strcmp(typeString, CGRECT_SIGNATURE0) || - !strcmp(typeString, CGRECT_SIGNATURE1) || - !strcmp(typeString, CGRECT_SIGNATURE2) - ) { - NSRect *rect = (NSRect *) objc_value; - id cursor = nu_value; - rect->origin.x = (CGFloat) [[cursor car] doubleValue]; cursor = [cursor cdr]; - rect->origin.y = (CGFloat) [[cursor car] doubleValue]; cursor = [cursor cdr]; - rect->size.width = (CGFloat) [[cursor car] doubleValue]; cursor = [cursor cdr]; - rect->size.height = (CGFloat) [[cursor car] doubleValue]; - //NSLog(@"nu->rect: %x %f %f %f %f", (void *) rect, rect->origin.x, rect->origin.y, rect->size.width, rect->size.height); - return NO; - } - else if ( - !strcmp(typeString, NSRANGE_SIGNATURE) || - !strcmp(typeString, NSRANGE_SIGNATURE1) - ) { - NSRange *range = (NSRange *) objc_value; - id cursor = nu_value; - range->location = [[cursor car] intValue]; cursor = [cursor cdr];; - range->length = [[cursor car] intValue]; - return NO; - } - else if ( - !strcmp(typeString, NSSIZE_SIGNATURE0) || - !strcmp(typeString, NSSIZE_SIGNATURE1) || - !strcmp(typeString, NSSIZE_SIGNATURE2) || - !strcmp(typeString, CGSIZE_SIGNATURE) - ) { - NSSize *size = (NSSize *) objc_value; - id cursor = nu_value; - size->width = [[cursor car] doubleValue]; cursor = [cursor cdr];; - size->height = [[cursor car] doubleValue]; - return NO; - } - else if ( - !strcmp(typeString, NSPOINT_SIGNATURE0) || - !strcmp(typeString, NSPOINT_SIGNATURE1) || - !strcmp(typeString, NSPOINT_SIGNATURE2) || - !strcmp(typeString, CGPOINT_SIGNATURE) - ) { - NSPoint *point = (NSPoint *) objc_value; - id cursor = nu_value; - point->x = [[cursor car] doubleValue]; cursor = [cursor cdr];; - point->y = [[cursor car] doubleValue]; - return NO; - } - else { - NSLog(@"UNIMPLEMENTED: can't wrap structure of type %s", typeString); - return NO; - } - } - - case '^': - { - if (!nu_value || (nu_value == [NSNull null])) { - *((char ***) objc_value) = NULL; - return NO; - } - // pointers require some work.. and cleanup. This LEAKS. - if (!strcmp(typeString, "^*")) { - // array of strings, which requires an NSArray or NSNull (handled above) - if (nu_objectIsKindOfClass(nu_value, [NSArray class])) { - NSUInteger array_size = [nu_value count]; - char **array = (char **) malloc (array_size * sizeof(char *)); - int i; - for (i = 0; i < array_size; i++) { - array[i] = strdup([[nu_value objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding]); - } - *((char ***) objc_value) = array; - return NO; - } - else { - NSLog(@"can't convert value of type %s to a pointer to strings", class_getName([nu_value class])); - *((char ***) objc_value) = NULL; - return NO; - } - } - else if (!strcmp(typeString, "^@")) { - if (nu_objectIsKindOfClass(nu_value, [NuReference class])) { - *((id **) objc_value) = [nu_value pointerToReferencedObject]; - return YES; - } - } - else if (nu_objectIsKindOfClass(nu_value, [NuPointer class])) { - if ([nu_value pointer] == 0) - [nu_value allocateSpaceForTypeString:[NSString stringWithCString:typeString encoding:NSUTF8StringEncoding]]; - *((void **) objc_value) = [nu_value pointer]; - return NO; // don't ask the receiver to retain this, it's just a pointer - } - else { - *((void **) objc_value) = nu_value; - return NO; // don't ask the receiver to retain this, it isn't expecting an object - } - } - - case '*': - { - *((char **) objc_value) = (char*)[[nu_value stringValue] cStringUsingEncoding:NSUTF8StringEncoding]; - return NO; - } - - case '#': - { - if (nu_objectIsKindOfClass(nu_value, [NuClass class])) { - *((Class *)objc_value) = [nu_value wrappedClass]; - return NO; - } - else { - NSLog(@"can't convert value of type %s to CLASS", class_getName([nu_value class])); - *((id *) objc_value) = 0; - return NO; - } - } - default: - NSLog(@"can't wrap argument of type %s", typeString); - } - return NO; -} - -static id get_nu_value_from_objc_value(void *objc_value, const char *typeString) -{ - //NSLog(@"%s => VALUE", typeString); - char typeChar = get_typeChar_from_typeString(typeString); - switch(typeChar) { - case 'v': - { - return [NSNull null]; - } - case '@': - { - id result = *((id *)objc_value); - return result ? result : (id)[NSNull null]; - } - case '#': - { - Class c = *((Class *)objc_value); - return c ? [[[NuClass alloc] initWithClass:c] autorelease] : Nu__null; - } -#ifndef __ppc__ - case 'c': - { - return [NSNumber numberWithChar:*((char *)objc_value)]; - } - case 's': - { - return [NSNumber numberWithShort:*((short *)objc_value)]; - } -#else - case 'c': - case 's': -#endif - case 'i': - { - return [NSNumber numberWithInt:*((int *)objc_value)]; - } -#ifndef __ppc__ - case 'C': - { - return [NSNumber numberWithUnsignedChar:*((unsigned char *)objc_value)]; - } - case 'S': - { - return [NSNumber numberWithUnsignedShort:*((unsigned short *)objc_value)]; - } -#else - case 'C': - case 'S': -#endif - case 'I': - { - return [NSNumber numberWithUnsignedInt:*((unsigned int *)objc_value)]; - } - case 'l': - { - return [NSNumber numberWithLong:*((long *)objc_value)]; - } - case 'L': - { - return [NSNumber numberWithUnsignedLong:*((unsigned long *)objc_value)]; - } - case 'q': - { - return [NSNumber numberWithLongLong:*((long long *)objc_value)]; - } - case 'Q': - { - return [NSNumber numberWithUnsignedLongLong:*((unsigned long long *)objc_value)]; - } - case 'f': - { - return [NSNumber numberWithFloat:*((float *)objc_value)]; - } - case 'd': - { - return [NSNumber numberWithDouble:*((double *)objc_value)]; - } - case ':': - { - SEL sel = *((SEL *)objc_value); - return [[NSString stringWithCString:sel_getName(sel) encoding:NSUTF8StringEncoding] retain]; - } - case '{': - { - if ( - !strcmp(typeString, NSRECT_SIGNATURE0) || - !strcmp(typeString, NSRECT_SIGNATURE1) || - !strcmp(typeString, NSRECT_SIGNATURE2) || - !strcmp(typeString, CGRECT_SIGNATURE0) || - !strcmp(typeString, CGRECT_SIGNATURE1) || - !strcmp(typeString, CGRECT_SIGNATURE2) - ) { - NSRect *rect = (NSRect *)objc_value; - NuCell *list = [[[NuCell alloc] init] autorelease]; - id cursor = list; - [cursor setCar:[NSNumber numberWithDouble:rect->origin.x]]; - [cursor setCdr:[[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - [cursor setCar:[NSNumber numberWithDouble:rect->origin.y]]; - [cursor setCdr:[[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - [cursor setCar:[NSNumber numberWithDouble:rect->size.width]]; - [cursor setCdr:[[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - [cursor setCar:[NSNumber numberWithDouble:rect->size.height]]; - //NSLog(@"converting rect at %x to list: %@", (void *) rect, [list stringValue]); - return list; - } - else if ( - !strcmp(typeString, NSRANGE_SIGNATURE) || - !strcmp(typeString, NSRANGE_SIGNATURE1) - ) { - NSRange *range = (NSRange *)objc_value; - NuCell *list = [[[NuCell alloc] init] autorelease]; - id cursor = list; - [cursor setCar:[NSNumber numberWithInteger:range->location]]; - [cursor setCdr:[[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - [cursor setCar:[NSNumber numberWithInteger:range->length]]; - return list; - } - else if ( - !strcmp(typeString, NSPOINT_SIGNATURE0) || - !strcmp(typeString, NSPOINT_SIGNATURE1) || - !strcmp(typeString, NSPOINT_SIGNATURE2) || - !strcmp(typeString, CGPOINT_SIGNATURE) - ) { - NSPoint *point = (NSPoint *)objc_value; - NuCell *list = [[[NuCell alloc] init] autorelease]; - id cursor = list; - [cursor setCar:[NSNumber numberWithDouble:point->x]]; - [cursor setCdr:[[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - [cursor setCar:[NSNumber numberWithDouble:point->y]]; - return list; - } - else if ( - !strcmp(typeString, NSSIZE_SIGNATURE0) || - !strcmp(typeString, NSSIZE_SIGNATURE1) || - !strcmp(typeString, NSSIZE_SIGNATURE2) || - !strcmp(typeString, CGSIZE_SIGNATURE) - ) { - NSSize *size = (NSSize *)objc_value; - NuCell *list = [[[NuCell alloc] init] autorelease]; - id cursor = list; - [cursor setCar:[NSNumber numberWithDouble:size->width]]; - [cursor setCdr:[[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - [cursor setCar:[NSNumber numberWithDouble:size->height]]; - return list; - } - else { - NSLog(@"UNIMPLEMENTED: can't wrap structure of type %s", typeString); - } - } - case '*': - { - return [NSString stringWithCString:*((char **)objc_value) encoding:NSUTF8StringEncoding]; - } - case 'B': - { - if (*((unsigned int *)objc_value) == 0) - return [NSNull null]; - else - return [NSNumber numberWithInt:1]; - } - case '^': - { - if (!strcmp(typeString, "^v")) { - if (*((unsigned long *)objc_value) == 0) - return [NSNull null]; - else { - id nupointer = [[[NuPointer alloc] init] autorelease]; - [nupointer setPointer:*((void **)objc_value)]; - [nupointer setTypeString:[NSString stringWithCString:typeString encoding:NSUTF8StringEncoding]]; - return nupointer; - } - } - else if (!strcmp(typeString, "^@")) { - id reference = [[[NuReference alloc] init] autorelease]; - [reference setPointer:*((id**)objc_value)]; - return reference; - } - // Certain pointer types are essentially just ids. - // CGImageRef is one. As we find others, we can add them here. - else if (!strcmp(typeString, "^{CGImage=}")) { - id result = *((id *)objc_value); - return result ? result : (id)[NSNull null]; - } - else if (!strcmp(typeString, "^{CGColor=}")) { - id result = *((id *)objc_value); - return result ? result : (id)[NSNull null]; - } - else { - if (*((unsigned long *)objc_value) == 0) - return [NSNull null]; - else { - id nupointer = [[[NuPointer alloc] init] autorelease]; - [nupointer setPointer:*((void **)objc_value)]; - [nupointer setTypeString:[NSString stringWithCString:typeString encoding:NSUTF8StringEncoding]]; - return nupointer; - } - } - return [NSNull null]; - } - default: - NSLog (@"UNIMPLEMENTED: unable to wrap object of type %s", typeString); - return [NSNull null]; - } - -} - -static void raise_argc_exception(SEL s, NSUInteger count, NSUInteger given) -{ - if (given != count) { - [NSException raise:@"NuIncorrectNumberOfArguments" - format:@"Incorrect number of arguments to selector %s. Received %ld but expected %ld", - sel_getName(s), - (unsigned long) given, - (unsigned long) count]; - } -} - -#define BUFSIZE 500 - -static id nu_calling_objc_method_handler(id target, Method m, NSMutableArray *args) -{ - // this call seems to force the class's +initialize method to be called. - [target class]; - - // NSLog(@"calling ObjC method %s with target of class %@", sel_getName(method_getName(m)), [target class]); - - IMP imp = method_getImplementation(m); - - // if the imp has an associated block, this is a nu-to-nu call. - // skip going through the ObjC runtime and evaluate the block directly. - NuBlock *block = nil; - if (nu_block_table && - ((block = [nu_block_table objectForKey:[NSNumber numberWithUnsignedLong:(unsigned long)imp]]))) { - // NSLog(@"nu calling nu method %s of class %@", sel_getName(method_getName(m)), [target class]); - id arguments = [[NuCell alloc] init]; - id cursor = arguments; - NSUInteger argc = [args count]; - int i; - for (i = 0; i < argc; i++) { - NuCell *nextCell = [[NuCell alloc] init]; - [cursor setCdr:nextCell]; - [nextCell release]; - cursor = [cursor cdr]; - [cursor setCar:[args objectAtIndex:i]]; - } - id result = [block evalWithArguments:[arguments cdr] context:nil self:target]; - [arguments release]; - // ensure that methods declared to return void always return void. - char return_type_buffer[BUFSIZE]; - method_getReturnType(m, return_type_buffer, BUFSIZE); - return (!strcmp(return_type_buffer, "v")) ? (id)[NSNull null] : result; - } - - id result; - // if we get here, we're going through the ObjC runtime to make the call. - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - SEL s = method_getName(m); - result = [NSNull null]; - - // dynamically construct the method call - - - int argument_count = method_getNumberOfArguments(m); - - if ( [args count] != argument_count-2) { - - raise_argc_exception(s, argument_count-2, [args count]); - } - else { - char return_type_buffer[BUFSIZE], arg_type_buffer[BUFSIZE]; - method_getReturnType(m, return_type_buffer, BUFSIZE); - ffi_type *result_type = ffi_type_for_objc_type(&return_type_buffer[0]); - void *result_value = value_buffer_for_objc_type(&return_type_buffer[0]); - ffi_type **argument_types = (ffi_type **) malloc (argument_count * sizeof(ffi_type *)); - void **argument_values = (void **) malloc (argument_count * sizeof(void *)); - int *argument_needs_retained = (int *) malloc (argument_count * sizeof(int)); - int i; - for (i = 0; i < argument_count; i++) { - - method_getArgumentType(m, i, &arg_type_buffer[0], BUFSIZE); - - argument_types[i] = ffi_type_for_objc_type(&arg_type_buffer[0]); - argument_values[i] = value_buffer_for_objc_type(&arg_type_buffer[0]); - if (i == 0) - *((id *) argument_values[i]) = target; - else if (i == 1) - *((SEL *) argument_values[i]) = method_getName(m); - else - argument_needs_retained[i-2] = set_objc_value_from_nu_value(argument_values[i], [args objectAtIndex:(i-2)], &arg_type_buffer[0]); - } - ffi_cif cif2; - int status = ffi_prep_cif(&cif2, FFI_DEFAULT_ABI, (unsigned int) argument_count, result_type, argument_types); - if (status != FFI_OK) { - NSLog (@"failed to prepare cif structure"); - } - else { - const char *method_name = sel_getName(method_getName(m)); - BOOL callingInitializer = !strncmp("init", method_name, 4); - if (callingInitializer) { - [target retain]; // in case an init method releases its target (to return something else), we preemptively retain it - } - // call the method handler - ffi_call(&cif2, FFI_FN(imp), result_value, argument_values); - // extract the return value - result = get_nu_value_from_objc_value(result_value, &return_type_buffer[0]); - // NSLog(@"result is %@", result); - // NSLog(@"retain count %d", [result retainCount]); - - // Return values should not require a release. - // Either they are owned by an existing object or are autoreleased. - // Exceptions to this rule are handled below. - // Since these methods create new objects that aren't autoreleased, we autorelease them. -#ifdef LINUX - const char *methodName = sel_getName(s); - bool already_retained = !strcmp(methodName,"alloc") || - !strcmp(methodName,"allocWithZone:") || - !strcmp(methodName,"copy") || - !strcmp(methodName,"copyWithZone:") || - !strcmp(methodName,"mutableCopy:") || - !strcmp(methodName,"mutableCopyWithZone:") || - !strcmp(methodName,"new"); -#else - bool already_retained = // see Anguish/Buck/Yacktman, p. 104 - (s == @selector(alloc)) || (s == @selector(allocWithZone:)) - || (s == @selector(copy)) || (s == @selector(copyWithZone:)) - || (s == @selector(mutableCopy)) || (s == @selector(mutableCopyWithZone:)) - || (s == @selector(new)); -#endif - // NSLog(@"already retained? %d", already_retained); - if (already_retained) { - [result autorelease]; - } - - if (callingInitializer) { - if (result == target) { - // NSLog(@"undoing preemptive retain of init target %@", [target className]); - [target release]; // undo our preemptive retain - } else { - // NSLog(@"keeping preemptive retain of init target %@", [target className]); - } - } - - for (i = 0; i < [args count]; i++) { - if (argument_needs_retained[i]) - [[args objectAtIndex:i] retainReferencedObject]; - } - - // free the value structures - for (i = 0; i < argument_count; i++) { - free(argument_values[i]); - } - free(argument_values); - free(result_value); - free(argument_types); - free(argument_needs_retained); - } - } - [result retain]; - [pool drain]; - [result autorelease]; - return result; -} - -@interface NSMethodSignature (UndocumentedInterface) -+ (id) signatureWithObjCTypes:(const char*)types; -@end - -static void objc_calling_nu_method_handler(ffi_cif* cif, void* returnvalue, void** args, void* userdata) -{ - int argc = cif->nargs - 2; - id rcv = *((id*)args[0]); // this is the object getting the message - // unused: SEL sel = *((SEL*)args[1]); - - // in rare cases, we need an autorelease pool (specifically detachNewThreadSelector:toTarget:withObject:) - // previously we used a private api to verify that one existed before creating a new one. Now we just make one. - NSAutoreleasePool *pool = nil; // [[NSAutoreleasePool alloc] init]; - - NuBlock *block = ((NuBlock **)userdata)[1]; - //NSLog(@"----------------------------------------"); - //NSLog(@"calling block %@", [block stringValue]); - id arguments = [[NuCell alloc] init]; - id cursor = arguments; - int i; - for (i = 0; i < argc; i++) { - NuCell *nextCell = [[NuCell alloc] init]; - [cursor setCdr:nextCell]; - [nextCell release]; - cursor = [cursor cdr]; - id value = get_nu_value_from_objc_value(args[i+2], ((char **)userdata)[i+2]); - [cursor setCar:value]; - } - id result = [block evalWithArguments:[arguments cdr] context:nil self:rcv]; - //NSLog(@"in nu method handler, putting result %@ in %x with type %s", [result stringValue], (int) returnvalue, ((char **)userdata)[0]); - char *resultType = (((char **)userdata)[0])+1;// skip the first character, it's a flag - set_objc_value_from_nu_value(returnvalue, result, resultType); -#ifdef __ppc__ - // It appears that at least on PowerPC architectures, small values (short, char, ushort, uchar) passed in via - // the ObjC runtime use their actual type while function return values are coerced up to integers. - // I suppose this is because values are passed as arguments in memory and returned in registers. - // This may also be the case on x86 but is unobserved because x86 is little endian. - switch (resultType[0]) { - case 'C': - { - *((unsigned int *) returnvalue) = *((unsigned char *) returnvalue); - break; - } - case 'c': - { - *((int *) returnvalue) = *((char *) returnvalue); - break; - } - case 'S': - { - *((unsigned int *) returnvalue) = *((unsigned short *) returnvalue); - break; - } - case 's': - { - *((int *) returnvalue) = *((short *) returnvalue); - break; - } - } -#endif - - if (((char **)userdata)[0][0] == '!') { - //NSLog(@"retaining result for object %@, count = %d", *(id *)returnvalue, [*(id *)returnvalue retainCount]); - [*((id *)returnvalue) retain]; - } - [arguments release]; - if (pool) { - if (resultType[0] == '@') - [*((id *)returnvalue) retain]; - [pool drain]; - if (resultType[0] == '@') - [*((id *)returnvalue) autorelease]; - } -} - -static char **generate_userdata(SEL sel, NuBlock *block, const char *signature) -{ - NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:signature]; - const char *return_type_string = [methodSignature methodReturnType]; - NSUInteger argument_count = [methodSignature numberOfArguments]; - char **userdata = (char **) malloc ((argument_count+3) * sizeof(char*)); - userdata[0] = (char *) malloc (2 + strlen(return_type_string)); - const char *methodName = sel_getName(sel); - BOOL returnsRetainedResult = NO; - if ((!strcmp(methodName, "alloc")) || - (!strcmp(methodName, "allocWithZone:")) || - (!strcmp(methodName, "copy")) || - (!strcmp(methodName, "copyWithZone:")) || - (!strcmp(methodName, "mutableCopy")) || - (!strcmp(methodName, "mutableCopyWithZone:")) || - (!strcmp(methodName, "new"))) - returnsRetainedResult = YES; - if (returnsRetainedResult) - sprintf(userdata[0], "!%s", return_type_string); - else - sprintf(userdata[0], " %s", return_type_string); - //NSLog(@"constructing handler for method %s with %d arguments and returnType %s", methodName, argument_count, userdata[0]); - userdata[1] = (char *) block; - [block retain]; - int i; - for (i = 0; i < argument_count; i++) { - const char *argument_type_string = [methodSignature getArgumentTypeAtIndex:i]; - if (i > 1) userdata[i] = strdup(argument_type_string); - } - userdata[argument_count] = NULL; - return userdata; -} - -static IMP construct_method_handler(SEL sel, NuBlock *block, const char *signature) -{ - char **userdata = generate_userdata(sel, block, signature); - IMP imp = [NuHandlerWarehouse handlerWithSelector:sel block:block signature:signature userdata:userdata]; - if (imp) { - return imp; - } - int argument_count = 0; - while (userdata[argument_count] != 0) argument_count++; -#if 0 - const char *methodName = sel_getName(sel); - NSLog(@"using libffi to construct handler for method %s with %d arguments and signature %s", methodName, argument_count, signature); -#endif - ffi_type **argument_types = (ffi_type **) malloc ((argument_count+1) * sizeof(ffi_type *)); - ffi_type *result_type = ffi_type_for_objc_type(userdata[0]+1); - argument_types[0] = ffi_type_for_objc_type("@"); - argument_types[1] = ffi_type_for_objc_type(":"); - for (int i = 2; i < argument_count; i++) - argument_types[i] = ffi_type_for_objc_type(userdata[i]); - argument_types[argument_count] = NULL; - ffi_cif *cif = (ffi_cif *)malloc(sizeof(ffi_cif)); - if (cif == NULL) { - NSLog(@"unable to prepare closure for signature %s (could not allocate memory for cif structure)", signature); - return NULL; - } - int status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, argument_count, result_type, argument_types); - if (status != FFI_OK) { - NSLog(@"unable to prepare closure for signature %s (ffi_prep_cif failed)", signature); - return NULL; - } - ffi_closure *closure = (ffi_closure *)mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (closure == (ffi_closure *) -1) { - NSLog(@"unable to prepare closure for signature %s (mmap failed with error %d)", signature, errno); - return NULL; - } - if (closure == NULL) { - NSLog(@"unable to prepare closure for signature %s (could not allocate memory for closure)", signature); - return NULL; - } - if (ffi_prep_closure(closure, cif, objc_calling_nu_method_handler, userdata) != FFI_OK) { - NSLog(@"unable to prepare closure for signature %s (ffi_prep_closure failed)", signature); - return NULL; - } - if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1) { - NSLog(@"unable to prepare closure for signature %s (mprotect failed with error %d)", signature, errno); - return NULL; - } - return (IMP) closure; -} - -static id add_method_to_class(Class c, NSString *methodName, NSString *signature, NuBlock *block) -{ - const char *method_name_str = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; - const char *signature_str = [signature cStringUsingEncoding:NSUTF8StringEncoding]; - SEL selector = sel_registerName(method_name_str); - - //NuSymbolTable *symbolTable = [[block context] objectForKey:SYMBOLS_KEY]; - //[[block context] setPossiblyNullObject:[[NuClass alloc] initWithClass:c] forKey:[symbolTable symbolWithString:@"_class"]]; - - IMP imp = construct_method_handler(selector, block, signature_str); - if (imp == NULL) { - NSLog(@"failed to construct handler for %s(%s)", method_name_str, signature_str); - return [NSNull null]; - } - - // save the block in a hash table keyed by the imp. - // this will let us introspect methods and optimize nu-to-nu method calls - if (!nu_block_table) nu_block_table = [[NSMutableDictionary alloc] init]; - // watch for problems caused by these ugly casts... - [nu_block_table setObject:block forKey:[NSNumber numberWithUnsignedLong:(unsigned long) imp]]; -#if !TARGET_OS_IPHONE - [[NSGarbageCollector defaultCollector] disableCollectorForPointer: block]; -#endif - // insert the method handler in the class method table - nu_class_replaceMethod(c, selector, imp, signature_str); - //NSLog(@"setting handler for %s(%s) in class %s", method_name_str, signature_str, class_getName(c)); - return [NSNull null]; -} - -@interface NuBridgedFunction () -{ - char *name; - char *signature; - void *function; -} -@end - -@implementation NuBridgedFunction - -- (void) dealloc -{ - free(name); - free(signature); - [super dealloc]; -} - -- (NuBridgedFunction *) initWithName:(NSString *)n signature:(NSString *)s -{ - name = strdup([n cStringUsingEncoding:NSUTF8StringEncoding]); - signature = strdup([s cStringUsingEncoding:NSUTF8StringEncoding]); - function = dlsym(RTLD_DEFAULT, name); - if (!function) { - [NSException raise:@"NuCantFindBridgedFunction" - format:@"%s\n%s\n%s\n", dlerror(), - "If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set.", - "In Xcode, check the 'Preserve Private External Symbols' checkbox."]; - } - return self; -} - -+ (NuBridgedFunction *) functionWithName:(NSString *)name signature:(NSString *)signature -{ - const char *function_name = [name cStringUsingEncoding:NSUTF8StringEncoding]; - void *function = dlsym(RTLD_DEFAULT, function_name); - if (!function) { - [NSException raise:@"NuCantFindBridgedFunction" - format:@"%s\n%s\n%s\n", dlerror(), - "If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set.", - "In Xcode, check the 'Preserve Private External Symbols' checkbox."]; - } - NuBridgedFunction *wrapper = [[[NuBridgedFunction alloc] initWithName:name signature:signature] autorelease]; - return wrapper; -} - -- (id) evalWithArguments:(id) cdr context:(NSMutableDictionary *) context -{ - //NSLog(@"----------------------------------------"); - //NSLog(@"calling C function %s with signature %s", name, signature); - id result; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - char *return_type_identifier = strdup(signature); - nu_markEndOfObjCTypeString(return_type_identifier, strlen(return_type_identifier)); - - int argument_count = 0; - char *argument_type_identifiers[100]; - char *cursor = &signature[strlen(return_type_identifier)]; - while (*cursor != 0) { - argument_type_identifiers[argument_count] = strdup(cursor); - nu_markEndOfObjCTypeString(argument_type_identifiers[argument_count], strlen(cursor)); - cursor = &cursor[strlen(argument_type_identifiers[argument_count])]; - argument_count++; - } - //NSLog(@"calling return type is %s", return_type_identifier); - int i; - for (i = 0; i < argument_count; i++) { - // NSLog(@"argument %d type is %s", i, argument_type_identifiers[i]); - } - - ffi_cif *cif = (ffi_cif *)malloc(sizeof(ffi_cif)); - - ffi_type *result_type = ffi_type_for_objc_type(return_type_identifier); - ffi_type **argument_types = (argument_count == 0) ? NULL : (ffi_type **) malloc (argument_count * sizeof(ffi_type *)); - for (i = 0; i < argument_count; i++) - argument_types[i] = ffi_type_for_objc_type(argument_type_identifiers[i]); - - int status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, argument_count, result_type, argument_types); - if (status != FFI_OK) { - NSLog (@"failed to prepare cif structure"); - return [NSNull null]; - } - - id arg_cursor = cdr; - void *result_value = value_buffer_for_objc_type(return_type_identifier); - void **argument_values = (void **) (argument_count ? malloc (argument_count * sizeof(void *)) : NULL); - - for (i = 0; i < argument_count; i++) { - argument_values[i] = value_buffer_for_objc_type( argument_type_identifiers[i]); - id arg_value = [[arg_cursor car] evalWithContext:context]; - set_objc_value_from_nu_value(argument_values[i], arg_value, argument_type_identifiers[i]); - arg_cursor = [arg_cursor cdr]; - } - ffi_call(cif, FFI_FN(function), result_value, argument_values); - result = get_nu_value_from_objc_value(result_value, return_type_identifier); - - // free the value structures - for (i = 0; i < argument_count; i++) { - free(argument_values[i]); - free(argument_type_identifiers[i]); - } - free(argument_values); - free(result_value); - free(return_type_identifier); - free(argument_types); - free(cif); - - [result retain]; - [pool drain]; - [result autorelease]; - return result; -} - -@end - -@implementation NuBridgedConstant - -+ (id) constantWithName:(NSString *) name signature:(NSString *) signature -{ - const char *constant_name = [name cStringUsingEncoding:NSUTF8StringEncoding]; - void *constant = dlsym(RTLD_DEFAULT, constant_name); - if (!constant) { - NSLog(@"%s", dlerror()); - NSLog(@"If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set."); - NSLog(@"In Xcode, check the 'Preserve Private External Symbols' checkbox."); - return nil; - } - return get_nu_value_from_objc_value(constant, [signature cStringUsingEncoding:NSUTF8StringEncoding]); -} - -@end - - -static NuSymbol *oneway_symbol, *in_symbol, *out_symbol, *inout_symbol, *bycopy_symbol, *byref_symbol, *const_symbol, -*void_symbol, *star_symbol, *id_symbol, *voidstar_symbol, *idstar_symbol, *int_symbol, *long_symbol, *NSComparisonResult_symbol, -*BOOL_symbol, *double_symbol, *float_symbol, *NSRect_symbol, *NSPoint_symbol, *NSSize_symbol, *NSRange_symbol, -*CGRect_symbol, *CGPoint_symbol, *CGSize_symbol, -*SEL_symbol, *Class_symbol; - - -static void prepare_symbols(NuSymbolTable *symbolTable) -{ - oneway_symbol = [symbolTable symbolWithString:@"oneway"]; - in_symbol = [symbolTable symbolWithString:@"in"]; - out_symbol = [symbolTable symbolWithString:@"out"]; - inout_symbol = [symbolTable symbolWithString:@"inout"]; - bycopy_symbol = [symbolTable symbolWithString:@"bycopy"]; - byref_symbol = [symbolTable symbolWithString:@"byref"]; - const_symbol = [symbolTable symbolWithString:@"const"]; - void_symbol = [symbolTable symbolWithString:@"void"]; - star_symbol = [symbolTable symbolWithString:@"*"]; - id_symbol = [symbolTable symbolWithString:@"id"]; - voidstar_symbol = [symbolTable symbolWithString:@"void*"]; - idstar_symbol = [symbolTable symbolWithString:@"id*"]; - int_symbol = [symbolTable symbolWithString:@"int"]; - long_symbol = [symbolTable symbolWithString:@"long"]; - NSComparisonResult_symbol = [symbolTable symbolWithString:@"NSComparisonResult"]; - BOOL_symbol = [symbolTable symbolWithString:@"BOOL"]; - double_symbol = [symbolTable symbolWithString:@"double"]; - float_symbol = [symbolTable symbolWithString:@"float"]; - NSRect_symbol = [symbolTable symbolWithString:@"NSRect"]; - NSPoint_symbol = [symbolTable symbolWithString:@"NSPoint"]; - NSSize_symbol = [symbolTable symbolWithString:@"NSSize"]; - NSRange_symbol = [symbolTable symbolWithString:@"NSRange"]; - CGRect_symbol = [symbolTable symbolWithString:@"CGRect"]; - CGPoint_symbol = [symbolTable symbolWithString:@"CGPoint"]; - CGSize_symbol = [symbolTable symbolWithString:@"CGSize"]; - SEL_symbol = [symbolTable symbolWithString:@"SEL"]; - Class_symbol = [symbolTable symbolWithString:@"Class"]; -} - -static NSString *signature_for_identifier(NuCell *cell, NuSymbolTable *symbolTable) -{ - static NuSymbolTable *currentSymbolTable = nil; - if (currentSymbolTable != symbolTable) { - prepare_symbols(symbolTable); - currentSymbolTable = symbolTable; - } - NSMutableArray *modifiers = nil; - NSMutableString *signature = [NSMutableString string]; - id cursor = cell; - BOOL finished = NO; - while (cursor && cursor != Nu__null) { - if (finished) { - // ERROR! - NSLog(@"I can't bridge this return type yet: %@ (%@)", [cell stringValue], signature); - return @"?"; - } - id cursor_car = [cursor car]; - if (cursor_car == oneway_symbol) { - if (!modifiers) modifiers = [NSMutableArray array]; - [modifiers addObject:@"V"]; - } - else if (cursor_car == in_symbol) { - if (!modifiers) modifiers = [NSMutableArray array]; - [modifiers addObject:@"n"]; - } - else if (cursor_car == out_symbol) { - if (!modifiers) modifiers = [NSMutableArray array]; - [modifiers addObject:@"o"]; - } - else if (cursor_car == inout_symbol) { - if (!modifiers) modifiers = [NSMutableArray array]; - [modifiers addObject:@"N"]; - } - else if (cursor_car == bycopy_symbol) { - if (!modifiers) modifiers = [NSMutableArray array]; - [modifiers addObject:@"O"]; - } - else if (cursor_car == byref_symbol) { - if (!modifiers) modifiers = [NSMutableArray array]; - [modifiers addObject:@"R"]; - } - else if (cursor_car == const_symbol) { - if (!modifiers) modifiers = [NSMutableArray array]; - [modifiers addObject:@"r"]; - } - else if (cursor_car == void_symbol) { - if (![cursor cdr] || ([cursor cdr] == [NSNull null])) { - if (modifiers) - [signature appendString:[[modifiers sortedArrayUsingSelector:@selector(compare:)] componentsJoinedByString:@""]]; - [signature appendString:@"v"]; - finished = YES; - } - else if ([[cursor cdr] car] == star_symbol) { - [signature appendString:@"^v"]; - cursor = [cursor cdr]; - finished = YES; - } - } - else if (cursor_car == id_symbol) { - if (![cursor cdr] || ([cursor cdr] == [NSNull null])) { - if (modifiers) - [signature appendString:[[modifiers sortedArrayUsingSelector:@selector(compare:)] componentsJoinedByString:@""]]; - [signature appendString:@"@"]; - finished = YES; - } - else if ([[cursor cdr] car] == star_symbol) { - [signature appendString:@"^@"]; - cursor = [cursor cdr]; - finished = YES; - } - } - else if (cursor_car == voidstar_symbol) { - [signature appendString:@"^v"]; - finished = YES; - } - else if (cursor_car == idstar_symbol) { - [signature appendString:@"^@"]; - finished = YES; - } - else if (cursor_car == int_symbol) { - [signature appendString:@"i"]; - finished = YES; - } - else if (cursor_car == long_symbol) { - [signature appendString:@"l"]; - finished = YES; - } - else if (cursor_car == NSComparisonResult_symbol) { - if (sizeof(NSComparisonResult) == 4) - [signature appendString:@"i"]; - else - [signature appendString:@"q"]; - finished = YES; - } - else if (cursor_car == BOOL_symbol) { - [signature appendString:@"C"]; - finished = YES; - } - else if (cursor_car == double_symbol) { - [signature appendString:@"d"]; - finished = YES; - } - else if (cursor_car == float_symbol) { - [signature appendString:@"f"]; - finished = YES; - } - else if (cursor_car == NSRect_symbol) { - [signature appendString:@NSRECT_SIGNATURE0]; - finished = YES; - } - else if (cursor_car == NSPoint_symbol) { - [signature appendString:@NSPOINT_SIGNATURE0]; - finished = YES; - } - else if (cursor_car == NSSize_symbol) { - [signature appendString:@NSSIZE_SIGNATURE0]; - finished = YES; - } - else if (cursor_car == NSRange_symbol) { - [signature appendString:@NSRANGE_SIGNATURE]; - finished = YES; - } - else if (cursor_car == CGRect_symbol) { - [signature appendString:@CGRECT_SIGNATURE0]; - finished = YES; - } - else if (cursor_car == CGPoint_symbol) { - [signature appendString:@CGPOINT_SIGNATURE]; - finished = YES; - } - else if (cursor_car == CGSize_symbol) { - [signature appendString:@CGSIZE_SIGNATURE]; - finished = YES; - } - else if (cursor_car == SEL_symbol) { - [signature appendString:@":"]; - finished = YES; - } - else if (cursor_car == Class_symbol) { - [signature appendString:@"#"]; - finished = YES; - } - cursor = [cursor cdr]; - } - if (finished) - return signature; - else { - NSLog(@"I can't bridge this return type yet: %@ (%@)", [cell stringValue], signature); - return @"?"; - } -} - -static id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *context, BOOL addClassMethod) -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - - id returnType = [NSNull null]; - id selector = [[[NuCell alloc] init] autorelease]; - id argumentTypes = [NSNull null]; - id argumentNames = [NSNull null]; - id isSymbol = [symbolTable symbolWithString:@"is"]; - id cursor = cdr; - id selector_cursor = nil; - id argumentTypes_cursor = nil; - id argumentNames_cursor = nil; - - if (cursor && (cursor != [NSNull null]) && ([cursor car] != isSymbol)) { - // scan the return type - if (![[cursor car] atom]) { - returnType = [cursor car] ; - cursor = [cursor cdr]; - } - else { - // The return type specifier must be a list (in parens). If it is missing, leave it as null. - returnType = Nu__null; - } - if (cursor && (cursor != [NSNull null])) { - [selector setCar:[cursor car]]; // scan a part of the selector - cursor = [cursor cdr]; - if (cursor && (cursor != [NSNull null])) { - if ([cursor car] != isSymbol) { - argumentTypes = [[[NuCell alloc] init] autorelease]; - argumentNames = [[[NuCell alloc] init] autorelease]; - if (![[cursor car] atom]) { - // the argument type specifier must be a list. If it is missing, we'll use a default. - [argumentTypes setCar:[cursor car]]; - cursor = [cursor cdr]; - } - if (cursor && (cursor != [NSNull null])) { - [argumentNames setCar:[cursor car]]; - cursor = [cursor cdr]; - if (cursor && (cursor != [NSNull null])) { - selector_cursor = selector; - argumentTypes_cursor = argumentTypes; - argumentNames_cursor = argumentNames; - } - } - } - } - } - } - // scan each remaining part of the selector - while (cursor && (cursor != [NSNull null]) && ([cursor car] != isSymbol)) { - [selector_cursor setCdr:[[[NuCell alloc] init] autorelease]]; - [argumentTypes_cursor setCdr:[[[NuCell alloc] init] autorelease]]; - [argumentNames_cursor setCdr:[[[NuCell alloc] init] autorelease]]; - selector_cursor = [selector_cursor cdr]; - argumentTypes_cursor = [argumentTypes_cursor cdr]; - argumentNames_cursor = [argumentNames_cursor cdr]; - - [selector_cursor setCar:[cursor car]]; - cursor = [cursor cdr]; - if (cursor && (cursor != [NSNull null])) { - if (![[cursor car] atom]) { - // the argument type specifier must be a list. If it is missing, we'll use a default. - [argumentTypes_cursor setCar:[cursor car]]; - cursor = [cursor cdr]; - } - if (cursor && (cursor != [NSNull null])) { - [argumentNames_cursor setCar:[cursor car]]; - cursor = [cursor cdr]; - } - } - } - - if (cursor && (cursor != [NSNull null])) { - //NSLog(@"selector: %@", [selector stringValue]); - //NSLog(@"argument names: %@", [argumentNames stringValue]); - //NSLog(@"argument types:%@", [argumentTypes stringValue]); - //NSLog(@"returns: %@", [returnType stringValue]); - - // skip the is - cursor = [cursor cdr]; - - // combine the selectors into the method name - NSMutableString *methodName = [[[NSMutableString alloc] init] autorelease]; - selector_cursor = selector; - while (selector_cursor && (selector_cursor != [NSNull null])) { - [methodName appendString:[[selector_cursor car] stringValue]]; - selector_cursor = [selector_cursor cdr]; - } - - NSMutableString *signature = nil; - - if ((returnType == Nu__null) || ([argumentTypes length] < [argumentNames length])) { - // look up the signature - SEL selector = sel_registerName([methodName cStringUsingEncoding:NSUTF8StringEncoding]); - NSMethodSignature *methodSignature = [classToExtend instanceMethodSignatureForSelector:selector]; - - if (!methodSignature) - methodSignature = [classToExtend methodSignatureForSelector:selector]; - if (methodSignature) - signature = [NSMutableString stringWithString:[methodSignature typeString]]; - // if we can't find a signature, use a default - if (!signature) { - // NSLog(@"no signature found. treating all arguments and the return type as (id)"); - signature = [NSMutableString stringWithString:@"@@:"]; - int i; - for (i = 0; i < [argumentNames length]; i++) { - [signature appendString:@"@"]; - } - } - } - else { - // build the signature, first get the return type - signature = [NSMutableString string]; - [signature appendString:signature_for_identifier(returnType, symbolTable)]; - - // then add the common stuff - [signature appendString:@"@:"]; - - // then describe the arguments - argumentTypes_cursor = argumentTypes; - while (argumentTypes_cursor && (argumentTypes_cursor != [NSNull null])) { - id typeIdentifier = [argumentTypes_cursor car]; - [signature appendString:signature_for_identifier(typeIdentifier, symbolTable)]; - argumentTypes_cursor = [argumentTypes_cursor cdr]; - } - } - id body = cursor; - NuBlock *block = [[[NuBlock alloc] initWithParameters:argumentNames body:body context:context] autorelease]; - [[block context] - setPossiblyNullObject:methodName - forKey:[symbolTable symbolWithString:@"_method"]]; - return add_method_to_class( - addClassMethod ? object_getClass(classToExtend) : classToExtend, - methodName, signature, block); - } - else { - // not good. you probably forgot the "is" in your method declaration. - [NSException raise:@"NuBadMethodDeclaration" - format:@"invalid method declaration: %@", - [cdr stringValue]]; - return nil; - } -} - -#ifdef __BLOCKS__ - -static id make_cblock (NuBlock *nuBlock, NSString *signature); -static void objc_calling_nu_block_handler(ffi_cif* cif, void* returnvalue, void** args, void* userdata); -static char **generate_block_userdata(NuBlock *nuBlock, const char *signature); -static void *construct_block_handler(NuBlock *block, const char *signature); - -@interface NuBridgedBlock () -{ - NuBlock *nuBlock; - id cBlock; -} -@end - -@implementation NuBridgedBlock - -+(id)cBlockWithNuBlock:(NuBlock*)nb signature:(NSString*)sig -{ - return [[[[self alloc] initWithNuBlock:nb signature:sig] autorelease] cBlock]; -} - --(id)initWithNuBlock:(NuBlock*)nb signature:(NSString*)sig -{ - nuBlock = [nb retain]; - cBlock = make_cblock(nb,sig); - - return self; -} - --(NuBlock*)nuBlock -{return [[nuBlock retain] autorelease];} - --(id)cBlock -{return [[cBlock retain] autorelease];} - --(void)dealloc -{ - [nuBlock release]; - [cBlock release]; - [super dealloc]; -} - -@end - -//the caller gets ownership of the block -static id make_cblock (NuBlock *nuBlock, NSString *signature) -{ - void *funcptr = construct_block_handler(nuBlock, [signature UTF8String]); - - int i = 0xFFFF; - void(^cBlock)(void)=[^(void){printf("%i",i);} copy]; - -#ifdef __x86_64__ - /* this is what happens when a block is called on x86 64 - mov %rax,-0x18(%rbp) //the pointer to the block object is in rax - mov -0x18(%rbp),%rax - mov 0x10(%rax),%rax //the pointer to the block function is at +0x10 into the block object - mov -0x18(%rbp),%rdi //the first argument (this examples has no others) is always the pointer to the block object - callq *%rax - */ - //2*(sizeof(void*)) = 0x10 - *((void **)(id)cBlock + 2) = (void *)funcptr; -#else - /* this is what happens when a block is called on x86 32 - mov %eax,-0x14(%ebp) //the pointer to the block object is in eax - mov -0x14(%ebp),%eax - mov 0xc(%eax),%eax //the pointer to the block function is at +0xc into the block object - mov %eax,%edx - mov -0x14(%ebp),%eax //the first argument (this examples has no others) is always the pointer to the block object - mov %eax,(%esp) - call *%edx - */ - //3*(sizeof(void*)) = 0xc - *((void **)(id)cBlock + 3) = (void *)funcptr; -#endif - return cBlock; -} - -static void objc_calling_nu_block_handler(ffi_cif* cif, void* returnvalue, void** args, void* userdata) -{ - int argc = cif->nargs - 1; - //void *ptr = (void*)args[0] //don't need this first parameter - // see objc_calling_nu_method_handler - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NuBlock *block = ((NuBlock **)userdata)[1]; - //NSLog(@"----------------------------------------"); - //NSLog(@"calling block %@", [block stringValue]); - id arguments = [[NuCell alloc] init]; - id cursor = arguments; - int i; - for (i = 0; i < argc; i++) { - NuCell *nextCell = [[NuCell alloc] init]; - [cursor setCdr:nextCell]; - [nextCell release]; - cursor = [cursor cdr]; - id value = get_nu_value_from_objc_value(args[i+1], ((char **)userdata)[i+2]); - [cursor setCar:value]; - } - //NSLog(@"in nu method handler, using arguments %@", [arguments stringValue]); - id result = [block evalWithArguments:[arguments cdr] context:nil]; - //NSLog(@"in nu method handler, putting result %@ in %x with type %s", [result stringValue], (size_t) returnvalue, ((char **)userdata)[0]); - char *resultType = (((char **)userdata)[0])+1;// skip the first character, it's a flag - set_objc_value_from_nu_value(returnvalue, result, resultType); - [arguments release]; - if (pool) { - if (resultType[0] == '@') - [*((id *)returnvalue) retain]; - [pool release]; - if (resultType[0] == '@') - [*((id *)returnvalue) autorelease]; - } -} - -static char **generate_block_userdata(NuBlock *nuBlock, const char *signature) -{ - NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:signature]; - const char *return_type_string = [methodSignature methodReturnType]; - NSUInteger argument_count = [methodSignature numberOfArguments]; - char **userdata = (char **) malloc ((argument_count+3) * sizeof(char*)); - userdata[0] = (char *) malloc (2 + strlen(return_type_string)); - - //assume blocks never return retained results - sprintf(userdata[0], " %s", return_type_string); - - //so first element is return type, second is nuBlock - userdata[1] = (char *) nuBlock; - [nuBlock retain]; - int i; - for (i = 0; i < argument_count; i++) { - const char *argument_type_string = [methodSignature getArgumentTypeAtIndex:i]; - userdata[i+2] = strdup(argument_type_string); - } - userdata[argument_count+2] = NULL; - -#if 0 - NSLog(@"Userdata for block: %@, signature: %s", [nuBlock stringValue], signature); - for (int i = 0; i < argument_count+2; i++) - { if (i != 1) - NSLog(@"userdata[%i] = %s",i,userdata[i]); } -#endif - return userdata; -} - - -static void *construct_block_handler(NuBlock *block, const char *signature) -{ - char **userdata = generate_block_userdata(block, signature); - - int argument_count = 0; - while (userdata[argument_count] != 0) argument_count++; - argument_count-=1; //unlike a method call, c blocks have one, not two hidden args (see comments in make_cblock() -#if 0 - NSLog(@"using libffi to construct handler for nu block with %d arguments and signature %s", argument_count, signature); -#endif - if (argument_count < 0) { - NSLog(@"error in argument construction"); - return NULL; - } - - ffi_type **argument_types = (ffi_type **) malloc ((argument_count+1) * sizeof(ffi_type *)); - ffi_type *result_type = ffi_type_for_objc_type(userdata[0]+1); - - argument_types[0] = ffi_type_for_objc_type("^?"); - - for (int i = 1; i < argument_count; i++) - argument_types[i] = ffi_type_for_objc_type(userdata[i+1]); - argument_types[argument_count] = NULL; - ffi_cif *cif = (ffi_cif *)malloc(sizeof(ffi_cif)); - if (cif == NULL) { - NSLog(@"unable to prepare closure for signature %s (could not allocate memory for cif structure)", signature); - return NULL; - } - int status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, argument_count, result_type, argument_types); - if (status != FFI_OK) { - NSLog(@"unable to prepare closure for signature %s (ffi_prep_cif failed)", signature); - return NULL; - } - ffi_closure *closure = (ffi_closure *)mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (closure == (ffi_closure *) -1) { - NSLog(@"unable to prepare closure for signature %s (mmap failed with error %d)", signature, errno); - return NULL; - } - if (closure == NULL) { - NSLog(@"unable to prepare closure for signature %s (could not allocate memory for closure)", signature); - return NULL; - } - if (ffi_prep_closure(closure, cif, objc_calling_nu_block_handler, userdata) != FFI_OK) { - NSLog(@"unable to prepare closure for signature %s (ffi_prep_closure failed)", signature); - return NULL; - } - if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1) { - NSLog(@"unable to prepare closure for signature %s (mprotect failed with error %d)", signature, errno); - return NULL; - } - return (void*)closure; -} - -#endif //__BLOCKS__ - -#pragma mark - NuBridgeSupport.m - -#if !TARGET_OS_IPHONE - -static NSString *getTypeStringFromNode(id node) -{ - static BOOL use64BitTypes = (sizeof(void *) == 8); - if (use64BitTypes ) { - id type64Attribute = [node attributeForName:@"type64"]; - if (type64Attribute) - return [type64Attribute stringValue]; - } - return [[node attributeForName:@"type"] stringValue]; -} - -@implementation NuBridgeSupport - -+ (void)importLibrary:(NSString *) libraryPath -{ - //NSLog(@"importing library %@", libraryPath); - dlopen([libraryPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_LAZY | RTLD_GLOBAL); -} - -+ (void)importFramework:(NSString *) framework fromPath:(NSString *) path intoDictionary:(NSMutableDictionary *) BridgeSupport -{ - NSMutableDictionary *frameworks = [BridgeSupport valueForKey:@"frameworks"]; - if ([frameworks valueForKey:framework]) - return; - else - [frameworks setValue:framework forKey:framework]; - - NSString *xmlPath; // constants, enums, functions, and more are described in an XML file. - NSString *dylibPath; // sometimes a dynamic library is included to provide implementations of inline functions. - - if (path) { - xmlPath = [NSString stringWithFormat:@"%@/Resources/BridgeSupport/%@.bridgesupport", path, framework]; - dylibPath = [NSString stringWithFormat:@"%@/Resources/BridgeSupport/%@.dylib", path, framework]; - } - else { - xmlPath = [NSString stringWithFormat:@"/System/Library/Frameworks/%@.framework/Resources/BridgeSupport/%@.bridgesupport", framework, framework]; - dylibPath = [NSString stringWithFormat:@"/System/Library/Frameworks/%@.framework/Resources/BridgeSupport/%@.dylib", framework, framework]; - } - - if ([NSFileManager fileExistsNamed:dylibPath]) - [self importLibrary:dylibPath]; - - NSMutableDictionary *constants = [BridgeSupport valueForKey:@"constants"]; - NSMutableDictionary *enums = [BridgeSupport valueForKey:@"enums"]; - NSMutableDictionary *functions = [BridgeSupport valueForKey:@"functions"]; - - NSXMLDocument *xmlDocument = [[[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:xmlPath] options:0 error:NULL] autorelease]; - if (xmlDocument) { - id node; - NSEnumerator *childEnumerator = [[[xmlDocument rootElement] children] objectEnumerator]; - while ((node = [childEnumerator nextObject])) { - if ([[node name] isEqual:@"depends_on"]) { - id fileName = [[node attributeForName:@"path"] stringValue]; - id frameworkName = [[[fileName lastPathComponent] componentsSeparatedByString:@"."] objectAtIndex:0]; - [NuBridgeSupport importFramework:frameworkName fromPath:fileName intoDictionary:BridgeSupport]; - } - else if ([[node name] isEqual:@"constant"]) { - [constants setValue:getTypeStringFromNode(node) - forKey:[[node attributeForName:@"name"] stringValue]]; - } - else if ([[node name] isEqual:@"enum"]) { - [enums setValue:[NSNumber numberWithInt:[[[node attributeForName:@"value"] stringValue] intValue]] - forKey:[[node attributeForName:@"name"] stringValue]]; - } - else if ([[node name] isEqual:@"function"]) { - id name = [[node attributeForName:@"name"] stringValue]; - id argumentTypes = [NSMutableString string]; - id returnType = @"v"; - id child; - NSEnumerator *nodeChildEnumerator = [[node children] objectEnumerator]; - while ((child = [nodeChildEnumerator nextObject])) { - if ([[child name] isEqual:@"arg"]) { - id typeModifier = [child attributeForName:@"type_modifier"]; - if (typeModifier) { - [argumentTypes appendString:[typeModifier stringValue]]; - } - [argumentTypes appendString:getTypeStringFromNode(child)]; - } - else if ([[child name] isEqual:@"retval"]) { - returnType = getTypeStringFromNode(child); - } - else { - NSLog(@"unrecognized type #{[child XMLString]}"); - } - } - id signature = [NSString stringWithFormat:@"%@%@", returnType, argumentTypes]; - [functions setValue:signature forKey:name]; - } - } - } - else { - // don't complain about missing bridge support files... - //NSString *reason = [NSString stringWithFormat:@"unable to find BridgeSupport file for %@", framework]; - //[[NSException exceptionWithName:@"NuBridgeSupportMissing" reason:reason userInfo:nil] raise]; - } -} - -+ (void) prune -{ - NuSymbolTable *symbolTable = [NuSymbolTable sharedSymbolTable]; - id BridgeSupport = [[symbolTable symbolWithString:@"BridgeSupport"] value]; - [[BridgeSupport objectForKey:@"frameworks"] removeAllObjects]; - - id key; - for (int i = 0; i < 3; i++) { - id dictionary = [BridgeSupport objectForKey:(i == 0) ? @"constants" : (i == 1) ? @"enums" : @"functions"]; - id keyEnumerator = [[dictionary allKeys] objectEnumerator]; - while ((key = [keyEnumerator nextObject])) { - if (![symbolTable lookup:key]) - [dictionary removeObjectForKey:key]; - } - } -} - -+ (NSString *) stringValue -{ - NuSymbolTable *symbolTable = [NuSymbolTable sharedSymbolTable]; - id BridgeSupport = [[symbolTable symbolWithString:@"BridgeSupport"] value]; - - id result = [NSMutableString stringWithString:@"(global BridgeSupport\n"]; - id d, keyEnumerator, key; - - [result appendString:@" (dict\n"]; - d = [BridgeSupport objectForKey:@"constants"]; - [result appendString:@" constants:\n"]; - [result appendString:@" (dict"]; - keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; - while ((key = [keyEnumerator nextObject])) { - [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; - } - [result appendString:@")\n"]; - - d = [BridgeSupport objectForKey:@"enums"]; - [result appendString:@" enums:\n"]; - [result appendString:@" (dict"]; - keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; - while ((key = [keyEnumerator nextObject])) { - [result appendString:[NSString stringWithFormat:@"\n \"%@\" %@", key, [d objectForKey:key]]]; - } - [result appendString:@")\n"]; - - d = [BridgeSupport objectForKey:@"functions"]; - [result appendString:@" functions:\n"]; - [result appendString:@" (dict"]; - keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; - while ((key = [keyEnumerator nextObject])) { - [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; - } - [result appendString:@")\n"]; - - d = [BridgeSupport objectForKey:@"frameworks"]; - [result appendString:@" frameworks:\n"]; - [result appendString:@" (dict"]; - keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; - while ((key = [keyEnumerator nextObject])) { - [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; - } - [result appendString:@")))\n"]; - return result; -} - -@end -#endif - -#pragma mark - NuCell.m - -@interface NuCell () -{ - id car; - id cdr; - int file; - int line; -} -@end - -@implementation NuCell - -+ (id) cellWithCar:(id)car cdr:(id)cdr -{ - NuCell *cell = [[self alloc] init]; - [cell setCar:car]; - [cell setCdr:cdr]; - return [cell autorelease]; -} - -- (id) init -{ - if ((self = [super init])) { - car = Nu__null; - cdr = Nu__null; - file = -1; - line = -1; - } - return self; -} - -- (void) dealloc -{ - [car release]; - [cdr release]; - [super dealloc]; -} - -- (bool) atom {return false;} - -- (id) car {return car;} - -- (id) cdr {return cdr;} - -- (void) setCar:(id) c -{ - [c retain]; - [car release]; - car = c; -} - -- (void) setCdr:(id) c -{ - [c retain]; - [cdr release]; - cdr = c; -} - -// additional accessors, for efficiency (from Nu) -- (id) caar {return [car car];} -- (id) cadr {return [car cdr];} -- (id) cdar {return [cdr car];} -- (id) cddr {return [cdr cdr];} -- (id) caaar {return [[car car] car];} -- (id) caadr {return [[car car] cdr];} -- (id) cadar {return [[car cdr] car];} -- (id) caddr {return [[car cdr] cdr];} -- (id) cdaar {return [[cdr car] car];} -- (id) cdadr {return [[cdr car] cdr];} -- (id) cddar {return [[cdr cdr] car];} -- (id) cdddr {return [[cdr cdr] cdr];} - -- (BOOL) isEqual:(id) other -{ - if (nu_objectIsKindOfClass(other, [NuCell class]) - && [[self car] isEqual:[other car]] && [[self cdr] isEqual:[other cdr]]) { - return YES; - } - else { - return NO; - } -} - -- (id) first -{ - return car; -} - -- (id) second -{ - return [cdr car]; -} - -- (id) third -{ - return [[cdr cdr] car]; -} - -- (id) fourth -{ - return [[[cdr cdr] cdr] car]; -} - -- (id) fifth -{ - return [[[[cdr cdr] cdr] cdr] car]; -} - -- (id) nth:(int) n -{ - if (n == 1) - return car; - id cursor = cdr; - int i; - for (i = 2; i < n; i++) { - cursor = [cursor cdr]; - if (cursor == Nu__null) return nil; - } - return [cursor car]; -} - -- (id) objectAtIndex:(int) n -{ - if (n < 0) - return nil; - else if (n == 0) - return car; - id cursor = cdr; - for (int i = 1; i < n; i++) { - cursor = [cursor cdr]; - if (cursor == Nu__null) return nil; - } - return [cursor car]; -} - -// When an unknown message is received by a cell, treat it as a call to objectAtIndex: -- (id) handleUnknownMessage:(NuCell *) method withContext:(NSMutableDictionary *) context -{ - if ([[method car] isKindOfClass:[NuSymbol class]]) { - NSString *methodName = [[method car] stringValue]; - NSUInteger length = [methodName length]; - if (([methodName characterAtIndex:0] == 'c') && ([methodName characterAtIndex:(length - 1)] == 'r')) { - id cursor = self; - BOOL valid = YES; - for (int i = 1; valid && (i < length - 1); i++) { - switch ([methodName characterAtIndex:i]) { - case 'd': cursor = [cursor cdr]; break; - case 'a': cursor = [cursor car]; break; - default: valid = NO; - } - } - if (valid) return cursor; - } - } - id m = [[method car] evalWithContext:context]; - if ([m isKindOfClass:[NSNumber class]]) { - int mm = [m intValue]; - if (mm < 0) { - // if the index is negative, index from the end of the array - mm += [self length]; - } - return [self objectAtIndex:mm]; - } - else { - return [super handleUnknownMessage:method withContext:context]; - } -} - -- (id) lastObject -{ - id cursor = self; - while ([cursor cdr] != Nu__null) { - cursor = [cursor cdr]; - } - return [cursor car]; -} - -- (NSMutableString *) stringValue -{ - NuCell *cursor = self; - NSMutableString *result = [NSMutableString stringWithString:@"("]; - int count = 0; - while (IS_NOT_NULL(cursor)) { - if (count > 0) - [result appendString:@" "]; - count++; - id item = [cursor car]; - if (nu_objectIsKindOfClass(item, [NuCell class])) { - [result appendString:[item stringValue]]; - } - else if (IS_NOT_NULL(item)) { - if ([item respondsToSelector:@selector(escapedStringRepresentation)]) { - [result appendString:[item escapedStringRepresentation]]; - } - else { - [result appendString:[item description]]; - } - } - else { - [result appendString:@"()"]; - } - cursor = [cursor cdr]; - // check for dotted pairs - if (IS_NOT_NULL(cursor) && !nu_objectIsKindOfClass(cursor, [NuCell class])) { - [result appendString:@" . "]; - if ([cursor respondsToSelector:@selector(escapedStringRepresentation)]) { - [result appendString:[((id) cursor) escapedStringRepresentation]]; - } - else { - [result appendString:[cursor description]]; - } - break; - } - } - [result appendString:@")"]; - return result; -} - -- (NSString *) description -{ - return [self stringValue]; -} - -- (void) addToException:(NuException*)e value:(id)value -{ - const char *parsedFilename = nu_parsedFilename(self->file); - - if (parsedFilename) { - NSString* filename = [NSString stringWithCString:parsedFilename encoding:NSUTF8StringEncoding]; - [e addFunction:value lineNumber:[self line] filename:filename]; - } - else { - [e addFunction:value lineNumber:[self line]]; - } -} - -- (id) evalWithContext:(NSMutableDictionary *)context -{ - id value = nil; - id result = nil; - - @try - { - value = [car evalWithContext:context]; - -#ifdef DARWIN - if (NU_LIST_EVAL_BEGIN_ENABLED()) { - if ((self->line != -1) && (self->file != -1)) { - NU_LIST_EVAL_BEGIN(nu_parsedFilename(self->file), self->line); - } - else { - NU_LIST_EVAL_BEGIN("", 0); - } - } -#endif - // to improve error reporting, add the currently-evaluating expression to the context - [context setObject:self forKey:[[NuSymbolTable sharedSymbolTable] symbolWithString:@"_expression"]]; - - result = [value evalWithArguments:cdr context:context]; - -#ifdef DARWIN - if (NU_LIST_EVAL_END_ENABLED()) { - if ((self->line != -1) && (self->file != -1)) { - NU_LIST_EVAL_END(nu_parsedFilename(self->file), self->line); - } - else { - NU_LIST_EVAL_END("", 0); - } - } -#endif - } - @catch (NuException* nuException) { - [self addToException:nuException value:[car stringValue]]; - @throw nuException; - } - @catch (NSException* e) { - if ( nu_objectIsKindOfClass(e, [NuBreakException class]) - || nu_objectIsKindOfClass(e, [NuContinueException class]) - || nu_objectIsKindOfClass(e, [NuReturnException class])) { - @throw e; - } - else { - NuException* nuException = [[NuException alloc] initWithName:[e name] - reason:[e reason] - userInfo:[e userInfo]]; - [self addToException:nuException value:[car stringValue]]; - @throw nuException; - } - } - - return result; -} - -- (id) each:(id) block -{ - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - id args = [[NuCell alloc] init]; - id cursor = self; - while (cursor && (cursor != Nu__null)) { - [args setCar:[cursor car]]; - [block evalWithArguments:args context:Nu__null]; - cursor = [cursor cdr]; - } - [args release]; - } - return self; -} - -- (id) eachPair:(id) block -{ - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - id args = [[NuCell alloc] init]; - [args setCdr:[[[NuCell alloc] init] autorelease]]; - id cursor = self; - while (cursor && (cursor != Nu__null)) { - [args setCar:[cursor car]]; - [[args cdr] setCar:[[cursor cdr] car]]; - [block evalWithArguments:args context:Nu__null]; - cursor = [[cursor cdr] cdr]; - } - [args release]; - } - return self; -} - -- (id) eachWithIndex:(id) block -{ - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - id args = [[NuCell alloc] init]; - [args setCdr:[[[NuCell alloc] init] autorelease]]; - id cursor = self; - int i = 0; - while (cursor && (cursor != Nu__null)) { - [args setCar:[cursor car]]; - [[args cdr] setCar:[NSNumber numberWithInt:i]]; - [block evalWithArguments:args context:Nu__null]; - cursor = [cursor cdr]; - i++; - } - [args release]; - } - return self; -} - -- (id) select:(id) block -{ - NuCell *parent = [[[NuCell alloc] init] autorelease]; - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - id args = [[NuCell alloc] init]; - id cursor = self; - id resultCursor = parent; - while (cursor && (cursor != Nu__null)) { - [args setCar:[cursor car]]; - id result = [block evalWithArguments:args context:Nu__null]; - if (nu_valueIsTrue(result)) { - [resultCursor setCdr:[NuCell cellWithCar:[cursor car] cdr:[resultCursor cdr]]]; - resultCursor = [resultCursor cdr]; - } - cursor = [cursor cdr]; - } - [args release]; - } - else - return Nu__null; - NuCell *selected = [parent cdr]; - return selected; -} - -- (id) find:(id) block -{ - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - id args = [[NuCell alloc] init]; - id cursor = self; - while (cursor && (cursor != Nu__null)) { - [args setCar:[cursor car]]; - id result = [block evalWithArguments:args context:Nu__null]; - if (nu_valueIsTrue(result)) { - [args release]; - return [cursor car]; - } - cursor = [cursor cdr]; - } - [args release]; - } - return Nu__null; -} - -- (id) map:(id) block -{ - NuCell *parent = [[[NuCell alloc] init] autorelease]; - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - id args = [[NuCell alloc] init]; - id cursor = self; - id resultCursor = parent; - while (cursor && (cursor != Nu__null)) { - [args setCar:[cursor car]]; - id result = [block evalWithArguments:args context:Nu__null]; - [resultCursor setCdr:[NuCell cellWithCar:result cdr:[resultCursor cdr]]]; - cursor = [cursor cdr]; - resultCursor = [resultCursor cdr]; - } - [args release]; - } - else - return Nu__null; - NuCell *result = [parent cdr]; - return result; -} - -- (id) mapSelector:(SEL) sel -{ - NuCell *parent = [[NuCell alloc] init]; - id args = [[NuCell alloc] init]; - id cursor = self; - id resultCursor = parent; - while (cursor && (cursor != Nu__null)) { - id object = [cursor car]; - id result = [object performSelector:sel]; - [resultCursor setCdr:[NuCell cellWithCar:result cdr:[resultCursor cdr]]]; - cursor = [cursor cdr]; - resultCursor = [resultCursor cdr]; - } - [args release]; - NuCell *result = [parent cdr]; - [parent release]; - return result; -} - -- (id) reduce:(id) block from:(id) initial -{ - id result = initial; - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - id args = [[NuCell alloc] init]; - [args setCdr:[[[NuCell alloc] init] autorelease]]; - id cursor = self; - while (cursor && (cursor != Nu__null)) { - [args setCar:result]; - [[args cdr] setCar:[cursor car]]; - result = [block evalWithArguments:args context:Nu__null]; - cursor = [cursor cdr]; - } - [args release]; - } - return result; -} - -- (NSUInteger) length -{ - int count = 0; - id cursor = self; - while (cursor && (cursor != Nu__null)) { - cursor = [cursor cdr]; - count++; - } - return count; -} - -- (NSMutableArray *) array -{ - NSMutableArray *a = [NSMutableArray array]; - id cursor = self; - while (cursor && cursor != Nu__null) { - [a addObject:[cursor car]]; - cursor = [cursor cdr]; - } - return a; -} - -- (NSUInteger) count -{ - return [self length]; -} - -- (id) comments {return nil;} - -- (void)encodeWithCoder:(NSCoder *)coder -{ - [coder encodeObject:car]; - [coder encodeObject:cdr]; -} - -- (id) initWithCoder:(NSCoder *)coder -{ - if ((self = [super init])) { - car = [[coder decodeObject] retain]; - cdr = [[coder decodeObject] retain]; - } - return self; -} - -- (void) setFile:(int) f line:(int) l -{ - file = f; - line = l; -} - -- (int) file {return file;} -- (int) line {return line;} -@end - -@interface NuCellWithComments () -{ - id comments; -} -@end - -@implementation NuCellWithComments - -- (void) dealloc -{ - [comments release]; - [super dealloc]; -} - -- (id) comments {return comments;} - -- (void) setComments:(id) c -{ - [c retain]; - [comments release]; - comments = c; -} - -@end - -#pragma mark - NuClass.m - -// getting a specific method... -// (set x (((Convert classMethods) select: (do (m) (eq (m name) "passRect:"))) objectAtIndex:0)) - -@interface NuClass () -{ - Class c; - BOOL isRegistered; -} -@end - -@implementation NuClass - -+ (NuClass *) classWithName:(NSString *)string -{ - const char *name = [string cStringUsingEncoding:NSUTF8StringEncoding]; - Class class = objc_getClass(name); - if (class) { - return [[[self alloc] initWithClass:class] autorelease]; - } - else { - return nil; - } -} - -+ (NuClass *) classWithClass:(Class) class -{ - if (class) { - return [[[self alloc] initWithClass:class] autorelease]; - } - else { - return nil; - } -} - -- (id) initWithClassNamed:(NSString *) string -{ - const char *name = [string cStringUsingEncoding:NSUTF8StringEncoding]; - Class class = objc_getClass(name); - return [self initWithClass: class]; -} - -- (id) initWithClass:(Class) class -{ - if ((self = [super init])) { - c = class; - isRegistered = YES; // unless we explicitly set otherwise - } - return self; -} - -+ (NSArray *) all -{ - NSMutableArray *array = [NSMutableArray array]; - int numClasses = objc_getClassList(NULL, 0); - if(numClasses > 0) { - Class *classes = (Class *) malloc( sizeof(Class) * numClasses ); - objc_getClassList(classes, numClasses); - int i = 0; - while (i < numClasses) { - NuClass *class = [[[NuClass alloc] initWithClass:classes[i]] autorelease]; - [array addObject:class]; - i++; - } - free(classes); - } - return array; -} - -- (NSString *) name -{ - // NSLog(@"calling NuClass name for object %@", self); - return [NSString stringWithCString:class_getName(c) encoding:NSUTF8StringEncoding]; -} - -- (NSString *) stringValue -{ - return [self name]; -} - -- (Class) wrappedClass -{ - return c; -} - -- (NSArray *) classMethods -{ - NSMutableArray *array = [NSMutableArray array]; - unsigned int method_count; - Method *method_list = class_copyMethodList(object_getClass([self wrappedClass]), &method_count); - int i; - for (i = 0; i < method_count; i++) { - [array addObject:[[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]]; - } - free(method_list); - [array sortUsingSelector:@selector(compare:)]; - return array; -} - -- (NSArray *) instanceMethods -{ - NSMutableArray *array = [NSMutableArray array]; - unsigned int method_count; - Method *method_list = class_copyMethodList([self wrappedClass], &method_count); - int i; - for (i = 0; i < method_count; i++) { - [array addObject:[[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]]; - } - free(method_list); - [array sortUsingSelector:@selector(compare:)]; - return array; -} - -/*! Get an array containing the names of the class methods of a class. */ -- (NSArray *) classMethodNames -{ - id methods = [self classMethods]; - return [methods mapSelector:@selector(name)]; -} - -/*! Get an array containing the names of the instance methods of a class. */ -- (NSArray *) instanceMethodNames -{ - id methods = [self instanceMethods]; - return [methods mapSelector:@selector(name)]; -} - -- (BOOL) isDerivedFromClass:(Class) parent -{ - Class myclass = [self wrappedClass]; - if (myclass == parent) - return true; - Class superclass = [myclass superclass]; - if (superclass) - return nu_objectIsKindOfClass(superclass, parent); - return false; -} - -- (NSComparisonResult) compare:(NuClass *) anotherClass -{ - return [[self name] compare:[anotherClass name]]; -} - -- (NuMethod *) classMethodWithName:(NSString *) methodName -{ - const char *methodNameString = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; - NuMethod *method = Nu__null; - unsigned int method_count; - Method *method_list = class_copyMethodList(object_getClass([self wrappedClass]), &method_count); - int i; - for (i = 0; i < method_count; i++) { - if (!strcmp(methodNameString, sel_getName(method_getName(method_list[i])))) { - method = [[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]; - } - } - free(method_list); - return method; -} - -- (NuMethod *) instanceMethodWithName:(NSString *) methodName -{ - const char *methodNameString = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; - NuMethod *method = Nu__null; - unsigned int method_count; - Method *method_list = class_copyMethodList([self wrappedClass], &method_count); - int i; - for (i = 0; i < method_count; i++) { - if (!strcmp(methodNameString, sel_getName(method_getName(method_list[i])))) { - method = [[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]; - } - } - free(method_list); - return method; -} - -- (id) addInstanceMethod:(NSString *)methodName signature:(NSString *)signature body:(NuBlock *)block -{ - //NSLog(@"adding instance method %@", methodName); - return add_method_to_class(c, methodName, signature, block); -} - -- (id) addClassMethod:(NSString *)methodName signature:(NSString *)signature body:(NuBlock *)block -{ - NSLog(@"adding class method %@", methodName); - return add_method_to_class(object_getClass(c), /* c->isa, */ methodName, signature, block); -} - -- (id) addInstanceVariable:(NSString *)variableName signature:(NSString *)signature -{ - //NSLog(@"adding instance variable %@", variableName); - nu_class_addInstanceVariable_withSignature(c, [variableName cStringUsingEncoding:NSUTF8StringEncoding], [signature cStringUsingEncoding:NSUTF8StringEncoding]); - return Nu__null; -} - -- (BOOL) isEqual:(NuClass *) anotherClass -{ - return c == anotherClass->c; -} - -- (void) setSuperclass:(NuClass *) newSuperclass -{ - struct nu_objc_class - { - Class isa; - Class super_class; - // other stuff... - }; - ((struct nu_objc_class *) self->c)->super_class = newSuperclass->c; -} - -- (BOOL) isRegistered -{ - return isRegistered; -} - -- (void) setRegistered:(BOOL) value -{ - isRegistered = value; -} - -- (void) registerClass -{ - if (isRegistered == NO) { - objc_registerClassPair(c); - isRegistered = YES; - } -} - -- (id) handleUnknownMessage:(id) cdr withContext:(NSMutableDictionary *) context -{ - return [[self wrappedClass] handleUnknownMessage:cdr withContext:context]; -} - -- (NSArray *) instanceVariableNames { - NSMutableArray *names = [NSMutableArray array]; - - unsigned int ivarCount = 0; - // Ivar *ivarList = class_copyIvarList(c, &ivarCount); - - NSLog(@"%d ivars", ivarCount); - return names; -} - -- (BOOL) addPropertyWithName:(NSString *) name { - const objc_property_attribute_t attributes[10]; - unsigned int attributeCount = 0; - return class_addProperty(c, [name cStringUsingEncoding:NSUTF8StringEncoding], - attributes, - attributeCount); -} - -- (NuProperty *) propertyWithName:(NSString *) name { - objc_property_t property = class_getProperty(c, [name cStringUsingEncoding:NSUTF8StringEncoding]); - - return [NuProperty propertyWithProperty:(objc_property_t) property]; -} - -- (NSArray *) properties { - unsigned int property_count; - objc_property_t *property_list = class_copyPropertyList(c, &property_count); - - NSMutableArray *properties = [NSMutableArray array]; - for (int i = 0; i < property_count; i++) { - [properties addObject:[NuProperty propertyWithProperty:property_list[i]]]; - } - free(property_list); - return properties; -} - -//OBJC_EXPORT objc_property_t class_getProperty(Class cls, const char *name) - - -@end - -#pragma mark - NuEnumerable.m - -@interface NuEnumerable(Unimplemented) -- (id) objectEnumerator; -@end - -@implementation NuEnumerable - -- (id) each:(id) callable -{ - id args = [[NuCell alloc] init]; - if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { - NSEnumerator *enumerator = [self objectEnumerator]; - id object; - while ((object = [enumerator nextObject])) { - @try - { - [args setCar:object]; - [callable evalWithArguments:args context:nil]; - } - @catch (NuBreakException *exception) { - break; - } - @catch (NuContinueException *exception) { - // do nothing, just continue with the next loop iteration - } - @catch (id exception) { - [args release]; - @throw(exception); - } - } - } - [args release]; - return self; -} - -- (id) eachWithIndex:(NuBlock *) block -{ - id args = [[NuCell alloc] init]; - [args setCdr:[[[NuCell alloc] init] autorelease]]; - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - NSEnumerator *enumerator = [self objectEnumerator]; - id object; - int i = 0; - while ((object = [enumerator nextObject])) { - @try - { - [args setCar:object]; - [[args cdr] setCar:[NSNumber numberWithInt:i]]; - [block evalWithArguments:args context:nil]; - } - @catch (NuBreakException *exception) { - break; - } - @catch (NuContinueException *exception) { - // do nothing, just continue with the next loop iteration - } - @catch (id exception) { - [args release]; - @throw(exception); - } - i++; - } - } - [args release]; - return self; -} - -- (NSArray *) select -{ - NSMutableArray *selected = [NSMutableArray array]; - NSEnumerator *enumerator = [self objectEnumerator]; - id object; - while ((object = [enumerator nextObject])) { - if (nu_valueIsTrue(object)) { - [selected addObject:object]; - } - } - return selected; -} - -- (NSArray *) select:(NuBlock *) block -{ - NSMutableArray *selected = [NSMutableArray array]; - id args = [[NuCell alloc] init]; - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - NSEnumerator *enumerator = [self objectEnumerator]; - id object; - while ((object = [enumerator nextObject])) { - [args setCar:object]; - id result = [block evalWithArguments:args context:Nu__null]; - if (nu_valueIsTrue(result)) { - [selected addObject:object]; - } - } - } - [args release]; - return selected; -} - -- (id) find:(NuBlock *) block -{ - id args = [[NuCell alloc] init]; - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - NSEnumerator *enumerator = [self objectEnumerator]; - id object; - while ((object = [enumerator nextObject])) { - [args setCar:object]; - id result = [block evalWithArguments:args context:Nu__null]; - if (nu_valueIsTrue(result)) { - [args release]; - return object; - } - } - } - [args release]; - return Nu__null; -} - -- (NSArray *) map:(id) callable -{ - NSMutableArray *results = [NSMutableArray array]; - id args = [[NuCell alloc] init]; - if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { - NSEnumerator *enumerator = [self objectEnumerator]; - id object; - while ((object = [enumerator nextObject])) { - [args setCar:object]; - [results addObject:[callable evalWithArguments:args context:nil]]; - } - } - [args release]; - return results; -} - -- (NSArray *) mapWithIndex:(id) callable -{ - NSMutableArray *results = [NSMutableArray array]; - id args = [[NuCell alloc] init]; - [args setCdr:[[[NuCell alloc] init] autorelease]]; - if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { - NSEnumerator *enumerator = [self objectEnumerator]; - id object; - int i = 0; - while ((object = [enumerator nextObject])) { - [args setCar:object]; - [[args cdr] setCar:[NSNumber numberWithInt:i]]; - [results addObject:[callable evalWithArguments:args context:nil]]; - i++; - } - } - [args release]; - return results; -} - -- (NSArray *) mapSelector:(SEL) sel -{ - NSMutableArray *results = [NSMutableArray array]; - NSEnumerator *enumerator = [self objectEnumerator]; - id object; - while ((object = [enumerator nextObject])) { - // this will fail (crash!) if the selector returns any type other than an object. - [results addObject:[object performSelector:sel]]; - } - return results; -} - -- (id) reduce:(id) callable from:(id) initial -{ - id args = [[NuCell alloc] init]; - [args setCdr:[[[NuCell alloc] init] autorelease]]; - id result = initial; - if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { - NSEnumerator *enumerator = [self objectEnumerator]; - id object; - while ((object = [enumerator nextObject])) { - [args setCar:result]; - [[args cdr] setCar: object]; - result = [callable evalWithArguments:args context:nil]; - } - } - [args release]; - return result; -} - -- (id) maximum:(NuBlock *) block -{ - id bestObject = nil; - - id args = [[NuCell alloc] init]; - [args setCdr:[[[NuCell alloc] init] autorelease]]; - - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - NSEnumerator *enumerator = [self objectEnumerator]; - id object; - while ((object = [enumerator nextObject])) { - if (!bestObject) { - bestObject = object; - } - else { - [args setCar:object]; - [[args cdr] setCar:bestObject]; - id result = [block evalWithArguments:args context:Nu__null]; - if (result && (result != Nu__null)) { - if ([result intValue] > 0) { - bestObject = object; - } - } - } - } - } - [args release]; - return bestObject; -} - -@end - - -#pragma mark - NuException.m - -#define kFilenameTopLevel @"" - -@implementation NSException (NuStackTrace) - -- (NSString*)dump -{ - NSMutableString* dump = [NSMutableString stringWithString:@""]; - - // Print the system stack trace (10.6 only) - if ([self respondsToSelector:@selector(callStackSymbols)]) - { - [dump appendString:@"\nSystem stack trace:\n"]; - - NSArray* callStackSymbols = [self callStackSymbols]; - NSUInteger count = [callStackSymbols count]; - for (int i = 0; i < count; i++) - { - [dump appendString:[callStackSymbols objectAtIndex:i]]; - [dump appendString:@"\n"]; - } - } - - return dump; -} - -@end - - -static void Nu_defaultExceptionHandler(NSException* e) -{ - [e dump]; -} - -static BOOL NuException_verboseExceptionReporting = NO; - -@interface NuException () -{ - NSMutableArray* stackTrace; -} -@end - -@implementation NuException - -+ (void)setDefaultExceptionHandler -{ - NSSetUncaughtExceptionHandler(*Nu_defaultExceptionHandler); - -#ifdef IMPORT_EXCEPTION_HANDLING_FRAMEWORK - [[NSExceptionHandler defaultExceptionHandler] - setExceptionHandlingMask:(NSHandleUncaughtExceptionMask - | NSHandleUncaughtSystemExceptionMask - | NSHandleUncaughtRuntimeErrorMask - | NSHandleTopLevelExceptionMask - | NSHandleOtherExceptionMask)]; -#endif -} - -+ (void)setVerbose:(BOOL)flag -{ - NuException_verboseExceptionReporting = flag; -} - - -- (void) dealloc -{ - if (stackTrace) - { - [stackTrace removeAllObjects]; - [stackTrace release]; - } - [super dealloc]; -} - -- (id)initWithName:(NSString *)name reason:(NSString *)reason userInfo:(NSDictionary *)userInfo -{ - self = [super initWithName:name reason:reason userInfo:userInfo]; - stackTrace = [[NSMutableArray alloc] init]; - return self; -} - -- (NSArray*)stackTrace -{ - return stackTrace; -} - -- (NuException *)addFunction:(NSString *)function lineNumber:(int)line -{ - return [self addFunction:function lineNumber:line filename:kFilenameTopLevel]; -} - -- (NuException *)addFunction:(NSString *)function lineNumber:(int)line filename:(NSString *)filename -{ - NuTraceInfo* traceInfo = [[[NuTraceInfo alloc] initWithFunction:function - lineNumber:line - filename:filename] - autorelease]; - [stackTrace addObject:traceInfo]; - - return self; -} - -- (NSString *)stringValue -{ - return [self reason]; -} - - -- (NSString*)dumpExcludingTopLevelCount:(NSUInteger)topLevelCount -{ - NSMutableString* dump = [NSMutableString stringWithString:@"Nu uncaught exception: "]; - - [dump appendString:[NSString stringWithFormat:@"%@: %@\n", [self name], [self reason]]]; - - NSUInteger count = [stackTrace count] - topLevelCount; - for (int i = 0; i < count; i++) - { - NuTraceInfo* trace = [stackTrace objectAtIndex:i]; - - NSString* traceString = [NSString stringWithFormat:@" from %@:%d: in %@\n", - [trace filename], - [trace lineNumber], - [trace function]]; - - [dump appendString:traceString]; - } - - if (NuException_verboseExceptionReporting) - { - [dump appendString:[super dump]]; - } - - return dump; -} - -- (NSString*)dump -{ - return [self dumpExcludingTopLevelCount:0]; -} - -@end - -@interface NuTraceInfo () -{ - NSString* filename; - int lineNumber; - NSString* function; -} -@end - -@implementation NuTraceInfo - -- (id)initWithFunction:(NSString *)aFunction lineNumber:(int)aLine filename:(NSString *)aFilename -{ - self = [super init]; - - if (self) - { - filename = [aFilename retain]; - lineNumber = aLine; - function = [aFunction retain]; - } - return self; -} - -- (void)dealloc -{ - [filename release]; - [function release]; - - [super dealloc]; -} - -- (NSString *)filename -{ - return filename; -} - -- (int)lineNumber -{ - return lineNumber; -} - -- (NSString *)function -{ - return function; -} - -@end - -#pragma mark - NuExtensions.m - -@implementation NSNull(Nu) -- (bool) atom -{ - return true; -} - -- (NSUInteger) length -{ - return 0; -} - -- (NSUInteger) count -{ - return 0; -} - -- (NSMutableArray *) array -{ - return [NSMutableArray array]; -} - -- (NSString *) stringValue -{ - return @"()"; -} - -- (BOOL) isEqual:(id) other -{ - return ((self == other) || (other == 0)) ? 1l : 0l; -} - -- (const char *) cStringUsingEncoding:(NSStringEncoding) encoding -{ - return [[self stringValue] cStringUsingEncoding:encoding]; -} - -@end - -@implementation NSArray(Nu) -+ (NSArray *) arrayWithList:(id) list -{ - NSMutableArray *a = [NSMutableArray array]; - id cursor = list; - while (cursor && cursor != Nu__null) { - [a addObject:[cursor car]]; - cursor = [cursor cdr]; - } - return a; -} - -// When an unknown message is received by an array, treat it as a call to objectAtIndex: -- (id) handleUnknownMessage:(NuCell *) method withContext:(NSMutableDictionary *) context -{ - id m = [[method car] evalWithContext:context]; - if ([m isKindOfClass:[NSNumber class]]) { - int mm = [m intValue]; - if (mm < 0) { - // if the index is negative, index from the end of the array - mm += [self count]; - } - if ((mm < [self count]) && (mm >= 0)) { - return [self objectAtIndex:mm]; - } - else { - return Nu__null; - } - } - else { - return [super handleUnknownMessage:method withContext:context]; - } -} - -// This default sort method sorts an array using its elements' compare: method. -- (NSArray *) sort -{ - return [self sortedArrayUsingSelector:@selector(compare:)]; -} - -// Convert an array into a list. -- (NuCell *) list -{ - NSUInteger count = [self count]; - if (count == 0) - return nil; - NuCell *result = [[[NuCell alloc] init] autorelease]; - NuCell *cursor = result; - [result setCar:[self objectAtIndex:0]]; - for (int i = 1; i < count; i++) { - [cursor setCdr:[[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - [cursor setCar:[self objectAtIndex:i]]; - } - return result; -} - -- (id) reduceLeft:(id)callable from:(id) initial -{ - id args = [[NuCell alloc] init]; - [args setCdr:[[[NuCell alloc] init] autorelease]]; - id result = initial; - if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { - for (NSInteger i = [self count] - 1; i >= 0; i--) { - id object = [self objectAtIndex:i]; - [args setCar:result]; - [[args cdr] setCar: object]; - result = [callable evalWithArguments:args context:nil]; - } - } - [args release]; - return result; -} - -- (id) eachInReverse:(id) callable -{ - id args = [[NuCell alloc] init]; - if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { - NSEnumerator *enumerator = [self reverseObjectEnumerator]; - id object; - while ((object = [enumerator nextObject])) { - @try - { - [args setCar:object]; - [callable evalWithArguments:args context:nil]; - } - @catch (NuBreakException *exception) { - break; - } - @catch (NuContinueException *exception) { - // do nothing, just continue with the next loop iteration - } - @catch (id exception) { - @throw(exception); - } - } - } - [args release]; - return self; -} - -static NSComparisonResult sortedArrayUsingBlockHelper(id a, id b, void *context) -{ - id args = [[NuCell alloc] init]; - [args setCdr:[[[NuCell alloc] init] autorelease]]; - [args setCar:a]; - [[args cdr] setCar:b]; - - // cast context as a block - NuBlock *block = (NuBlock *)context; - id result = [block evalWithArguments:args context:nil]; - - [args release]; - return [result intValue]; -} - -- (NSArray *) sortedArrayUsingBlock:(NuBlock *) block -{ - return [self sortedArrayUsingFunction:sortedArrayUsingBlockHelper context:block]; -} - -@end - -@implementation NSMutableArray(Nu) - -- (void) addObjectsFromList:(id)list -{ - [self addObjectsFromArray:[NSArray arrayWithList:list]]; -} - -- (void) addPossiblyNullObject:(id)anObject -{ - [self addObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; -} - -- (void) insertPossiblyNullObject:(id)anObject atIndex:(int)index -{ - [self insertObject:((anObject == nil) ? (id)[NSNull null] : anObject) atIndex:index]; -} - -- (void) replaceObjectAtIndex:(int)index withPossiblyNullObject:(id)anObject -{ - [self replaceObjectAtIndex:index withObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; -} - -- (void) sortUsingBlock:(NuBlock *) block -{ - [self sortUsingFunction:sortedArrayUsingBlockHelper context:block]; -} - -@end - -@implementation NSSet(Nu) -+ (NSSet *) setWithList:(id) list -{ - NSMutableSet *s = [NSMutableSet set]; - id cursor = list; - while (cursor && cursor != Nu__null) { - [s addObject:[cursor car]]; - cursor = [cursor cdr]; - } - return s; -} - -// Convert a set into a list. -- (NuCell *) list -{ - NSEnumerator *setEnumerator = [self objectEnumerator]; - NSObject *anObject = [setEnumerator nextObject]; - - if(!anObject) - return nil; - - NuCell *result = [[[NuCell alloc] init] autorelease]; - NuCell *cursor = result; - [cursor setCar:anObject]; - - while ((anObject = [setEnumerator nextObject])) { - [cursor setCdr:[[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - [cursor setCar:anObject]; - } - return result; -} - -@end - -@implementation NSMutableSet(Nu) - -- (void) addPossiblyNullObject:(id)anObject -{ - [self addObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; -} - -@end - -@implementation NSDictionary(Nu) - -+ (NSDictionary *) dictionaryWithList:(id) list -{ - NSMutableDictionary *d = [NSMutableDictionary dictionary]; - id cursor = list; - while (cursor && (cursor != Nu__null) && ([cursor cdr]) && ([cursor cdr] != Nu__null)) { - id key = [cursor car]; - if ([key isKindOfClass:[NuSymbol class]] && [key isLabel]) { - key = [key labelName]; - } - id value = [[cursor cdr] car]; - if (!value || [value isEqual:[NSNull null]]) { - [d removeObjectForKey:key]; - } else { - [d setValue:value forKey:key]; - } - cursor = [[cursor cdr] cdr]; - } - return d; -} - -- (id) objectForKey:(id)key withDefault:(id)defaultValue -{ - id value = [self objectForKey:key]; - return value ? value : defaultValue; -} - -// When an unknown message is received by a dictionary, treat it as a call to objectForKey: -- (id) handleUnknownMessage:(NuCell *) method withContext:(NSMutableDictionary *) context -{ - id cursor = method; - while (cursor && (cursor != Nu__null) && ([cursor cdr]) && ([cursor cdr] != Nu__null)) { - id key = [cursor car]; - id value = [[cursor cdr] car]; - if ([key isKindOfClass:[NuSymbol class]] && [key isLabel]) { - id evaluated_key = [key labelName]; - id evaluated_value = [value evalWithContext:context]; - [self setValue:evaluated_value forKey:evaluated_key]; - } - else { - id evaluated_key = [key evalWithContext:context]; - id evaluated_value = [value evalWithContext:context]; - [self setValue:evaluated_value forKey:evaluated_key]; - } - cursor = [[cursor cdr] cdr]; - } - if (cursor && (cursor != Nu__null)) { - // if the method is a label, use its value as the key. - if ([[cursor car] isKindOfClass:[NuSymbol class]] && ([[cursor car] isLabel])) { - id result = [self objectForKey:[[cursor car] labelName]]; - return result ? result : Nu__null; - } - else { - id result = [self objectForKey:[[cursor car] evalWithContext:context]]; - return result ? result : Nu__null; - } - } - else { - return Nu__null; - } -} - -// Iterate over the key-object pairs in a dictionary. Pass it a block with two arguments: (key object). -- (id) each:(id) block -{ - id args = [[NuCell alloc] init]; - [args setCdr:[[[NuCell alloc] init] autorelease]]; - NSEnumerator *keyEnumerator = [[self allKeys] objectEnumerator]; - id key; - while ((key = [keyEnumerator nextObject])) { - @try - { - [args setCar:key]; - [[args cdr] setCar:[self objectForKey:key]]; - [block evalWithArguments:args context:Nu__null]; - } - @catch (NuBreakException *exception) { - break; - } - @catch (NuContinueException *exception) { - // do nothing, just continue with the next loop iteration - } - @catch (id exception) { - @throw(exception); - } - } - [args release]; - return self; -} - -- (NSDictionary *) map: (id) callable -{ - NSMutableDictionary *results = [NSMutableDictionary dictionary]; - id args = [[NuCell alloc] init]; - if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { - NSEnumerator *enumerator = [self keyEnumerator]; - id object; - while ((object = [enumerator nextObject])) { - [args setCar:object]; - [args setCdr:[[[NuCell alloc] init] autorelease]]; - [[args cdr] setCar:[self objectForKey:object]]; - [results setObject:[callable evalWithArguments:args context:nil] forKey:object]; - } - } - [args release]; - return results; -} - -@end - -@implementation NSMutableDictionary(Nu) -- (id) lookupObjectForKey:(id)key -{ - id object = [self objectForKey:key]; - if (object) return object; - id parent = [self objectForKey:PARENT_KEY]; - if (!parent) return nil; - return [parent lookupObjectForKey:key]; -} - -- (void) setPossiblyNullObject:(id) anObject forKey:(id) aKey -{ - [self setObject:((anObject == nil) ? (id)[NSNull null] : anObject) forKey:aKey]; -} - -@end - -@interface NuStringEnumerator : NSEnumerator -{ - NSString *string; - int index; -} -@end - -@implementation NuStringEnumerator - -+ (NuStringEnumerator *) enumeratorWithString:(NSString *) string -{ - return [[[self alloc] initWithString:string] autorelease]; -} - -- (id) initWithString:(NSString *) s -{ - self = [super init]; - string = [s retain]; - index = 0; - return self; -} - -- (id) nextObject { - if (index < [string length]) { - return [NSNumber numberWithInt:[string characterAtIndex:index++]]; - } else { - return nil; - } -} - -- (void) dealloc { - [string release]; - [super dealloc]; -} - -@end - -@implementation NSString(Nu) -- (NSString *) stringValue -{ - return self; -} - -- (NSString *) escapedStringRepresentation -{ - NSMutableString *result = [NSMutableString stringWithString:@"\""]; - NSUInteger length = [self length]; - for (int i = 0; i < length; i++) { - unichar c = [self characterAtIndex:i]; - if (c < 32) { - switch (c) { - case 0x07: [result appendString:@"\\a"]; break; - case 0x08: [result appendString:@"\\b"]; break; - case 0x09: [result appendString:@"\\t"]; break; - case 0x0a: [result appendString:@"\\n"]; break; - case 0x0c: [result appendString:@"\\f"]; break; - case 0x0d: [result appendString:@"\\r"]; break; - case 0x1b: [result appendString:@"\\e"]; break; - default: - [result appendFormat:@"\\x%02x", c]; - } - } - else if (c == '"') { - [result appendString:@"\\\""]; - } - else if (c == '\\') { - [result appendString:@"\\\\"]; - } - else if (c < 127) { - [result appendCharacter:c]; - } - else if (c < 256) { - [result appendFormat:@"\\x%02x", c]; - } - else { - [result appendFormat:@"\\u%04x", c]; - } - } - [result appendString:@"\""]; - return result; -} - -- (id) evalWithContext:(NSMutableDictionary *) context -{ - NSMutableString *result; - NSArray *components = [self componentsSeparatedByString:@"#{"]; - if ([components count] == 1) { - result = [NSMutableString stringWithString:self]; - } - else { - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id parser = [context lookupObjectForKey:[symbolTable symbolWithString:@"_parser"]]; - result = [NSMutableString stringWithString:[components objectAtIndex:0]]; - int i; - for (i = 1; i < [components count]; i++) { - NSArray *parts = [[components objectAtIndex:i] componentsSeparatedByString:@"}"]; - NSString *expression = [parts objectAtIndex:0]; - // evaluate each expression - if (expression) { - id body; - @synchronized(parser) { - body = [parser parse:expression]; - } - id value = [body evalWithContext:context]; - NSString *stringValue = [value stringValue]; - [result appendString:stringValue]; - } - [result appendString:[parts objectAtIndex:1]]; - int j = 2; - while (j < [parts count]) { - [result appendString:@"}"]; - [result appendString:[parts objectAtIndex:j]]; - j++; - } - } - } - return result; -} - -+ (id) carriageReturn -{ - return [self stringWithCString:"\n" encoding:NSUTF8StringEncoding]; -} - -#if !TARGET_OS_IPHONE - -// Read the text output of a shell command into a string and return the string. -+ (NSString *) stringWithShellCommand:(NSString *) command -{ - return [self stringWithShellCommand:command standardInput:nil]; -} - -+ (NSString *) stringWithShellCommand:(NSString *) command standardInput:(id) input -{ - NSData *data = [NSData dataWithShellCommand:command standardInput:input]; - return data ? [[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease] chomp] : nil; -} -#endif - -+ (NSString *) stringWithData:(NSData *) data encoding:(int) encoding -{ - return [[[NSString alloc] initWithData:data encoding:encoding] autorelease]; -} - -// Read the contents of standard input into a string. -+ (NSString *) stringWithStandardInput -{ - return [[[NSString alloc] initWithData:[NSData dataWithStandardInput] encoding:NSUTF8StringEncoding] autorelease]; -} - -// If the last character is a newline, delete it. -- (NSString *) chomp -{ - NSInteger lastIndex = [self length] - 1; - if (lastIndex >= 0) { - if ([self characterAtIndex:lastIndex] == 10) { - return [self substringWithRange:NSMakeRange(0, lastIndex)]; - } - else { - return self; - } - } - else { - return self; - } -} - -+ (NSString *) stringWithCharacter:(unichar) c -{ - return [self stringWithFormat:@"%C", c]; -} - -// Convert a string into a symbol. -- (id) symbolValue -{ - return [[NuSymbolTable sharedSymbolTable] symbolWithString:self]; -} - -// Split a string into lines. -- (NSArray *) lines -{ - NSArray *a = [self componentsSeparatedByString:@"\n"]; - if ([[a lastObject] isEqualToString:@""]) { - return [a subarrayWithRange:NSMakeRange(0, [a count]-1)]; - } - else { - return a; - } -} - -// Replace a substring with another. -- (NSString *) replaceString:(NSString *) target withString:(NSString *) replacement -{ - NSMutableString *s = [NSMutableString stringWithString:self]; - [s replaceOccurrencesOfString:target withString:replacement options:0 range:NSMakeRange(0, [self length])]; - return s; -} - -- (id) objectEnumerator -{ - return [NuStringEnumerator enumeratorWithString:self]; -} - -- (id) each:(id) block -{ - id args = [[NuCell alloc] init]; - NSEnumerator *characterEnumerator = [self objectEnumerator]; - id character; - while ((character = [characterEnumerator nextObject])) { - @try - { - [args setCar:character]; - [block evalWithArguments:args context:Nu__null]; - } - @catch (NuBreakException *exception) { - break; - } - @catch (NuContinueException *exception) { - // do nothing, just continue with the next loop iteration - } - @catch (id exception) { - @throw(exception); - } - } - [args release]; - return self; -} - -@end - -@implementation NSMutableString(Nu) -- (void) appendCharacter:(unichar) c -{ - [self appendFormat:@"%C", c]; -} - -@end - -@implementation NSData(Nu) - -- (const unsigned char) byteAtIndex:(int) i -{ - const unsigned char buffer[2]; - [self getBytes:(void *)&buffer range:NSMakeRange(i,1)]; - return buffer[0]; -} - -#if !TARGET_OS_IPHONE -// Read the output of a shell command into an NSData object and return the object. -+ (NSData *) dataWithShellCommand:(NSString *) command -{ - return [self dataWithShellCommand:command standardInput:nil]; -} - -+ (NSData *) dataWithShellCommand:(NSString *) command standardInput:(id) input -{ - char *input_template = strdup("/tmp/nuXXXXXX"); - char *input_filename = mktemp(input_template); - char *output_template = strdup("/tmp/nuXXXXXX"); - char *output_filename = mktemp(output_template); - id returnValue = nil; - if (input_filename || output_filename) { - NSString *inputFileName = [NSString stringWithCString:input_filename encoding:NSUTF8StringEncoding]; - NSString *outputFileName = [NSString stringWithCString:output_filename encoding:NSUTF8StringEncoding]; - NSString *fullCommand; - if (input) { - if ([input isKindOfClass:[NSData class]]) { - [input writeToFile:inputFileName atomically:NO]; - } else if ([input isKindOfClass:[NSString class]]) { - [input writeToFile:inputFileName atomically:NO encoding:NSUTF8StringEncoding error:NULL]; - } else { - [[input stringValue] writeToFile:inputFileName atomically:NO encoding:NSUTF8StringEncoding error:NULL]; - } - fullCommand = [NSString stringWithFormat:@"%@ < %@ > %@", command, inputFileName, outputFileName]; - } - else { - fullCommand = [NSString stringWithFormat:@"%@ > %@", command, outputFileName]; - } - const char *commandString = [[fullCommand stringValue] cStringUsingEncoding:NSUTF8StringEncoding]; - int result = system(commandString) >> 8; // this needs an explanation - if (!result) - returnValue = [NSData dataWithContentsOfFile:outputFileName]; - system([[NSString stringWithFormat:@"rm -f %@ %@", inputFileName, outputFileName] cStringUsingEncoding:NSUTF8StringEncoding]); - } - free(input_template); - free(output_template); - return returnValue; -} -#endif - -// Read the contents of standard input into a string. -+ (NSData *) dataWithStandardInput -{ - return [[NSFileHandle fileHandleWithStandardInput] readDataToEndOfFile]; -} - -// Helper. Included because it's so useful. -- (id) propertyListValue { - return [NSPropertyListSerialization propertyListWithData:self - options:NSPropertyListImmutable - format:0 - error:NULL]; -} - -@end - -@implementation NSNumber(Nu) - -- (id) times:(id) block -{ - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - id args = [[NuCell alloc] init]; - int x = [self intValue]; - int i; - for (i = 0; i < x; i++) { - @try - { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [args setCar:[NSNumber numberWithInt:i]]; - [block evalWithArguments:args context:Nu__null]; - [pool release]; - } - @catch (NuBreakException *exception) { - break; - } - @catch (NuContinueException *exception) { - // do nothing, just continue with the next loop iteration - } - @catch (id exception) { - @throw(exception); - } - } - [args release]; - } - return self; -} - -- (id) downTo:(id) number do:(id) block -{ - int startValue = [self intValue]; - int finalValue = [number intValue]; - if (startValue < finalValue) { - return self; - } - else { - id args = [[NuCell alloc] init]; - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - int i; - for (i = startValue; i >= finalValue; i--) { - @try - { - [args setCar:[NSNumber numberWithInt:i]]; - [block evalWithArguments:args context:Nu__null]; - } - @catch (NuBreakException *exception) { - break; - } - @catch (NuContinueException *exception) { - // do nothing, just continue with the next loop iteration - } - @catch (id exception) { - @throw(exception); - } - } - } - [args release]; - } - return self; -} - -- (id) upTo:(id) number do:(id) block -{ - int startValue = [self intValue]; - int finalValue = [number intValue]; - id args = [[NuCell alloc] init]; - if (nu_objectIsKindOfClass(block, [NuBlock class])) { - int i; - for (i = startValue; i <= finalValue; i++) { - @try - { - [args setCar:[NSNumber numberWithInt:i]]; - [block evalWithArguments:args context:Nu__null]; - } - @catch (NuBreakException *exception) { - break; - } - @catch (NuContinueException *exception) { - // do nothing, just continue with the next loop iteration - } - @catch (id exception) { - @throw(exception); - } - } - } - [args release]; - return self; -} - -- (NSString *) hexValue -{ - int x = [self intValue]; - return [NSString stringWithFormat:@"0x%x", x]; -} - -@end - -@implementation NuMath - -+ (double) cos: (double) x {return cos(x);} -+ (double) sin: (double) x {return sin(x);} -+ (double) sqrt: (double) x {return sqrt(x);} -+ (double) cbrt: (double) x {return cbrt(x);} -+ (double) square: (double) x {return x*x;} -+ (double) exp: (double) x {return exp(x);} -+ (double) exp2: (double) x {return exp2(x);} -+ (double) log: (double) x {return log(x);} - -#ifdef FREEBSD -+ (double) log2: (double) x {return log10(x)/log10(2.0);} // not in FreeBSD -#else -+ (double) log2: (double) x {return log2(x);} -#endif - -+ (double) log10: (double) x {return log10(x);} - -+ (double) floor: (double) x {return floor(x);} -+ (double) ceil: (double) x {return ceil(x);} -+ (double) round: (double) x {return round(x);} - -+ (double) raiseNumber: (double) x toPower: (double) y {return pow(x, y);} -+ (int) integerDivide:(int) x by:(int) y {return x / y;} -+ (int) integerMod:(int) x by:(int) y {return x % y;} - -+ (double) abs: (double) x {return (x < 0) ? -x : x;} - -+ (long) random -{ - long r = random(); - return r; -} - -+ (void) srandom:(unsigned long) seed -{ - srandom((unsigned int) seed); -} - -@end - -@implementation NSDate(Nu) - -#ifndef LINUX -+ dateWithTimeIntervalSinceNow:(NSTimeInterval) seconds -{ - return [[[NSDate alloc] initWithTimeIntervalSinceNow:seconds] autorelease]; -} -#endif - -@end - -@implementation NSFileManager(Nu) - -// crashes -+ (id) _timestampForFileNamed:(NSString *) filename -{ - if (filename == Nu__null) return nil; - NSError *error; - NSDictionary *attributes = [[NSFileManager defaultManager] - attributesOfItemAtPath:[filename stringByExpandingTildeInPath] - error:&error]; - return [attributes valueForKey:NSFileModificationDate]; -} - -+ (id) creationTimeForFileNamed:(NSString *) filename -{ - if (!filename) - return nil; - const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; - struct stat sb; - int result = stat(path, &sb); - if (result == -1) { - return nil; - } - // return [NSDate dateWithTimeIntervalSince1970:sb.st_ctimespec.tv_sec]; - return [NSDate dateWithTimeIntervalSince1970:sb.st_ctime]; -} - -+ (id) modificationTimeForFileNamed:(NSString *) filename -{ - if (!filename) - return nil; - const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; - struct stat sb; - int result = stat(path, &sb); - if (result == -1) { - return nil; - } - return [NSDate dateWithTimeIntervalSince1970:sb.st_mtime]; -} - -+ (int) directoryExistsNamed:(NSString *) filename -{ - if (!filename) - return NO; - const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; - struct stat sb; - int result = stat(path, &sb); - if (result == -1) { - return NO; - } - return (S_ISDIR(sb.st_mode) != 0) ? 1 : 0; -} - -+ (int) fileExistsNamed:(NSString *) filename -{ - if (!filename) - return NO; - const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; - struct stat sb; - int result = stat(path, &sb); - if (result == -1) { - return NO; - } - return (S_ISDIR(sb.st_mode) == 0) ? 1 : 0; -} - -@end - -@implementation NSBundle(Nu) - -+ (NSBundle *) frameworkWithName:(NSString *) frameworkName -{ - NSBundle *framework = nil; - - // is the framework already loaded? - NSArray *fw = [NSBundle allFrameworks]; - NSEnumerator *frameworkEnumerator = [fw objectEnumerator]; - while ((framework = [frameworkEnumerator nextObject])) { - if ([frameworkName isEqual: [[framework infoDictionary] objectForKey:@"CFBundleName"]]) { - return framework; - } - } - - // first try the current directory - framework = [NSBundle bundleWithPath:[NSString stringWithFormat:@"%@/%@.framework", [[NSFileManager defaultManager] currentDirectoryPath], frameworkName]]; - - // then /Library/Frameworks - if (!framework) - framework = [NSBundle bundleWithPath:[NSString stringWithFormat:@"/Library/Frameworks/%@.framework", frameworkName]]; - - // then /System/Library/Frameworks - if (!framework) - framework = [NSBundle bundleWithPath:[NSString stringWithFormat:@"/System/Library/Frameworks/%@.framework", frameworkName]]; - - // then /usr/frameworks - if (!framework) - framework = [NSBundle bundleWithPath:[NSString stringWithFormat:@"/usr/frameworks/%@.framework", frameworkName]]; - - // then /usr/local/frameworks - if (!framework) - framework = [NSBundle bundleWithPath:[NSString stringWithFormat:@"/usr/local/frameworks/%@.framework", frameworkName]]; - - if (framework) { - if ([framework load]) - return framework; - } - return nil; -} - -- (id) loadNuFile:(NSString *) nuFileName withContext:(NSMutableDictionary *) context -{ - NSString *fileName = [self pathForResource:nuFileName ofType:@"nu"]; - if (fileName) { - NSString *string = [NSString stringWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:NULL]; - if (string) { - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id parser = [context lookupObjectForKey:[symbolTable symbolWithString:@"_parser"]]; - id body = [parser parse:string asIfFromFilename:[fileName cStringUsingEncoding:NSUTF8StringEncoding]]; - [body evalWithContext:context]; - return [symbolTable symbolWithString:@"t"]; - } - return nil; - } - else { - return nil; - } -} - -@end - - -@implementation NSMethodSignature(Nu) - -- (NSString *) typeString -{ - // in 10.5, we can do this: - // return [self _typeString]; - NSMutableString *result = [NSMutableString stringWithFormat:@"%s", [self methodReturnType]]; - NSInteger i; - NSUInteger max = [self numberOfArguments]; - for (i = 0; i < max; i++) { - [result appendFormat:@"%s", [self getArgumentTypeAtIndex:i]]; - } - return result; -} - -@end - - -#pragma mark - NuHandler.m - -static id collect_arguments(struct nu_handler_description *description, va_list ap) -{ - int i = 0; - char *type; - id arguments = [[NuCell alloc] init]; - id cursor = arguments; - while((type = description->description[2+i])) { - [cursor setCdr:[[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - // NSLog(@"argument type %d: %s", i, type); - if (!strcmp(type, "@")) { - [cursor setCar:va_arg(ap, id)]; - } - else if (!strcmp(type, "i")) { - int x = va_arg(ap, int); - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; - } - else if (!strcmp(type, "C")) { - // unsigned char is promoted to int in va_arg() - //unsigned char x = va_arg(ap, unsigned char); - int x = va_arg(ap, int); - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; - } - else if (!strcmp(type, "f")) { - // calling this w/ float crashes on intel - double x = (double) va_arg(ap, double); - //NSLog(@"argument is %f", *((float *) &x)); - ap = ap - sizeof(float); // messy, messy... - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; - } - else if (!strcmp(type, "d")) { - double x = va_arg(ap, double); - //NSLog(@"argument is %lf", x); - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; - } - else if (!strcmp(type, ":")) { - SEL x = va_arg(ap, SEL); - //NSLog(@"collect_arguments: [:] (SEL) = %@", NSStringFromSelector(x)); - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; - } - else if (!strcmp(type, "^@")) { - void *x = va_arg(ap, void *); - //NSLog(@"argument is %lf", x); - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; - } -#if TARGET_OS_IPHONE - else if (!strcmp(type, "{CGRect={CGPoint=ff}{CGSize=ff}}") - || (!strcmp(type, "{CGRect=\"origin\"{CGPoint=\"x\"f\"y\"f}\"size\"{CGSize=\"width\"f\"height\"f}}"))) { - CGRect x = va_arg(ap, CGRect); - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; - } -#else - else if (!strcmp(type, "{_NSRect={_NSPoint=dd}{_NSSize=dd}}")) { - NSRect x = va_arg(ap, NSRect); - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; - } - else if (!strcmp(type, "{CGRect={CGPoint=dd}{CGSize=dd}}")) { -#ifdef DARWIN - CGRect x = va_arg(ap, CGRect); - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; -#endif - } - else if (!strcmp(type, "{_NSPoint=dd}")) { - NSPoint x = va_arg(ap, NSPoint); - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; - } - else if (!strcmp(type, "{_NSSize=dd}")) { - NSSize x = va_arg(ap, NSSize); - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; - } - else if (!strcmp(type, "{_NSRange=QQ}")) { - NSRange x = va_arg(ap, NSRange); - [cursor setCar:get_nu_value_from_objc_value(&x, type)]; - } -#endif - else { - NSLog(@"unsupported argument type %s, see objc/handler.m to add support for it", type); - } - i++; - } - return arguments; -} - -// helper function called by method handlers -static void nu_handler(void *return_value, struct nu_handler_description *handler, id receiver, va_list ap) -{ - id result; - BOOL retained_through_autorelease = NO; - @autoreleasepool { - NuBlock *block = (NuBlock *) handler->description[1]; - // NSLog(@"handling %@", [block stringValue]); - id arguments = collect_arguments(handler, ap); - result = [block evalWithArguments:[arguments cdr] context:nil self:receiver]; - if (return_value) { - // if the call returns an object, retain the result so that it will survive the autorelease. - // we undo this retain once we're safely outside of the autorelease block. - if (handler->description[0][1] == '@') { - retained_through_autorelease = YES; - [result retain]; - // if the call is supposed to return a retained object, add an additional retain. - if (handler->description[0][0] == '!') { - // The static analyzer says this is a potential leak. - // It's intentional, we are returning from a method that should return a retained (+1) object. - [result retain]; - } - } - set_objc_value_from_nu_value(return_value, result, handler->description[0]+1); - } - [arguments release]; - } - if (retained_through_autorelease) { - // undo the object-preserving retain we made in the autorelease block above. - [result autorelease]; - } -} - -@interface NuHandlers : NSObject -{ -@public - struct nu_handler_description *handlers; - int handler_count; - int next_free_handler; -} - -@end - -@implementation NuHandlers -- (id) initWithHandlers:(struct nu_handler_description *) h count:(int) count -{ - if ((self = [super init])) { - handlers = h; - handler_count = count; - next_free_handler = 0; - } - return self; -} - -@end - -static IMP handler_returning_void(void *userdata) { - return imp_implementationWithBlock(^(id receiver, ...) { - struct nu_handler_description description; - description.handler = NULL; - description.description = userdata; - va_list ap; - va_start(ap, receiver); - nu_handler(0, &description, receiver, ap); - }); -} - -#define MAKE_HANDLER_WITH_TYPE(type) \ -static IMP handler_returning_ ## type (void* userdata) \ -{ \ -return imp_implementationWithBlock(^(id receiver, ...) { \ -struct nu_handler_description description; \ -description.handler = NULL; \ -description.description = userdata; \ -va_list ap; \ -va_start(ap, receiver); \ -type result; \ -nu_handler(&result, &description, receiver, ap); \ -return result; \ -}); \ -} - -MAKE_HANDLER_WITH_TYPE(id) -MAKE_HANDLER_WITH_TYPE(int) -MAKE_HANDLER_WITH_TYPE(bool) -MAKE_HANDLER_WITH_TYPE(float) -MAKE_HANDLER_WITH_TYPE(double) -#ifdef DARWIN -MAKE_HANDLER_WITH_TYPE(CGRect) -MAKE_HANDLER_WITH_TYPE(CGPoint) -MAKE_HANDLER_WITH_TYPE(CGSize) -#endif -#if !TARGET_OS_IPHONE -MAKE_HANDLER_WITH_TYPE(NSRect) -MAKE_HANDLER_WITH_TYPE(NSPoint) -MAKE_HANDLER_WITH_TYPE(NSSize) -#endif -MAKE_HANDLER_WITH_TYPE(NSRange) - -static NSMutableDictionary *handlerWarehouse = nil; - -@implementation NuHandlerWarehouse - -+ (void) registerHandlers:(struct nu_handler_description *) description withCount:(int) count forReturnType:(NSString *) returnType -{ - if (!handlerWarehouse) { - handlerWarehouse = [[NSMutableDictionary alloc] init]; - } - NuHandlers *handlers = [[NuHandlers alloc] initWithHandlers:description count:count]; - [handlerWarehouse setObject:handlers forKey:returnType]; - [handlers release]; -} - -+ (IMP) handlerWithSelector:(SEL)sel block:(NuBlock *)block signature:(const char *) signature userdata:(char **) userdata -{ - NSString *returnType = [NSString stringWithCString:userdata[0]+1 encoding:NSUTF8StringEncoding]; - if ([returnType isEqualToString:@"v"]) { - return handler_returning_void(userdata); - } - else if ([returnType isEqualToString:@"@"]) { - return handler_returning_id(userdata); - } - else if ([returnType isEqualToString:@"i"]) { - return handler_returning_int(userdata); - } - else if ([returnType isEqualToString:@"C"]) { - return handler_returning_bool(userdata); - } - else if ([returnType isEqualToString:@"f"]) { - return handler_returning_float(userdata); - } - else if ([returnType isEqualToString:@"d"]) { - return handler_returning_double(userdata); - } -#ifdef DARWIN - else if ([returnType isEqualToString:@"{CGRect={CGPoint=ff}{CGSize=ff}}"]) { - return handler_returning_CGRect(userdata); - } - else if ([returnType isEqualToString:@"{CGPoint=ff}"]) { - return handler_returning_CGPoint(userdata); - } - else if ([returnType isEqualToString:@"{CGSize=ff}"]) { - return handler_returning_CGSize(userdata); - } -#endif - else if ([returnType isEqualToString:@"{_NSRange=II}"]) { - return handler_returning_NSRange(userdata); - } -#if !TARGET_OS_IPHONE - else if ([returnType isEqualToString:@"{_NSRect={_NSPoint=dd}{_NSSize=dd}}"]) { - return handler_returning_NSRect(userdata); - } - else if ([returnType isEqualToString:@"{_NSPoint=dd}"]) { - return handler_returning_NSPoint(userdata); - } - else if ([returnType isEqualToString:@"{_NSSize=dd}"]) { - return handler_returning_NSSize(userdata); - } - else if ([returnType isEqualToString:@"{_NSRange=QQ}"]) { - return handler_returning_NSRange(userdata); - } -#endif - else { -#if TARGET_OS_IPHONE - // this is only a problem on iOS. - NSLog(@"UNKNOWN RETURN TYPE %@", returnType); -#endif - } - // the following is deprecated. Now that we can create IMPs from blocks, we don't need handler pools. - if (!handlerWarehouse) { - return NULL; - } - NuHandlers *handlers = [handlerWarehouse objectForKey:returnType]; - if (handlers) { - if (handlers->next_free_handler < handlers->handler_count) { - handlers->handlers[handlers->next_free_handler].description = userdata; - IMP handler = handlers->handlers[handlers->next_free_handler].handler; - handlers->next_free_handler++; - return handler; - } - } - return NULL; -} - -@end - -#pragma mark - NuMacro_0.m -@interface NuMacro_0 () -{ -@protected - NSString *name; - NuCell *body; - NSMutableSet *gensyms; -} -@end - -@implementation NuMacro_0 - -+ (id) macroWithName:(NSString *)n body:(NuCell *)b -{ - return [[[self alloc] initWithName:n body:b] autorelease]; -} - -- (void) dealloc -{ - [body release]; - [super dealloc]; -} - -- (NSString *) name -{ - return name; -} - -- (NuCell *) body -{ - return body; -} - -- (NSSet *) gensyms -{ - return gensyms; -} - -- (void) collectGensyms:(NuCell *)cell -{ - id car = [cell car]; - if ([car atom]) { - if (nu_objectIsKindOfClass(car, [NuSymbol class]) && [car isGensym]) { - [gensyms addObject:car]; - } - } - else if (car && (car != Nu__null)) { - [self collectGensyms:car]; - } - id cdr = [cell cdr]; - if (cdr && (cdr != Nu__null)) { - [self collectGensyms:cdr]; - } -} - -- (id) initWithName:(NSString *)n body:(NuCell *)b -{ - if ((self = [super init])) { - name = [n retain]; - body = [b retain]; - gensyms = [[NSMutableSet alloc] init]; - [self collectGensyms:body]; - } - return self; -} - -- (NSString *) stringValue -{ - return [NSString stringWithFormat:@"(macro-0 %@ %@)", name, [body stringValue]]; -} - -- (id) body:(NuCell *) oldBody withGensymPrefix:(NSString *) prefix symbolTable:(NuSymbolTable *) symbolTable -{ - NuCell *newBody = [[[NuCell alloc] init] autorelease]; - id car = [oldBody car]; - if (car == Nu__null) { - [newBody setCar:car]; - } - else if ([car atom]) { - if (nu_objectIsKindOfClass(car, [NuSymbol class]) && [car isGensym]) { - [newBody setCar:[symbolTable symbolWithString:[NSString stringWithFormat:@"%@%@", prefix, [car stringValue]]]]; - } - else if (nu_objectIsKindOfClass(car, [NSString class])) { - // Here we replace gensyms in interpolated strings. - // The current solution is workable but fragile; - // we just blindly replace the gensym names with their expanded names. - // It would be better to - // 1. only replace gensym names in interpolated expressions. - // 2. ensure substitutions never overlap. To do this, I think we should - // a. order gensyms by size and do the longest ones first. - // b. make the gensym transformation idempotent. - // That's for another day. - // For now, I just substitute each gensym name with its expansion. - // - NSMutableString *tempString = [NSMutableString stringWithString:car]; - //NSLog(@"checking %@", tempString); - NSEnumerator *gensymEnumerator = [gensyms objectEnumerator]; - NuSymbol *gensymSymbol; - while ((gensymSymbol = [gensymEnumerator nextObject])) { - //NSLog(@"gensym is %@", [gensymSymbol stringValue]); - [tempString replaceOccurrencesOfString:[gensymSymbol stringValue] - withString:[NSString stringWithFormat:@"%@%@", prefix, [gensymSymbol stringValue]] - options:0 range:NSMakeRange(0, [tempString length])]; - } - //NSLog(@"setting string to %@", tempString); - [newBody setCar:tempString]; - } - else { - [newBody setCar:car]; - } - } - else { - [newBody setCar:[self body:car withGensymPrefix:prefix symbolTable:symbolTable]]; - } - id cdr = [oldBody cdr]; - if (cdr && (cdr != Nu__null)) { - [newBody setCdr:[self body:cdr withGensymPrefix:prefix symbolTable:symbolTable]]; - } - else { - [newBody setCdr:cdr]; - } - return newBody; -} - -- (id) expandUnquotes:(id) oldBody withContext:(NSMutableDictionary *) context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - if (oldBody == [NSNull null]) - return oldBody; - id unquote = [symbolTable symbolWithString:@"unquote"]; - id car = [oldBody car]; - id cdr = [oldBody cdr]; - if ([car atom]) { - if (car == unquote) { - return [[cdr car] evalWithContext:context]; - } - else { - NuCell *newBody = [[[NuCell alloc] init] autorelease]; - [newBody setCar:car]; - [newBody setCdr:[self expandUnquotes:cdr withContext:context]]; - return newBody; - } - } - else { - NuCell *newBody = [[[NuCell alloc] init] autorelease]; - [newBody setCar:[self expandUnquotes:car withContext:context]]; - [newBody setCdr:[self expandUnquotes:cdr withContext:context]]; - return newBody; - } -} - - -- (id) expandAndEval:(id)cdr context:(NSMutableDictionary *)calling_context evalFlag:(BOOL)evalFlag -{ - NuSymbolTable *symbolTable = [calling_context objectForKey:SYMBOLS_KEY]; - - // save the current value of margs - id old_margs = [calling_context objectForKey:[symbolTable symbolWithString:@"margs"]]; - // set the arguments to the special variable "margs" - [calling_context setPossiblyNullObject:cdr forKey:[symbolTable symbolWithString:@"margs"]]; - // evaluate the body of the block in the calling context (implicit progn) - - // if the macro contains gensyms, give them a unique prefix - NSUInteger gensymCount = [[self gensyms] count]; - id gensymPrefix = nil; - if (gensymCount > 0) { - gensymPrefix = [NSString stringWithFormat:@"g%ld", [NuMath random]]; - } - - id bodyToEvaluate = (gensymCount == 0) - ? (id)body : [self body:body withGensymPrefix:gensymPrefix symbolTable:symbolTable]; - - // uncomment this to get the old (no gensym) behavior. - //bodyToEvaluate = body; - //NSLog(@"evaluating %@", [bodyToEvaluate stringValue]); - - id value = [self expandUnquotes:bodyToEvaluate withContext:calling_context]; - - if (evalFlag) - { - id cursor = value; - - while (cursor && (cursor != Nu__null)) { - value = [[cursor car] evalWithContext:calling_context]; - cursor = [cursor cdr]; - } - } - - // restore the old value of margs - if (old_margs == nil) { - [calling_context removeObjectForKey:[symbolTable symbolWithString:@"margs"]]; - } - else { - [calling_context setPossiblyNullObject:old_margs forKey:[symbolTable symbolWithString:@"margs"]]; - } - -#if 0 - // I would like to remove gensym values and symbols at the end of a macro's execution, - // but there is a problem with this: the gensym assignments could be used in a closure, - // and deleting them would cause that to break. See the testIvarAccessorMacro unit - // test for an example of this. So for now, the code below is disabled. - // - // remove the gensyms from the context; this also releases their assigned values - NSArray *gensymArray = [gensyms allObjects]; - for (int i = 0; i < gensymCount; i++) { - NuSymbol *gensymBase = [gensymArray objectAtIndex:i]; - NuSymbol *gensymSymbol = [symbolTable symbolWithString:[NSString stringWithFormat:@"%@%@", gensymPrefix, [gensymBase stringValue]]]; - [calling_context removeObjectForKey:gensymSymbol]; - [symbolTable removeSymbol:gensymSymbol]; - } -#endif - return value; -} - - -- (id) expand1:(id)cdr context:(NSMutableDictionary*)calling_context -{ - return [self expandAndEval:cdr context:calling_context evalFlag:NO]; -} - - -- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context -{ - return [self expandAndEval:cdr context:calling_context evalFlag:YES]; -} - -@end - -#pragma mark - NuMacro_1.m - -//#define MACRO1_DEBUG 1 - -// Following debug output on and off for this file only -#ifdef MACRO1_DEBUG -#define Macro1Debug(arg...) NSLog(arg) -#else -#define Macro1Debug(arg...) -#endif - -@interface NuMacro_1 () -{ - NuCell *parameters; -} -@end - -@implementation NuMacro_1 - -+ (id) macroWithName:(NSString *)n parameters:(NuCell*)p body:(NuCell *)b -{ - return [[[self alloc] initWithName:n parameters:p body:b] autorelease]; -} - -- (void) dealloc -{ - [parameters release]; - [super dealloc]; -} - -- (BOOL) findAtom:(id)atom inSequence:(id)sequence -{ - if (atom == nil || atom == Nu__null) - return NO; - - if (sequence == nil || sequence == Nu__null) - return NO; - - if ([[atom stringValue] isEqualToString:[sequence stringValue]]) - return YES; - - if ([sequence class] == [NuCell class]) { - return ( [self findAtom:atom inSequence:[sequence car]] - || [self findAtom:atom inSequence:[sequence cdr]]); - } - - return NO; -} - -- (id) initWithName:(NSString *)n parameters:(NuCell *)p body:(NuCell *)b -{ - if ((self = [super initWithName:n body:b])) { - parameters = [p retain]; - - if (([parameters length] == 1) - && ([[[parameters car] stringValue] isEqualToString:@"*args"])) { - // Skip the check - } - else { - BOOL foundArgs = [self findAtom:@"*args" inSequence:parameters]; - - if (foundArgs) { - printf("Warning: Overriding implicit variable '*args'.\n"); - } - } - } - return self; -} - -- (NSString *) stringValue -{ - return [NSString stringWithFormat:@"(macro %@ %@ %@)", name, [parameters stringValue], [body stringValue]]; -} - -- (void) dumpContext:(NSMutableDictionary*)context -{ -#ifdef MACRO1_DEBUG - NSArray* keys = [context allKeys]; - NSUInteger count = [keys count]; - for (int i = 0; i < count; i++) { - id key = [keys objectAtIndex:i]; - Macro1Debug(@"contextdump: %@ = %@ [%@]", key, - [[context objectForKey:key] stringValue], - [[context objectForKey:key] class]); - } -#endif -} - -- (void) restoreArgs:(id)old_args context:(NSMutableDictionary*)calling_context -{ - NuSymbolTable *symbolTable = [calling_context objectForKey:SYMBOLS_KEY]; - - if (old_args == nil) { - [calling_context removeObjectForKey:[symbolTable symbolWithString:@"*args"]]; - } - else { - [calling_context setPossiblyNullObject:old_args forKey:[symbolTable symbolWithString:@"*args"]]; - } -} - -- (void)restoreBindings:(id)bindings - forMaskedVariables:(NSMutableDictionary*)maskedVariables - fromContext:(NSMutableDictionary*)calling_context -{ - id plist = bindings; - - while (plist && (plist != Nu__null)) { - id param = [[plist car] car]; - - Macro1Debug(@"restoring bindings: looking up key: %@", - [param stringValue]); - - [calling_context removeObjectForKey:param]; - id pvalue = [maskedVariables objectForKey:param]; - - Macro1Debug(@"restoring calling context for: %@, value: %@", - [param stringValue], [pvalue stringValue]); - - if (pvalue) { - [calling_context setPossiblyNullObject:pvalue forKey:param]; - } - - plist = [plist cdr]; - } -} - -- (id) destructuringListAppend:(id)lhs withList:(id)rhs -{ - Macro1Debug(@"Append: lhs = %@ rhs = %@", [lhs stringValue], [rhs stringValue]); - - if (lhs == nil || lhs == Nu__null) - return rhs; - - if (rhs == nil || rhs == Nu__null) - return lhs; - - id cursor = lhs; - - while ( cursor - && (cursor != Nu__null) - && [cursor cdr] - && ([cursor cdr] != Nu__null)) { - cursor = [cursor cdr]; - } - - [cursor setCdr:rhs]; - - Macro1Debug(@"Append: result = %@", [lhs stringValue]); - - return lhs; -} - -- (id) mdestructure:(id)pattern withSequence:(id)sequence -{ - Macro1Debug(@"mdestructure: pat: %@ seq: %@", [pattern stringValue], [sequence stringValue]); - - // ((and (not pat) seq) - if ( ((pattern == nil) || (pattern == Nu__null)) - && !((sequence == Nu__null) || (sequence == nil))) { - [NSException raise:@"NuDestructureException" - format:@"Attempt to match empty pattern to non-empty object %@", [self stringValue]]; - } - // ((not pat) nil) - else if ((pattern == nil) || (pattern == Nu__null)) { - return nil; - } - // ((eq pat '_) '()) ; wildcard match produces no binding - else if ([[pattern stringValue] isEqualToString:@"_"]) { - return nil; - } - // ((symbol? pat) - // (let (seq (if (eq ((pat stringValue) characterAtIndex:0) '*') - // (then (list seq)) - // (else seq))) - // (list (list pat seq)))) - else if ([pattern class] == [NuSymbol class]) { - id result; - - if ([[pattern stringValue] characterAtIndex:0] == '*') { - // List-ify sequence - id l = [[[NuCell alloc] init] autorelease]; - [l setCar:sequence]; - result = l; - } - else { - result = sequence; - } - - // (list pattern sequence) - id p = [[[NuCell alloc] init] autorelease]; - id s = [[[NuCell alloc] init] autorelease]; - - [p setCar:pattern]; - [p setCdr:s]; - [s setCar:result]; - - // (list (list pattern sequence)) - id l = [[[NuCell alloc] init] autorelease]; - [l setCar:p]; - - return l; - } - // ((pair? pat) - // (if (and (symbol? (car pat)) - // (eq (((car pat) stringValue) characterAtIndex:0) '*')) - // (then (list (list (car pat) seq))) - // (else ((let ((bindings1 (mdestructure (car pat) (car seq))) - // (bindings2 (mdestructure (cdr pat) (cdr seq)))) - // (append bindings1 bindings2)))))) - else if ([pattern class] == [NuCell class]) { - if ( ([[pattern car] class] == [NuSymbol class]) - && ([[[pattern car] stringValue] characterAtIndex:0] == '*')) { - - id l1 = [[[NuCell alloc] init] autorelease]; - id l2 = [[[NuCell alloc] init] autorelease]; - id l3 = [[[NuCell alloc] init] autorelease]; - [l1 setCar:[pattern car]]; - [l1 setCdr:l2]; - [l2 setCar:sequence]; - [l3 setCar:l1]; - - return l3; - } - else { - if (sequence == nil || sequence == Nu__null) { - [NSException raise:@"NuDestructureException" - format:@"Attempt to match non-empty pattern to empty object"]; - } - - id b1 = [self mdestructure:[pattern car] withSequence:[sequence car]]; - id b2 = [self mdestructure:[pattern cdr] withSequence:[sequence cdr]]; - - id newList = [self destructuringListAppend:b1 withList:b2]; - - Macro1Debug(@"jsb: dbind: %@", [newList stringValue]); - return newList; - } - } - // (else (throw* "NuMatchException" - // "pattern is not nil, a symbol or a pair: #{pat}")))) - else { - [NSException raise:@"NuDestructureException" - format:@"Pattern is not nil, a symbol or a pair: %@", [pattern stringValue]]; - } - - // Just for aesthetics... - return nil; -} - -- (id) expandAndEval:(id)cdr context:(NSMutableDictionary*)calling_context evalFlag:(BOOL)evalFlag -{ - NuSymbolTable *symbolTable = [calling_context objectForKey:SYMBOLS_KEY]; - - NSMutableDictionary* maskedVariables = [[NSMutableDictionary alloc] init]; - - id plist; - - Macro1Debug(@"Dumping context:"); - Macro1Debug(@"---------------:"); -#ifdef MACRO1_DEBUG - [self dumpContext:calling_context]; -#endif - id old_args = [calling_context objectForKey:[symbolTable symbolWithString:@"*args"]]; - [calling_context setPossiblyNullObject:cdr forKey:[symbolTable symbolWithString:@"*args"]]; - - id destructure; - - @try - { - // Destructure the arguments - destructure = [self mdestructure:parameters withSequence:cdr]; - } - @catch (id exception) { - // Destructure failed...restore/remove *args - [self restoreArgs:old_args context:calling_context]; - - @throw; - } - - plist = destructure; - while (plist && (plist != Nu__null)) { - id parameter = [[plist car] car]; - id value = [[[plist car] cdr] car]; - Macro1Debug(@"Destructure: %@ = %@", [parameter stringValue], [value stringValue]); - - id pvalue = [calling_context objectForKey:parameter]; - - if (pvalue) { - Macro1Debug(@" Saving context: %@ = %@", - [parameter stringValue], - [pvalue stringValue]); - [maskedVariables setPossiblyNullObject:pvalue forKey:parameter]; - } - - [calling_context setPossiblyNullObject:value forKey:parameter]; - - plist = [plist cdr]; - } - - Macro1Debug(@"Dumping context (after destructure):"); - Macro1Debug(@"-----------------------------------:"); -#ifdef MACRO1_DEBUG - [self dumpContext:calling_context]; -#endif - // evaluate the body of the block in the calling context (implicit progn) - id value = Nu__null; - - // if the macro contains gensyms, give them a unique prefix - NSUInteger gensymCount = [[self gensyms] count]; - id gensymPrefix = nil; - if (gensymCount > 0) { - gensymPrefix = [NSString stringWithFormat:@"g%ld", [NuMath random]]; - } - - id bodyToEvaluate = (gensymCount == 0) - ? (id)body : [self body:body withGensymPrefix:gensymPrefix symbolTable:symbolTable]; - - // Macro1Debug(@"macro evaluating: %@", [bodyToEvaluate stringValue]); - // Macro1Debug(@"macro context: %@", [calling_context stringValue]); - - @try - { - // Macro expansion - id cursor = [self expandUnquotes:bodyToEvaluate withContext:calling_context]; - while (cursor && (cursor != Nu__null)) { - Macro1Debug(@"macro eval cursor: %@", [cursor stringValue]); - value = [[cursor car] evalWithContext:calling_context]; - Macro1Debug(@"macro expand value: %@", [value stringValue]); - cursor = [cursor cdr]; - } - - // Now that macro expansion is done, restore the masked calling context variables - [self restoreBindings:destructure - forMaskedVariables:maskedVariables - fromContext:calling_context]; - - [maskedVariables release]; - maskedVariables = nil; - - // Macro evaluation - // If we're just macro-expanding, don't do this step... - if (evalFlag) { - Macro1Debug(@"About to execute: %@", [value stringValue]); - value = [value evalWithContext:calling_context]; - Macro1Debug(@"macro eval value: %@", [value stringValue]); - } - - Macro1Debug(@"Dumping context at end:"); - Macro1Debug(@"----------------------:"); -#ifdef MACRO1_DEBUG - [self dumpContext:calling_context]; -#endif - // restore the old value of *args - [self restoreArgs:old_args context:calling_context]; - - Macro1Debug(@"macro result: %@", value); - } - @catch (id exception) { - if (maskedVariables) { - Macro1Debug(@"Caught exception in macro, restoring bindings"); - - [self restoreBindings:destructure - forMaskedVariables:maskedVariables - fromContext:calling_context]; - - Macro1Debug(@"Caught exception in macro, releasing maskedVariables"); - - [maskedVariables release]; - } - - Macro1Debug(@"Caught exception in macro, restoring masked arguments"); - - [self restoreArgs:old_args context:calling_context]; - - Macro1Debug(@"Caught exception in macro, rethrowing..."); - - @throw; - } - - return value; -} - -- (id) expand1:(id)cdr context:(NSMutableDictionary*)calling_context -{ - return [self expandAndEval:cdr context:calling_context evalFlag:NO]; -} - -- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context -{ - return [self expandAndEval:cdr context:calling_context evalFlag:YES]; -} - -@end - -#pragma mark - NuMethod.m -@interface NuMethod () -{ - Method m; -} -@end - -@implementation NuMethod - -- (id) initWithMethod:(Method) method -{ - if ((self = [super init])) { - m = method; - } - return self; -} - -- (NSString *) name -{ - return m ? [NSString stringWithCString:(sel_getName(method_getName(m))) encoding:NSUTF8StringEncoding] : [NSNull null]; -} - -- (int) argumentCount -{ - return method_getNumberOfArguments(m); -} - -- (NSString *) typeEncoding -{ - return [NSString stringWithCString:method_getTypeEncoding(m) encoding:NSUTF8StringEncoding]; -} - -- (NSString *) signature -{ - const char *encoding = method_getTypeEncoding(m); - NSInteger len = strlen(encoding)+1; - char *signature = (char *) malloc (len * sizeof(char)); - method_getReturnType(m, signature, len); - NSInteger step = strlen(signature); - char *start = &signature[step]; - len -= step; - int argc = method_getNumberOfArguments(m); - int i; - for (i = 0; i < argc; i++) { - method_getArgumentType(m, i, start, len); - step = strlen(start); - start = &start[step]; - len -= step; - } - // printf("name:%s i:%d len:%d signature:%s\n", sel_getName(method_getName(m)), i, len, signature); - id result = [NSString stringWithCString:signature encoding:NSUTF8StringEncoding]; - free(signature); - return result; -} - -- (NSString *) argumentType:(int) i -{ - if (i >= method_getNumberOfArguments(m)) - return nil; - char *argumentType = method_copyArgumentType(m, i); - id result = [NSString stringWithCString:argumentType encoding:NSUTF8StringEncoding]; - free(argumentType); - return result; -} - -- (NSString *) returnType -{ - char *returnType = method_copyReturnType(m); - id result = [NSString stringWithCString:returnType encoding:NSUTF8StringEncoding]; - free(returnType); - return result; -} - -- (NuBlock *) block -{ - IMP imp = method_getImplementation(m); - NuBlock *block = nil; - if (nu_block_table) { - block = [nu_block_table objectForKey:[NSNumber numberWithUnsignedLong:(unsigned long) imp]]; - } - return block; -} - -- (NSComparisonResult) compare:(NuMethod *) anotherMethod -{ - return [[self name] compare:[anotherMethod name]]; -} - -@end - -#pragma mark - NuObjCRuntime.m - -static IMP nu_class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) -{ - if (class_addMethod(cls, name, imp, types)) { - return imp; - } else { - return class_replaceMethod(cls, name, imp, types); - } -} - -static void nu_class_addInstanceVariable_withSignature(Class thisClass, const char *variableName, const char *signature) -{ - extern size_t size_of_objc_type(const char *typeString); - size_t size = size_of_objc_type(signature); - uint8_t alignment = log2(size); - BOOL result = class_addIvar(thisClass, variableName, size, alignment, signature); - if (!result) { - [NSException raise:@"NuAddIvarFailed" - format:@"failed to add instance variable %s to class %s", variableName, class_getName(thisClass)]; - } - //NSLog(@"adding ivar named %s to %s, result is %d", variableName, class_getName(thisClass), result); -} - -static BOOL nu_copyInstanceMethod(Class destinationClass, Class sourceClass, SEL selector) -{ - Method m = class_getInstanceMethod(sourceClass, selector); - if (!m) { - return NO; - } - IMP imp = method_getImplementation(m); - if (!imp) { - return NO; - } - const char *signature = method_getTypeEncoding(m); - if (!signature) { - return NO; - } - BOOL result = (nu_class_replaceMethod(destinationClass, selector, imp, signature) != 0); - return result; -} - -static BOOL nu_objectIsKindOfClass(id object, Class class) -{ - if (object == NULL) { - return NO; - } - Class classCursor = object_getClass(object); - while (classCursor) { - if (classCursor == class) { - return YES; - } - classCursor = class_getSuperclass(classCursor); - } - return NO; -} - -// This function attempts to recognize the return type from a method signature. -// It scans across the signature until it finds a complete return type string, -// then it inserts a null to mark the end of the string. -static void nu_markEndOfObjCTypeString(char *type, size_t len) -{ - size_t i; - char final_char = 0; - char start_char = 0; - int depth = 0; - for (i = 0; i < len; i++) { - switch(type[i]) { - case '[': - case '{': - case '(': - // we want to scan forward to a closing character - if (!final_char) { - start_char = type[i]; - final_char = (start_char == '[') ? ']' : (start_char == '(') ? ')' : '}'; - depth = 1; - } - else if (type[i] == start_char) { - depth++; - } - break; - case ']': - case '}': - case ')': - if (type[i] == final_char) { - depth--; - if (depth == 0) { - if (i+1 < len) - type[i+1] = 0; - return; - } - } - break; - case 'b': // bitfields - if (depth == 0) { - // scan forward, reading all subsequent digits - i++; - while ((i < len) && (type[i] >= '0') && (type[i] <= '9')) - i++; - if (i+1 < len) - type[i+1] = 0; - return; - } - case '^': // pointer - case 'r': // const - case 'n': // in - case 'N': // inout - case 'o': // out - case 'O': // bycopy - case 'R': // byref - case 'V': // oneway - break; // keep going, these are all modifiers. - case 'c': case 'i': case 's': case 'l': case 'q': - case 'C': case 'I': case 'S': case 'L': case 'Q': - case 'f': case 'd': case 'B': case 'v': case '*': - case '@': case '#': case ':': case '?': default: - if (depth == 0) { - if (i+1 < len) - type[i+1] = 0; - return; - } - break; - } - } -} -#pragma mark - NuObject.m - -@protocol NuCanSetAction -- (void) setAction:(SEL) action; -@end - -// use this to look up selectors with symbols -@interface NuSelectorCache : NSObject -{ - NuSymbol *symbol; - NuSelectorCache *parent; - NSMutableDictionary *children; - SEL selector; -} - -@end - -@implementation NuSelectorCache - -+ (NuSelectorCache *) sharedSelectorCache -{ - static NuSelectorCache *sharedCache = nil; - if (!sharedCache) - sharedCache = [[self alloc] init]; - return sharedCache; -} - -- (NuSelectorCache *) init -{ - if ((self = [super init])) { - symbol = nil; - parent = nil; - children = [[NSMutableDictionary alloc] init]; - selector = NULL; - } - return self; -} - -- (NuSymbol *) symbol {return symbol;} -- (NuSelectorCache *) parent {return parent;} -- (NSMutableDictionary *) children {return children;} - -- (SEL) selector -{ - return selector; -} - -- (void) setSelector:(SEL) s -{ - selector = s; -} - -- (NuSelectorCache *) initWithSymbol:(NuSymbol *)s parent:(NuSelectorCache *)p -{ - if ((self = [super init])) { - symbol = s; - parent = p; - children = [[NSMutableDictionary alloc] init]; - selector = NULL; - } - return self; -} - -- (NSString *) selectorName -{ - NSMutableArray *selectorStrings = [NSMutableArray array]; - [selectorStrings addObject:[[self symbol] stringValue]]; - id p = parent; - while ([p symbol]) { - [selectorStrings addObject:[[p symbol] stringValue]]; - p = [p parent]; - } - NSUInteger max = [selectorStrings count]; - NSInteger i; - for (i = 0; i < max/2; i++) { - [selectorStrings exchangeObjectAtIndex:i withObjectAtIndex:(max - i - 1)]; - } - return [selectorStrings componentsJoinedByString:@""]; -} - -- (NuSelectorCache *) lookupSymbol:(NuSymbol *)childSymbol -{ - NuSelectorCache *child = [children objectForKey:childSymbol]; - if (!child) { - child = [[[NuSelectorCache alloc] initWithSymbol:childSymbol parent:self] autorelease]; - NSString *selectorString = [child selectorName]; - [child setSelector:sel_registerName([selectorString cStringUsingEncoding:NSUTF8StringEncoding])]; - [children setValue:child forKey:(id)childSymbol]; - } - return child; -} - -@end - -@implementation NSObject(Nu) -- (bool) atom -{ - return true; -} - -- (id) evalWithContext:(NSMutableDictionary *) context -{ - return self; -} - -- (NSString *) stringValue -{ - return [NSString stringWithFormat:@"<%s:%lx>", class_getName(object_getClass(self)), (long) self]; -} - -- (id) car -{ - [NSException raise:@"NuCarCalledOnAtom" - format:@"car called on atom for object %@", - self]; - return Nu__null; -} - -- (id) cdr -{ - [NSException raise:@"NuCdrCalledOnAtom" - format:@"cdr called on atom for object %@", - self]; - return Nu__null; -} - - -- (id) sendMessage:(id)cdr withContext:(NSMutableDictionary *)context -{ - // By themselves, Objective-C objects evaluate to themselves. - if (!cdr || (cdr == Nu__null)) - return self; - - // But when they're at the head of a list, that list is converted into a message that is sent to the object. - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - // Collect the method selector and arguments. - // This seems like a bottleneck, and it also lacks flexibility. - // Replacing explicit string building with the selector cache reduced runtimes by around 20%. - // Methods with variadic arguments (NSArray arrayWithObjects:...) are not supported. - NSMutableArray *args = [[NSMutableArray alloc] init]; - id cursor = cdr; - SEL sel = 0; - id nextSymbol = [cursor car]; - if (nu_objectIsKindOfClass(nextSymbol, [NuSymbol class])) { - // The commented out code below was the original approach. - // methods were identified by concatenating symbols and looking up the resulting method -- on every method call - // that was slow but simple - // NSMutableString *selectorString = [NSMutableString stringWithString:[nextSymbol stringValue]]; - NuSelectorCache *selectorCache = [[NuSelectorCache sharedSelectorCache] lookupSymbol:nextSymbol]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - [args addObject:[cursor car]]; - cursor = [cursor cdr]; - if (cursor && (cursor != Nu__null)) { - id nextSymbol = [cursor car]; - if (nu_objectIsKindOfClass(nextSymbol, [NuSymbol class]) && [nextSymbol isLabel]) { - // [selectorString appendString:[nextSymbol stringValue]]; - selectorCache = [selectorCache lookupSymbol:nextSymbol]; - } - cursor = [cursor cdr]; - } - } - // sel = sel_getUid([selectorString cStringUsingEncoding:NSUTF8StringEncoding]); - sel = [selectorCache selector]; - } - - id target = self; - - // Look up the appropriate method to call for the specified selector. - Method m; - // instead of isMemberOfClass:, which may be blocked by an NSProtocolChecker - BOOL isAClass = (object_getClass(self) == [NuClass class]); - if (isAClass) { - // Class wrappers (objects of type NuClass) get special treatment. Instance methods are sent directly to the class wrapper object. - // But when a class method is sent to a class wrapper, the method is instead sent as a class method to the wrapped class. - // This makes it possible to call class methods from Nu, but there is no way to directly call class methods of NuClass from Nu. - id wrappedClass = [((NuClass *) self) wrappedClass]; - m = class_getClassMethod(wrappedClass, sel); - if (m) - target = wrappedClass; - else - m = class_getInstanceMethod(object_getClass(self), sel); - } - else { - m = class_getInstanceMethod(object_getClass(self), sel); - if (!m) m = class_getClassMethod(object_getClass(self), sel); - } - id result = Nu__null; - if (m) { - // We have a method that matches the selector. - // First, evaluate the arguments. - NSMutableArray *argValues = [[NSMutableArray alloc] init]; - NSUInteger i; - NSUInteger imax = [args count]; - for (i = 0; i < imax; i++) { - [argValues addObject:[[args objectAtIndex:i] evalWithContext:context]]; - } - // Then call the method. - result = nu_calling_objc_method_handler(target, m, argValues); - [argValues release]; - } - else { - // If the head of the list is a label, we treat the list as a property list. - // We just evaluate the elements of the list and return the result. - if (nu_objectIsKindOfClass(self, [NuSymbol class]) && [((NuSymbol *)self) isLabel]) { - NuCell *cell = [[[NuCell alloc] init] autorelease]; - [cell setCar: self]; - id cursor = cdr; - id result_cursor = cell; - while (cursor && (cursor != Nu__null)) { - id arg = [[cursor car] evalWithContext:context]; - [result_cursor setCdr:[[[NuCell alloc] init] autorelease]]; - result_cursor = [result_cursor cdr]; - [result_cursor setCar:arg]; - cursor = [cursor cdr]; - } - result = cell; - } - // Messaging null is ok. - else if (self == Nu__null) { - } - // Test if target specifies another object that should receive the message - else if ( (target = [target forwardingTargetForSelector:sel]) ) { - //NSLog(@"found forwarding target: %@ for selector: %@", target, NSStringFromSelector(sel)); - result = [target sendMessage:cdr withContext:context]; - } - // Otherwise, call the overridable handler for unknown messages. - else { - //NSLog(@"calling handle unknown message for %@", [cdr stringValue]); - result = [self handleUnknownMessage:cdr withContext:context]; - //NSLog(@"result is %@", result); - } - } - - [args release]; - [result retain]; - [pool drain]; - [result autorelease]; - return result; -} - -- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - return [self sendMessage:cdr withContext:context]; -} - -+ (id) handleUnknownMessage:(id) cdr withContext:(NSMutableDictionary *) context -{ - [NSException raise:@"NuUnknownMessage" - format:@"unable to find message handler for %@", - [cdr stringValue]]; - return Nu__null; -} - - -- (id) handleUnknownMessage:(id) message withContext:(NSMutableDictionary *) context -{ - // Collect the method selector and arguments. - // This seems like a bottleneck, and it also lacks flexibility. - // Replacing explicit string building with the selector cache reduced runtimes by around 20%. - // Methods with variadic arguments (NSArray arrayWithObjects:...) are not supported. - NSMutableArray *args = [NSMutableArray array]; - id cursor = message; - SEL sel = 0; - id nextSymbol = [cursor car]; - if (nu_objectIsKindOfClass(nextSymbol, [NuSymbol class])) { - // The commented out code below was the original approach. - // methods were identified by concatenating symbols and looking up the resulting method -- on every method call - // that was slow but simple - // NSMutableString *selectorString = [NSMutableString stringWithString:[nextSymbol stringValue]]; - NuSelectorCache *selectorCache = [[NuSelectorCache sharedSelectorCache] lookupSymbol:nextSymbol]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - [args addObject:[cursor car]]; - cursor = [cursor cdr]; - if (cursor && (cursor != Nu__null)) { - id nextSymbol = [cursor car]; - if (nu_objectIsKindOfClass(nextSymbol, [NuSymbol class]) && [nextSymbol isLabel]) { - // [selectorString appendString:[nextSymbol stringValue]]; - selectorCache = [selectorCache lookupSymbol:nextSymbol]; - } - cursor = [cursor cdr]; - } - } - // sel = sel_getUid([selectorString cStringUsingEncoding:NSUTF8StringEncoding]); - sel = [selectorCache selector]; - } - - // If the object responds to methodSignatureForSelector:, we should create and forward an invocation to it. - NSMethodSignature *methodSignature = sel ? [self methodSignatureForSelector:sel] : 0; - if (methodSignature) { - id result = [NSNull null]; - // Create an invocation to forward. - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; - [invocation setTarget:self]; - [invocation setSelector:sel]; - // Set any arguments to the invocation. - NSUInteger i; - NSUInteger imax = [args count]; - for (i = 0; i < imax; i++) { - const char *argument_type = [methodSignature getArgumentTypeAtIndex:i+2]; - char *buffer = value_buffer_for_objc_type(argument_type); - set_objc_value_from_nu_value(buffer, [[args objectAtIndex:i] evalWithContext:context], argument_type); - [invocation setArgument:buffer atIndex:i+2]; - free(buffer); - } - // Forward the invocation. - [self forwardInvocation:invocation]; - // Get the return value from the invocation. - NSUInteger length = [[invocation methodSignature] methodReturnLength]; - if (length > 0) { - char *buffer = (void *)malloc(length); - @try { - // In GNUstep, invocations that have no return values throw exceptions when this is called. - [invocation getReturnValue:buffer]; - result = get_nu_value_from_objc_value(buffer, [methodSignature methodReturnType]); - } @catch (id exception) { - result = [NSNull null]; - } - free(buffer); - } - return result; - } - -#define AUTOMATIC_IVAR_ACCESSORS -#ifdef AUTOMATIC_IVAR_ACCESSORS - //NSLog(@"attempting to access ivar %@", [message stringValue]); - NSInteger message_length = [message length]; - if (message_length == 1) { - // try to automatically get an ivar - NSString *ivarName = [[message car] stringValue]; - if ([self hasValueForIvar:ivarName]) { - id result = [self valueForIvar:ivarName]; - return result; - } - } - else if (message_length == 2) { - // try to automatically set an ivar - if ([[[[message car] stringValue] substringWithRange:NSMakeRange(0,3)] isEqualToString:@"set"]) { - @try - { - id firstArgument = [[message car] stringValue]; - id variableName0 = [[firstArgument substringWithRange:NSMakeRange(3,1)] lowercaseString]; - id variableName1 = [firstArgument substringWithRange:NSMakeRange(4, [firstArgument length] - 5)]; - [self setValue:[[[message cdr] car] evalWithContext:context] - forIvar:[NSString stringWithFormat:@"%@%@", variableName0, variableName1]]; - return Nu__null; - } - @catch (id error) { - // NSLog(@"skipping this error: %@", [error description]); - // no ivar, keep going - } - } - } -#endif - NuCell *cell = [[[NuCell alloc] init] autorelease]; - [cell setCar:self]; - [cell setCdr:message]; - [NSException raise:@"NuUnknownMessage" - format:@"unable to find message handler for %@", - [cell stringValue]]; - return Nu__null; -} - -- (id) valueForIvar:(NSString *) name -{ - Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); - if (!v) { - // look for sparse ivar storage - NSMutableDictionary *sparseIvars = [self associatedObjectForKey:@"__nuivars"]; - if (sparseIvars) { - // NSLog(@"sparse %@", [sparseIvars description]); - id result = [sparseIvars objectForKey:name]; - if (result) { - return result; - } else { - return Nu__null; - } - } - return Nu__null; - } - void *location = (void *)&(((char *)self)[ivar_getOffset(v)]); - id result = get_nu_value_from_objc_value(location, ivar_getTypeEncoding(v)); - return result; -} - -- (BOOL) hasValueForIvar:(NSString *) name -{ - Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); - if (!v) { - // look for sparse ivar storage - NSMutableDictionary *sparseIvars = [self associatedObjectForKey:@"__nuivars"]; - if (sparseIvars) { - // NSLog(@"sparse %@", [sparseIvars description]); - id result = [sparseIvars objectForKey:name]; - if (result) { - return YES; - } else { - return NO; - } - } - return NO; - } - //void *location = (void *)&(((char *)self)[ivar_getOffset(v)]); - //id result = get_nu_value_from_objc_value(location, ivar_getTypeEncoding(v)); - return YES; -} - - -- (void) setValue:(id) value forIvar:(NSString *)name -{ - Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); - if (!v) { - NSMutableDictionary *sparseIvars = [self associatedObjectForKey:@"__nuivars"]; - if (!sparseIvars) { - sparseIvars = [[[NSMutableDictionary alloc] init] autorelease]; - [self setRetainedAssociatedObject:sparseIvars forKey:@"__nuivars"]; - } - [self willChangeValueForKey:name]; - [sparseIvars setPossiblyNullObject:value forKey:name]; - [self didChangeValueForKey:name]; - return; - } - [self willChangeValueForKey:name]; - void *location = (void *)&(((char *)self)[ivar_getOffset(v)]); - const char *encoding = ivar_getTypeEncoding(v); - if (encoding && (strlen(encoding) > 0) && (encoding[0] == '@')) { - [value retain]; - [*((id *)location) release]; - } - set_objc_value_from_nu_value(location, value, ivar_getTypeEncoding(v)); - [self didChangeValueForKey:name]; -} - -+ (NSArray *) classMethods -{ - NSMutableArray *array = [NSMutableArray array]; - unsigned int method_count; - Method *method_list = class_copyMethodList(object_getClass([self class]), &method_count); - int i; - for (i = 0; i < method_count; i++) { - [array addObject:[[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]]; - } - free(method_list); - [array sortUsingSelector:@selector(compare:)]; - return array; -} - -+ (NSArray *) instanceMethods -{ - NSMutableArray *array = [NSMutableArray array]; - unsigned int method_count; - Method *method_list = class_copyMethodList([self class], &method_count); - int i; - for (i = 0; i < method_count; i++) { - [array addObject:[[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]]; - } - free(method_list); - [array sortUsingSelector:@selector(compare:)]; - return array; -} - -+ (NSArray *) classMethodNames -{ - Class c = [self class]; - id methods = [c classMethods]; - return [methods mapSelector:@selector(name)]; - // return [[c classMethods] mapSelector:@selector(name)]; -} - -+ (NSArray *) instanceMethodNames -{ - Class c = [self class]; - id methods = [c instanceMethods]; - return [methods mapSelector:@selector(name)]; - // return [[c instanceMethods] mapSelector:@selector(name)]; -} - -+ (NSArray *) instanceVariableNames -{ - NSMutableArray *array = [NSMutableArray array]; - unsigned int ivar_count; - Ivar *ivar_list = class_copyIvarList([self class], &ivar_count); - int i; - for (i = 0; i < ivar_count; i++) { - [array addObject:[NSString stringWithCString:ivar_getName(ivar_list[i]) encoding:NSUTF8StringEncoding]]; - } - free(ivar_list); - [array sortUsingSelector:@selector(compare:)]; - return array; -} - -+ (NSString *) signatureForIvar:(NSString *)name -{ - Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); - return [NSString stringWithCString:ivar_getTypeEncoding(v) encoding:NSUTF8StringEncoding]; -} - -+ (id) inheritedByClass:(NuClass *) newClass -{ - return nil; -} - -+ (id) createSubclassNamed:(NSString *) subclassName -{ - Class c = [self class]; - const char *name = [subclassName cStringUsingEncoding:NSUTF8StringEncoding]; - - // does the class already exist? - Class s = objc_getClass(name); - if (s) { - // the subclass's superclass must be the current class! - if (c != [s superclass]) { - NSLog(@"Warning: Class %s already exists and is not a subclass of %s", name, class_getName(c)); - } - } - else { - s = objc_allocateClassPair(c, name, 0); - objc_registerClassPair(s); - } - NuClass *newClass = [[[NuClass alloc] initWithClass:s] autorelease]; - - if ([self respondsToSelector:@selector(inheritedByClass:)]) { - [self inheritedByClass:newClass]; - } - - return newClass; -} - -/* - + (id) addInstanceMethod:(NSString *)methodName signature:(NSString *)signature body:(NuBlock *)block - { - Class c = [self class]; - return add_method_to_class(c, methodName, signature, block); - } - - + (id) addClassMethod:(NSString *)methodName signature:(NSString *)signature body:(NuBlock *)block - { - Class c = [self class]->isa; - return add_method_to_class(c, methodName, signature, block); - } - */ -+ (BOOL) copyInstanceMethod:(NSString *) methodName fromClass:(NuClass *)prototypeClass -{ - Class thisClass = [self class]; - Class otherClass = [prototypeClass wrappedClass]; - const char *method_name_str = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; - SEL selector = sel_registerName(method_name_str); - BOOL result = nu_copyInstanceMethod(thisClass, otherClass, selector); - return result; -} - -+ (BOOL) include:(NuClass *)prototypeClass -{ - NSArray *methods = [prototypeClass instanceMethods]; - NSEnumerator *enumerator = [methods objectEnumerator]; - id method; - while ((method = [enumerator nextObject])) { - // NSLog(@"copying method %@", [method name]); - [self copyInstanceMethod:[method name] fromClass:prototypeClass]; - } - return true; -} - -+ (NSString *) help -{ - return [NSString stringWithFormat:@"This is a class named %s.", class_getName([self class])]; -} - -- (NSString *) help -{ - return [NSString stringWithFormat:@"This is an instance of %s.", class_getName([self class])]; -} - -// adapted from the CocoaDev MethodSwizzling page - -+ (BOOL) exchangeInstanceMethod:(SEL)sel1 withMethod:(SEL)sel2 -{ - Class myClass = [self class]; - Method method1 = NULL, method2 = NULL; - - // First, look for the methods - method1 = class_getInstanceMethod(myClass, sel1); - method2 = class_getInstanceMethod(myClass, sel2); - // If both are found, swizzle them - if ((method1 != NULL) && (method2 != NULL)) { - method_exchangeImplementations(method1, method2); - return true; - } - else { - if (method1 == NULL) NSLog(@"swap failed: can't find %s", sel_getName(sel1)); - if (method2 == NULL) NSLog(@"swap failed: can't find %s", sel_getName(sel2)); - return false; - } - - return YES; -} - -+ (BOOL) exchangeClassMethod:(SEL)sel1 withMethod:(SEL)sel2 -{ - Class myClass = [self class]; - Method method1 = NULL, method2 = NULL; - - // First, look for the methods - method1 = class_getClassMethod(myClass, sel1); - method2 = class_getClassMethod(myClass, sel2); - - // If both are found, swizzle them - if ((method1 != NULL) && (method2 != NULL)) { - method_exchangeImplementations(method1, method2); - return true; - } - else { - if (method1 == NULL) NSLog(@"swap failed: can't find %s", sel_getName(sel1)); - if (method2 == NULL) NSLog(@"swap failed: can't find %s", sel_getName(sel2)); - return false; - } - - return YES; -} - -// Concisely set key-value pairs from a property list. - -- (id) set:(NuCell *) propertyList -{ - id cursor = propertyList; - while (cursor && (cursor != Nu__null) && ([cursor cdr]) && ([cursor cdr] != Nu__null)) { - id key = [cursor car]; - id value = [[cursor cdr] car]; - id label = ([key isKindOfClass:[NuSymbol class]] && [key isLabel]) ? [key labelName] : key; - if ([label isEqualToString:@"action"] && [self respondsToSelector:@selector(setAction:)]) { - SEL selector = sel_registerName([value cStringUsingEncoding:NSUTF8StringEncoding]); - [(id) self setAction:selector]; - } - else { - [self setValue:value forKey:label]; - } - cursor = [[cursor cdr] cdr]; - } - return self; -} - -- (void) setRetainedAssociatedObject:(id) object forKey:(id) key { - if ([key isKindOfClass:[NSString class]]) - key = [[NuSymbolTable sharedSymbolTable] symbolWithString:key]; - objc_setAssociatedObject(self, key, object, OBJC_ASSOCIATION_RETAIN); -} - -- (void) setAssignedAssociatedObject:(id) object forKey:(id) key { - if ([key isKindOfClass:[NSString class]]) - key = [[NuSymbolTable sharedSymbolTable] symbolWithString:key]; - objc_setAssociatedObject(self, key, object, OBJC_ASSOCIATION_ASSIGN); -} - -- (void) setCopiedAssociatedObject:(id) object forKey:(id) key { - if ([key isKindOfClass:[NSString class]]) - key = [[NuSymbolTable sharedSymbolTable] symbolWithString:key]; - objc_setAssociatedObject(self, key, object, OBJC_ASSOCIATION_COPY); -} - -- (id) associatedObjectForKey:(id) key { - if ([key isKindOfClass:[NSString class]]) - key = [[NuSymbolTable sharedSymbolTable] symbolWithString:key]; - return objc_getAssociatedObject(self, key); -} - -- (void) removeAssociatedObjects { - objc_removeAssociatedObjects(self); -} - -// Helper. Included because it's so useful. -- (NSData *) XMLPropertyListRepresentation { - return [NSPropertyListSerialization dataWithPropertyList:self - format: NSPropertyListXMLFormat_v1_0 - options:0 - error:NULL]; -} - -// Helper. Included because it's so useful. -- (NSData *) binaryPropertyListRepresentation { - return [NSPropertyListSerialization dataWithPropertyList:self - format: NSPropertyListBinaryFormat_v1_0 - options:0 - error:NULL]; -} - -@end - -#pragma mark - NuOperator.m - -@implementation NuBreakException -- (id) init -{ - return [super initWithName:@"NuBreakException" reason:@"A break operator was evaluated" userInfo:nil]; -} - -@end - -@implementation NuContinueException -- (id) init -{ - return [super initWithName:@"NuContinueException" reason:@"A continue operator was evaluated" userInfo:nil]; -} - -@end - -@implementation NuReturnException -- (id) initWithValue:(id) v -{ - if ((self = [super initWithName:@"NuReturnException" reason:@"A return operator was evaluated" userInfo:nil])) { - value = [v retain]; - blockForReturn = nil; - } - return self; -} - -- (id) initWithValue:(id) v blockForReturn:(id) b -{ - if ((self = [super initWithName:@"NuReturnException" reason:@"A return operator was evaluated" userInfo:nil])) { - value = [v retain]; - blockForReturn = b; // weak reference - } - return self; -} - -- (void) dealloc -{ - [value release]; - [super dealloc]; -} - -- (id) value -{ - return value; -} - -- (id) blockForReturn -{ - return blockForReturn; -} - -@end - -@implementation NuOperator : NSObject -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context {return nil;} -- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context {return [self callWithArguments:cdr context:context];} -@end - -@interface Nu_car_operator : NuOperator {} -@end - -@implementation Nu_car_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cadr = [cdr car]; - id value = [cadr evalWithContext:context]; - return ([value respondsToSelector:@selector(car)]) ? [value car] : Nu__null; -} - -@end - -@interface Nu_cdr_operator : NuOperator {} -@end - -@implementation Nu_cdr_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cadr = [cdr car]; - id value = [cadr evalWithContext:context]; - return ([value respondsToSelector:@selector(cdr)]) ? [value cdr] : Nu__null; -} - -@end - -@interface Nu_atom_operator : NuOperator {} -@end - -@implementation Nu_atom_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cadr = [cdr car]; - id value = [cadr evalWithContext:context]; - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - if ([value atom]) - return [symbolTable symbolWithString:@"t"]; - else - return Nu__null; -} - -@end - -@interface Nu_defined_operator : NuOperator {} -@end - -@implementation Nu_defined_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - bool is_defined = YES; - id cadr = [cdr car]; - @try - { - [cadr evalWithContext:context]; - } - @catch (id exception) { - // is this an undefined symbol exception? if not, throw it - if ([[exception name] isEqualToString:@"NuUndefinedSymbol"]) { - is_defined = NO; - } - else { - @throw(exception); - } - } - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - if (is_defined) - return [symbolTable symbolWithString:@"t"]; - else - return Nu__null; -} - -@end - -@interface Nu_eq_operator : NuOperator {} -@end - -@implementation Nu_eq_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id cursor = cdr; - id current = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - id next = [[cursor car] evalWithContext: context]; - if (![current isEqual:next]) - return Nu__null; - current = next; - cursor = [cursor cdr]; - } - return [symbolTable symbolWithString:@"t"]; -} - -@end - -@interface Nu_neq_operator : NuOperator {} -@end - -@implementation Nu_neq_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cadr = [cdr car]; - id caddr = [[cdr cdr] car]; - id value1 = [cadr evalWithContext:context]; - id value2 = [caddr evalWithContext:context]; - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - if ((value1 == nil) && (value2 == nil)) { - return Nu__null; - } - else if ([value1 isEqual:value2]) { - return Nu__null; - } - else { - return [symbolTable symbolWithString:@"t"]; - } -} - -@end - -@interface Nu_cons_operator : NuOperator {} -@end - -@implementation Nu_cons_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cadr = [cdr car]; - id cddr = [cdr cdr]; - id value1 = [cadr evalWithContext:context]; - id value2 = [cddr evalWithContext:context]; - id newCell = [[[NuCell alloc] init] autorelease]; - [newCell setCar:value1]; - [newCell setCdr:value2]; - return newCell; -} - -@end - -@interface Nu_append_operator : NuOperator {} -@end - -@implementation Nu_append_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id newList = Nu__null; - id cursor = nil; - id list_to_append = cdr; - while (list_to_append && (list_to_append != Nu__null)) { - id item_to_append = [[list_to_append car] evalWithContext:context]; - while (item_to_append && (item_to_append != Nu__null)) { - if (newList == Nu__null) { - newList = [[[NuCell alloc] init] autorelease]; - cursor = newList; - } - else { - [cursor setCdr: [[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - } - id item = [item_to_append car]; - [cursor setCar: item]; - item_to_append = [item_to_append cdr]; - } - list_to_append = [list_to_append cdr]; - } - return newList; -} - -@end - - -@interface Nu_apply_operator : NuOperator {} -@end - -@implementation Nu_apply_operator -- (id) prependCell:(id)item withSymbol:(id)symbol -{ - id qitem = [[[NuCell alloc] init] autorelease]; - [qitem setCar:symbol]; - [qitem setCdr:[[[NuCell alloc] init] autorelease]]; - [[qitem cdr] setCar:item]; - return qitem; -} - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id quoteSymbol = [symbolTable symbolWithString:@"quote"]; - - id fn = [cdr car]; - - // Arguments to fn can be anything, but last item must be a list - id qargs = Nu__null; - id qargs_cursor = Nu__null; - id cursor = [cdr cdr]; - - while (cursor && (cursor != Nu__null) && [cursor cdr] && ([cursor cdr] != Nu__null)) { - if (qargs == Nu__null) { - qargs = [[[NuCell alloc] init] autorelease]; - qargs_cursor = qargs; - } - else { - [qargs_cursor setCdr:[[[NuCell alloc] init] autorelease]]; - qargs_cursor = [qargs_cursor cdr]; - } - - id item = [[cursor car] evalWithContext:context]; - id qitem = [self prependCell:item withSymbol:quoteSymbol]; - [qargs_cursor setCar:qitem]; - cursor = [cursor cdr]; - } - - // The rest of the arguments are in a list - id args = [cursor evalWithContext:context]; - cursor = args; - - while (cursor && (cursor != Nu__null)) { - if (qargs == Nu__null) { - qargs = [[[NuCell alloc] init] autorelease]; - qargs_cursor = qargs; - } - else { - [qargs_cursor setCdr:[[[NuCell alloc] init] autorelease]]; - qargs_cursor = [qargs_cursor cdr]; - } - id item = [cursor car]; - - id qitem = [self prependCell:item withSymbol:quoteSymbol]; - [qargs_cursor setCar:qitem]; - cursor = [cursor cdr]; - } - - // Call the real function with the evaluated and quoted args - id expr = [[[NuCell alloc] init] autorelease]; - [expr setCar:fn]; - [expr setCdr:qargs]; - - id result = [expr evalWithContext:context]; - - return result; -} -@end - -@interface Nu_cond_operator : NuOperator {} -@end - -@implementation Nu_cond_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id pairs = cdr; - id value = Nu__null; - while (pairs != Nu__null) { - id condition = [[pairs car] car]; - id test = [condition evalWithContext:context]; - if (nu_valueIsTrue(test)) { - value = test; - id cursor = [[pairs car] cdr]; - while (cursor && (cursor != Nu__null)) { - value = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - } - return value; - } - pairs = [pairs cdr]; - } - return value; -} - -@end - -@interface Nu_case_operator : NuOperator {} -@end - -@implementation Nu_case_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id target = [[cdr car] evalWithContext:context]; - id cases = [cdr cdr]; - while ([cases cdr] != Nu__null) { - id condition = [[cases car] car]; - id result = [condition evalWithContext:context]; - if ([result isEqual:target]) { - id value = Nu__null; - id cursor = [[cases car] cdr]; - while (cursor && (cursor != Nu__null)) { - value = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - } - return value; - } - cases = [cases cdr]; - } - // or return the last one - id value = Nu__null; - id cursor = [[cases car] cdr]; - while (cursor && (cursor != Nu__null)) { - value = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - } - return value; -} - -@end - -@interface Nu_if_operator : NuOperator {} -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context flipped:(bool)flip; -@end - -@implementation Nu_if_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - return [self callWithArguments:cdr context:context flipped:NO]; -} - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context flipped:(bool)flip -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - //id thenSymbol = [symbolTable symbolWithString:@"then"]; - id elseSymbol = [symbolTable symbolWithString:@"else"]; - //id elseifSymbol = [symbolTable symbolWithString:@"elseif"]; - - id result = Nu__null; - id test = [[cdr car] evalWithContext:context]; - - bool testIsTrue = flip ^ nu_valueIsTrue(test); - bool noneIsTrue = !testIsTrue; - - id expressions = [cdr cdr]; - while (expressions && (expressions != Nu__null)) { - id nextExpression = [expressions car]; - if (nu_objectIsKindOfClass(nextExpression, [NuCell class])) { - /*if ([nextExpression car] == elseifSymbol) { - test = [[[[expressions car] cdr] car] evalWithContext:context]; - testIsTrue = noneIsTrue && nu_valueIsTrue(test); - noneIsTrue = noneIsTrue && !testIsTrue; - if (testIsTrue) - // skip the test: - result = [[[nextExpression cdr] cdr] evalWithContext:context]; - } - else */ - if ([nextExpression car] == elseSymbol) { - if (noneIsTrue) - result = [nextExpression evalWithContext:context]; - } - else { - if (testIsTrue) - result = [nextExpression evalWithContext:context]; - } - } - else { - /*if (nextExpression == elseifSymbol) { - test = [[[expressions cdr] car] evalWithContext:context]; - testIsTrue = noneIsTrue && nu_valueIsTrue(test); - noneIsTrue = noneIsTrue && !testIsTrue; - expressions = [expressions cdr]; // skip the test - } - else */ - if (nextExpression == elseSymbol) { - testIsTrue = noneIsTrue; - noneIsTrue = NO; - } - else { - if (testIsTrue) - result = [nextExpression evalWithContext:context]; - } - } - expressions = [expressions cdr]; - } - return result; -} - -@end - -@interface Nu_unless_operator : Nu_if_operator {} -@end - -@implementation Nu_unless_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - return [super callWithArguments:cdr context:context flipped:YES]; -} - -@end - -@interface Nu_while_operator : NuOperator {} -@end - -@implementation Nu_while_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id result = Nu__null; - id test = [[cdr car] evalWithContext:context]; - while (nu_valueIsTrue(test)) { - @try - { - id expressions = [cdr cdr]; - while (expressions && (expressions != Nu__null)) { - result = [[expressions car] evalWithContext:context]; - expressions = [expressions cdr]; - } - } - @catch (NuBreakException *exception) { - break; - } - @catch (NuContinueException *exception) { - // do nothing, just continue with the next loop iteration - } - @catch (id exception) { - @throw(exception); - } - test = [[cdr car] evalWithContext:context]; - } - return result; -} - -@end - -@interface Nu_until_operator : NuOperator {} -@end - -@implementation Nu_until_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id result = Nu__null; - id test = [[cdr car] evalWithContext:context]; - while (!nu_valueIsTrue(test)) { - @try - { - id expressions = [cdr cdr]; - while (expressions && (expressions != Nu__null)) { - result = [[expressions car] evalWithContext:context]; - expressions = [expressions cdr]; - } - } - @catch (NuBreakException *exception) { - break; - } - @catch (NuContinueException *exception) { - // do nothing, just continue with the next loop iteration - } - @catch (id exception) { - @throw(exception); - } - test = [[cdr car] evalWithContext:context]; - } - return result; -} - -@end - -@interface Nu_for_operator : NuOperator {} -@end - -@implementation Nu_for_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id result = Nu__null; - id controls = [cdr car]; // this could use some error checking! - id loopinit = [controls car]; - id looptest = [[controls cdr] car]; - id loopincr = [[[controls cdr] cdr] car]; - // initialize the loop - [loopinit evalWithContext:context]; - // evaluate the loop condition - id test = [looptest evalWithContext:context]; - while (nu_valueIsTrue(test)) { - @try - { - id expressions = [cdr cdr]; - while (expressions && (expressions != Nu__null)) { - result = [[expressions car] evalWithContext:context]; - expressions = [expressions cdr]; - } - } - @catch (NuBreakException *exception) { - break; - } - @catch (NuContinueException *exception) { - // do nothing, just continue with the next loop iteration - } - @catch (id exception) { - @throw(exception); - } - // perform the end of loop increment step - [loopincr evalWithContext:context]; - // evaluate the loop condition - test = [looptest evalWithContext:context]; - } - return result; -} - -@end - -@interface Nu_try_operator : NuOperator {} -@end - -@implementation Nu_try_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id catchSymbol = [symbolTable symbolWithString:@"catch"]; - id finallySymbol = [symbolTable symbolWithString:@"finally"]; - id result = Nu__null; - - @try - { - // evaluate all the expressions that are outside catch and finally blocks - id expressions = cdr; - while (expressions && (expressions != Nu__null)) { - id nextExpression = [expressions car]; - if (nu_objectIsKindOfClass(nextExpression, [NuCell class])) { - if (([nextExpression car] != catchSymbol) && ([nextExpression car] != finallySymbol)) { - result = [nextExpression evalWithContext:context]; - } - } - else { - result = [nextExpression evalWithContext:context]; - } - expressions = [expressions cdr]; - } - } - @catch (id thrownObject) { - // evaluate all the expressions that are in catch blocks - id expressions = cdr; - while (expressions && (expressions != Nu__null)) { - id nextExpression = [expressions car]; - if (nu_objectIsKindOfClass(nextExpression, [NuCell class])) { - if (([nextExpression car] == catchSymbol)) { - // this is a catch block. - // the first expression should be a list with a single symbol - // that's a name. we'll set that name to the thing we caught - id nameList = [[nextExpression cdr] car]; - id name = [nameList car]; - [context setValue:thrownObject forKey:name]; - // now we loop over the rest of the expressions and evaluate them one by one - id cursor = [[nextExpression cdr] cdr]; - while (cursor && (cursor != Nu__null)) { - result = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - } - } - } - expressions = [expressions cdr]; - } - } - @finally - { - // evaluate all the expressions that are in finally blocks - id expressions = cdr; - while (expressions && (expressions != Nu__null)) { - id nextExpression = [expressions car]; - if (nu_objectIsKindOfClass(nextExpression, [NuCell class])) { - if (([nextExpression car] == finallySymbol)) { - // this is a finally block - // loop over the rest of the expressions and evaluate them one by one - id cursor = [nextExpression cdr]; - while (cursor && (cursor != Nu__null)) { - result = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - } - } - } - expressions = [expressions cdr]; - } - } - return result; -} - -@end - -@interface Nu_throw_operator : NuOperator {} -@end - -@implementation Nu_throw_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id exception = [[cdr car] evalWithContext:context]; - @throw exception; - return exception; -} - -@end - -@interface Nu_synchronized_operator : NuOperator {} -@end - -@implementation Nu_synchronized_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - // NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - - id object = [[cdr car] evalWithContext:context]; - id result = Nu__null; - - @synchronized(object) { - // evaluate the rest of the expressions - id expressions = [cdr cdr]; - while (expressions && (expressions != Nu__null)) { - id nextExpression = [expressions car]; - result = [nextExpression evalWithContext:context]; - expressions = [expressions cdr]; - } - } - return result; -} - -@end - -@interface Nu_quote_operator : NuOperator {} -@end - -@implementation Nu_quote_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cadr = [cdr car]; - return cadr; -} - -@end - -@interface Nu_quasiquote_eval_operator : NuOperator {} -@end - -@implementation Nu_quasiquote_eval_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - // bqcomma is handled by Nu_quasiquote_operator. - // If we get here, it means someone called bq_comma - // outside of a backquote - [NSException raise:@"NuQuasiquoteEvalOutsideQuasiquote" - format:@"Comma must be inside a backquote"]; - - // Purely cosmetic... - return Nu__null; -} - -@end - -@interface Nu_quasiquote_splice_operator : NuOperator {} -@end - -@implementation Nu_quasiquote_splice_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - // bqcomma-at is handled by Nu_quasiquote_operator. - // If we get here, it means someone called bq_comma - // outside of a backquote - [NSException raise:@"NuQuasiquoteSpliceOutsideQuasiquote" - format:@"Comma-at must be inside a backquote"]; - - // Purely cosmetic... - return Nu__null; -} - -@end - -// Temporary use for debugging quasiquote functions... -#if 0 -#define QuasiLog(args...) NSLog(args) -#else -#define QuasiLog(args...) -#endif - -@interface Nu_quasiquote_operator : NuOperator {} -@end - -@implementation Nu_quasiquote_operator - -- (id) evalQuasiquote:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - - id quasiquote_eval = [[symbolTable symbolWithString:@"quasiquote-eval"] value]; - id quasiquote_splice = [[symbolTable symbolWithString:@"quasiquote-splice"] value]; - - QuasiLog(@"bq:Entered. callWithArguments cdr = %@", [cdr stringValue]); - - id result = Nu__null; - id result_cursor = Nu__null; - id cursor = cdr; - - while (cursor && (cursor != Nu__null)) { - id value; - QuasiLog(@"quasiquote: [cursor car] == %@", [[cursor car] stringValue]); - - if ([[cursor car] atom]) { - // Treat it as a quoted value - QuasiLog(@"quasiquote: Quoting cursor car: %@", [[cursor car] stringValue]); - value = [cursor car]; - } - else if ([cursor car] == Nu__null) { - QuasiLog(@" quasiquote: null-list"); - value = Nu__null; - } - else if ([[symbolTable lookup:[[[cursor car] car] stringValue]] value] == quasiquote_eval) { - QuasiLog(@"quasiquote-eval: Evaling: [[cursor car] cdr]: %@", [[[cursor car] cdr] stringValue]); - value = [[[cursor car] cdr] evalWithContext:context]; - QuasiLog(@" quasiquote-eval: Value: %@", [value stringValue]); - } - else if ([[symbolTable lookup:[[[cursor car] car] stringValue]] value] == quasiquote_splice) { - QuasiLog(@"quasiquote-splice: Evaling: [[cursor car] cdr]: %@", - [[[cursor car] cdr] stringValue]); - value = [[[cursor car] cdr] evalWithContext:context]; - QuasiLog(@" quasiquote-splice: Value: %@", [value stringValue]); - - if (value != Nu__null && [value atom]) { - [NSException raise:@"NuQuasiquoteSpliceNoListError" - format:@"An atom was passed to Quasiquote splicer. Splicing can only splice a list."]; - } - - id value_cursor = value; - - while (value_cursor && (value_cursor != Nu__null)) { - id value_item = [value_cursor car]; - - if (result_cursor == Nu__null) { - result_cursor = [[[NuCell alloc] init] autorelease]; - result = result_cursor; - } - else { - [result_cursor setCdr: [[[NuCell alloc] init] autorelease]]; - result_cursor = [result_cursor cdr]; - } - - [result_cursor setCar: value_item]; - value_cursor = [value_cursor cdr]; - } - - QuasiLog(@" quasiquote-splice-append: result: %@", [result stringValue]); - - cursor = [cursor cdr]; - - // Don't want to do the normal cursor handling at bottom of the loop - // in this case as we've already done it in the splicing above... - continue; - } - else { - QuasiLog(@"quasiquote: recursive callWithArguments: %@", [[cursor car] stringValue]); - value = [self evalQuasiquote:[cursor car] context:context]; - QuasiLog(@"quasiquote: leaving recursive call with value: %@", [value stringValue]); - } - - if (result == Nu__null) { - result = [[[NuCell alloc] init] autorelease]; - result_cursor = result; - } - else { - [result_cursor setCdr:[[[NuCell alloc] init] autorelease]]; - result_cursor = [result_cursor cdr]; - } - - [result_cursor setCar:value]; - - QuasiLog(@"quasiquote: result_cursor: %@", [result_cursor stringValue]); - QuasiLog(@"quasiquote: result: %@", [result stringValue]); - - cursor = [cursor cdr]; - } - QuasiLog(@"quasiquote: returning result = %@", [result stringValue]); - return result; -} - -#if 0 -@implementation Nu_append_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id newList = Nu__null; - id cursor = nil; - id list_to_append = cdr; - while (list_to_append && (list_to_append != Nu__null)) { - id item_to_append = [[list_to_append car] evalWithContext:context]; - while (item_to_append && (item_to_append != Nu__null)) { - if (newList == Nu__null) { - newList = [[[NuCell alloc] init] autorelease]; - cursor = newList; - } - else { - [cursor setCdr: [[[NuCell alloc] init] autorelease]]; - cursor = [cursor cdr]; - } - id item = [item_to_append car]; - [cursor setCar: item]; - item_to_append = [item_to_append cdr]; - } - list_to_append = [list_to_append cdr]; - } - return newList; -} - -@end -#endif - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - return [[self evalQuasiquote:cdr context:context] car]; -} - -@end - -@interface Nu_context_operator : NuOperator {} -@end - -@implementation Nu_context_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - return context; -} - -@end - -@interface Nu_set_operator : NuOperator {} -@end - -@implementation Nu_set_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - - NuSymbol *symbol = [cdr car]; - id value = [[cdr cdr] car]; - id result = [value evalWithContext:context]; - - char c = (char) [[symbol stringValue] characterAtIndex:0]; - if (c == '$') { - [symbol setValue:result]; - } - else if (c == '@') { - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id object = [context lookupObjectForKey:[symbolTable symbolWithString:@"self"]]; - id ivar = [[symbol stringValue] substringFromIndex:1]; - [object setValue:result forIvar:ivar]; - } - else { -#ifndef CLOSE_ON_VALUES - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id classSymbol = [symbolTable symbolWithString:@"_class"]; - id searchContext = context; - while (searchContext) { - if ([searchContext objectForKey:symbol]) { - [searchContext setPossiblyNullObject:result forKey:symbol]; - return result; - } - else if ([searchContext objectForKey:classSymbol]) { - break; - } - searchContext = [searchContext objectForKey:PARENT_KEY]; - } -#endif - [context setPossiblyNullObject:result forKey:symbol]; - } - return result; -} - -@end - -@interface Nu_local_operator : NuOperator {} -@end - -@implementation Nu_local_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - - NuSymbol *symbol = [cdr car]; - id value = [[cdr cdr] car]; - id result = [value evalWithContext:context]; - [context setPossiblyNullObject:result forKey:symbol]; - return result; -} - -@end - - -@interface Nu_global_operator : NuOperator {} -@end - -@implementation Nu_global_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - - NuSymbol *symbol = [cdr car]; - id value = [[cdr cdr] car]; - id result = [value evalWithContext:context]; - [symbol setValue:result]; - return result; -} - -@end - -@interface Nu_regex_operator : NuOperator {} -@end - -@implementation Nu_regex_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id value = [cdr car]; - value = [value evalWithContext:context]; - return [NSRegularExpression regexWithPattern:value]; -} - -@end - -@interface Nu_do_operator : NuOperator {} -@end - -@implementation Nu_do_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id args = [cdr car]; - id body = [cdr cdr]; - NuBlock *block = [[[NuBlock alloc] initWithParameters:args body:body context:context] autorelease]; - return block; -} - -@end - -@interface Nu_function_operator : NuOperator {} -@end - -@implementation Nu_function_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id symbol = [cdr car]; - id args = [[cdr cdr] car]; - id body = [[cdr cdr] cdr]; - NuBlock *block = [[[NuBlock alloc] initWithParameters:args body:body context:context] autorelease]; - // this defines the function in the calling context, lexical closures make recursion possible - [context setPossiblyNullObject:block forKey:symbol]; -#ifdef CLOSE_ON_VALUES - // in this case, we don't have closures, so we set this to allow recursion (but it creates a retain cycle) - [[block context] setPossiblyNullObject:block forKey:symbol]; -#endif - return block; -} - -@end - -@interface Nu_label_operator : NuOperator {} -@end - -@implementation Nu_label_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id symbol = [cdr car]; - id value = [[cdr cdr] car]; - value = [value evalWithContext:context]; - if (nu_objectIsKindOfClass(value, [NuBlock class])) { - //NSLog(@"setting context[%@] = %@", symbol, value); - [((NSMutableDictionary *)[value context]) setPossiblyNullObject:value forKey:symbol]; - } - return value; -} - -@end - -@interface Nu_macro_0_operator : NuOperator {} -@end - -@implementation Nu_macro_0_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id name = [cdr car]; - id body = [cdr cdr]; - - NuMacro_0 *macro = [[[NuMacro_0 alloc] initWithName:name body:body] autorelease]; - // this defines the function in the calling context - [context setPossiblyNullObject:macro forKey:name]; - return macro; -} - -@end - -@interface Nu_macro_1_operator : NuOperator {} -@end - -@implementation Nu_macro_1_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id name = [cdr car]; - id args = [[cdr cdr] car]; - id body = [[cdr cdr] cdr]; - - NuMacro_1 *macro = [[[NuMacro_1 alloc] initWithName:name parameters:args body:body] autorelease]; - // this defines the function in the calling context - [context setPossiblyNullObject:macro forKey:name]; - return macro; -} - -@end - -@interface Nu_macrox_operator : NuOperator {} -@end - -@implementation Nu_macrox_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id call = [cdr car]; - id name = [call car]; - id margs = [call cdr]; - - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id macro = [context objectForKey:[symbolTable symbolWithString:[name stringValue]]]; - - if (macro == nil) { - [NSException raise:@"NuMacroxWrongType" format:@"macrox was called on an object which is not a macro"]; - } - - id expanded = [macro expand1:margs context:context]; - return expanded; -} - -@end - -@interface Nu_list_operator : NuOperator {} -@end - -@implementation Nu_list_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id result = Nu__null; - id cursor = cdr; - id result_cursor = Nu__null; - while (cursor && (cursor != Nu__null)) { - if (result == Nu__null) { - result = [[[NuCell alloc] init] autorelease]; - result_cursor = result; - } - else { - [result_cursor setCdr:[[[NuCell alloc] init] autorelease]]; - result_cursor = [result_cursor cdr]; - } - id value = [[cursor car] evalWithContext:context]; - [result_cursor setCar:value]; - cursor = [cursor cdr]; - } - return result; -} - -@end - -@interface Nu_add_operator : NuOperator {} -@end - -@implementation Nu_add_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - if ([context objectForKey:[symbolTable symbolWithString:@"_class"]] && ![context objectForKey:[symbolTable symbolWithString:@"_method"]]) { - // we are inside a class declaration and outside a method declaration. - // treat this as a "cmethod" call - NuClass *classWrapper = [context objectForKey:[symbolTable symbolWithString:@"_class"]]; - [classWrapper registerClass]; - Class classToExtend = [classWrapper wrappedClass]; - return help_add_method_to_class(classToExtend, cdr, context, YES); - } - // otherwise, it's an addition - id firstArgument = [[cdr car] evalWithContext:context]; - if (nu_objectIsKindOfClass(firstArgument, [NSValue class])) { - double sum = [firstArgument doubleValue]; - id cursor = [cdr cdr]; - while (cursor && (cursor != Nu__null)) { - sum += [[[cursor car] evalWithContext:context] doubleValue]; - cursor = [cursor cdr]; - } - return [NSNumber numberWithDouble:sum]; - } - else { - NSMutableString *result = [NSMutableString stringWithString:[firstArgument stringValue]]; - id cursor = [cdr cdr]; - while (cursor && (cursor != Nu__null)) { - id carValue = [[cursor car] evalWithContext:context]; - if (carValue && (carValue != Nu__null)) { - [result appendString:[carValue stringValue]]; - } - cursor = [cursor cdr]; - } - return result; - } -} - -@end - -@interface Nu_multiply_operator : NuOperator {} -@end - -@implementation Nu_multiply_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - double product = 1; - id cursor = cdr; - while (cursor && (cursor != Nu__null)) { - product *= [[[cursor car] evalWithContext:context] doubleValue]; - cursor = [cursor cdr]; - } - return [NSNumber numberWithDouble:product]; -} - -@end - -@interface Nu_subtract_operator : NuOperator {} -@end - -@implementation Nu_subtract_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - if ([context objectForKey:[symbolTable symbolWithString:@"_class"]] && ![context objectForKey:[symbolTable symbolWithString:@"_method"]]) { - // we are inside a class declaration and outside a method declaration. - // treat this as an "imethod" call - NuClass *classWrapper = [context objectForKey:[symbolTable symbolWithString:@"_class"]]; - [classWrapper registerClass]; - Class classToExtend = [classWrapper wrappedClass]; - return help_add_method_to_class(classToExtend, cdr, context, NO); - } - // otherwise, it's a subtraction - id cursor = cdr; - double sum = [[[cursor car] evalWithContext:context] doubleValue]; - cursor = [cursor cdr]; - if (!cursor || (cursor == Nu__null)) { - // if there is just one operand, negate it - sum = -sum; - } - else { - // otherwise, subtract all the remaining operands from the first one - while (cursor && (cursor != Nu__null)) { - sum -= [[[cursor car] evalWithContext:context] doubleValue]; - cursor = [cursor cdr]; - } - } - return [NSNumber numberWithDouble:sum]; -} - -@end - -@interface Nu_exponentiation_operator : NuOperator {} -@end - -@implementation Nu_exponentiation_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cursor = cdr; - double result = [[[cursor car] evalWithContext:context] doubleValue]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - result = pow(result, [[[cursor car] evalWithContext:context] doubleValue]); - cursor = [cursor cdr]; - } - return [NSNumber numberWithDouble:result]; -} - -@end - -@interface Nu_divide_operator : NuOperator {} -@end - -@implementation Nu_divide_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cursor = cdr; - double product = [[[cursor car] evalWithContext:context] doubleValue]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - product /= [[[cursor car] evalWithContext:context] doubleValue]; - cursor = [cursor cdr]; - } - return [NSNumber numberWithDouble:product]; -} - -@end - -@interface Nu_modulus_operator : NuOperator {} -@end - -@implementation Nu_modulus_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cursor = cdr; - int product = [[[cursor car] evalWithContext:context] intValue]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - product %= [[[cursor car] evalWithContext:context] intValue]; - cursor = [cursor cdr]; - } - return [NSNumber numberWithInt:product]; -} - -@end - -@interface Nu_bitwiseand_operator : NuOperator {} -@end - -@implementation Nu_bitwiseand_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cursor = cdr; - long result = [[[cursor car] evalWithContext:context] longValue]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - result &= [[[cursor car] evalWithContext:context] longValue]; - cursor = [cursor cdr]; - } - return [NSNumber numberWithLong:result]; -} - -@end - -@interface Nu_bitwiseor_operator : NuOperator {} -@end - -@implementation Nu_bitwiseor_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cursor = cdr; - long result = [[[cursor car] evalWithContext:context] longValue]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - result |= [[[cursor car] evalWithContext:context] longValue]; - cursor = [cursor cdr]; - } - return [NSNumber numberWithLong:result]; -} - -@end - -@interface Nu_greaterthan_operator : NuOperator {} -@end - -@implementation Nu_greaterthan_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id cursor = cdr; - id current = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - id next = [[cursor car] evalWithContext:context]; - NSComparisonResult result = [current compare:next]; - if (result != NSOrderedDescending) - return Nu__null; - current = next; - cursor = [cursor cdr]; - } - return [symbolTable symbolWithString:@"t"]; -} - -@end - -@interface Nu_lessthan_operator : NuOperator {} -@end - -@implementation Nu_lessthan_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id cursor = cdr; - id current = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - id next = [[cursor car] evalWithContext:context]; - NSComparisonResult result = [current compare:next]; - if (result != NSOrderedAscending) - return Nu__null; - current = next; - cursor = [cursor cdr]; - } - return [symbolTable symbolWithString:@"t"]; -} - -@end - -@interface Nu_gte_operator : NuOperator {} -@end - -@implementation Nu_gte_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id cursor = cdr; - id current = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - id next = [[cursor car] evalWithContext:context]; - NSComparisonResult result = [current compare:next]; - if (result == NSOrderedAscending) - return Nu__null; - current = next; - cursor = [cursor cdr]; - } - return [symbolTable symbolWithString:@"t"]; -} - -@end - -@interface Nu_lte_operator : NuOperator {} -@end - -@implementation Nu_lte_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id cursor = cdr; - id current = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - while (cursor && (cursor != Nu__null)) { - id next = [[cursor car] evalWithContext:context]; - NSComparisonResult result = [current compare:next]; - if (result == NSOrderedDescending) - return Nu__null; - current = next; - cursor = [cursor cdr]; - } - return [symbolTable symbolWithString:@"t"]; -} - -@end - -@interface Nu_leftshift_operator : NuOperator {} -@end - -@implementation Nu_leftshift_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - long result = [[[cdr car] evalWithContext:context] longValue]; - result = result << [[[[cdr cdr] car] evalWithContext:context] longValue]; - return [NSNumber numberWithLong:result]; -} - -@end - -@interface Nu_rightshift_operator : NuOperator {} -@end - -@implementation Nu_rightshift_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - long result = [[[cdr car] evalWithContext:context] longValue]; - result = result >> [[[[cdr cdr] car] evalWithContext:context] longValue]; - return [NSNumber numberWithLong:result]; -} - -@end - -@interface Nu_and_operator : NuOperator {} -@end - -@implementation Nu_and_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cursor = cdr; - id value = Nu__null; - while (cursor && (cursor != Nu__null)) { - value = [[cursor car] evalWithContext:context]; - if (!nu_valueIsTrue(value)) - return Nu__null; - cursor = [cursor cdr]; - } - return value; -} - -@end - -@interface Nu_or_operator : NuOperator {} -@end - -@implementation Nu_or_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cursor = cdr; - while (cursor && (cursor != Nu__null)) { - id value = [[cursor car] evalWithContext:context]; - if (nu_valueIsTrue(value)) - return value; - cursor = [cursor cdr]; - } - return Nu__null; -} - -@end - -@interface Nu_not_operator : NuOperator {} -@end - -@implementation Nu_not_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id cursor = cdr; - if (cursor && (cursor != Nu__null)) { - id value = [[cursor car] evalWithContext:context]; - return nu_valueIsTrue(value) ? Nu__null : [symbolTable symbolWithString:@"t"]; - } - return Nu__null; -} - -@end - -#if !TARGET_OS_IPHONE -@interface NuConsoleViewController : NSObject {} -- (void) write:(id) string; -@end -#endif - -@interface Nu_puts_operator : NuOperator {} -@end - -@implementation Nu_puts_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ -#if !TARGET_OS_IPHONE - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - NuConsoleViewController *console = (NuConsoleViewController*) - [[symbolTable symbolWithString:@"$$console"] value]; -#endif - NSString *string; - id cursor = cdr; - while (cursor && (cursor != Nu__null)) { - id value = [[cursor car] evalWithContext:context]; - if (value) { - string = [value stringValue]; -#if !TARGET_OS_IPHONE - if (console && (console != Nu__null)) { - [console write:string]; - [console write:[NSString carriageReturn]]; - } - else { -#endif - printf("%s\n", [string cStringUsingEncoding:NSUTF8StringEncoding]); -#if !TARGET_OS_IPHONE - } -#endif - } - cursor = [cursor cdr]; - } - return Nu__null;; -} - -@end - -#if !TARGET_OS_IPHONE -@interface Nu_gets_operator : NuOperator {} -@end - -@implementation Nu_gets_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - char *input = readline(""); - NSString *result = [NSString stringWithUTF8String: input]; - return result; -} - -@end -#endif - -@interface Nu_print_operator : NuOperator {} -@end - -@implementation Nu_print_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ -#if !TARGET_OS_IPHONE - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - NuConsoleViewController *console = (NuConsoleViewController*)[[symbolTable symbolWithString:@"$$console"] value]; -#endif - NSString *string; - id cursor = cdr; - while (cursor && (cursor != Nu__null)) { - string = [[[cursor car] evalWithContext:context] stringValue]; -#if !TARGET_OS_IPHONE - if (console && (console != Nu__null)) { - [console write:string]; - } - else { -#endif - printf("%s", [string cStringUsingEncoding:NSUTF8StringEncoding]); -#if !TARGET_OS_IPHONE - } -#endif - cursor = [cursor cdr]; - } - return Nu__null;; -} - -@end - -@interface Nu_call_operator : NuOperator {} -@end - -@implementation Nu_call_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id function = [[cdr car] evalWithContext:context]; - id arguments = [cdr cdr]; - id value = [function callWithArguments:arguments context:context]; - return value; -} - -@end - -@interface Nu_send_operator : NuOperator {} -@end - -@implementation Nu_send_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id target = [[cdr car] evalWithContext:context]; - id message = [cdr cdr]; - id value = [target sendMessage:message withContext:context]; - return value; -} - -@end - -@interface Nu_progn_operator : NuOperator {} -@end - -@implementation Nu_progn_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id value = Nu__null; - id cursor = cdr; - while (cursor && (cursor != Nu__null)) { - value = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - } - return value; -} - -@end - -@interface Nu_eval_operator : NuOperator {} -@end - -@implementation Nu_eval_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id value = [[[cdr car] evalWithContext:context] evalWithContext:context]; - return value; -} - -@end - -#ifdef LINUX -id loadNuLibraryFile(NSString *nuFileName, id parser, id context, id symbolTable) -{ - NSString *fullPath = [NSString stringWithFormat:@"/usr/local/share/libNu/%@.nu", nuFileName]; - if ([NSFileManager fileExistsNamed:fullPath]) { - NSString *string = [NSString stringWithContentsOfFile:fullPath]; - id value = Nu__null; - if (string) { - id body = [parser parse:string asIfFromFilename:[fullPath cStringUsingEncoding:NSUTF8StringEncoding]]; - value = [body evalWithContext:context]; - return [symbolTable symbolWithString:@"t"]; - } - else { - return nil; - } - } - else { - return nil; - } -} -#endif - -@interface Nu_load_operator : NuOperator {} -@end - -@implementation Nu_load_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id parser = [context lookupObjectForKey:[symbolTable symbolWithString:@"_parser"]]; - id resourceName = [[cdr car] evalWithContext:context]; - - // does the resourceName contain a colon? if so, it's a framework:nu-source-file pair. - NSArray *split = [resourceName componentsSeparatedByString:@":"]; - if ([split count] == 2) { - id frameworkName = [split objectAtIndex:0]; - id nuFileName = [split objectAtIndex:1]; - #ifdef LINUX - if ([frameworkName isEqual:@"Nu"]) { - if (loadNuLibraryFile(nuFileName, parser, context, symbolTable) == nil) { - [NSException raise:@"NuLoadFailed" format:@"unable to load %@", nuFileName]; - } - else { - return [symbolTable symbolWithString:@"t"]; - } - } - #endif - - NSBundle *framework = [NSBundle frameworkWithName:frameworkName]; - if ([framework loadNuFile:nuFileName withContext:context]) - return [symbolTable symbolWithString:@"t"]; - else { - [NSException raise:@"NuLoadFailed" format:@"unable to load %@", resourceName]; - return nil; - } - } - else { - // first try to find a file at the specified path - id fileName = [resourceName stringByExpandingTildeInPath]; - if (![NSFileManager fileExistsNamed:fileName]) { - // if that failed, try looking for a Nu_ source file in the current directory, - // first with and then without the ".nu" suffix - fileName = [NSString stringWithFormat:@"./%@.nu", resourceName]; - if (![NSFileManager fileExistsNamed: fileName]) { - fileName = [NSString stringWithFormat:@"./%@", resourceName]; - if (![NSFileManager fileExistsNamed: fileName]) fileName = nil; - } - } - if (fileName) { - NSString *string = [NSString stringWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:NULL]; - if (string) { - id body = [parser parse:string asIfFromFilename:[fileName cStringUsingEncoding:NSUTF8StringEncoding]]; - [body evalWithContext:context]; - return [symbolTable symbolWithString:@"t"]; - } - else { - [NSException raise:@"NuLoadFailed" format:@"unable to load %@", fileName]; - return nil; - } - } - - // if that failed, try to load the file the main application bundle - if ([[NSBundle mainBundle] loadNuFile:resourceName withContext:context]) { - return [symbolTable symbolWithString:@"t"]; - } - - // next, try the main Nu bundle - if ([Nu loadNuFile:resourceName fromBundleWithIdentifier:@"nu.programming.framework" withContext:context]) { - return [symbolTable symbolWithString:@"t"]; - } - - // if no file was found, try to load a framework with the given name - if ([NSBundle frameworkWithName:resourceName]) { - #ifdef LINUX - // if we're on Linux, call this a second (redundant) time because GNUstep seems to sometimes fail to properly load on the first call. - [NSBundle frameworkWithName:resourceName]; - #endif - return [symbolTable symbolWithString:@"t"]; - } - - #ifdef LINUX - if (loadNuLibraryFile(resourceName, parser, context, symbolTable)) { - return [symbolTable symbolWithString:@"t"]; - } - #endif - - [NSException raise:@"NuLoadFailed" format:@"unable to load %@", resourceName]; - return nil; - } -} - -@end - -@interface Nu_let_operator : NuOperator {} -@end - -@implementation Nu_let_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - id arg_names = [[NuCell alloc] init]; - id arg_values = [[NuCell alloc] init]; - - id cursor = [cdr car]; - if ((cursor != [NSNull null]) && [[cursor car] atom]) { - [arg_names setCar:[cursor car]]; - [arg_values setCar:[[cursor cdr] car]]; - } - else { - id arg_name_cursor = arg_names; - id arg_value_cursor = arg_values; - while (cursor && (cursor != Nu__null)) { - [arg_name_cursor setCar:[[cursor car] car]]; - [arg_value_cursor setCar:[[[cursor car] cdr] car]]; - cursor = [cursor cdr]; - if (cursor && (cursor != Nu__null)) { - [arg_name_cursor setCdr:[[[NuCell alloc] init] autorelease]]; - [arg_value_cursor setCdr:[[[NuCell alloc] init] autorelease]]; - arg_name_cursor = [arg_name_cursor cdr]; - arg_value_cursor = [arg_value_cursor cdr]; - } - } - } - id body = [cdr cdr]; - NuBlock *block = [[NuBlock alloc] initWithParameters:arg_names body:body context:context]; - id result = [[block evalWithArguments:arg_values context:context] retain]; - [block release]; - - [arg_names release]; - [arg_values release]; - [pool drain]; - [result autorelease]; - return result; -} - -@end - -@interface Nu_class_operator : NuOperator {} -@end - -@implementation Nu_class_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id className = [cdr car]; - id body; -#if defined(__x86_64__) || TARGET_OS_IPHONE - Class newClass = nil; -#endif - - NuClass *childClass; - //NSLog(@"class name: %@", className); - if ([cdr cdr] - && ([cdr cdr] != Nu__null) - && [[[cdr cdr] car] isEqual: [symbolTable symbolWithString:@"is"]] - ) { - id parentName = [[[cdr cdr] cdr] car]; - //NSLog(@"parent name: %@", [parentName stringValue]); - Class parentClass = NSClassFromString([parentName stringValue]); - if (!parentClass) - [NSException raise:@"NuUndefinedSuperclass" format:@"undefined superclass %@", [parentName stringValue]]; - -#if defined(__x86_64__) || TARGET_OS_IPHONE - - newClass = objc_allocateClassPair(parentClass, [[className stringValue] cStringUsingEncoding:NSUTF8StringEncoding], 0); - childClass = [NuClass classWithClass:newClass]; - [childClass setRegistered:NO]; - //NSLog(@"created class %@", [childClass name]); - // it seems dangerous to call this here. Maybe it's better to wait until the new class is registered. - if ([parentClass respondsToSelector:@selector(inheritedByClass:)]) { - [parentClass inheritedByClass:childClass]; - } - - if (!childClass) { - // This class may have already been defined previously - // (perhaps by loading the same .nu file twice). - // If so, the above call to objc_allocateClassPair() returns nil. - // So if childClass is nil, it may be that the class was - // already defined, so we'll try to find it and use it. - Class existingClass = NSClassFromString([className stringValue]); - if (existingClass) { - childClass = [NuClass classWithClass:existingClass]; - //if (childClass) - // NSLog(@"Warning: attempting to re-define existing class: %@. Ignoring.", [className stringValue]); - } - } - -#else - [parentClass createSubclassNamed:[className stringValue]]; - childClass = [NuClass classWithName:[className stringValue]]; -#endif - body = [[[cdr cdr] cdr] cdr]; - } - else { - childClass = [NuClass classWithName:[className stringValue]]; - body = [cdr cdr]; - } - if (!childClass) - [NSException raise:@"NuUndefinedClass" format:@"undefined class %@", [className stringValue]]; - id result = nil; - if (body && (body != Nu__null)) { - NuBlock *block = [[NuBlock alloc] initWithParameters:Nu__null body:body context:context]; - [[block context] - setPossiblyNullObject:childClass - forKey:[symbolTable symbolWithString:@"_class"]]; - result = [block evalWithArguments:Nu__null context:Nu__null]; - [block release]; - } -#if defined(__x86_64__) || TARGET_OS_IPHONE - if (newClass && ([childClass isRegistered] == NO)) { - [childClass registerClass]; - } -#endif - return result; -} - -@end - -@interface Nu_cmethod_operator : NuOperator {} -@end - -@implementation Nu_cmethod_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NSLog(@"The cmethod operator is deprecated. Please replace it with '+' in your code."); - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - NuClass *classWrapper = [context objectForKey:[symbolTable symbolWithString:@"_class"]]; - [classWrapper registerClass]; - Class classToExtend = [classWrapper wrappedClass]; - if (!classToExtend) - [NSException raise:@"NuMisplacedDeclaration" format:@"class method declaration with no enclosing class declaration"]; - return help_add_method_to_class(classToExtend, cdr, context, YES); -} - -@end - -@interface Nu_imethod_operator : NuOperator {} -@end - -@implementation Nu_imethod_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NSLog(@"The imethod operator is deprecated. Please replace it with '-' in your code."); - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - NuClass *classWrapper = [context objectForKey:[symbolTable symbolWithString:@"_class"]]; - [classWrapper registerClass]; - Class classToExtend = [classWrapper wrappedClass]; - if (!classToExtend) - [NSException raise:@"NuMisplacedDeclaration" format:@"instance method declaration with no enclosing class declaration"]; - return help_add_method_to_class(classToExtend, cdr, context, NO); -} - -@end - -@interface Nu_ivar_operator : NuOperator {} -@end - -@implementation Nu_ivar_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - NuClass *classWrapper = [context objectForKey:[symbolTable symbolWithString:@"_class"]]; - // this will only work if the class is unregistered... - if ([classWrapper isRegistered]) { - [NSException raise:@"NuIvarAddedTooLate" format:@"explicit instance variables must be added when a class is created and before any method declarations"]; - } - Class classToExtend = [classWrapper wrappedClass]; - if (!classToExtend) - [NSException raise:@"NuMisplacedDeclaration" format:@"instance variable declaration with no enclosing class declaration"]; - id cursor = cdr; - while (cursor && (cursor != Nu__null)) { - id variableType = [cursor car]; - cursor = [cursor cdr]; - id variableName = [cursor car]; - cursor = [cursor cdr]; - NSString *signature = signature_for_identifier(variableType, symbolTable); - nu_class_addInstanceVariable_withSignature(classToExtend, - [[variableName stringValue] cStringUsingEncoding:NSUTF8StringEncoding], - [signature cStringUsingEncoding:NSUTF8StringEncoding]); - //NSLog(@"adding ivar %@ with signature %@", [variableName stringValue], signature); - } - return Nu__null; -} - -@end - -@interface Nu_ivars_operator : NuOperator {} -@end - -@implementation Nu_ivars_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NSLog(@"The ivars operator is unnecessary. Please remove it from your source."); - return Nu__null; -} - -@end - -@interface Nu_ivar_accessors_operator : NuOperator {} -@end - -@implementation Nu_ivar_accessors_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NSLog(@"The ivar-accessors operator is unnecessary. Please remove it from your source."); - return Nu__null; -} - -@end - -@interface Nu_system_operator : NuOperator {} -@end - -@implementation Nu_system_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id cursor = cdr; - NSMutableString *command = [NSMutableString string]; - while (cursor && (cursor != [NSNull null])) { - [command appendString:[[[cursor car] evalWithContext:context] stringValue]]; - cursor = [cursor cdr]; - } - const char *commandString = [command cStringUsingEncoding:NSUTF8StringEncoding]; - int result = system(commandString) >> 8; // this needs an explanation - return [NSNumber numberWithInt:result]; -} - -@end - -@interface Nu_exit_operator : NuOperator {} -@end - -@implementation Nu_exit_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - if (cdr && (cdr != Nu__null)) { - int status = [[[cdr car] evalWithContext:context] intValue]; - exit(status); - } - else { - exit (0); - } - return Nu__null; // we'll never get here. -} - -@end - -@interface Nu_sleep_operator : NuOperator {} -@end - -@implementation Nu_sleep_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - int result = -1; - if (cdr && (cdr != Nu__null)) { - int seconds = [[[cdr car] evalWithContext:context] intValue]; - result = sleep(seconds); - } - else { - [NSException raise: @"NuArityError" format:@"sleep expects 1 argument, got 0"]; - } - return [NSNumber numberWithInt:result]; -} - -@end - -@interface Nu_uname_operator : NuOperator {} -@end - -@implementation Nu_uname_operator -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - if (!cdr || (cdr == Nu__null)) { -#if TARGET_OS_IPHONE - return @"iOS"; -#else -#ifdef DARWIN - return @"Darwin"; -#else - return @"Linux"; -#endif -#endif - } - if ([[[cdr car] stringValue] isEqualToString:@"systemName"]) { -#if TARGET_OS_IPHONE - return [[UIDevice currentDevice] systemName]; -#else - return @"Macintosh"; -#endif - } - return nil; -} - -@end - -@interface Nu_help_operator : NuOperator {} -@end - -@implementation Nu_help_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id object = [[cdr car] evalWithContext:context]; - return [object help]; -} - -@end - -@interface Nu_break_operator : NuOperator {} -@end - -@implementation Nu_break_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - @throw [[[NuBreakException alloc] init] autorelease]; - return nil; // unreached -} - -@end - -@interface Nu_continue_operator : NuOperator {} -@end - -@implementation Nu_continue_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - @throw [[[NuContinueException alloc] init] autorelease]; - return nil; // unreached -} - -@end - -@interface Nu_return_operator : NuOperator {} -@end - -@implementation Nu_return_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id value = nil; - if (cdr && cdr != Nu__null) { - value = [[cdr car] evalWithContext:context]; - } - @throw [[[NuReturnException alloc] initWithValue:value] autorelease]; - return nil; // unreached -} - -@end - -@interface Nu_return_from_operator : NuOperator {} -@end - -@implementation Nu_return_from_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id block = nil; - id value = nil; - id cursor = cdr; - if (cursor && cursor != Nu__null) { - block = [[cursor car] evalWithContext:context]; - cursor = [cursor cdr]; - } - if (cursor && cursor != Nu__null) { - value = [[cursor car] evalWithContext:context]; - } - @throw [[[NuReturnException alloc] initWithValue:value blockForReturn:block] autorelease]; - return nil; // unreached -} - -@end - -@interface Nu_version_operator : NuOperator {} -@end - -@implementation Nu_version_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - return [NSString stringWithFormat:@"Nu %s (%s)", NU_VERSION, NU_RELEASE_DATE]; -} - -@end - -@interface Nu_min_operator : NuOperator {} -@end - -@implementation Nu_min_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - if (cdr == Nu__null) - [NSException raise: @"NuArityError" format:@"min expects at least 1 argument, got 0"]; - id smallest = [[cdr car] evalWithContext:context]; - id cursor = [cdr cdr]; - while (cursor && (cursor != Nu__null)) { - id nextValue = [[cursor car] evalWithContext:context]; - if([smallest compare:nextValue] == 1) { - smallest = nextValue; - } - cursor = [cursor cdr]; - } - return smallest; -} - -@end - -@interface Nu_max_operator : NuOperator {} -@end - -@implementation Nu_max_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - if (cdr == Nu__null) - [NSException raise: @"NuArityError" format:@"max expects at least 1 argument, got 0"]; - id biggest = [[cdr car] evalWithContext:context]; - id cursor = [cdr cdr]; - while (cursor && (cursor != Nu__null)) { - id nextValue = [[cursor car] evalWithContext:context]; - if([biggest compare:nextValue] == -1) { - biggest = nextValue; - } - cursor = [cursor cdr]; - } - return biggest; -} - -@end - -static id evaluatedArguments(id cdr, NSMutableDictionary *context) -{ - NuCell *evaluatedArguments = nil; - id cursor = cdr; - id outCursor = nil; - while (cursor && (cursor != Nu__null)) { - id nextValue = [[cursor car] evalWithContext:context]; - id newCell = [[[NuCell alloc] init] autorelease]; - [newCell setCar:nextValue]; - if (!outCursor) { - evaluatedArguments = newCell; - } - else { - [outCursor setCdr:newCell]; - } - outCursor = newCell; - cursor = [cursor cdr]; - } - return evaluatedArguments; -} - -@interface Nu_array_operator : NuOperator {} -@end - -@implementation Nu_array_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - return [NSArray arrayWithList:evaluatedArguments(cdr, context)]; -} - -@end - -@interface Nu_dict_operator : NuOperator {} -@end - -@implementation Nu_dict_operator - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - return [NSDictionary dictionaryWithList:evaluatedArguments(cdr, context)]; -} - -@end - -@interface Nu_parse_operator : NuOperator {} -@end - -@implementation Nu_parse_operator - -// parse operator; parses a string into Nu code objects -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - id parser = [[[NuParser alloc] init] autorelease]; - return [parser parse:[[cdr car] evalWithContext:context]]; -} - -@end - -@interface Nu_signature_operator : NuOperator {} -@end - -@implementation Nu_signature_operator - -// signature operator; basically gives access to the static signature_for_identifier function from within Nu code -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - return signature_for_identifier( [[cdr car] evalWithContext:context],[NuSymbolTable sharedSymbolTable]); -} - -@end - -#define install(name, class) [(NuSymbol *) [symbolTable symbolWithString:name] setValue:[[[class alloc] init] autorelease]] - -void load_builtins(NuSymbolTable *symbolTable); - -void load_builtins(NuSymbolTable *symbolTable) -{ - [(NuSymbol *) [symbolTable symbolWithString:@"t"] setValue:[symbolTable symbolWithString:@"t"]]; - [(NuSymbol *) [symbolTable symbolWithString:@"nil"] setValue:Nu__null]; - [(NuSymbol *) [symbolTable symbolWithString:@"YES"] setValue:[NSNumber numberWithBool:YES]]; - [(NuSymbol *) [symbolTable symbolWithString:@"NO"] setValue:[NSNumber numberWithBool:NO]]; - - install(@"car", Nu_car_operator); - install(@"cdr", Nu_cdr_operator); - install(@"first", Nu_car_operator); - install(@"rest", Nu_cdr_operator); - install(@"head", Nu_car_operator); - install(@"tail", Nu_cdr_operator); - install(@"atom", Nu_atom_operator); - install(@"defined", Nu_defined_operator); - - install(@"eq", Nu_eq_operator); - install(@"==", Nu_eq_operator); - install(@"ne", Nu_neq_operator); - install(@"!=", Nu_neq_operator); - install(@"gt", Nu_greaterthan_operator); - install(@">", Nu_greaterthan_operator); - install(@"lt", Nu_lessthan_operator); - install(@"<", Nu_lessthan_operator); - install(@"ge", Nu_gte_operator); - install(@">=", Nu_gte_operator); - install(@"le", Nu_lte_operator); - install(@"<=", Nu_lte_operator); - - install(@"cons", Nu_cons_operator); - install(@"append", Nu_append_operator); - install(@"apply", Nu_apply_operator); - - install(@"cond", Nu_cond_operator); - install(@"case", Nu_case_operator); - install(@"if", Nu_if_operator); - install(@"unless", Nu_unless_operator); - install(@"while", Nu_while_operator); - install(@"until", Nu_until_operator); - install(@"for", Nu_for_operator); - install(@"break", Nu_break_operator); - install(@"continue", Nu_continue_operator); - install(@"return", Nu_return_operator); - install(@"return-from", Nu_return_from_operator); - - install(@"try", Nu_try_operator); - - install(@"throw", Nu_throw_operator); - install(@"synchronized", Nu_synchronized_operator); - - install(@"quote", Nu_quote_operator); - install(@"eval", Nu_eval_operator); - - install(@"context", Nu_context_operator); - install(@"set", Nu_set_operator); - install(@"global", Nu_global_operator); - install(@"local", Nu_local_operator); - - install(@"regex", Nu_regex_operator); - - install(@"function", Nu_function_operator); - install(@"def", Nu_function_operator); - - install(@"progn", Nu_progn_operator); - install(@"then", Nu_progn_operator); - install(@"else", Nu_progn_operator); - - install(@"macro", Nu_macro_1_operator); - install(@"macrox", Nu_macrox_operator); - - install(@"quasiquote", Nu_quasiquote_operator); - install(@"quasiquote-eval", Nu_quasiquote_eval_operator); - install(@"quasiquote-splice", Nu_quasiquote_splice_operator); - - install(@"+", Nu_add_operator); - install(@"-", Nu_subtract_operator); - install(@"*", Nu_multiply_operator); - install(@"/", Nu_divide_operator); - install(@"**", Nu_exponentiation_operator); - install(@"%", Nu_modulus_operator); - - install(@"&", Nu_bitwiseand_operator); - install(@"|", Nu_bitwiseor_operator); - install(@"<<", Nu_leftshift_operator); - install(@">>", Nu_rightshift_operator); - - install(@"&&", Nu_and_operator); - install(@"||", Nu_or_operator); - - install(@"and", Nu_and_operator); - install(@"or", Nu_or_operator); - install(@"not", Nu_not_operator); - - install(@"min", Nu_min_operator); - install(@"max", Nu_max_operator); - - install(@"list", Nu_list_operator); - - install(@"do", Nu_do_operator); - -#if !TARGET_OS_IPHONE - install(@"gets", Nu_gets_operator); -#endif - install(@"puts", Nu_puts_operator); - install(@"print", Nu_print_operator); - - install(@"let", Nu_let_operator); - - install(@"load", Nu_load_operator); - - install(@"uname", Nu_uname_operator); - install(@"system", Nu_system_operator); - install(@"exit", Nu_exit_operator); - install(@"sleep", Nu_sleep_operator); - - install(@"class", Nu_class_operator); - install(@"imethod", Nu_imethod_operator); - install(@"cmethod", Nu_cmethod_operator); - install(@"ivar", Nu_ivar_operator); - install(@"ivars", Nu_ivars_operator); - install(@"ivar-accessors", Nu_ivar_accessors_operator); - - install(@"call", Nu_call_operator); - install(@"send", Nu_send_operator); - - install(@"array", Nu_array_operator); - install(@"dict", Nu_dict_operator); - install(@"parse", Nu_parse_operator); - - install(@"help", Nu_help_operator); - install(@"?", Nu_help_operator); - install(@"version", Nu_version_operator); - - install(@"signature", Nu_signature_operator); - - // set some commonly-used globals - [(NuSymbol *) [symbolTable symbolWithString:@"NSUTF8StringEncoding"] - setValue:[NSNumber numberWithInt:NSUTF8StringEncoding]]; - - [(NuSymbol *) [symbolTable symbolWithString:@"NSLog"] // let's make this an operator someday - setValue:[NuBridgedFunction functionWithName:@"NSLog" signature:@"v@"]]; -} - -#pragma mark - NuParser.m - -#define PARSE_NORMAL 0 -#define PARSE_COMMENT 1 -#define PARSE_STRING 2 -#define PARSE_HERESTRING 3 -#define PARSE_REGEX 4 - -#define MAX_FILES 1024 -static char *filenames[MAX_FILES]; -static int filecount = 0; - -// Turn debug output on and off for this file only -//#define PARSER_DEBUG 1 - -#ifdef PARSER_DEBUG -#define ParserDebug(arg...) NSLog(arg) -#else -#define ParserDebug(arg...) -#endif - -static const char *nu_parsedFilename(int i) -{ - return (i < 0) ? NULL: filenames[i]; -} - -@interface NuParser(Internal) -- (int) depth; -- (int) parens; -- (int) state; -- (NuCell *) root; -- (NuStack *) opens; -- (NSString *) stringValue; -- (const char *) cStringUsingEncoding:(NSStringEncoding) encoding; -- (id) init; -- (void) openList; -- (void) closeList; -- (void) addAtom:(id)atom; -- (void) quoteNextElement; -- (void) quasiquoteNextElement; -- (void) quasiquoteEvalNextElement; -- (void) quasiquoteSpliceNextElement; -- (int) interact; -@end - -static id atomWithString(NSString *string, NuSymbolTable *symbolTable) -{ - const char *cstring = [string cStringUsingEncoding:NSUTF8StringEncoding]; - char *endptr; - // If the string can be converted to a long, it's an NSNumber. - long lvalue = strtol(cstring, &endptr, 0); - if (*endptr == 0) { - return [NSNumber numberWithLong:lvalue]; - } - // If the string can be converted to a double, it's an NSNumber. - double dvalue = strtod(cstring, &endptr); - if (*endptr == 0) { - return [NSNumber numberWithDouble:dvalue]; - } - // Otherwise, it's a symbol. - NuSymbol *symbol = [symbolTable symbolWithString:string]; - return symbol; -} - -static id regexWithString(NSString *string) -{ - // If the first character of the string is a forward slash, it's a regular expression literal. - if (([string characterAtIndex:0] == '/') && ([string length] > 1)) { - NSUInteger lastSlash = [string length]; - NSInteger i = lastSlash-1; - while (i > 0) { - if ([string characterAtIndex:i] == '/') { - lastSlash = i; - break; - } - i--; - } - // characters after the last slash specify options. - NSInteger options = 0; - NSInteger j; - for (j = lastSlash+1; j < [string length]; j++) { - unichar c = [string characterAtIndex:j]; - switch (c) { - case 'i': options += NSRegularExpressionCaseInsensitive; break; - case 's': options += NSRegularExpressionDotMatchesLineSeparators; break; - case 'x': options += NSRegularExpressionAllowCommentsAndWhitespace; break; - case 'm': options += NSRegularExpressionAnchorsMatchLines; break; // multiline - default: - [NSException raise:@"NuParseError" format:@"unsupported regular expression option character: %C", c]; - } - } - NSString *pattern = [string substringWithRange:NSMakeRange(1, lastSlash-1)]; - return [NSRegularExpression regularExpressionWithPattern:pattern - options:options - error:NULL]; - } - else { - return nil; - } -} - -#define NU_MAX_PARSER_MACRO_DEPTH 1000 - -@interface NuParser () -{ - int state; - int start; - int depth; - int parens; - int column; - - NSMutableArray* readerMacroStack; - int readerMacroDepth[NU_MAX_PARSER_MACRO_DEPTH]; - - int filenum; - int linenum; - int parseEscapes; - - NuCell *root; - NuCell *current; - bool addToCar; - NSMutableString *hereString; - bool hereStringOpened; - NuStack *stack; - NuStack *opens; - NuSymbolTable *symbolTable; - NSMutableDictionary *context; - NSMutableString *partial; - NSMutableString *comments; - NSString *pattern; // used for herestrings -} -@end - -@implementation NuParser - -+ (const char *) filename:(int)i -{ - if ((i < 0) || (i >= filecount)) - return ""; - else - return filenames[i]; -} - -- (void) setFilename:(const char *) name -{ - if (name == NULL) - filenum = -1; - else { - filenames[filecount] = strdup(name); - filenum = filecount; - filecount++; - } - linenum = 1; -} - -- (const char *) filename -{ - if (filenum == -1) - return NULL; - else - return filenames[filenum]; -} - -- (BOOL) incomplete -{ - return (depth > 0) || (state == PARSE_REGEX) || (state == PARSE_HERESTRING); -} - -- (int) depth -{ - return depth; -} - -- (int) parens -{ - return parens; -} - -- (int) state -{ - return state; -} - -- (NuCell *) root -{ - return [root cdr]; -} - -- (NuStack *) opens -{ - return opens; -} - -- (NSMutableDictionary *) context -{ - return context; -} - -- (NuSymbolTable *) symbolTable -{ - return symbolTable; -} - -- (NSString *) stringValue -{ - return [self description]; -} - -- (const char *) cStringUsingEncoding:(NSStringEncoding) encoding -{ - return [[self stringValue] cStringUsingEncoding:encoding]; -} - -- (void) reset -{ - state = PARSE_NORMAL; - [partial setString:@""]; - depth = 0; - parens = 0; - - [readerMacroStack removeAllObjects]; - - int i; - for (i = 0; i < NU_MAX_PARSER_MACRO_DEPTH; i++) { - readerMacroDepth[i] = 0; - } - - [root release]; - root = current = [[NuCell alloc] init]; - [root setFile:filenum line:linenum]; - [root setCar:[symbolTable symbolWithString:@"progn"]]; - addToCar = false; - [stack release]; - stack = [[NuStack alloc] init]; -} - -- (id) init -{ - if (Nu__null == 0) Nu__null = [NSNull null]; - if ((self = [super init])) { - - filenum = -1; - linenum = 1; - column = 0; - opens = [[NuStack alloc] init]; - // attach to symbol table (or create one if we want a separate table per parser) - symbolTable = [[NuSymbolTable sharedSymbolTable] retain]; - // create top-level context - context = [[NSMutableDictionary alloc] init]; - - readerMacroStack = [[NSMutableArray alloc] init]; - - [context setPossiblyNullObject:self forKey:[symbolTable symbolWithString:@"_parser"]]; - [context setPossiblyNullObject:symbolTable forKey:SYMBOLS_KEY]; - - partial = [[NSMutableString alloc] initWithString:@""]; - - [self reset]; - } - return self; -} - -- (void) close -{ - // break this retain cycle so the parser can be deleted. - [context setPossiblyNullObject:[NSNull null] forKey:[symbolTable symbolWithString:@"_parser"]]; -} - -- (void) dealloc -{ - [opens release]; - [context release]; - [symbolTable release]; - [root release]; - [stack release]; - [comments release]; - [readerMacroStack release]; - [pattern release]; - [partial release]; - [super dealloc]; -} - -- (void) addAtomCell:(id)atom -{ - ParserDebug(@"addAtomCell: depth = %d atom = %@", depth, [atom stringValue]); - - // when we have two consecutive labels, concatenate them. - // this allows us to have ':' characters inside labels. - if ([atom isKindOfClass:[NuSymbol class]] && [atom isLabel]) { - id currentCar = [current car]; - if ([currentCar isKindOfClass:[NuSymbol class]] && [currentCar isLabel]) { - NuSymbol *combinedLabel = [symbolTable symbolWithString:[[currentCar stringValue] stringByAppendingString:[atom stringValue]]]; - [current setCar:combinedLabel]; - return; - } - } - - NuCell *newCell; - if (comments) { - NuCellWithComments *newCellWithComments = [[[NuCellWithComments alloc] init] autorelease]; - [newCellWithComments setComments:comments]; - newCell = newCellWithComments; - [comments release]; - comments = nil; - } - else { - newCell = [[[NuCell alloc] init] autorelease]; - [newCell setFile:filenum line:linenum]; - } - if (addToCar) { - [current setCar:newCell]; - [stack push:current]; - } - else { - [current setCdr:newCell]; - } - current = newCell; - [current setCar:atom]; - addToCar = false; -} - -- (void) openListCell -{ - ParserDebug(@"openListCell: depth = %d", depth); - - depth++; - NuCell *newCell = [[[NuCell alloc] init] autorelease]; - [newCell setFile:filenum line:linenum]; - if (addToCar) { - [current setCar:newCell]; - [stack push:current]; - } - else { - [current setCdr:newCell]; - } - current = newCell; - - addToCar = true; -} - -- (void) openList -{ - ParserDebug(@"openList: depth = %d", depth); - - while ([readerMacroStack count] > 0) { - ParserDebug(@" openList: readerMacro"); - - [self openListCell]; - ++readerMacroDepth[depth]; - ParserDebug(@" openList: ++RMD[%d] = %d", depth, readerMacroDepth[depth]); - [self addAtomCell: - [symbolTable symbolWithString: - [readerMacroStack objectAtIndex:0]]]; - - [readerMacroStack removeObjectAtIndex:0]; - } - - [self openListCell]; -} - -- (void) addAtom:(id)atom -{ - ParserDebug(@"addAtom: depth = %d atom: %@", depth, [atom stringValue]); - - while ([readerMacroStack count] > 0) { - ParserDebug(@" addAtom: readerMacro"); - [self openListCell]; - ++readerMacroDepth[depth]; - ParserDebug(@" addAtom: ++RMD[%d] = %d", depth, readerMacroDepth[depth]); - [self addAtomCell: - [symbolTable symbolWithString:[readerMacroStack objectAtIndex:0]]]; - - [readerMacroStack removeObjectAtIndex:0]; - } - - [self addAtomCell:atom]; - - while (readerMacroDepth[depth] > 0) { - --readerMacroDepth[depth]; - ParserDebug(@" addAtom: --RMD[%d] = %d", depth, readerMacroDepth[depth]); - [self closeList]; - } -} - -- (void) closeListCell -{ - ParserDebug(@"closeListCell: depth = %d", depth); - - --depth; - - if (addToCar) { - [current setCar:[NSNull null]]; - } - else { - [current setCdr:[NSNull null]]; - current = [stack pop]; - } - addToCar = false; - - while (readerMacroDepth[depth] > 0) { - --readerMacroDepth[depth]; - ParserDebug(@" closeListCell: --RMD[%d] = %d", depth, readerMacroDepth[depth]); - [self closeList]; - } -} - -- (void) closeList -{ - ParserDebug(@"closeList: depth = %d", depth); - - [self closeListCell]; -} - --(void) openReaderMacro:(NSString*) operator -{ - [readerMacroStack addObject:operator]; -} - --(void) quoteNextElement -{ - [self openReaderMacro:@"quote"]; -} - --(void) quasiquoteNextElement -{ - [self openReaderMacro:@"quasiquote"]; -} - --(void) quasiquoteEvalNextElement -{ - [self openReaderMacro:@"quasiquote-eval"]; -} - --(void) quasiquoteSpliceNextElement -{ - [self openReaderMacro:@"quasiquote-splice"]; -} - -static int nu_octal_digit_value(unichar c) -{ - int x = (c - '0'); - if ((x >= 0) && (x <= 7)) - return x; - [NSException raise:@"NuParseError" format:@"invalid octal character: %C", c]; - return 0; -} - -static unichar nu_hex_digit_value(unichar c) -{ - int x = (c - '0'); - if ((x >= 0) && (x <= 9)) - return x; - x = (c - 'A'); - if ((x >= 0) && (x <= 5)) - return x + 10; - x = (c - 'a'); - if ((x >= 0) && (x <= 5)) - return x + 10; - [NSException raise:@"NuParseError" format:@"invalid hex character: %C", c]; - return 0; -} - -static unichar nu_octal_digits_to_unichar(unichar c0, unichar c1, unichar c2) -{ - return nu_octal_digit_value(c0)*64 + nu_octal_digit_value(c1)*8 + nu_octal_digit_value(c2); -} - -static unichar nu_hex_digits_to_unichar(unichar c1, unichar c2) -{ - return nu_hex_digit_value(c1)*16 + nu_hex_digit_value(c2); -} - -static unichar nu_unicode_digits_to_unichar(unichar c1, unichar c2, unichar c3, unichar c4) -{ - unichar value = nu_hex_digit_value(c1)*4096 + nu_hex_digit_value(c2)*256 + nu_hex_digit_value(c3)*16 + nu_hex_digit_value(c4); - return value; -} - -static NSUInteger nu_parse_escape_sequences(NSString *string, NSUInteger i, NSUInteger imax, NSMutableString *partial) -{ - i++; - unichar c = [string characterAtIndex:i]; - switch(c) { - case 'n': [partial appendCharacter:0x0a]; break; - case 'r': [partial appendCharacter:0x0d]; break; - case 'f': [partial appendCharacter:0x0c]; break; - case 't': [partial appendCharacter:0x09]; break; - case 'b': [partial appendCharacter:0x08]; break; - case 'a': [partial appendCharacter:0x07]; break; - case 'e': [partial appendCharacter:0x1b]; break; - case 's': [partial appendCharacter:0x20]; break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - // octal. expect two more digits (\nnn). - if (imax < i+2) { - [NSException raise:@"NuParseError" format:@"not enough characters for octal constant"]; - } - char c1 = [string characterAtIndex:++i]; - char c2 = [string characterAtIndex:++i]; - [partial appendCharacter:nu_octal_digits_to_unichar(c, c1, c2)]; - break; - } - case 'x': - { - // hex. expect two more digits (\xnn). - if (imax < i+2) { - [NSException raise:@"NuParseError" format:@"not enough characters for hex constant"]; - } - char c1 = [string characterAtIndex:++i]; - char c2 = [string characterAtIndex:++i]; - [partial appendCharacter:nu_hex_digits_to_unichar(c1, c2)]; - break; - } - case 'u': - { - // unicode. expect four more digits (\unnnn) - if (imax < i+4) { - [NSException raise:@"NuParseError" format:@"not enough characters for unicode constant"]; - } - char c1 = [string characterAtIndex:++i]; - char c2 = [string characterAtIndex:++i]; - char c3 = [string characterAtIndex:++i]; - char c4 = [string characterAtIndex:++i]; - [partial appendCharacter:nu_unicode_digits_to_unichar(c1, c2, c3, c4)]; - break; - } - case 'c': case 'C': - { - // control character. Unsupported, fall through to default. - } - case 'M': - { - // meta character. Unsupported, fall through to default. - } - default: - [partial appendCharacter:c]; - } - return i; -} - --(id) parse:(NSString*)string -{ - if (!string) return [NSNull null]; // don't crash, at least. - - column = 0; - if (state != PARSE_REGEX) - [partial setString:@""]; - else - [partial autorelease]; - - NSUInteger i = 0; - NSUInteger imax = [string length]; - for (i = 0; i < imax; i++) { - column++; - unichar stri = [string characterAtIndex:i]; - switch (state) { - case PARSE_NORMAL: - switch(stri) { - case '(': - ParserDebug(@"Parser: ( %d on line %d", column, linenum); - [opens push:[NSNumber numberWithInt:column]]; - parens++; - if ([partial length] == 0) { - [self openList]; - } - break; - case ')': - ParserDebug(@"Parser: ) %d on line %d", column, linenum); - [opens pop]; - parens--; - if (parens < 0) parens = 0; - if ([partial length] > 0) { - [self addAtom:atomWithString(partial, symbolTable)]; - [partial setString:@""]; - } - if (depth > 0) { - [self closeList]; - } - else { - [NSException raise:@"NuParseError" format:@"no open sexpr"]; - } - break; - case '"': - { - state = PARSE_STRING; - parseEscapes = YES; - [partial setString:@""]; - break; - } - case '-': - case '+': - { - if ((i+1 < imax) && ([string characterAtIndex:i+1] == '"')) { - state = PARSE_STRING; - parseEscapes = (stri == '+'); - [partial setString:@""]; - i++; - } - else { - [partial appendCharacter:stri]; - } - break; - } - case '/': - { - if (i+1 < imax) { - unichar nextc = [string characterAtIndex:i+1]; - if (nextc == ' ') { - [partial appendCharacter:stri]; - } - else { - state = PARSE_REGEX; - [partial setString:@""]; - [partial appendCharacter:'/']; - } - } - else { - [partial appendCharacter:stri]; - } - break; - } - case ':': - [partial appendCharacter:':']; - // ordinarily we break symbols on trailing colons. - // one exception: we don't do it when the symbol begins with an ampersand. - // that's because these symbols are usually markup generators, and - // sometimes we want to generate markup tags that contain colons. - if ([partial characterAtIndex:0] != '&') { - [self addAtom:atomWithString(partial, symbolTable)]; - [partial setString:@""]; - } - break; - case '\'': - { - // try to parse a character literal. - // if that doesn't work, then interpret the quote as the quote operator. - bool isACharacterLiteral = false; - int characterLiteralValue; - if (i + 2 < imax) { - if ([string characterAtIndex:i+1] != '\\') { - if ([string characterAtIndex:i+2] == '\'') { - isACharacterLiteral = true; - characterLiteralValue = [string characterAtIndex:i+1]; - i = i + 2; - } - else if ((i + 5 < imax) && - isalnum([string characterAtIndex:i+1]) && - isalnum([string characterAtIndex:i+2]) && - isalnum([string characterAtIndex:i+3]) && - isalnum([string characterAtIndex:i+4]) && - ([string characterAtIndex:i+5] == '\'')) { - characterLiteralValue = - ((([string characterAtIndex:i+1]*256 - + [string characterAtIndex:i+2])*256 - + [string characterAtIndex:i+3])*256 - + [string characterAtIndex:i+4]); - isACharacterLiteral = true; - i = i + 5; - } - } - else { - // look for an escaped character - NSUInteger newi = nu_parse_escape_sequences(string, i+1, imax, partial); - if ([partial length] > 0) { - isACharacterLiteral = true; - characterLiteralValue = [partial characterAtIndex:0]; - [partial setString:@""]; - i = newi; - // make sure that we have a closing single-quote - if ((i + 1 < imax) && ([string characterAtIndex:i+1] == '\'')) { - i = i + 1;// move past the closing single-quote - } - else { - [NSException raise:@"NuParseError" format:@"missing close quote from character literal"]; - } - } - } - } - if (isACharacterLiteral) { - [self addAtom:[NSNumber numberWithInt:characterLiteralValue]]; - } - else { - [self quoteNextElement]; - } - break; - } - case '`': - { - [self quasiquoteNextElement]; - break; - } - case ',': - { - if ((i + 1 < imax) && ([string characterAtIndex:i+1] == '@')) { - [self quasiquoteSpliceNextElement]; - i = i + 1; - } - else { - [self quasiquoteEvalNextElement]; - } - break; - } - case '\n': // end of line - column = 0; - linenum++; - case ' ': // end of token - case '\t': - case 0: // end of string - if ([partial length] > 0) { - [self addAtom:atomWithString(partial, symbolTable)]; - [partial setString:@""]; - } - break; - case ';': - case '#': - if ((stri == '#') && ([partial length] > 0)) { - // this allows us to include '#' in symbols (but not as the first character) - [partial appendCharacter:'#']; - } else { - if ([partial length]) { - NuSymbol *symbol = [symbolTable symbolWithString:partial]; - [self addAtom:symbol]; - [partial setString:@""]; - } - state = PARSE_COMMENT; - } - break; - case '<': - if ((i+3 < imax) && ([string characterAtIndex:i+1] == '<') - && (([string characterAtIndex:i+2] == '-') || ([string characterAtIndex:i+2] == '+'))) { - // parse a here string - state = PARSE_HERESTRING; - parseEscapes = ([string characterAtIndex:i+2] == '+'); - // get the tag to match - NSUInteger j = i+3; - while ((j < imax) && ([string characterAtIndex:j] != '\n')) { - j++; - } - [pattern release]; - pattern = [[string substringWithRange:NSMakeRange(i+3, j-(i+3))] retain]; - //NSLog(@"herestring pattern: %@", pattern); - [partial setString:@""]; - // skip the newline - i = j; - //NSLog(@"parsing herestring that ends with %@ from %@", pattern, [string substringFromIndex:i]); - hereString = nil; - hereStringOpened = true; - break; - } - // if this is not a here string, fall through to the general handler - default: - [partial appendCharacter:stri]; - } - break; - case PARSE_HERESTRING: - //NSLog(@"pattern %@", pattern); - if ((stri == [pattern characterAtIndex:0]) && - (i + [pattern length] < imax) && - ([pattern isEqual:[string substringWithRange:NSMakeRange(i, [pattern length])]])) { - // everything up to here is the string - NSString *string = [[[NSString alloc] initWithString:partial] autorelease]; - [partial setString:@""]; - if (!hereString) - hereString = [[[NSMutableString alloc] init] autorelease]; - else - [hereString appendString:@"\n"]; - [hereString appendString:string]; - if (hereString == nil) - hereString = [NSMutableString string]; - //NSLog(@"got herestring **%@**", hereString); - [self addAtom:hereString]; - // to continue, set i to point to the next character after the tag - i = i + [pattern length] - 1; - //NSLog(@"continuing parsing with:%s", &str[i+1]); - //NSLog(@"ok------------"); - state = PARSE_NORMAL; - start = -1; - } - else { - if (parseEscapes && (stri == '\\')) { - // parse escape sequencs in here strings - i = nu_parse_escape_sequences(string, i, imax, partial); - } - else { - [partial appendCharacter:stri]; - } - } - break; - case PARSE_STRING: - switch(stri) { - case '"': - { - state = PARSE_NORMAL; - NSString *string = [NSString stringWithString:partial]; - //NSLog(@"parsed string:%@:", string); - [self addAtom:string]; - [partial setString:@""]; - break; - } - case '\n': - { - column = 0; - linenum++; - NSString *string = [[NSString alloc] initWithString:partial]; - [NSException raise:@"NuParseError" format:@"partial string (terminated by newline): %@", string]; - [partial setString:@""]; - break; - } - case '\\': - { // parse escape sequences in strings - if (parseEscapes) { - i = nu_parse_escape_sequences(string, i, imax, partial); - } - else { - [partial appendCharacter:stri]; - } - break; - } - default: - { - [partial appendCharacter:stri]; - } - } - break; - case PARSE_REGEX: - switch(stri) { - case '/': // that's the end of it - { - [partial appendCharacter:'/']; - i++; - // add any remaining option characters - while (i < imax) { - unichar nextc = [string characterAtIndex:i]; - if ((nextc >= 'a') && (nextc <= 'z')) { - [partial appendCharacter:nextc]; - i++; - } - else { - i--; // back up to revisit this character - break; - } - } - [self addAtom:regexWithString(partial)]; - [partial setString:@""]; - state = PARSE_NORMAL; - break; - } - case '\\': - { - [partial appendCharacter:stri]; - i++; - [partial appendCharacter:[string characterAtIndex:i]]; - break; - } - default: - { - [partial appendCharacter:stri]; - } - } - break; - case PARSE_COMMENT: - switch(stri) { - case '\n': - { - if (!comments) comments = [[NSMutableString alloc] init]; - else [comments appendString:@"\n"]; - [comments appendString:[[[NSString alloc] initWithString:partial] autorelease]]; - [partial setString:@""]; - column = 0; - linenum++; - state = PARSE_NORMAL; - break; - } - default: - { - [partial appendCharacter:stri]; - } - } - } - } - // close off anything that is still being scanned. - if (state == PARSE_NORMAL) { - if ([partial length] > 0) { - [self addAtom:atomWithString(partial, symbolTable)]; - } - [partial setString:@""]; - } - else if (state == PARSE_COMMENT) { - if (!comments) comments = [[NSMutableString alloc] init]; - [comments appendString:[[[NSString alloc] initWithString:partial] autorelease]]; - [partial setString:@""]; - column = 0; - linenum++; - state = PARSE_NORMAL; - } - else if (state == PARSE_STRING) { - [NSException raise:@"NuParseError" format:@"partial string (terminated by newline): %@", partial]; - } - else if (state == PARSE_HERESTRING) { - if (hereStringOpened) { - hereStringOpened = false; - } - else { - if (hereString) { - [hereString appendString:@"\n"]; - } - else { - hereString = [[NSMutableString alloc] init]; - } - [hereString appendString:partial]; - [partial setString:@""]; - } - } - else if (state == PARSE_REGEX) { - // we stay in this state and leave the regex open. - [partial appendCharacter:'\n']; - [partial retain]; - } - if ([self incomplete]) { - return [NSNull null]; - } - else { - NuCell *expressions = root; - root = nil; - [self reset]; - [expressions autorelease]; - return expressions; - } -} - -- (id) parse:(NSString *)string asIfFromFilename:(const char *) filename; -{ - [self setFilename:filename]; - id result = [self parse:string]; - [self setFilename:NULL]; - return result; -} - -- (void) newline -{ - linenum++; -} - -- (id) eval: (id) code -{ - return [code evalWithContext:context]; -} - -- (id) valueForKey:(NSString *)string -{ - return [self eval:[self parse:string]]; -} - -- (void) setValue:(id)value forKey:(NSString *)string -{ - [context setObject:value forKey:[symbolTable symbolWithString:string]]; -} - -- (NSString *) parseEval:(NSString *)string -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NuCell *expressions = [self parse:string]; - id result = [[expressions evalWithContext:context] stringValue]; - [result retain]; - [pool drain]; - [result autorelease]; - return result; -} - -#if !TARGET_OS_IPHONE -- (int) interact -{ - printf("Nu Shell.\n"); - - char* homedir = getenv("HOME"); - char history_file[FILENAME_MAX]; - int valid_history_file = 0; - - if (homedir) { // Not likely, but could be NULL - // Since we're getting something from the shell environment, - // try to be safe about it - int n = snprintf(history_file, FILENAME_MAX, "%s/.nush_history", homedir); - if (n <= FILENAME_MAX) { - read_history(history_file); - valid_history_file = 1; - } - } - - const char *unbufferedIO = getenv("NSUnbufferedIO"); - if (unbufferedIO && !strcmp(unbufferedIO, "YES")) { - system("stty -echo"); // Turn off echoing to avoid duplicated input. Surely there's a better way to do this. - puts("It looks like you are running in the Xcode debugger console. Beware: command history is broken."); - } - - do { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - char *prompt = ([self incomplete] ? "- " : "% "); -#ifdef IPHONENOREADLINE - puts(prompt); - char line[1024]; // careful - int count = gets(line); -#else - char *line = readline(prompt); - if (line && *line && strcmp(line, "quit")) - add_history (line); -#endif - if(!line || !strcmp(line, "quit")) { - break; - } - else { - id progn = nil; - - @try - { - progn = [[self parse:[NSString stringWithCString:line encoding:NSUTF8StringEncoding]] retain]; - } - @catch (NuException* nuException) { - printf("%s\n", [[nuException dump] cStringUsingEncoding:NSUTF8StringEncoding]); - [self reset]; - } - @catch (id exception) { - printf("%s: %s\n", - [[exception name] cStringUsingEncoding:NSUTF8StringEncoding], - [[exception reason] cStringUsingEncoding:NSUTF8StringEncoding]); - [self reset]; - } - - if (progn && (progn != [NSNull null])) { - id cursor = [progn cdr]; - while (cursor && (cursor != [NSNull null])) { - if ([cursor car] != [NSNull null]) { - id expression = [cursor car]; - //printf("evaluating %s\n", [[expression stringValue] cStringUsingEncoding:NSUTF8StringEncoding]); - - @try - { - id result = [expression evalWithContext:context]; - if (result) { - id stringToDisplay; - if ([result respondsToSelector:@selector(escapedStringRepresentation)]) { - stringToDisplay = [result escapedStringRepresentation]; - } - else { - stringToDisplay = [result stringValue]; - } - printf("%s\n", [stringToDisplay cStringUsingEncoding:NSUTF8StringEncoding]); - } - } - @catch (NuException* nuException) { - printf("%s\n", [[nuException dump] cStringUsingEncoding:NSUTF8StringEncoding]); - } - @catch (id exception) { - printf("%s: %s\n", - [[exception name] cStringUsingEncoding:NSUTF8StringEncoding], - [[exception reason] cStringUsingEncoding:NSUTF8StringEncoding]); - } - } - cursor = [cursor cdr]; - } - } - [progn release]; - } - [pool release]; - } while(1); - - if (valid_history_file) { - write_history(history_file); - } - - return 0; -} -#endif -+ (int) main -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NuParser *parser = [Nu sharedParser]; - int result = [parser interact]; - [pool drain]; - return result; -} - -@end - -#pragma mark - NuPointer.m - -@interface NuPointer () -{ - void *pointer; - NSString *typeString; - bool thePointerIsMine; -} -@end - -@implementation NuPointer - -- (id) init -{ - if ((self = [super init])) { - pointer = 0; - typeString = nil; - thePointerIsMine = NO; - } - return self; -} - -- (void *) pointer {return pointer;} - -- (void) setPointer:(void *) p -{ - pointer = p; -} - -- (NSString *) typeString {return typeString;} - -- (id) object -{ - return pointer; -} - -- (void) setTypeString:(NSString *) s -{ - [s retain]; - [typeString release]; - typeString = s; -} - -- (void) allocateSpaceForTypeString:(NSString *) s -{ - if (thePointerIsMine) - free(pointer); - [self setTypeString:s]; - const char *type = [s cStringUsingEncoding:NSUTF8StringEncoding]; - while (*type && (*type != '^')) - type++; - if (*type) - type++; - //NSLog(@"allocating space for type %s", type); - pointer = value_buffer_for_objc_type(type); - thePointerIsMine = YES; -} - -- (void) dealloc -{ - [typeString release]; - if (thePointerIsMine) - free(pointer); - [super dealloc]; -} - -- (id) value -{ - const char *type = [typeString cStringUsingEncoding:NSUTF8StringEncoding]; - while (*type && (*type != '^')) - type++; - if (*type) - type++; - //NSLog(@"getting value for type %s", type); - return get_nu_value_from_objc_value(pointer, type); -} - -@end - -#pragma mark - NuProfiler.h - -@interface NuProfileStackElement : NSObject -{ -@public - NSString *name; - uint64_t start; - NuProfileStackElement *parent; -} - -@end - -@interface NuProfileTimeSlice : NSObject -{ -@public - float time; - int count; -} - -@end - -@implementation NuProfileStackElement - -- (NSString *) name {return name;} -- (uint64_t) start {return start;} -- (NuProfileStackElement *) parent {return parent;} - -- (NSString *) description -{ - return [NSString stringWithFormat:@"name:%@ start:%llx", name, start]; -} - -@end - -@implementation NuProfileTimeSlice - -- (float) time {return time;} -- (int) count {return count;} - -- (NSString *) description -{ - return [NSString stringWithFormat:@"time:%f count:%d", time, count]; -} - -@end - -@interface NuProfiler () -{ - NSMutableDictionary *sections; - NuProfileStackElement *stack; -} -@end - -@implementation NuProfiler - -static NuProfiler *defaultProfiler = nil; - -+ (NuProfiler *) defaultProfiler -{ - if (!defaultProfiler) - defaultProfiler = [[NuProfiler alloc] init]; - return defaultProfiler; -} - -- (NuProfiler *) init -{ - self = [super init]; - sections = [[NSMutableDictionary alloc] init]; - stack = nil; - return self; -} - -- (void) start:(NSString *) name -{ -#ifdef DARWIN - NuProfileStackElement *stackElement = [[NuProfileStackElement alloc] init]; - stackElement->name = [name retain]; - stackElement->start = mach_absolute_time(); - stackElement->parent = stack; - stack = stackElement; -#endif -} - -- (void) stop -{ -#ifdef DARWIN - if (stack) { - uint64_t current_time = mach_absolute_time(); - uint64_t time_delta = current_time - stack->start; - struct mach_timebase_info info; - mach_timebase_info(&info); - float timeDelta = 1e-9 * time_delta * (double) info.numer / info.denom; - //NSNumber *delta = [NSNumber numberWithFloat:timeDelta]; - NuProfileTimeSlice *entry = [sections objectForKey:stack->name]; - if (!entry) { - entry = [[[NuProfileTimeSlice alloc] init] autorelease]; - entry->count = 1; - entry->time = timeDelta; - [sections setObject:entry forKey:stack->name]; - } - else { - entry->count++; - entry->time += timeDelta; - } - [stack->name release]; - NuProfileStackElement *top = stack; - stack = stack->parent; - [top release]; - } -#endif -} - -- (NSMutableDictionary *) sections -{ - return sections; -} - -- (void) reset -{ - [sections removeAllObjects]; - while (stack) { - NuProfileStackElement *top = stack; - stack = stack->parent; - [top release]; - } -} - -@end - -#pragma mark - NuProperty.m - -@interface NuProperty () -{ - objc_property_t p; -} -@end - -@implementation NuProperty - -+ (NuProperty *) propertyWithProperty:(objc_property_t) property { - return [[[self alloc] initWithProperty:property] autorelease]; -} - -- (id) initWithProperty:(objc_property_t) property -{ - if ((self = [super init])) { - p = property; - } - return self; -} - -- (NSString *) name -{ - return [NSString stringWithCString:property_getName(p) encoding:NSUTF8StringEncoding]; -} - -@end - -#pragma mark - NuReference.m - -@interface NuReference () -{ - id *pointer; - bool thePointerIsMine; -} -@end - -@implementation NuReference - -- (id) init -{ - if ((self = [super init])) { - pointer = 0; - thePointerIsMine = false; - } - return self; -} - -- (id) value {return pointer ? *pointer : nil;} - -- (void) setValue:(id) v -{ - if (!pointer) { - pointer = (id *) malloc (sizeof (id)); - *pointer = nil; - thePointerIsMine = true; - } - [v retain]; - [(*pointer) release]; - (*pointer) = v; -} - -- (void) setPointer:(id *) p -{ - if (thePointerIsMine) { - free(pointer); - thePointerIsMine = false; - } - pointer = p; -} - -- (id *) pointerToReferencedObject -{ - if (!pointer) { - pointer = (id *) malloc (sizeof (id)); - *pointer = nil; - thePointerIsMine = true; - } - return pointer; -} - -- (void) retainReferencedObject -{ - [(*pointer) retain]; -} - -- (void) dealloc -{ - if (thePointerIsMine) - free(pointer); - [super dealloc]; -} - -@end -#pragma mark - NuRegex.m - -@implementation NSTextCheckingResult (NuRegexMatch) -/*! - @method regex - The regular expression used to make this match. */ -- (NSRegularExpression *)regex { - return [self regularExpression]; -} - -/*! - @method count - The number of capturing subpatterns, including the pattern itself. */ -- (NSUInteger)count { - return [self numberOfRanges]; -} - -/*! - @method group - Returns the part of the target string that matched the pattern. */ -- (NSString *)group { - return [self groupAtIndex:0]; -} - -/*! - @method groupAtIndex: - Returns the part of the target string that matched the subpattern at the given index or nil if it wasn't matched. The subpatterns are indexed in order of their opening parentheses, 0 is the entire pattern, 1 is the first capturing subpattern, and so on. */ -- (NSString *)groupAtIndex:(int)i { - NSRange range = [self rangeAtIndex:i]; - NSString *string = [self associatedObjectForKey:@"string"]; - if (string && (range.location != NSNotFound)) { - return [string substringWithRange:range]; - } else { - return nil; - } -} - -/*! - @method string - Returns the target string. */ -- (NSString *)string { - return [self associatedObjectForKey:@"string"]; -} - -@end - -@implementation NSRegularExpression (NuRegex) - -/*! - @method regexWithPattern: - Creates a new regex using the given pattern string. Returns nil if the pattern string is invalid. */ -+ (id)regexWithPattern:(NSString *)pattern { - return [self regularExpressionWithPattern:pattern - options:0 - error:NULL]; -} - -/*! - @method regexWithPattern:options: - Creates a new regex using the given pattern string and option flags. Returns nil if the pattern string is invalid. */ -+ (id)regexWithPattern:(NSString *)pattern options:(int)options { - return [self regularExpressionWithPattern:pattern - options:options - error:NULL]; -} - -/*! - @method initWithPattern: - Initializes the regex using the given pattern string. Returns nil if the pattern string is invalid. */ -- (id)initWithPattern:(NSString *)pattern { - return [self initWithPattern:pattern - options:0 - error:NULL]; -} - -/*! - @method initWithPattern:options: - Initializes the regex using the given pattern string and option flags. Returns nil if the pattern string is invalid. */ -- (id)initWithPattern:(NSString *)pattern options:(int)optionFlags { - return [self initWithPattern:pattern - options:optionFlags - error:NULL]; -} - - -/*! - @method findInString: - Calls findInString:range: using the full range of the target string. */ -- (NSTextCheckingResult *)findInString:(NSString *)string { - NSTextCheckingResult *result = [self firstMatchInString:string - options:0 - range:NSMakeRange(0,[string length])]; - if (result) { - [result setRetainedAssociatedObject:string forKey:@"string"]; - } - return result; -} - -/*! - @method findInString:range: - Returns an NuRegexMatch for the first occurrence of the regex in the given range of the target string or nil if none is found. */ -- (NSTextCheckingResult *)findInString:(NSString *)string range:(NSRange)range { - NSTextCheckingResult *result = [self firstMatchInString:string - options:0 - range:range]; - if (result) { - [result setRetainedAssociatedObject:string forKey:@"string"]; - } - return result; -} - -/*! - @method findAllInString: - Calls findAllInString:range: using the full range of the target string. */ -- (NSArray *)findAllInString:(NSString *)string { - NSArray *result = [self matchesInString:string - options:0 - range:NSMakeRange(0, [string length])]; - if (result) { - for (NSObject *match in result) { - [match setRetainedAssociatedObject:string forKey:@"string"]; - } - } - return result; -} - -/*! - @method findAllInString:range: - Returns an array of all non-overlapping occurrences of the regex in the given range of the target string. The members of the array are NuRegexMatches. */ -- (NSArray *)findAllInString:(NSString *)string range:(NSRange)range { - NSArray *result = [self matchesInString:string options:0 range:range]; - if (result) { - for (NSObject *match in result) { - [match setRetainedAssociatedObject:string forKey:@"string"]; - } - } - return result; -} - -/*! - @method replaceWithString:inString: - Calls replaceWithString:inString:limit: with no limit. */ -- (NSString *)replaceWithString:(NSString *)replacement inString:(NSString *)string { - return [self stringByReplacingMatchesInString:string - options:0 - range:NSMakeRange(0, [string length]) - withTemplate:replacement]; - -} - -#ifdef LINUX -- (BOOL) isEqual:(NSRegularExpression *)other -{ - return ([other isKindOfClass:[NSRegularExpression class]] && - [[self pattern] isEqual:[other pattern]] && - ([self options] == [other options])); -} -#endif - -@end - -#pragma mark - NuStack.m - -@interface NuStack () -{ - NSMutableArray *storage; -} -@end - -@implementation NuStack -- (id) init -{ - if ((self = [super init])) { - storage = [[NSMutableArray alloc] init]; - } - return self; -} - -- (void) dealloc -{ - [storage release]; - [super dealloc]; -} - -- (void) push:(id) object -{ - [storage addObject:object]; -} - -- (id) pop -{ - if ([storage count] > 0) { - id object = [[storage lastObject] retain]; - [storage removeLastObject]; - [object autorelease]; - return object; - } - else { - return nil; - } -} - -- (NSUInteger) depth -{ - return [storage count]; -} - -- (id) top -{ - return [storage lastObject]; -} - -- (id) objectAtIndex:(int) i -{ - return [storage objectAtIndex:i]; -} - -- (void) dump -{ - for (NSInteger i = [storage count]-1; i >= 0; i--) { - NSLog(@"stack: %@", [storage objectAtIndex:i]); - } -} - -@end - -#pragma mark - NuSuper.m -@interface NuSuper () -{ - id object; - Class class; -} -@end - -@implementation NuSuper - -- (NuSuper *) initWithObject:(id) o ofClass:(Class) c -{ - if ((self = [super init])) { - object = o; // weak reference - class = c; // weak reference - } - return self; -} - -+ (NuSuper *) superWithObject:(id) o ofClass:(Class) c -{ - return [[[self alloc] initWithObject:o ofClass:c] autorelease]; -} - -- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - // By themselves, Objective-C objects evaluate to themselves. - if (!cdr || (cdr == [NSNull null])) - return object; - - //NSLog(@"messaging super with %@", [cdr stringValue]); - // But when they're at the head of a list, the list is converted to a message and sent to the object - - NSMutableArray *args = [[NSMutableArray alloc] init]; - id cursor = cdr; - id selector = [cursor car]; - NSMutableString *selectorString = [NSMutableString stringWithString:[selector stringValue]]; - cursor = [cursor cdr]; - while (cursor && (cursor != [NSNull null])) { - [args addObject:[[cursor car] evalWithContext:context]]; - cursor = [cursor cdr]; - if (cursor && (cursor != [NSNull null])) { - [selectorString appendString:[[cursor car] stringValue]]; - cursor = [cursor cdr]; - } - } - SEL sel = sel_getUid([selectorString cStringUsingEncoding:NSUTF8StringEncoding]); - - // we're going to send the message to the handler of its superclass instead of one defined for its class. - Class c = class_getSuperclass(class); - Method m = class_getInstanceMethod(c, sel); - if (!m) m = class_getClassMethod(c, sel); - - id result; - if (m) { - result = nu_calling_objc_method_handler(object, m, args); - } - else { - NSLog(@"can't find function in superclass!"); - result = self; - } - [args release]; - return result; -} - -@end - -#pragma mark - NuSwizzles.m - -@interface NSCFDictionarySwizzles : NSObject {} -@end - -@implementation NSCFDictionarySwizzles - -- (void)nuSetObject:(id)anObject forKey:(id)aKey -{ - [self nuSetObject:((anObject == nil) ? (id)[NSNull null] : anObject) forKey:aKey]; -} - -@end - -@interface NSCFArraySwizzles : NSObject {} -@end - -@implementation NSCFArraySwizzles - -- (void)nuAddObject:(id)anObject -{ - [self nuAddObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; -} - -- (void)nuInsertObject:(id)anObject atIndex:(int)index -{ - [self nuInsertObject:((anObject == nil) ? (id)[NSNull null] : anObject) atIndex:index]; -} - -- (void)nuReplaceObjectAtIndex:(int)index withObject:(id)anObject -{ - [self nuReplaceObjectAtIndex:index withObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; -} - -@end - -@interface NSCFSetSwizzles : NSObject {} -@end - -@implementation NSCFSetSwizzles - -- (void)nuAddObject:(id)anObject -{ - [self nuAddObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; -} - -@end - -static void nu_swizzleContainerClasses() -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - Class NSCFDictionary = NSClassFromString(@"NSCFDictionary"); - Class NSCFArray = NSClassFromString(@"NSCFArray"); - Class NSCFSet = NSClassFromString(@"NSCFSet"); - [NSCFDictionary include:[NuClass classWithName:@"NSCFDictionarySwizzles"]]; - [NSCFArray include:[NuClass classWithName:@"NSCFArraySwizzles"]]; - [NSCFSet include:[NuClass classWithName:@"NSCFSetSwizzles"]]; - [NSCFDictionary exchangeInstanceMethod:@selector(setObject:forKey:) withMethod:@selector(nuSetObject:forKey:)]; - [NSCFArray exchangeInstanceMethod:@selector(addObject:) withMethod:@selector(nuAddObject:)]; - [NSCFArray exchangeInstanceMethod:@selector(insertObject:atIndex:) withMethod:@selector(nuInsertObject:atIndex:)]; - [NSCFArray exchangeInstanceMethod:@selector(replaceObjectAtIndex:withObject:) withMethod:@selector(nuReplaceObjectAtIndex:withObject:)]; - [NSCFSet exchangeInstanceMethod:@selector(addObject:) withMethod:@selector(nuAddObject:)]; - [pool drain]; -} - -#pragma mark - NuSymbol.m - -@interface NuSymbol () -{ - NuSymbolTable *table; - id value; -@public // only for use by the symbol table - bool isLabel; - bool isGensym; // in macro evaluation, symbol is replaced with an automatically-generated unique symbol. - NSString *stringValue; // let's keep this for efficiency -} -- (void) _setStringValue:(NSString *) string; -@end - -@interface NuSymbolTable () -{ - NSMutableDictionary *symbol_table; -} -@end - -void load_builtins(NuSymbolTable *); - -static NuSymbolTable *sharedSymbolTable = 0; - - -@implementation NuSymbolTable - -+ (NuSymbolTable *) sharedSymbolTable -{ - if (!sharedSymbolTable) { - sharedSymbolTable = [[self alloc] init]; - load_builtins(sharedSymbolTable); - } - return sharedSymbolTable; -} - -- (void) dealloc -{ - NSLog(@"WARNING: deleting a symbol table. Leaking stored symbols."); - [super dealloc]; -} - -// Designated initializer -- (NuSymbol *) symbolWithString:(NSString *)string -{ - if (!symbol_table) symbol_table = [[NSMutableDictionary alloc] init]; - - // If the symbol is already in the table, return it. - NuSymbol *symbol; - symbol = [symbol_table objectForKey:string]; - if (symbol) { - return symbol; - } - - // If not, create it. - symbol = [[[NuSymbol alloc] init] autorelease]; // keep construction private - [symbol _setStringValue:string]; - - // Put the new symbol in the symbol table and return it. - [symbol_table setObject:symbol forKey:string]; - return symbol; -} - -- (NuSymbol *) lookup:(NSString *) string -{ - return [symbol_table objectForKey:string]; -} - -- (NSArray *) all -{ - return [symbol_table allValues]; -} - -- (void) removeSymbol:(NuSymbol *) symbol -{ - [symbol_table removeObjectForKey:[symbol stringValue]]; -} - -@end - -@implementation NuSymbol - -- (void) _setStringValue:(NSString *) string { - self->stringValue = [string copy]; - - const char *cstring = [string cStringUsingEncoding:NSUTF8StringEncoding]; - NSUInteger len = strlen(cstring); - self->isLabel = (cstring[len - 1] == ':'); - self->isGensym = (len > 2) && (cstring[0] == '_') && (cstring[1] == '_'); -} - -- (void) dealloc -{ - [stringValue release]; - [super dealloc]; -} - -- (BOOL) isEqual: (NuSymbol *)other -{ - return (self == other) ? 1l : 0l; -} - -- (id) value -{ - return value; -} - -- (void) setValue:(id)v -{ - [v retain]; - [value release]; - value = v; -} - -- (NSString *) description -{ - return stringValue; -} - -- (NSString *) stringValue -{ - return stringValue; -} - -- (int) intValue -{ - return (value == [NSNull null]) ? 0 : 1; -} - -- (bool) isGensym -{ - return isGensym; -} - -- (bool) isLabel -{ - return isLabel; -} - -- (NSString *) labelName -{ - if (isLabel) - return [[self stringValue] substringToIndex:[[self stringValue] length] - 1]; - else - return [self stringValue]; -} - -- (NSString *) labelValue -{ - if (isLabel) - return [[self stringValue] substringToIndex:[[self stringValue] length] - 1]; - else - return [self stringValue]; -} - -- (id) evalWithContext:(NSMutableDictionary *)context -{ - - char c = (char) [[self stringValue] characterAtIndex:0]; - // If the symbol is a class instance variable, find "self" and ask it for the ivar value. - if (c == '@') { - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id object = [context lookupObjectForKey:[symbolTable symbolWithString:@"self"]]; - if (!object) return [NSNull null]; - id ivarName = [[self stringValue] substringFromIndex:1]; - id result = [object valueForIvar:ivarName]; - return result ? result : (id) [NSNull null]; - } - - // Next, try to find the symbol in the local evaluation context. - id valueInContext = [context lookupObjectForKey:self]; - if (valueInContext) - return valueInContext; - -#if 0 - // if it's not there, try the next context up - id parentContext = [context objectForKey:@"context"]; - if (parentContext) { - valueInContext = [parentContext objectForKey:self]; - if (valueInContext) - return valueInContext; - } -#endif - - // Next, return the global value assigned to the value. - if (value) - return value; - - // If the symbol is a label (ends in ':'), then it will evaluate to itself. - if (isLabel) - return self; - - // If the symbol is still unknown, try to find a class with this name. - id className = [self stringValue]; - // the symbol should retain its value. - value = [[NuClass classWithName:className] retain]; - if (value) - return value; - - // Undefined globals evaluate to null. - if (c == '$') - return [NSNull null]; - - // Now we try looking in the bridge support dictionaries. - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - NuSymbol *bridgeSupportSymbol = [symbolTable symbolWithString:@"BridgeSupport"]; - NSDictionary *bridgeSupport = bridgeSupportSymbol ? [bridgeSupportSymbol value] : nil; - if (bridgeSupport) { - // is it an enum? - id enumValue = [[bridgeSupport valueForKey:@"enums"] valueForKey:[self stringValue]]; - if (enumValue) { - value = enumValue; - return value; - } - // is it a constant? - id constantSignature = [[bridgeSupport valueForKey:@"constants"] valueForKey:[self stringValue]]; - if (constantSignature) { - value = [[NuBridgedConstant constantWithName:[self stringValue] signature:constantSignature] retain]; - return value; - } - // is it a function? - id functionSignature = [[bridgeSupport valueForKey:@"functions"] valueForKey:[self stringValue]]; - if (functionSignature) { - value = [[NuBridgedFunction functionWithName:[self stringValue] signature:functionSignature] retain]; - return value; - } - } - - // Automatically create markup operators - if ([[self stringValue] characterAtIndex:0] == '&') { - NuMarkupOperator *newOperator = [NuMarkupOperator operatorWithTag:[[self stringValue] substringFromIndex:1]]; - [self setValue:newOperator]; - return newOperator; - } - - // Still-undefined symbols throw an exception. - NSMutableString *errorDescription = [NSMutableString stringWithFormat:@"undefined symbol %@", [self stringValue]]; - id expression = [context lookupObjectForKey:[symbolTable symbolWithString:@"_expression"]]; - if (expression) { - [errorDescription appendFormat:@" while evaluating expression %@", [expression stringValue]]; - const char *filename = nu_parsedFilename([expression file]); - if (filename) { - [errorDescription appendFormat:@" at %s:%d", filename, [expression line]]; - } - } - [NSException raise:@"NuUndefinedSymbol" format:@"%@", errorDescription]; - return [NSNull null]; -} - -- (NSComparisonResult) compare:(NuSymbol *) anotherSymbol -{ - return [stringValue compare:anotherSymbol->stringValue]; -} - -- (id) copyWithZone:(NSZone *) zone -{ - // Symbols are unique, so we don't copy them, but we retain them again since copies are automatically retained. - return [self retain]; -} - -- (void)encodeWithCoder:(NSCoder *)coder -{ - [coder encodeObject:[self stringValue]]; -} - -- (id) initWithCoder:(NSCoder *)coder -{ - [super init]; - [self autorelease]; - return [[[NuSymbolTable sharedSymbolTable] symbolWithString:[coder decodeObject]] retain]; -} - -@end - -#pragma mark - NuTestHelper.m - -static BOOL verbose_helper = false; - -@protocol NuTestProxy - -#ifdef DARWIN -- (CGRect) CGRectValue; -- (CGPoint) CGPointValue; -- (CGSize) CGSizeValue; -#endif -- (NSRange) NSRangeValue; - -@end - -@interface NuTestHelper : NSObject -{ -} - -@end - -static int deallocationCount = 0; - -@implementation NuTestHelper - -+ (void) cycle -{ - NuTestHelper *object = [[NuTestHelper alloc] init]; -//Class before = object->isa; - objc_setAssociatedObject(object, @"number", @"123", OBJC_ASSOCIATION_RETAIN); -//Class after = object->isa; -//SEL cxx_destruct = sel_registerName(".cxx_destruct"); -//NSLog(@"class %@ %@", before, after); -//NSLog(@"responds? %d", [object respondsToSelector:cxx_destruct]); - [object release]; -} - -+ (void) setVerbose:(BOOL) v -{ - verbose_helper = v; -} - -+ (BOOL) verbose -{ - return verbose_helper; -} - -+ (id) helperInObjCUsingAllocInit -{ - id object = [[[NuTestHelper alloc] init] autorelease]; - return object; -} - -+ (id) helperInObjCUsingNew -{ - id object = [NuTestHelper new]; - // the GNUstep runtime returns nil from this call. - [object autorelease]; - return object; -} - -- (id) init -{ - if (verbose_helper) - NSLog(@"(NuTestHelper init %p)", self); - return [super init]; -} - -- (id) retain -{ - if (verbose_helper) - NSLog(@"(NuTestHelper retain %p)", self); - return [super retain]; -} - -- (oneway void) release -{ - if (verbose_helper) - NSLog(@"(NuTestHelper release %p)", self); - [super release]; -} - -- (id) autorelease -{ - if (verbose_helper) - NSLog(@"(NuTestHelper autorelease %p)", self); - return [super autorelease]; -} - -- (void) dealloc -{ - if (verbose_helper) - NSLog(@"(NuTestHelper dealloc %p)", self); - deallocationCount++; - [super dealloc]; -} - -- (void) finalize -{ - if (verbose_helper) - NSLog(@"(NuTestHelper finalize %p)", self); - deallocationCount++; - [super finalize]; -} - -+ (void) resetDeallocationCount -{ -#if !TARGET_OS_IPHONE - [[NSGarbageCollector defaultCollector] collectExhaustively]; -#endif - deallocationCount = 0; -} - -+ (int) deallocationCount -{ -#if !TARGET_OS_IPHONE - [[NSGarbageCollector defaultCollector] collectExhaustively]; -#endif - return deallocationCount; -} - -#ifdef DARWIN -+ (CGRect) getCGRectFromProxy:(id) proxy { - return [proxy CGRectValue]; -} - -+ (CGPoint) getCGPointFromProxy:(id) proxy { - return [proxy CGPointValue]; -} - -+ (CGSize) getCGSizeFromProxy:(id) proxy { - return [proxy CGSizeValue]; -} -#endif - -+ (NSRange) getNSRangeFromProxy:(id) proxy { - return [proxy NSRangeValue]; -} - -@end - -@implementation NuMarkupOperator - -static NSArray *voidHTMLElements = nil; -static NSDictionary *elementPrefixes = nil; - -+ (void) initialize { - voidHTMLElements = [[NSSet setWithObjects: - @"area", - @"base", - @"br", - @"col", - @"command", - @"embed", - @"hr", - @"img", - @"input", - @"keygen", - @"link", - @"meta", - @"param", - @"source", - @"track", - @"wbr", - nil] retain]; - elementPrefixes = [[NSDictionary dictionaryWithObjectsAndKeys: - @"", @"html", - nil] retain]; -} - -+ (id) operatorWithTag:(NSString *) _tag -{ - return [[[self alloc] initWithTag:_tag] autorelease]; -} - -+ (id) operatorWithTag:(NSString *) _tag prefix:(NSString *) _prefix -{ - return [[[self alloc] initWithTag:_tag prefix:_prefix contents:nil] autorelease]; -} - -+ (id) operatorWithTag:(NSString *) _tag prefix:(NSString *) _prefix contents:(id) _contents -{ - return [[[self alloc] initWithTag:_tag prefix:_prefix contents:_contents] autorelease]; -} - -- (id) initWithTag:(NSString *) _tag -{ - return [self initWithTag:_tag prefix:nil contents:nil]; -} - -- (id) initWithTag:(NSString *) _tag prefix:(NSString *) _prefix contents:(id) _contents -{ - self = [super init]; - - // Scan through the tag looking for "." or "#" characters. - // When we find them, we split the and use the following strings as class or id attributes. - if (_tag) { - NSScanner *scanner = [NSScanner scannerWithString:_tag]; - NSCharacterSet *scanSet = [NSCharacterSet characterSetWithCharactersInString:@".#"]; - NSString *token; - char typeFlag = 0; - while ([scanner scanUpToCharactersFromSet:scanSet intoString:&token]) { - if (typeFlag == 0) { - _tag = token; - } else if (typeFlag == '.') { - if (!tagClasses) { - tagClasses = [[NSMutableArray alloc] init]; - } - [tagClasses addObject:token]; - } else if (typeFlag == '#') { - if (!tagIds) { - tagIds = [[NSMutableArray alloc] init]; - } - [tagIds addObject:token]; - } - if ([scanner scanCharactersFromSet:scanSet intoString:&token]) { - if ([token length]) { - typeFlag = [token characterAtIndex:[token length] - 1]; - } else { - typeFlag = 0; - } - } - } - } - tag = _tag ? [_tag stringByReplacingOccurrencesOfString:@"=" withString:@":"] : nil; - [tag retain]; - prefix = _prefix ? _prefix : [elementPrefixes objectForKey:tag]; - if (!prefix) { - prefix = @""; - } - [prefix retain]; - contents = _contents ? _contents : [NSNull null]; - [contents retain]; - empty = [voidHTMLElements containsObject:tag]; - return self; -} - -- (void) dealloc -{ - [tag release]; - [prefix release]; - [contents release]; - [tagIds release]; - [tagClasses release]; - [super dealloc]; -} - -- (void) setEmpty:(BOOL) e -{ - empty = e; -} - -- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context -{ - NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id t_symbol = [symbolTable symbolWithString:@"t"]; - - NSMutableString *body = [NSMutableString string]; - NSMutableString *attributes = [NSMutableString string]; - - static id NuSymbol = nil; - if (!NuSymbol) { - NuSymbol = NSClassFromString(@"NuSymbol"); - } - if (tagIds) { - for (int i = 0; i < [tagIds count]; i++) { - [attributes appendFormat:@" id=\"%@\"", [tagIds objectAtIndex:i]]; - } - } - if (tagClasses) { - for (int i = 0; i < [tagClasses count]; i++) { - [attributes appendFormat:@" class=\"%@\"", [tagClasses objectAtIndex:i]]; - } - } - for (int i = 0; i < 2; i++) { - id cursor = (i == 0) ? contents : cdr; - while (cursor && (cursor != [NSNull null])) { - id item = [cursor car]; - if ([item isKindOfClass:[NuSymbol class]] && [item isLabel]) { - cursor = [cursor cdr]; - if (cursor && (cursor != [NSNull null])) { - id value = [[cursor car] evalWithContext:context]; - id attributeName = [[item labelName] stringByReplacingOccurrencesOfString:@"=" withString:@":"]; - if ([value isEqual:[NSNull null]]) { - // omit attributes that are "false" - } else if ([value isEqual:t_symbol]) { - // boolean attributes with "true" are written without values - [attributes appendFormat:@" %@", attributeName]; - } else { - id stringValue = [value isEqual:[NSNull null]] ? @"" : [value stringValue]; - [attributes appendFormat:@" %@=\"%@\"", attributeName, stringValue]; - } - } - } - else { - id evaluatedItem = [item evalWithContext:context]; - if (!evaluatedItem || (evaluatedItem == [NSNull null])) { - // do nothing - } - else if ([evaluatedItem isKindOfClass:[NSString class]]) { - [body appendString:evaluatedItem]; - } - else if ([evaluatedItem isKindOfClass:[NSArray class]]) { - NSArray *evaluatedArray = (NSArray *) evaluatedItem; - int max = [evaluatedArray count]; - for (int i = 0; i < max; i++) { - id objectAtIndex = [evaluatedArray objectAtIndex:i]; - [body appendString:[objectAtIndex stringValue]]; - } - } - else { - [body appendString:[evaluatedItem stringValue]]; - } - } - if (cursor && (cursor != [NSNull null])) - cursor = [cursor cdr]; - } - } - - if (!tag) { - return body; - } - else if ([body length] || !empty) { - return [NSString stringWithFormat:@"%@<%@%@>%@", prefix, tag, attributes, body, tag]; - } - else { - return [NSString stringWithFormat:@"%@<%@%@/>", prefix, tag, attributes]; - } -} - -- (NSString *) tag {return tag;} -- (NSString *) prefix {return prefix;} -- (id) contents {return contents;} -- (BOOL) empty {return empty;} - -@end diff --git a/objc/NuBlock.h b/objc/NuBlock.h new file mode 100644 index 0000000..ee58a1e --- /dev/null +++ b/objc/NuBlock.h @@ -0,0 +1,58 @@ +// +// NuBlock.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +@class NuCell; + +/*! + @class NuBlock + @abstract The Nu representation of functions. + @discussion A Nu Block is an anonymous function with a saved execution context. + This is commonly referred to as a closure. + + In Nu programs, blocks may be directly created using the do operator. + Since blocks are objects, they may be passed as method and function arguments and may be assigned to names. + When a block is assigned to a name, the block will be called when a list is evaluated that + contains that name at its head; + the remainder of the list will be evaluated and passed to the block as the block's arguments. + + Blocks are implicitly created by several other operators. + + The Nu function operator uses blocks to create new named functions. + + The Nu macro operator uses blocks to create macros. + Since macros evaluate in their callers' contexts, no context information is kept for blocks used to create macros. + + When used in a class context, the - and + operators + use blocks to create new method implementations. + When a block is called as a method implementation, its context includes the symbols + self and super. This allows method implementations to send messages to + the owning object and its superclass. + */ +@interface NuBlock : NSObject + +/*! Create a block. Requires a list of parameters, the code to be executed, and an execution context. */ +- (id) initWithParameters:(NuCell *)a body:(NuCell *)b context:(NSMutableDictionary *)c; +/*! Get the list of parameters required by the block. */ +- (NuCell *) parameters; +/*! Get the body of code that is evaluated during block evaluation. */ +- (NuCell *) body; +/*! Get the lexical context of the block. + This is a dictionary containing the symbols and associated values at the point + where the block was created. */ +- (NSMutableDictionary *) context; +/*! Evaluate a block using the specified arguments and calling context. */ +- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context; +/*! Evaluate a block using the specified arguments, calling context, and owner. + This is the mechanism used to evaluate blocks as methods. */ +- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context self:(id)object; +/*! Get a string representation of the block. */ +- (NSString *) stringValue; + +@end \ No newline at end of file diff --git a/objc/NuBlock.m b/objc/NuBlock.m new file mode 100644 index 0000000..85cd9ce --- /dev/null +++ b/objc/NuBlock.m @@ -0,0 +1,257 @@ +// +// NuBlock.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuBlock.h" +#import "NuInternals.h" +#import "NuSuper.h" +#import "NSDictionary+Nu.h" +#import "NuCell.h" + +@interface NuBlock () +{ + NuCell *parameters; + NuCell *body; + NSMutableDictionary *context; +} +@end + +@implementation NuBlock + +- (void) dealloc +{ + [parameters release]; + [body release]; + [context release]; + [super dealloc]; +} + +- (id) initWithParameters:(NuCell *)p body:(NuCell *)b context:(NSMutableDictionary *)c +{ + if ((self = [super init])) { + parameters = [p retain]; + body = [b retain]; +#ifdef CLOSE_ON_VALUES + context = [c mutableCopy]; +#else + context = [[NSMutableDictionary alloc] init]; + [context setPossiblyNullObject:c forKey:PARENT_KEY]; + [context setPossiblyNullObject:[c objectForKey:SYMBOLS_KEY] forKey:SYMBOLS_KEY]; +#endif + + // Check for the presence of "*args" in parameter list + id plist = parameters; + + if (!( ([parameters length] == 1) + && ([[[parameters car] stringValue] isEqualToString:@"*args"]))) + { + while (plist && (plist != Nu__null)) + { + id parameter = [plist car]; + + if ([[parameter stringValue] isEqualToString:@"*args"]) + { + printf("Warning: Overriding implicit variable '*args'.\n"); + return self; + } + + plist = [plist cdr]; + } + } + } + return self; +} + +- (NSString *) stringValue +{ + return [NSString stringWithFormat:@"(do %@ %@)", [parameters stringValue], [body stringValue]]; +} + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context +{ + NSUInteger numberOfArguments = [cdr length]; + NSUInteger numberOfParameters = [parameters length]; + + if (numberOfArguments != numberOfParameters) { + // is the last parameter a variable argument? if so, it's ok, and we allow it to have zero elements. + id lastParameter = [parameters lastObject]; + if (lastParameter && ([[lastParameter stringValue] characterAtIndex:0] == '*')) { + if (numberOfArguments < (numberOfParameters - 1)) { + [NSException raise:@"NuIncorrectNumberOfArguments" + format:@"Incorrect number of arguments to block. Received %ld but expected %ld or more: %@", + (unsigned long) numberOfArguments, + (unsigned long) (numberOfParameters - 1), + [parameters stringValue]]; + } + } + else { + [NSException raise:@"NuIncorrectNumberOfArguments" + format:@"Incorrect number of arguments to block. Received %ld but expected %ld: %@", + (unsigned long) numberOfArguments, + (unsigned long) numberOfParameters, + [parameters stringValue]]; + } + } + //NSLog(@"block eval %@", [cdr stringValue]); + // loop over the parameters, looking up their values in the calling_context and copying them into the evaluation_context + id plist = parameters; + id vlist = cdr; + id evaluation_context = [context mutableCopy]; + + // Insert the implicit variable "*args". It contains the entire parameter list. + NuSymbolTable *symbolTable = [evaluation_context objectForKey:SYMBOLS_KEY]; + [evaluation_context setPossiblyNullObject:cdr forKey:[symbolTable symbolWithString:@"*args"]]; + + while (plist && (plist != Nu__null)) { + id parameter = [plist car]; + if ([[parameter stringValue] characterAtIndex:0] == '*') { + id varargs = [[[NuCell alloc] init] autorelease]; + id cursor = varargs; + while (vlist != Nu__null) { + [cursor setCdr:[[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + id value = [vlist car]; + if (calling_context && (calling_context != Nu__null)) + value = [value evalWithContext:calling_context]; + [cursor setCar:value]; + vlist = [vlist cdr]; + } + [evaluation_context setPossiblyNullObject:[varargs cdr] forKey:parameter]; + plist = [plist cdr]; + // this must be the last element in the parameter list + if (plist != Nu__null) { + [NSException raise:@"NuBadParameterList" + format:@"Variable argument list must be the last parameter in the parameter list: %@", + [parameters stringValue]]; + } + } + else { + id value = [vlist car]; + if (calling_context && (calling_context != Nu__null)) + value = [value evalWithContext:calling_context]; + //NSLog(@"setting %@ = %@", parameter, value); + [evaluation_context setPossiblyNullObject:value forKey:parameter]; + plist = [plist cdr]; + vlist = [vlist cdr]; + } + } + // evaluate the body of the block with the saved context (implicit progn) + id value = Nu__null; + id cursor = body; + @try + { + while (cursor && (cursor != Nu__null)) { + value = [[cursor car] evalWithContext:evaluation_context]; + cursor = [cursor cdr]; + } + } + @catch (NuReturnException *exception) { + value = [exception value]; + if ([exception blockForReturn] && ([exception blockForReturn] != self)) { + @throw(exception); + } + } + @catch (id exception) { + @throw(exception); + } + [value retain]; + [value autorelease]; + [evaluation_context release]; + return value; +} + +- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context +{ + return [self callWithArguments:cdr context:calling_context]; +} + +static id getObjectFromContext(id context, id symbol) +{ + while (IS_NOT_NULL(context)) { + id object = [context objectForKey:symbol]; + if (object) + return object; + context = [context objectForKey:PARENT_KEY]; + } + return nil; +} + +- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context self:(id)object +{ + NSUInteger numberOfArguments = [cdr length]; + NSUInteger numberOfParameters = [parameters length]; + if (numberOfArguments != numberOfParameters) { + [NSException raise:@"NuIncorrectNumberOfArguments" + format:@"Incorrect number of arguments to method. Received %ld but expected %ld, %@", + (unsigned long) numberOfArguments, + (unsigned long) numberOfParameters, + [parameters stringValue]]; + } + // NSLog(@"block eval %@", [cdr stringValue]); + // loop over the arguments, looking up their values in the calling_context and copying them into the evaluation_context + id plist = parameters; + id vlist = cdr; + id evaluation_context = [context mutableCopy]; + // NSLog(@"after copying, evaluation context %@ retain count %d", evaluation_context, [evaluation_context retainCount]); + if (object) { + NuSymbolTable *symbolTable = [evaluation_context objectForKey:SYMBOLS_KEY]; + // look up one level for the _class value, but allow for it to be higher (in the perverse case of nested method declarations). + NuClass *c = getObjectFromContext([context objectForKey:PARENT_KEY], [symbolTable symbolWithString:@"_class"]); + [evaluation_context setPossiblyNullObject:object forKey:[symbolTable symbolWithString:@"self"]]; + [evaluation_context setPossiblyNullObject:[NuSuper superWithObject:object ofClass:[c wrappedClass]] forKey:[symbolTable symbolWithString:@"super"]]; + } + while (plist && (plist != Nu__null) && vlist && (vlist != Nu__null)) { + id arg = [plist car]; + // since this message is sent by a method handler (which has already evaluated the block arguments), + // we don't evaluate them here; instead we just copy them + id value = [vlist car]; + // NSLog(@"setting %@ = %@", arg, value); + [evaluation_context setPossiblyNullObject:value forKey:arg]; + plist = [plist cdr]; + vlist = [vlist cdr]; + } + // evaluate the body of the block with the saved context (implicit progn) + id value = Nu__null; + id cursor = body; + @try + { + while (cursor && (cursor != Nu__null)) { + value = [[cursor car] evalWithContext:evaluation_context]; + cursor = [cursor cdr]; + } + } + @catch (NuReturnException *exception) { + value = [exception value]; + if ([exception blockForReturn] && ([exception blockForReturn] != self)) { + @throw(exception); + } + } + @catch (id exception) { + @throw(exception); + } + [value retain]; + [value autorelease]; + [evaluation_context release]; + return value; +} + +- (NSMutableDictionary *) context +{ + return context; +} + +- (NuCell *) parameters +{ + return parameters; +} + +- (NuCell *) body +{ + return body; +} + +@end diff --git a/objc/NuBridge.h b/objc/NuBridge.h new file mode 100644 index 0000000..da7e8b2 --- /dev/null +++ b/objc/NuBridge.h @@ -0,0 +1,142 @@ +// +// NuBridge.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +#import "NuBlock.h" +#import "NuCell.h" + +#pragma mark - +#pragma mark Callables: Functions, Macros, Operators + +#pragma mark - +#pragma mark Bridging C + +/*! + @class NuBridgedFunction + @abstract The Nu wrapper for imported C functions. + @discussion Instances of this class wrap functions imported from C. + + Because NuBridgedFunction is a subclass of NuOperator, Nu expressions that + begin with NuBridgedFunction instances are treated as operator calls. + + In general, operators may or may not evaluate their arguments, + but for NuBridgedFunctions, all arguments are evaluated. + The resulting values are then passed to the bridged C function + using the foreign function interface (libFFI). + + The C function's return value is converted into a Nu object and returned. + + Here is an example showing the use of this class from Nu. + The example imports and calls the C function NSApplicationMain. + +
+ + (set NSApplicationMain
+     (NuBridgedFunction
+         functionWithName:"NSApplicationMain"
+         signature:"ii^*"))

+ (NSApplicationMain 0 nil) +
+
+ + The signature string used to create a NuBridgedFunction must be a valid Objective-C type signature. + In the future, convenience methods may be added to make those signatures easier to generate. + But in practice, this has not been much of a problem. + */ + +#import "NuOperators.h" + + +@interface NuBridgedFunction : NuOperator + +/*! Create a wrapper for a C function with the specified name and signature. + The function is looked up using the dlsym() function and the wrapper is + constructed using libFFI. If the result of this method is assigned to a + symbol, that symbol may be used as the name of the bridged function. + */ ++ (NuBridgedFunction *) functionWithName:(NSString *)name signature:(NSString *)signature; +/*! Initialize a wrapper for a C function with the specified name and signature. + The function is looked up using the dlsym() function and the wrapper is + constructed using libFFI. If the result of this method is assigned to a + symbol, that symbol may be used as the name of the bridged function. + */ +- (NuBridgedFunction *) initWithName:(NSString *)name signature:(NSString *)signature; +/*! Evaluate a bridged function with the specified arguments and context. + Arguments must be in a Nu list. + */ +- (id) evalWithArguments:(id)arguments context:(NSMutableDictionary *)context; +@end + +/*! + @class NuBridgedConstant + @abstract The Nu wrapper for imported C constants. + @discussion This class can be used to import constants defined in C code. + The signature string used to import a constant must be a valid Objective-C type signature. + */ +@interface NuBridgedConstant : NSObject {} +/*! Look up the value of a constant with specified name and type. + The function is looked up using the dlsym() function. + The returned value is of the type specified by the signature argument. + */ ++ (id) constantWithName:(NSString *) name signature:(NSString *) signature; + +@end + +#ifdef __BLOCKS__ +/*! + @class NuBridgedBlock + @abstract Generates a C block that wraps a nu block + @discussion This class makes a C block that wraps a nu block using a supplied + Objective-C-style function signature. This works by copying a dummy c block and + then writing over its function pointer with a libFFI-generated closure function. + */ +@interface NuBridgedBlock : NSObject + +/*! Returns a C block that wraps the supplied nu block using the supplied + Objective-C-style function signature. + */ ++(id)cBlockWithNuBlock:(NuBlock*)nb signature:(NSString*)sig; + +/*! Initializes a NuBridgedBlock object using a NuBlock and an Objective-C-style + function signature. A C block is generated during the initialization. + */ +-(id)initWithNuBlock:(NuBlock*)nb signature:(NSString*)sig; + +/*! Returns the NuBlock associated with the NuBridgedBlock object. + */ +-(NuBlock*)nuBlock; + +/*! Returns the C block generated by the NuBridgedBlock object. + */ +-(id)cBlock; + +@end +#endif //__BLOCKS__ + +#import "NuMethod.h" + +#pragma mark - +#pragma mark Interacting with the Objective-C Runtime + +#import "NuClass.h" + +#if !TARGET_OS_IPHONE +/*! + @class NuBridgeSupport + @abstract A reader for Apple's BridgeSupport files. + @discussion Methods of this class are used to read Apple's BridgeSupport files. + */ +@interface NuBridgeSupport : NSObject +/*! Import a dynamic library at the specified path. */ ++ (void)importLibrary:(NSString *) libraryPath; +/*! Import a BridgeSupport description of a framework from a specified path. Store the results in the specified dictionary. */ ++ (void)importFramework:(NSString *) framework fromPath:(NSString *) path intoDictionary:(NSMutableDictionary *) BridgeSupport; + +@end +#endif \ No newline at end of file diff --git a/objc/NuBridge.m b/objc/NuBridge.m new file mode 100644 index 0000000..8092795 --- /dev/null +++ b/objc/NuBridge.m @@ -0,0 +1,2096 @@ +// +// NuBridge.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuBridge.h" +#import "NuInternals.h" + +#import +#import + +#import +#import + +#if TARGET_OS_IPHONE +#import +#define NSRect CGRect +#define NSPoint CGPoint +#define NSSize CGSize +#endif + +#if TARGET_OS_IPHONE +#import +#endif + +#if TARGET_OS_IPHONE +#import "ffi.h" +#else +#ifdef DARWIN +#import +#else +#import +#endif +#endif + +#import + +#pragma mark - NuBridge.m + +#import "NuHandler.h" +#import "NuReference.h" +#import "NuPointer.h" + +/* + * types: + * c char + * i int + * s short + * l long + * q long long + * C unsigned char + * I unsigned int + * S unsigned short + * L unsigned long + * Q unsigned long long + * f float + * d double + * B bool (c++) + * v void + * * char * + * @ id + * # Class + * : SEL + * ? unknown + * b4 bit field of 4 bits + * ^type pointer to type + * [type] array + * {name=type...} structure + * (name=type...) union + * + * modifiers: + * r const + * n in + * N inout + * o out + * O bycopy + * R byref + * V oneway + */ + +NSMutableDictionary *nu_block_table = nil; + +#ifdef __x86_64__ + +#define NSRECT_SIGNATURE0 "{_NSRect={_NSPoint=dd}{_NSSize=dd}}" +#define NSRECT_SIGNATURE1 "{_NSRect=\"origin\"{_NSPoint=\"x\"d\"y\"d}\"size\"{_NSSize=\"width\"d\"height\"d}}" +#define NSRECT_SIGNATURE2 "{_NSRect}" + +#define CGRECT_SIGNATURE0 "{CGRect={CGPoint=dd}{CGSize=dd}}" +#define CGRECT_SIGNATURE1 "{CGRect=\"origin\"{CGPoint=\"x\"d\"y\"d}\"size\"{CGSize=\"width\"d\"height\"d}}" +#define CGRECT_SIGNATURE2 "{CGRect}" + +#define NSRANGE_SIGNATURE "{_NSRange=QQ}" +#define NSRANGE_SIGNATURE1 "{_NSRange}" + +#define NSPOINT_SIGNATURE0 "{_NSPoint=dd}" +#define NSPOINT_SIGNATURE1 "{_NSPoint=\"x\"d\"y\"d}" +#define NSPOINT_SIGNATURE2 "{_NSPoint}" + +#define CGPOINT_SIGNATURE "{CGPoint=dd}" + +#define NSSIZE_SIGNATURE0 "{_NSSize=dd}" +#define NSSIZE_SIGNATURE1 "{_NSSize=\"width\"d\"height\"d}" +#define NSSIZE_SIGNATURE2 "{_NSSize}" + +#define CGSIZE_SIGNATURE "{CGSize=dd}" + +#else + +#define NSRECT_SIGNATURE0 "{_NSRect={_NSPoint=ff}{_NSSize=ff}}" +#define NSRECT_SIGNATURE1 "{_NSRect=\"origin\"{_NSPoint=\"x\"f\"y\"f}\"size\"{_NSSize=\"width\"f\"height\"f}}" +#define NSRECT_SIGNATURE2 "{_NSRect}" + +#define CGRECT_SIGNATURE0 "{CGRect={CGPoint=ff}{CGSize=ff}}" +#define CGRECT_SIGNATURE1 "{CGRect=\"origin\"{CGPoint=\"x\"f\"y\"f}\"size\"{CGSize=\"width\"f\"height\"f}}" +#define CGRECT_SIGNATURE2 "{CGRect}" + +#define NSRANGE_SIGNATURE "{_NSRange=II}" +#define NSRANGE_SIGNATURE1 "{_NSRange}" + +#define NSPOINT_SIGNATURE0 "{_NSPoint=ff}" +#define NSPOINT_SIGNATURE1 "{_NSPoint=\"x\"f\"y\"f}" +#define NSPOINT_SIGNATURE2 "{_NSPoint}" + +#define CGPOINT_SIGNATURE "{CGPoint=ff}" + +#define NSSIZE_SIGNATURE0 "{_NSSize=ff}" +#define NSSIZE_SIGNATURE1 "{_NSSize=\"width\"f\"height\"f}" +#define NSSIZE_SIGNATURE2 "{_NSSize}" + +#define CGSIZE_SIGNATURE "{CGSize=ff}" +#endif + +// private ffi types +static int initialized_ffi_types = false; +static ffi_type ffi_type_nspoint; +static ffi_type ffi_type_nssize; +static ffi_type ffi_type_nsrect; +static ffi_type ffi_type_nsrange; + +static void initialize_ffi_types(void) +{ + if (initialized_ffi_types) return; + initialized_ffi_types = true; + + // It would be better to do this automatically by parsing the ObjC type signatures + ffi_type_nspoint.size = 0; // to be computed automatically + ffi_type_nspoint.alignment = 0; + ffi_type_nspoint.type = FFI_TYPE_STRUCT; + ffi_type_nspoint.elements = malloc(3 * sizeof(ffi_type*)); +#ifdef __x86_64__ + ffi_type_nspoint.elements[0] = &ffi_type_double; + ffi_type_nspoint.elements[1] = &ffi_type_double; +#else + ffi_type_nspoint.elements[0] = &ffi_type_float; + ffi_type_nspoint.elements[1] = &ffi_type_float; +#endif + ffi_type_nspoint.elements[2] = NULL; + + ffi_type_nssize.size = 0; // to be computed automatically + ffi_type_nssize.alignment = 0; + ffi_type_nssize.type = FFI_TYPE_STRUCT; + ffi_type_nssize.elements = malloc(3 * sizeof(ffi_type*)); +#ifdef __x86_64__ + ffi_type_nssize.elements[0] = &ffi_type_double; + ffi_type_nssize.elements[1] = &ffi_type_double; +#else + ffi_type_nssize.elements[0] = &ffi_type_float; + ffi_type_nssize.elements[1] = &ffi_type_float; +#endif + ffi_type_nssize.elements[2] = NULL; + + ffi_type_nsrect.size = 0; // to be computed automatically + ffi_type_nsrect.alignment = 0; + ffi_type_nsrect.type = FFI_TYPE_STRUCT; + ffi_type_nsrect.elements = malloc(3 * sizeof(ffi_type*)); + ffi_type_nsrect.elements[0] = &ffi_type_nspoint; + ffi_type_nsrect.elements[1] = &ffi_type_nssize; + ffi_type_nsrect.elements[2] = NULL; + + ffi_type_nsrange.size = 0; // to be computed automatically + ffi_type_nsrange.alignment = 0; + ffi_type_nsrange.type = FFI_TYPE_STRUCT; + ffi_type_nsrange.elements = malloc(3 * sizeof(ffi_type*)); +#ifdef __x86_64__ + ffi_type_nsrange.elements[0] = &ffi_type_uint64; + ffi_type_nsrange.elements[1] = &ffi_type_uint64; +#else + ffi_type_nsrange.elements[0] = &ffi_type_uint; + ffi_type_nsrange.elements[1] = &ffi_type_uint; +#endif + ffi_type_nsrange.elements[2] = NULL; +} + +static char get_typeChar_from_typeString(const char *typeString) +{ + int i = 0; + char typeChar = typeString[i]; + while ((typeChar == 'r') || (typeChar == 'R') || + (typeChar == 'n') || (typeChar == 'N') || + (typeChar == 'o') || (typeChar == 'O') || + (typeChar == 'V') + ) { + // uncomment the following two lines to complain about unused quantifiers in ObjC type encodings + // if (typeChar != 'r') // don't worry about const + // NSLog(@"ignoring qualifier %c in %s", typeChar, typeString); + typeChar = typeString[++i]; + } + return typeChar; +} + +static ffi_type *ffi_type_for_objc_type(const char *typeString) +{ + char typeChar = get_typeChar_from_typeString(typeString); + switch (typeChar) { + case 'f': return &ffi_type_float; + case 'd': return &ffi_type_double; + case 'v': return &ffi_type_void; + case 'B': return &ffi_type_uchar; + case 'C': return &ffi_type_uchar; + case 'c': return &ffi_type_schar; + case 'S': return &ffi_type_ushort; + case 's': return &ffi_type_sshort; + case 'I': return &ffi_type_uint; + case 'i': return &ffi_type_sint; +#ifdef __x86_64__ + case 'L': return &ffi_type_ulong; + case 'l': return &ffi_type_slong; +#else + case 'L': return &ffi_type_uint; + case 'l': return &ffi_type_sint; +#endif + case 'Q': return &ffi_type_uint64; + case 'q': return &ffi_type_sint64; + case '@': return &ffi_type_pointer; + case '#': return &ffi_type_pointer; + case '*': return &ffi_type_pointer; + case ':': return &ffi_type_pointer; + case '^': return &ffi_type_pointer; + case '{': + { + if (!strcmp(typeString, NSRECT_SIGNATURE0) || + !strcmp(typeString, NSRECT_SIGNATURE1) || + !strcmp(typeString, NSRECT_SIGNATURE2) || + !strcmp(typeString, CGRECT_SIGNATURE0) || + !strcmp(typeString, CGRECT_SIGNATURE1) || + !strcmp(typeString, CGRECT_SIGNATURE2)) { + if (!initialized_ffi_types) initialize_ffi_types(); + return &ffi_type_nsrect; + } + else if ( + !strcmp(typeString, NSRANGE_SIGNATURE) || + !strcmp(typeString, NSRANGE_SIGNATURE1) + ) { + if (!initialized_ffi_types) initialize_ffi_types(); + return &ffi_type_nsrange; + } + else if ( + !strcmp(typeString, NSPOINT_SIGNATURE0) || + !strcmp(typeString, NSPOINT_SIGNATURE1) || + !strcmp(typeString, NSPOINT_SIGNATURE2) || + !strcmp(typeString, CGPOINT_SIGNATURE) + ) { + if (!initialized_ffi_types) initialize_ffi_types(); + return &ffi_type_nspoint; + } + else if ( + !strcmp(typeString, NSSIZE_SIGNATURE0) || + !strcmp(typeString, NSSIZE_SIGNATURE1) || + !strcmp(typeString, NSSIZE_SIGNATURE2) || + !strcmp(typeString, CGSIZE_SIGNATURE) + ) { + if (!initialized_ffi_types) initialize_ffi_types(); + return &ffi_type_nssize; + } + else { + NSLog(@"unknown type identifier %s", typeString); + return &ffi_type_void; + } + } + default: + { + NSLog(@"unknown type identifier %s", typeString); + return &ffi_type_void; // urfkd + } + } +} + +size_t size_of_objc_type(const char *typeString) +{ + char typeChar = get_typeChar_from_typeString(typeString); + switch (typeChar) { + case 'f': return sizeof(float); + case 'd': return sizeof(double); + case 'v': return sizeof(void *); + case 'B': return sizeof(unsigned int); + case 'C': return sizeof(unsigned int); + case 'c': return sizeof(int); + case 'S': return sizeof(unsigned int); + case 's': return sizeof(int); + case 'I': return sizeof(unsigned int); + case 'i': return sizeof(int); + case 'L': return sizeof(unsigned long); + case 'l': return sizeof(long); + case 'Q': return sizeof(unsigned long long); + case 'q': return sizeof(long long); + case '@': return sizeof(void *); + case '#': return sizeof(void *); + case '*': return sizeof(void *); + case ':': return sizeof(void *); + case '^': return sizeof(void *); + case '{': + { + if (!strcmp(typeString, NSRECT_SIGNATURE0) || + !strcmp(typeString, NSRECT_SIGNATURE1) || + !strcmp(typeString, NSRECT_SIGNATURE2) || + !strcmp(typeString, CGRECT_SIGNATURE0) || + !strcmp(typeString, CGRECT_SIGNATURE1) || + !strcmp(typeString, CGRECT_SIGNATURE2) + ) { + return sizeof(NSRect); + } + else if ( + !strcmp(typeString, NSRANGE_SIGNATURE) || + !strcmp(typeString, NSRANGE_SIGNATURE1) + ) { + return sizeof(NSRange); + } + else if ( + !strcmp(typeString, NSPOINT_SIGNATURE0) || + !strcmp(typeString, NSPOINT_SIGNATURE1) || + !strcmp(typeString, NSPOINT_SIGNATURE2) || + !strcmp(typeString, CGPOINT_SIGNATURE) + ) { + return sizeof(NSPoint); + } + else if ( + !strcmp(typeString, NSSIZE_SIGNATURE0) || + !strcmp(typeString, NSSIZE_SIGNATURE1) || + !strcmp(typeString, NSSIZE_SIGNATURE2) || + !strcmp(typeString, CGSIZE_SIGNATURE) + ) { + return sizeof(NSSize); + } + else { + NSLog(@"unknown type identifier %s", typeString); + return sizeof (void *); + } + } + default: + { + NSLog(@"unknown type identifier %s", typeString); + return sizeof (void *); + } + } +} + +void *value_buffer_for_objc_type(const char *typeString) +{ + char typeChar = get_typeChar_from_typeString(typeString); + switch (typeChar) { + case 'f': return malloc(sizeof(float)); + case 'd': return malloc(sizeof(double)); + case 'v': return malloc(sizeof(void *)); + case 'B': return malloc(sizeof(unsigned int)); + case 'C': return malloc(sizeof(unsigned int)); + case 'c': return malloc(sizeof(int)); + case 'S': return malloc(sizeof(unsigned int)); + case 's': return malloc(sizeof(int)); + case 'I': return malloc(sizeof(unsigned int)); + case 'i': return malloc(sizeof(int)); + case 'L': return malloc(sizeof(unsigned long)); + case 'l': return malloc(sizeof(long)); + case 'Q': return malloc(sizeof(unsigned long long)); + case 'q': return malloc(sizeof(long long)); + case '@': return malloc(sizeof(void *)); + case '#': return malloc(sizeof(void *)); + case '*': return malloc(sizeof(void *)); + case ':': return malloc(sizeof(void *)); + case '^': return malloc(sizeof(void *)); + case '{': + { + if (!strcmp(typeString, NSRECT_SIGNATURE0) || + !strcmp(typeString, NSRECT_SIGNATURE1) || + !strcmp(typeString, NSRECT_SIGNATURE2) || + !strcmp(typeString, CGRECT_SIGNATURE0) || + !strcmp(typeString, CGRECT_SIGNATURE1) || + !strcmp(typeString, CGRECT_SIGNATURE2) + ) { + return malloc(sizeof(NSRect)); + } + else if ( + !strcmp(typeString, NSRANGE_SIGNATURE) || + !strcmp(typeString, NSRANGE_SIGNATURE1) + ) { + return malloc(sizeof(NSRange)); + } + else if ( + !strcmp(typeString, NSPOINT_SIGNATURE0) || + !strcmp(typeString, NSPOINT_SIGNATURE1) || + !strcmp(typeString, NSPOINT_SIGNATURE2) || + !strcmp(typeString, CGPOINT_SIGNATURE) + ) { + return malloc(sizeof(NSPoint)); + } + else if ( + !strcmp(typeString, NSSIZE_SIGNATURE0) || + !strcmp(typeString, NSSIZE_SIGNATURE1) || + !strcmp(typeString, NSSIZE_SIGNATURE2) || + !strcmp(typeString, CGSIZE_SIGNATURE) + ) { + return malloc(sizeof(NSSize)); + } + else { + NSLog(@"unknown type identifier %s", typeString); + return malloc(sizeof (void *)); + } + } + default: + { + NSLog(@"unknown type identifier %s", typeString); + return malloc(sizeof (void *)); + } + } +} + +int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *typeString) +{ + // NSLog(@"VALUE => %s", typeString); + char typeChar = get_typeChar_from_typeString(typeString); + switch (typeChar) { + case '@': + { + if (nu_value == Nu__null) { + *((id *) objc_value) = nil; + return NO; + } + *((id *) objc_value) = nu_value; + return NO; + } + case 'I': +#ifndef __ppc__ + case 'S': + case 'C': +#endif + { + if (nu_value == Nu__null) { + *((unsigned int *) objc_value) = 0; + return NO; + } + *((unsigned int *) objc_value) = [nu_value unsignedIntValue]; + return NO; + } +#ifdef __ppc__ + case 'S': + { + if (nu_value == Nu__null) { + *((unsigned short *) objc_value) = 0; + return NO; + } + *((unsigned short *) objc_value) = [nu_value unsignedShortValue]; + return NO; + } + case 'C': + { + if (nu_value == Nu__null) { + *((unsigned char *) objc_value) = 0; + return NO; + } + *((unsigned char *) objc_value) = [nu_value unsignedCharValue]; + return NO; + } +#endif + case 'i': +#ifndef __ppc__ + case 's': + case 'c': +#endif + { + if (nu_value == [NSNull null]) { + *((int *) objc_value) = 0; + return NO; + } + *((int *) objc_value) = [nu_value intValue]; + return NO; + } +#ifdef __ppc__ + case 's': + { + if (nu_value == Nu__null) { + *((short *) objc_value) = 0; + return NO; + } + *((short *) objc_value) = [nu_value shortValue]; + return NO; + } + case 'c': + { + if (nu_value == Nu__null) { + *((char *) objc_value) = 0; + return NO; + } + *((char *) objc_value) = [nu_value charValue]; + return NO; + } +#endif + case 'L': + { + if (nu_value == [NSNull null]) { + *((unsigned long *) objc_value) = 0; + return NO; + } + *((unsigned long *) objc_value) = [nu_value unsignedLongValue]; + return NO; + } + case 'l': + { + if (nu_value == [NSNull null]) { + *((long *) objc_value) = 0; + return NO; + } + *((long *) objc_value) = [nu_value longValue]; + return NO; + } + case 'Q': + { + if (nu_value == [NSNull null]) { + *((unsigned long long *) objc_value) = 0; + return NO; + } + *((unsigned long long *) objc_value) = [nu_value unsignedLongLongValue]; + return NO; + } + case 'q': + { + if (nu_value == [NSNull null]) { + *((long long *) objc_value) = 0; + return NO; + } + *((long long *) objc_value) = [nu_value longLongValue]; + return NO; + } + case 'd': + { + *((double *) objc_value) = [nu_value doubleValue]; + return NO; + } + case 'f': + { + *((float *) objc_value) = (float) [nu_value doubleValue]; + return NO; + } + case 'v': + { + return NO; + } + case ':': + { + // selectors must be strings (symbols could be ok too...) + if (!nu_value || (nu_value == [NSNull null])) { + *((SEL *) objc_value) = 0; + return NO; + } + const char *selectorName = [nu_value cStringUsingEncoding:NSUTF8StringEncoding]; + if (selectorName) { + *((SEL *) objc_value) = sel_registerName(selectorName); + return NO; + } + else { + NSLog(@"can't convert %@ to a selector", nu_value); + return NO; + } + } + case '{': + { + if ( + !strcmp(typeString, NSRECT_SIGNATURE0) || + !strcmp(typeString, NSRECT_SIGNATURE1) || + !strcmp(typeString, NSRECT_SIGNATURE2) || + !strcmp(typeString, CGRECT_SIGNATURE0) || + !strcmp(typeString, CGRECT_SIGNATURE1) || + !strcmp(typeString, CGRECT_SIGNATURE2) + ) { + NSRect *rect = (NSRect *) objc_value; + id cursor = nu_value; + rect->origin.x = (CGFloat) [[cursor car] doubleValue]; cursor = [cursor cdr]; + rect->origin.y = (CGFloat) [[cursor car] doubleValue]; cursor = [cursor cdr]; + rect->size.width = (CGFloat) [[cursor car] doubleValue]; cursor = [cursor cdr]; + rect->size.height = (CGFloat) [[cursor car] doubleValue]; + //NSLog(@"nu->rect: %x %f %f %f %f", (void *) rect, rect->origin.x, rect->origin.y, rect->size.width, rect->size.height); + return NO; + } + else if ( + !strcmp(typeString, NSRANGE_SIGNATURE) || + !strcmp(typeString, NSRANGE_SIGNATURE1) + ) { + NSRange *range = (NSRange *) objc_value; + id cursor = nu_value; + range->location = [[cursor car] intValue]; cursor = [cursor cdr];; + range->length = [[cursor car] intValue]; + return NO; + } + else if ( + !strcmp(typeString, NSSIZE_SIGNATURE0) || + !strcmp(typeString, NSSIZE_SIGNATURE1) || + !strcmp(typeString, NSSIZE_SIGNATURE2) || + !strcmp(typeString, CGSIZE_SIGNATURE) + ) { + NSSize *size = (NSSize *) objc_value; + id cursor = nu_value; + size->width = [[cursor car] doubleValue]; cursor = [cursor cdr];; + size->height = [[cursor car] doubleValue]; + return NO; + } + else if ( + !strcmp(typeString, NSPOINT_SIGNATURE0) || + !strcmp(typeString, NSPOINT_SIGNATURE1) || + !strcmp(typeString, NSPOINT_SIGNATURE2) || + !strcmp(typeString, CGPOINT_SIGNATURE) + ) { + NSPoint *point = (NSPoint *) objc_value; + id cursor = nu_value; + point->x = [[cursor car] doubleValue]; cursor = [cursor cdr];; + point->y = [[cursor car] doubleValue]; + return NO; + } + else { + NSLog(@"UNIMPLEMENTED: can't wrap structure of type %s", typeString); + return NO; + } + } + + case '^': + { + if (!nu_value || (nu_value == [NSNull null])) { + *((char ***) objc_value) = NULL; + return NO; + } + // pointers require some work.. and cleanup. This LEAKS. + if (!strcmp(typeString, "^*")) { + // array of strings, which requires an NSArray or NSNull (handled above) + if (nu_objectIsKindOfClass(nu_value, [NSArray class])) { + NSUInteger array_size = [nu_value count]; + char **array = (char **) malloc (array_size * sizeof(char *)); + int i; + for (i = 0; i < array_size; i++) { + array[i] = strdup([[nu_value objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding]); + } + *((char ***) objc_value) = array; + return NO; + } + else { + NSLog(@"can't convert value of type %s to a pointer to strings", class_getName([nu_value class])); + *((char ***) objc_value) = NULL; + return NO; + } + } + else if (!strcmp(typeString, "^@")) { + if (nu_objectIsKindOfClass(nu_value, [NuReference class])) { + *((id **) objc_value) = [nu_value pointerToReferencedObject]; + return YES; + } + } + else if (nu_objectIsKindOfClass(nu_value, [NuPointer class])) { + if ([nu_value pointer] == 0) + [nu_value allocateSpaceForTypeString:[NSString stringWithCString:typeString encoding:NSUTF8StringEncoding]]; + *((void **) objc_value) = [nu_value pointer]; + return NO; // don't ask the receiver to retain this, it's just a pointer + } + else { + *((void **) objc_value) = nu_value; + return NO; // don't ask the receiver to retain this, it isn't expecting an object + } + } + + case '*': + { + *((char **) objc_value) = (char*)[[nu_value stringValue] cStringUsingEncoding:NSUTF8StringEncoding]; + return NO; + } + + case '#': + { + if (nu_objectIsKindOfClass(nu_value, [NuClass class])) { + *((Class *)objc_value) = [nu_value wrappedClass]; + return NO; + } + else { + NSLog(@"can't convert value of type %s to CLASS", class_getName([nu_value class])); + *((id *) objc_value) = 0; + return NO; + } + } + default: + NSLog(@"can't wrap argument of type %s", typeString); + } + return NO; +} + +id get_nu_value_from_objc_value(void *objc_value, const char *typeString) +{ + //NSLog(@"%s => VALUE", typeString); + char typeChar = get_typeChar_from_typeString(typeString); + switch(typeChar) { + case 'v': + { + return [NSNull null]; + } + case '@': + { + id result = *((id *)objc_value); + return result ? result : (id)[NSNull null]; + } + case '#': + { + Class c = *((Class *)objc_value); + return c ? [[[NuClass alloc] initWithClass:c] autorelease] : Nu__null; + } +#ifndef __ppc__ + case 'c': + { + return [NSNumber numberWithChar:*((char *)objc_value)]; + } + case 's': + { + return [NSNumber numberWithShort:*((short *)objc_value)]; + } +#else + case 'c': + case 's': +#endif + case 'i': + { + return [NSNumber numberWithInt:*((int *)objc_value)]; + } +#ifndef __ppc__ + case 'C': + { + return [NSNumber numberWithUnsignedChar:*((unsigned char *)objc_value)]; + } + case 'S': + { + return [NSNumber numberWithUnsignedShort:*((unsigned short *)objc_value)]; + } +#else + case 'C': + case 'S': +#endif + case 'I': + { + return [NSNumber numberWithUnsignedInt:*((unsigned int *)objc_value)]; + } + case 'l': + { + return [NSNumber numberWithLong:*((long *)objc_value)]; + } + case 'L': + { + return [NSNumber numberWithUnsignedLong:*((unsigned long *)objc_value)]; + } + case 'q': + { + return [NSNumber numberWithLongLong:*((long long *)objc_value)]; + } + case 'Q': + { + return [NSNumber numberWithUnsignedLongLong:*((unsigned long long *)objc_value)]; + } + case 'f': + { + return [NSNumber numberWithFloat:*((float *)objc_value)]; + } + case 'd': + { + return [NSNumber numberWithDouble:*((double *)objc_value)]; + } + case ':': + { + SEL sel = *((SEL *)objc_value); + return [[NSString stringWithCString:sel_getName(sel) encoding:NSUTF8StringEncoding] retain]; + } + case '{': + { + if ( + !strcmp(typeString, NSRECT_SIGNATURE0) || + !strcmp(typeString, NSRECT_SIGNATURE1) || + !strcmp(typeString, NSRECT_SIGNATURE2) || + !strcmp(typeString, CGRECT_SIGNATURE0) || + !strcmp(typeString, CGRECT_SIGNATURE1) || + !strcmp(typeString, CGRECT_SIGNATURE2) + ) { + NSRect *rect = (NSRect *)objc_value; + NuCell *list = [[[NuCell alloc] init] autorelease]; + id cursor = list; + [cursor setCar:[NSNumber numberWithDouble:rect->origin.x]]; + [cursor setCdr:[[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + [cursor setCar:[NSNumber numberWithDouble:rect->origin.y]]; + [cursor setCdr:[[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + [cursor setCar:[NSNumber numberWithDouble:rect->size.width]]; + [cursor setCdr:[[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + [cursor setCar:[NSNumber numberWithDouble:rect->size.height]]; + //NSLog(@"converting rect at %x to list: %@", (void *) rect, [list stringValue]); + return list; + } + else if ( + !strcmp(typeString, NSRANGE_SIGNATURE) || + !strcmp(typeString, NSRANGE_SIGNATURE1) + ) { + NSRange *range = (NSRange *)objc_value; + NuCell *list = [[[NuCell alloc] init] autorelease]; + id cursor = list; + [cursor setCar:[NSNumber numberWithInteger:range->location]]; + [cursor setCdr:[[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + [cursor setCar:[NSNumber numberWithInteger:range->length]]; + return list; + } + else if ( + !strcmp(typeString, NSPOINT_SIGNATURE0) || + !strcmp(typeString, NSPOINT_SIGNATURE1) || + !strcmp(typeString, NSPOINT_SIGNATURE2) || + !strcmp(typeString, CGPOINT_SIGNATURE) + ) { + NSPoint *point = (NSPoint *)objc_value; + NuCell *list = [[[NuCell alloc] init] autorelease]; + id cursor = list; + [cursor setCar:[NSNumber numberWithDouble:point->x]]; + [cursor setCdr:[[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + [cursor setCar:[NSNumber numberWithDouble:point->y]]; + return list; + } + else if ( + !strcmp(typeString, NSSIZE_SIGNATURE0) || + !strcmp(typeString, NSSIZE_SIGNATURE1) || + !strcmp(typeString, NSSIZE_SIGNATURE2) || + !strcmp(typeString, CGSIZE_SIGNATURE) + ) { + NSSize *size = (NSSize *)objc_value; + NuCell *list = [[[NuCell alloc] init] autorelease]; + id cursor = list; + [cursor setCar:[NSNumber numberWithDouble:size->width]]; + [cursor setCdr:[[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + [cursor setCar:[NSNumber numberWithDouble:size->height]]; + return list; + } + else { + NSLog(@"UNIMPLEMENTED: can't wrap structure of type %s", typeString); + } + } + case '*': + { + return [NSString stringWithCString:*((char **)objc_value) encoding:NSUTF8StringEncoding]; + } + case 'B': + { + if (*((unsigned int *)objc_value) == 0) + return [NSNull null]; + else + return [NSNumber numberWithInt:1]; + } + case '^': + { + if (!strcmp(typeString, "^v")) { + if (*((unsigned long *)objc_value) == 0) + return [NSNull null]; + else { + id nupointer = [[[NuPointer alloc] init] autorelease]; + [nupointer setPointer:*((void **)objc_value)]; + [nupointer setTypeString:[NSString stringWithCString:typeString encoding:NSUTF8StringEncoding]]; + return nupointer; + } + } + else if (!strcmp(typeString, "^@")) { + id reference = [[[NuReference alloc] init] autorelease]; + [reference setPointer:*((id**)objc_value)]; + return reference; + } + // Certain pointer types are essentially just ids. + // CGImageRef is one. As we find others, we can add them here. + else if (!strcmp(typeString, "^{CGImage=}")) { + id result = *((id *)objc_value); + return result ? result : (id)[NSNull null]; + } + else if (!strcmp(typeString, "^{CGColor=}")) { + id result = *((id *)objc_value); + return result ? result : (id)[NSNull null]; + } + else { + if (*((unsigned long *)objc_value) == 0) + return [NSNull null]; + else { + id nupointer = [[[NuPointer alloc] init] autorelease]; + [nupointer setPointer:*((void **)objc_value)]; + [nupointer setTypeString:[NSString stringWithCString:typeString encoding:NSUTF8StringEncoding]]; + return nupointer; + } + } + return [NSNull null]; + } + default: + NSLog (@"UNIMPLEMENTED: unable to wrap object of type %s", typeString); + return [NSNull null]; + } + +} + +static void raise_argc_exception(SEL s, NSUInteger count, NSUInteger given) +{ + if (given != count) { + [NSException raise:@"NuIncorrectNumberOfArguments" + format:@"Incorrect number of arguments to selector %s. Received %ld but expected %ld", + sel_getName(s), + (unsigned long) given, + (unsigned long) count]; + } +} + +#define BUFSIZE 500 + +id nu_calling_objc_method_handler(id target, Method m, NSMutableArray *args) +{ + // this call seems to force the class's +initialize method to be called. + [target class]; + + // NSLog(@"calling ObjC method %s with target of class %@", sel_getName(method_getName(m)), [target class]); + + IMP imp = method_getImplementation(m); + + // if the imp has an associated block, this is a nu-to-nu call. + // skip going through the ObjC runtime and evaluate the block directly. + NuBlock *block = nil; + if (nu_block_table && + ((block = [nu_block_table objectForKey:[NSNumber numberWithUnsignedLong:(unsigned long)imp]]))) { + // NSLog(@"nu calling nu method %s of class %@", sel_getName(method_getName(m)), [target class]); + id arguments = [[NuCell alloc] init]; + id cursor = arguments; + NSUInteger argc = [args count]; + int i; + for (i = 0; i < argc; i++) { + NuCell *nextCell = [[NuCell alloc] init]; + [cursor setCdr:nextCell]; + [nextCell release]; + cursor = [cursor cdr]; + [cursor setCar:[args objectAtIndex:i]]; + } + id result = [block evalWithArguments:[arguments cdr] context:nil self:target]; + [arguments release]; + // ensure that methods declared to return void always return void. + char return_type_buffer[BUFSIZE]; + method_getReturnType(m, return_type_buffer, BUFSIZE); + return (!strcmp(return_type_buffer, "v")) ? (id)[NSNull null] : result; + } + + id result; + // if we get here, we're going through the ObjC runtime to make the call. + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + SEL s = method_getName(m); + result = [NSNull null]; + + // dynamically construct the method call + + + int argument_count = method_getNumberOfArguments(m); + + if ( [args count] != argument_count-2) { + + raise_argc_exception(s, argument_count-2, [args count]); + } + else { + char return_type_buffer[BUFSIZE], arg_type_buffer[BUFSIZE]; + method_getReturnType(m, return_type_buffer, BUFSIZE); + ffi_type *result_type = ffi_type_for_objc_type(&return_type_buffer[0]); + void *result_value = value_buffer_for_objc_type(&return_type_buffer[0]); + ffi_type **argument_types = (ffi_type **) malloc (argument_count * sizeof(ffi_type *)); + void **argument_values = (void **) malloc (argument_count * sizeof(void *)); + int *argument_needs_retained = (int *) malloc (argument_count * sizeof(int)); + int i; + for (i = 0; i < argument_count; i++) { + + method_getArgumentType(m, i, &arg_type_buffer[0], BUFSIZE); + + argument_types[i] = ffi_type_for_objc_type(&arg_type_buffer[0]); + argument_values[i] = value_buffer_for_objc_type(&arg_type_buffer[0]); + if (i == 0) + *((id *) argument_values[i]) = target; + else if (i == 1) + *((SEL *) argument_values[i]) = method_getName(m); + else + argument_needs_retained[i-2] = set_objc_value_from_nu_value(argument_values[i], [args objectAtIndex:(i-2)], &arg_type_buffer[0]); + } + ffi_cif cif2; + int status = ffi_prep_cif(&cif2, FFI_DEFAULT_ABI, (unsigned int) argument_count, result_type, argument_types); + if (status != FFI_OK) { + NSLog (@"failed to prepare cif structure"); + } + else { + const char *method_name = sel_getName(method_getName(m)); + BOOL callingInitializer = !strncmp("init", method_name, 4); + if (callingInitializer) { + [target retain]; // in case an init method releases its target (to return something else), we preemptively retain it + } + // call the method handler + ffi_call(&cif2, FFI_FN(imp), result_value, argument_values); + // extract the return value + result = get_nu_value_from_objc_value(result_value, &return_type_buffer[0]); + // NSLog(@"result is %@", result); + // NSLog(@"retain count %d", [result retainCount]); + + // Return values should not require a release. + // Either they are owned by an existing object or are autoreleased. + // Exceptions to this rule are handled below. + // Since these methods create new objects that aren't autoreleased, we autorelease them. +#ifdef LINUX + const char *methodName = sel_getName(s); + bool already_retained = !strcmp(methodName,"alloc") || + !strcmp(methodName,"allocWithZone:") || + !strcmp(methodName,"copy") || + !strcmp(methodName,"copyWithZone:") || + !strcmp(methodName,"mutableCopy:") || + !strcmp(methodName,"mutableCopyWithZone:") || + !strcmp(methodName,"new"); +#else + bool already_retained = // see Anguish/Buck/Yacktman, p. 104 + (s == @selector(alloc)) || (s == @selector(allocWithZone:)) + || (s == @selector(copy)) || (s == @selector(copyWithZone:)) + || (s == @selector(mutableCopy)) || (s == @selector(mutableCopyWithZone:)) + || (s == @selector(new)); +#endif + // NSLog(@"already retained? %d", already_retained); + if (already_retained) { + [result autorelease]; + } + + if (callingInitializer) { + if (result == target) { + // NSLog(@"undoing preemptive retain of init target %@", [target className]); + [target release]; // undo our preemptive retain + } else { + // NSLog(@"keeping preemptive retain of init target %@", [target className]); + } + } + + for (i = 0; i < [args count]; i++) { + if (argument_needs_retained[i]) + [[args objectAtIndex:i] retainReferencedObject]; + } + + // free the value structures + for (i = 0; i < argument_count; i++) { + free(argument_values[i]); + } + free(argument_values); + free(result_value); + free(argument_types); + free(argument_needs_retained); + } + } + [result retain]; + [pool drain]; + [result autorelease]; + return result; +} + +@interface NSMethodSignature (UndocumentedInterface) ++ (id) signatureWithObjCTypes:(const char*)types; +@end + +static void objc_calling_nu_method_handler(ffi_cif* cif, void* returnvalue, void** args, void* userdata) +{ + int argc = cif->nargs - 2; + id rcv = *((id*)args[0]); // this is the object getting the message + // unused: SEL sel = *((SEL*)args[1]); + + // in rare cases, we need an autorelease pool (specifically detachNewThreadSelector:toTarget:withObject:) + // previously we used a private api to verify that one existed before creating a new one. Now we just make one. + NSAutoreleasePool *pool = nil; // [[NSAutoreleasePool alloc] init]; + + NuBlock *block = ((NuBlock **)userdata)[1]; + //NSLog(@"----------------------------------------"); + //NSLog(@"calling block %@", [block stringValue]); + id arguments = [[NuCell alloc] init]; + id cursor = arguments; + int i; + for (i = 0; i < argc; i++) { + NuCell *nextCell = [[NuCell alloc] init]; + [cursor setCdr:nextCell]; + [nextCell release]; + cursor = [cursor cdr]; + id value = get_nu_value_from_objc_value(args[i+2], ((char **)userdata)[i+2]); + [cursor setCar:value]; + } + id result = [block evalWithArguments:[arguments cdr] context:nil self:rcv]; + //NSLog(@"in nu method handler, putting result %@ in %x with type %s", [result stringValue], (int) returnvalue, ((char **)userdata)[0]); + char *resultType = (((char **)userdata)[0])+1;// skip the first character, it's a flag + set_objc_value_from_nu_value(returnvalue, result, resultType); +#ifdef __ppc__ + // It appears that at least on PowerPC architectures, small values (short, char, ushort, uchar) passed in via + // the ObjC runtime use their actual type while function return values are coerced up to integers. + // I suppose this is because values are passed as arguments in memory and returned in registers. + // This may also be the case on x86 but is unobserved because x86 is little endian. + switch (resultType[0]) { + case 'C': + { + *((unsigned int *) returnvalue) = *((unsigned char *) returnvalue); + break; + } + case 'c': + { + *((int *) returnvalue) = *((char *) returnvalue); + break; + } + case 'S': + { + *((unsigned int *) returnvalue) = *((unsigned short *) returnvalue); + break; + } + case 's': + { + *((int *) returnvalue) = *((short *) returnvalue); + break; + } + } +#endif + + if (((char **)userdata)[0][0] == '!') { + //NSLog(@"retaining result for object %@, count = %d", *(id *)returnvalue, [*(id *)returnvalue retainCount]); + [*((id *)returnvalue) retain]; + } + [arguments release]; + if (pool) { + if (resultType[0] == '@') + [*((id *)returnvalue) retain]; + [pool drain]; + if (resultType[0] == '@') + [*((id *)returnvalue) autorelease]; + } +} + +static char **generate_userdata(SEL sel, NuBlock *block, const char *signature) +{ + NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:signature]; + const char *return_type_string = [methodSignature methodReturnType]; + NSUInteger argument_count = [methodSignature numberOfArguments]; + char **userdata = (char **) malloc ((argument_count+3) * sizeof(char*)); + userdata[0] = (char *) malloc (2 + strlen(return_type_string)); + const char *methodName = sel_getName(sel); + BOOL returnsRetainedResult = NO; + if ((!strcmp(methodName, "alloc")) || + (!strcmp(methodName, "allocWithZone:")) || + (!strcmp(methodName, "copy")) || + (!strcmp(methodName, "copyWithZone:")) || + (!strcmp(methodName, "mutableCopy")) || + (!strcmp(methodName, "mutableCopyWithZone:")) || + (!strcmp(methodName, "new"))) + returnsRetainedResult = YES; + if (returnsRetainedResult) + sprintf(userdata[0], "!%s", return_type_string); + else + sprintf(userdata[0], " %s", return_type_string); + //NSLog(@"constructing handler for method %s with %d arguments and returnType %s", methodName, argument_count, userdata[0]); + userdata[1] = (char *) block; + [block retain]; + int i; + for (i = 0; i < argument_count; i++) { + const char *argument_type_string = [methodSignature getArgumentTypeAtIndex:i]; + if (i > 1) userdata[i] = strdup(argument_type_string); + } + userdata[argument_count] = NULL; + return userdata; +} + +static IMP construct_method_handler(SEL sel, NuBlock *block, const char *signature) +{ + char **userdata = generate_userdata(sel, block, signature); + IMP imp = [NuHandlerWarehouse handlerWithSelector:sel block:block signature:signature userdata:userdata]; + if (imp) { + return imp; + } + int argument_count = 0; + while (userdata[argument_count] != 0) argument_count++; +#if 0 + const char *methodName = sel_getName(sel); + NSLog(@"using libffi to construct handler for method %s with %d arguments and signature %s", methodName, argument_count, signature); +#endif + ffi_type **argument_types = (ffi_type **) malloc ((argument_count+1) * sizeof(ffi_type *)); + ffi_type *result_type = ffi_type_for_objc_type(userdata[0]+1); + argument_types[0] = ffi_type_for_objc_type("@"); + argument_types[1] = ffi_type_for_objc_type(":"); + for (int i = 2; i < argument_count; i++) + argument_types[i] = ffi_type_for_objc_type(userdata[i]); + argument_types[argument_count] = NULL; + ffi_cif *cif = (ffi_cif *)malloc(sizeof(ffi_cif)); + if (cif == NULL) { + NSLog(@"unable to prepare closure for signature %s (could not allocate memory for cif structure)", signature); + return NULL; + } + int status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, argument_count, result_type, argument_types); + if (status != FFI_OK) { + NSLog(@"unable to prepare closure for signature %s (ffi_prep_cif failed)", signature); + return NULL; + } + ffi_closure *closure = (ffi_closure *)mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (closure == (ffi_closure *) -1) { + NSLog(@"unable to prepare closure for signature %s (mmap failed with error %d)", signature, errno); + return NULL; + } + if (closure == NULL) { + NSLog(@"unable to prepare closure for signature %s (could not allocate memory for closure)", signature); + return NULL; + } + if (ffi_prep_closure(closure, cif, objc_calling_nu_method_handler, userdata) != FFI_OK) { + NSLog(@"unable to prepare closure for signature %s (ffi_prep_closure failed)", signature); + return NULL; + } + if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1) { + NSLog(@"unable to prepare closure for signature %s (mprotect failed with error %d)", signature, errno); + return NULL; + } + return (IMP) closure; +} + +id add_method_to_class(Class c, NSString *methodName, NSString *signature, NuBlock *block) +{ + const char *method_name_str = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; + const char *signature_str = [signature cStringUsingEncoding:NSUTF8StringEncoding]; + SEL selector = sel_registerName(method_name_str); + + //NuSymbolTable *symbolTable = [[block context] objectForKey:SYMBOLS_KEY]; + //[[block context] setPossiblyNullObject:[[NuClass alloc] initWithClass:c] forKey:[symbolTable symbolWithString:@"_class"]]; + + IMP imp = construct_method_handler(selector, block, signature_str); + if (imp == NULL) { + NSLog(@"failed to construct handler for %s(%s)", method_name_str, signature_str); + return [NSNull null]; + } + + // save the block in a hash table keyed by the imp. + // this will let us introspect methods and optimize nu-to-nu method calls + if (!nu_block_table) nu_block_table = [[NSMutableDictionary alloc] init]; + // watch for problems caused by these ugly casts... + [nu_block_table setObject:block forKey:[NSNumber numberWithUnsignedLong:(unsigned long) imp]]; +#if !TARGET_OS_IPHONE + [[NSGarbageCollector defaultCollector] disableCollectorForPointer: block]; +#endif + // insert the method handler in the class method table + nu_class_replaceMethod(c, selector, imp, signature_str); + //NSLog(@"setting handler for %s(%s) in class %s", method_name_str, signature_str, class_getName(c)); + return [NSNull null]; +} + +@interface NuBridgedFunction () +{ + char *name; + char *signature; + void *function; +} +@end + +@implementation NuBridgedFunction + +- (void) dealloc +{ + free(name); + free(signature); + [super dealloc]; +} + +- (NuBridgedFunction *) initWithName:(NSString *)n signature:(NSString *)s +{ + name = strdup([n cStringUsingEncoding:NSUTF8StringEncoding]); + signature = strdup([s cStringUsingEncoding:NSUTF8StringEncoding]); + function = dlsym(RTLD_DEFAULT, name); + if (!function) { + [NSException raise:@"NuCantFindBridgedFunction" + format:@"%s\n%s\n%s\n", dlerror(), + "If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set.", + "In Xcode, check the 'Preserve Private External Symbols' checkbox."]; + } + return self; +} + ++ (NuBridgedFunction *) functionWithName:(NSString *)name signature:(NSString *)signature +{ + const char *function_name = [name cStringUsingEncoding:NSUTF8StringEncoding]; + void *function = dlsym(RTLD_DEFAULT, function_name); + if (!function) { + [NSException raise:@"NuCantFindBridgedFunction" + format:@"%s\n%s\n%s\n", dlerror(), + "If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set.", + "In Xcode, check the 'Preserve Private External Symbols' checkbox."]; + } + NuBridgedFunction *wrapper = [[[NuBridgedFunction alloc] initWithName:name signature:signature] autorelease]; + return wrapper; +} + +- (id) evalWithArguments:(id) cdr context:(NSMutableDictionary *) context +{ + //NSLog(@"----------------------------------------"); + //NSLog(@"calling C function %s with signature %s", name, signature); + id result; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + char *return_type_identifier = strdup(signature); + nu_markEndOfObjCTypeString(return_type_identifier, strlen(return_type_identifier)); + + int argument_count = 0; + char *argument_type_identifiers[100]; + char *cursor = &signature[strlen(return_type_identifier)]; + while (*cursor != 0) { + argument_type_identifiers[argument_count] = strdup(cursor); + nu_markEndOfObjCTypeString(argument_type_identifiers[argument_count], strlen(cursor)); + cursor = &cursor[strlen(argument_type_identifiers[argument_count])]; + argument_count++; + } + //NSLog(@"calling return type is %s", return_type_identifier); + int i; + for (i = 0; i < argument_count; i++) { + // NSLog(@"argument %d type is %s", i, argument_type_identifiers[i]); + } + + ffi_cif *cif = (ffi_cif *)malloc(sizeof(ffi_cif)); + + ffi_type *result_type = ffi_type_for_objc_type(return_type_identifier); + ffi_type **argument_types = (argument_count == 0) ? NULL : (ffi_type **) malloc (argument_count * sizeof(ffi_type *)); + for (i = 0; i < argument_count; i++) + argument_types[i] = ffi_type_for_objc_type(argument_type_identifiers[i]); + + int status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, argument_count, result_type, argument_types); + if (status != FFI_OK) { + NSLog (@"failed to prepare cif structure"); + return [NSNull null]; + } + + id arg_cursor = cdr; + void *result_value = value_buffer_for_objc_type(return_type_identifier); + void **argument_values = (void **) (argument_count ? malloc (argument_count * sizeof(void *)) : NULL); + + for (i = 0; i < argument_count; i++) { + argument_values[i] = value_buffer_for_objc_type( argument_type_identifiers[i]); + id arg_value = [[arg_cursor car] evalWithContext:context]; + set_objc_value_from_nu_value(argument_values[i], arg_value, argument_type_identifiers[i]); + arg_cursor = [arg_cursor cdr]; + } + ffi_call(cif, FFI_FN(function), result_value, argument_values); + result = get_nu_value_from_objc_value(result_value, return_type_identifier); + + // free the value structures + for (i = 0; i < argument_count; i++) { + free(argument_values[i]); + free(argument_type_identifiers[i]); + } + free(argument_values); + free(result_value); + free(return_type_identifier); + free(argument_types); + free(cif); + + [result retain]; + [pool drain]; + [result autorelease]; + return result; +} + +@end + +@implementation NuBridgedConstant + ++ (id) constantWithName:(NSString *) name signature:(NSString *) signature +{ + const char *constant_name = [name cStringUsingEncoding:NSUTF8StringEncoding]; + void *constant = dlsym(RTLD_DEFAULT, constant_name); + if (!constant) { + NSLog(@"%s", dlerror()); + NSLog(@"If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set."); + NSLog(@"In Xcode, check the 'Preserve Private External Symbols' checkbox."); + return nil; + } + return get_nu_value_from_objc_value(constant, [signature cStringUsingEncoding:NSUTF8StringEncoding]); +} + +@end + + +static NuSymbol *oneway_symbol, *in_symbol, *out_symbol, *inout_symbol, *bycopy_symbol, *byref_symbol, *const_symbol, +*void_symbol, *star_symbol, *id_symbol, *voidstar_symbol, *idstar_symbol, *int_symbol, *long_symbol, *NSComparisonResult_symbol, +*BOOL_symbol, *double_symbol, *float_symbol, *NSRect_symbol, *NSPoint_symbol, *NSSize_symbol, *NSRange_symbol, +*CGRect_symbol, *CGPoint_symbol, *CGSize_symbol, +*SEL_symbol, *Class_symbol; + + +static void prepare_symbols(NuSymbolTable *symbolTable) +{ + oneway_symbol = [symbolTable symbolWithString:@"oneway"]; + in_symbol = [symbolTable symbolWithString:@"in"]; + out_symbol = [symbolTable symbolWithString:@"out"]; + inout_symbol = [symbolTable symbolWithString:@"inout"]; + bycopy_symbol = [symbolTable symbolWithString:@"bycopy"]; + byref_symbol = [symbolTable symbolWithString:@"byref"]; + const_symbol = [symbolTable symbolWithString:@"const"]; + void_symbol = [symbolTable symbolWithString:@"void"]; + star_symbol = [symbolTable symbolWithString:@"*"]; + id_symbol = [symbolTable symbolWithString:@"id"]; + voidstar_symbol = [symbolTable symbolWithString:@"void*"]; + idstar_symbol = [symbolTable symbolWithString:@"id*"]; + int_symbol = [symbolTable symbolWithString:@"int"]; + long_symbol = [symbolTable symbolWithString:@"long"]; + NSComparisonResult_symbol = [symbolTable symbolWithString:@"NSComparisonResult"]; + BOOL_symbol = [symbolTable symbolWithString:@"BOOL"]; + double_symbol = [symbolTable symbolWithString:@"double"]; + float_symbol = [symbolTable symbolWithString:@"float"]; + NSRect_symbol = [symbolTable symbolWithString:@"NSRect"]; + NSPoint_symbol = [symbolTable symbolWithString:@"NSPoint"]; + NSSize_symbol = [symbolTable symbolWithString:@"NSSize"]; + NSRange_symbol = [symbolTable symbolWithString:@"NSRange"]; + CGRect_symbol = [symbolTable symbolWithString:@"CGRect"]; + CGPoint_symbol = [symbolTable symbolWithString:@"CGPoint"]; + CGSize_symbol = [symbolTable symbolWithString:@"CGSize"]; + SEL_symbol = [symbolTable symbolWithString:@"SEL"]; + Class_symbol = [symbolTable symbolWithString:@"Class"]; +} + +NSString *signature_for_identifier(NuCell *cell, NuSymbolTable *symbolTable) +{ + static NuSymbolTable *currentSymbolTable = nil; + if (currentSymbolTable != symbolTable) { + prepare_symbols(symbolTable); + currentSymbolTable = symbolTable; + } + NSMutableArray *modifiers = nil; + NSMutableString *signature = [NSMutableString string]; + id cursor = cell; + BOOL finished = NO; + while (cursor && cursor != Nu__null) { + if (finished) { + // ERROR! + NSLog(@"I can't bridge this return type yet: %@ (%@)", [cell stringValue], signature); + return @"?"; + } + id cursor_car = [cursor car]; + if (cursor_car == oneway_symbol) { + if (!modifiers) modifiers = [NSMutableArray array]; + [modifiers addObject:@"V"]; + } + else if (cursor_car == in_symbol) { + if (!modifiers) modifiers = [NSMutableArray array]; + [modifiers addObject:@"n"]; + } + else if (cursor_car == out_symbol) { + if (!modifiers) modifiers = [NSMutableArray array]; + [modifiers addObject:@"o"]; + } + else if (cursor_car == inout_symbol) { + if (!modifiers) modifiers = [NSMutableArray array]; + [modifiers addObject:@"N"]; + } + else if (cursor_car == bycopy_symbol) { + if (!modifiers) modifiers = [NSMutableArray array]; + [modifiers addObject:@"O"]; + } + else if (cursor_car == byref_symbol) { + if (!modifiers) modifiers = [NSMutableArray array]; + [modifiers addObject:@"R"]; + } + else if (cursor_car == const_symbol) { + if (!modifiers) modifiers = [NSMutableArray array]; + [modifiers addObject:@"r"]; + } + else if (cursor_car == void_symbol) { + if (![cursor cdr] || ([cursor cdr] == [NSNull null])) { + if (modifiers) + [signature appendString:[[modifiers sortedArrayUsingSelector:@selector(compare:)] componentsJoinedByString:@""]]; + [signature appendString:@"v"]; + finished = YES; + } + else if ([[cursor cdr] car] == star_symbol) { + [signature appendString:@"^v"]; + cursor = [cursor cdr]; + finished = YES; + } + } + else if (cursor_car == id_symbol) { + if (![cursor cdr] || ([cursor cdr] == [NSNull null])) { + if (modifiers) + [signature appendString:[[modifiers sortedArrayUsingSelector:@selector(compare:)] componentsJoinedByString:@""]]; + [signature appendString:@"@"]; + finished = YES; + } + else if ([[cursor cdr] car] == star_symbol) { + [signature appendString:@"^@"]; + cursor = [cursor cdr]; + finished = YES; + } + } + else if (cursor_car == voidstar_symbol) { + [signature appendString:@"^v"]; + finished = YES; + } + else if (cursor_car == idstar_symbol) { + [signature appendString:@"^@"]; + finished = YES; + } + else if (cursor_car == int_symbol) { + [signature appendString:@"i"]; + finished = YES; + } + else if (cursor_car == long_symbol) { + [signature appendString:@"l"]; + finished = YES; + } + else if (cursor_car == NSComparisonResult_symbol) { + if (sizeof(NSComparisonResult) == 4) + [signature appendString:@"i"]; + else + [signature appendString:@"q"]; + finished = YES; + } + else if (cursor_car == BOOL_symbol) { + [signature appendString:@"C"]; + finished = YES; + } + else if (cursor_car == double_symbol) { + [signature appendString:@"d"]; + finished = YES; + } + else if (cursor_car == float_symbol) { + [signature appendString:@"f"]; + finished = YES; + } + else if (cursor_car == NSRect_symbol) { + [signature appendString:@NSRECT_SIGNATURE0]; + finished = YES; + } + else if (cursor_car == NSPoint_symbol) { + [signature appendString:@NSPOINT_SIGNATURE0]; + finished = YES; + } + else if (cursor_car == NSSize_symbol) { + [signature appendString:@NSSIZE_SIGNATURE0]; + finished = YES; + } + else if (cursor_car == NSRange_symbol) { + [signature appendString:@NSRANGE_SIGNATURE]; + finished = YES; + } + else if (cursor_car == CGRect_symbol) { + [signature appendString:@CGRECT_SIGNATURE0]; + finished = YES; + } + else if (cursor_car == CGPoint_symbol) { + [signature appendString:@CGPOINT_SIGNATURE]; + finished = YES; + } + else if (cursor_car == CGSize_symbol) { + [signature appendString:@CGSIZE_SIGNATURE]; + finished = YES; + } + else if (cursor_car == SEL_symbol) { + [signature appendString:@":"]; + finished = YES; + } + else if (cursor_car == Class_symbol) { + [signature appendString:@"#"]; + finished = YES; + } + cursor = [cursor cdr]; + } + if (finished) + return signature; + else { + NSLog(@"I can't bridge this return type yet: %@ (%@)", [cell stringValue], signature); + return @"?"; + } +} + +id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *context, BOOL addClassMethod) +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + + id returnType = [NSNull null]; + id selector = [[[NuCell alloc] init] autorelease]; + id argumentTypes = [NSNull null]; + id argumentNames = [NSNull null]; + id isSymbol = [symbolTable symbolWithString:@"is"]; + id cursor = cdr; + id selector_cursor = nil; + id argumentTypes_cursor = nil; + id argumentNames_cursor = nil; + + if (cursor && (cursor != [NSNull null]) && ([cursor car] != isSymbol)) { + // scan the return type + if (![[cursor car] atom]) { + returnType = [cursor car] ; + cursor = [cursor cdr]; + } + else { + // The return type specifier must be a list (in parens). If it is missing, leave it as null. + returnType = Nu__null; + } + if (cursor && (cursor != [NSNull null])) { + [selector setCar:[cursor car]]; // scan a part of the selector + cursor = [cursor cdr]; + if (cursor && (cursor != [NSNull null])) { + if ([cursor car] != isSymbol) { + argumentTypes = [[[NuCell alloc] init] autorelease]; + argumentNames = [[[NuCell alloc] init] autorelease]; + if (![[cursor car] atom]) { + // the argument type specifier must be a list. If it is missing, we'll use a default. + [argumentTypes setCar:[cursor car]]; + cursor = [cursor cdr]; + } + if (cursor && (cursor != [NSNull null])) { + [argumentNames setCar:[cursor car]]; + cursor = [cursor cdr]; + if (cursor && (cursor != [NSNull null])) { + selector_cursor = selector; + argumentTypes_cursor = argumentTypes; + argumentNames_cursor = argumentNames; + } + } + } + } + } + } + // scan each remaining part of the selector + while (cursor && (cursor != [NSNull null]) && ([cursor car] != isSymbol)) { + [selector_cursor setCdr:[[[NuCell alloc] init] autorelease]]; + [argumentTypes_cursor setCdr:[[[NuCell alloc] init] autorelease]]; + [argumentNames_cursor setCdr:[[[NuCell alloc] init] autorelease]]; + selector_cursor = [selector_cursor cdr]; + argumentTypes_cursor = [argumentTypes_cursor cdr]; + argumentNames_cursor = [argumentNames_cursor cdr]; + + [selector_cursor setCar:[cursor car]]; + cursor = [cursor cdr]; + if (cursor && (cursor != [NSNull null])) { + if (![[cursor car] atom]) { + // the argument type specifier must be a list. If it is missing, we'll use a default. + [argumentTypes_cursor setCar:[cursor car]]; + cursor = [cursor cdr]; + } + if (cursor && (cursor != [NSNull null])) { + [argumentNames_cursor setCar:[cursor car]]; + cursor = [cursor cdr]; + } + } + } + + if (cursor && (cursor != [NSNull null])) { + //NSLog(@"selector: %@", [selector stringValue]); + //NSLog(@"argument names: %@", [argumentNames stringValue]); + //NSLog(@"argument types:%@", [argumentTypes stringValue]); + //NSLog(@"returns: %@", [returnType stringValue]); + + // skip the is + cursor = [cursor cdr]; + + // combine the selectors into the method name + NSMutableString *methodName = [[[NSMutableString alloc] init] autorelease]; + selector_cursor = selector; + while (selector_cursor && (selector_cursor != [NSNull null])) { + [methodName appendString:[[selector_cursor car] stringValue]]; + selector_cursor = [selector_cursor cdr]; + } + + NSMutableString *signature = nil; + + if ((returnType == Nu__null) || ([argumentTypes length] < [argumentNames length])) { + // look up the signature + SEL selector = sel_registerName([methodName cStringUsingEncoding:NSUTF8StringEncoding]); + NSMethodSignature *methodSignature = [classToExtend instanceMethodSignatureForSelector:selector]; + + if (!methodSignature) + methodSignature = [classToExtend methodSignatureForSelector:selector]; + if (methodSignature) + signature = [NSMutableString stringWithString:[methodSignature typeString]]; + // if we can't find a signature, use a default + if (!signature) { + // NSLog(@"no signature found. treating all arguments and the return type as (id)"); + signature = [NSMutableString stringWithString:@"@@:"]; + int i; + for (i = 0; i < [argumentNames length]; i++) { + [signature appendString:@"@"]; + } + } + } + else { + // build the signature, first get the return type + signature = [NSMutableString string]; + [signature appendString:signature_for_identifier(returnType, symbolTable)]; + + // then add the common stuff + [signature appendString:@"@:"]; + + // then describe the arguments + argumentTypes_cursor = argumentTypes; + while (argumentTypes_cursor && (argumentTypes_cursor != [NSNull null])) { + id typeIdentifier = [argumentTypes_cursor car]; + [signature appendString:signature_for_identifier(typeIdentifier, symbolTable)]; + argumentTypes_cursor = [argumentTypes_cursor cdr]; + } + } + id body = cursor; + NuBlock *block = [[[NuBlock alloc] initWithParameters:argumentNames body:body context:context] autorelease]; + [[block context] + setPossiblyNullObject:methodName + forKey:[symbolTable symbolWithString:@"_method"]]; + return add_method_to_class( + addClassMethod ? object_getClass(classToExtend) : classToExtend, + methodName, signature, block); + } + else { + // not good. you probably forgot the "is" in your method declaration. + [NSException raise:@"NuBadMethodDeclaration" + format:@"invalid method declaration: %@", + [cdr stringValue]]; + return nil; + } +} + +#ifdef __BLOCKS__ + +static id make_cblock (NuBlock *nuBlock, NSString *signature); +static void objc_calling_nu_block_handler(ffi_cif* cif, void* returnvalue, void** args, void* userdata); +static char **generate_block_userdata(NuBlock *nuBlock, const char *signature); +static void *construct_block_handler(NuBlock *block, const char *signature); + +@interface NuBridgedBlock () +{ + NuBlock *nuBlock; + id cBlock; +} +@end + +@implementation NuBridgedBlock + ++(id)cBlockWithNuBlock:(NuBlock*)nb signature:(NSString*)sig +{ + return [[[[self alloc] initWithNuBlock:nb signature:sig] autorelease] cBlock]; +} + +-(id)initWithNuBlock:(NuBlock*)nb signature:(NSString*)sig +{ + nuBlock = [nb retain]; + cBlock = make_cblock(nb,sig); + + return self; +} + +-(NuBlock*)nuBlock +{return [[nuBlock retain] autorelease];} + +-(id)cBlock +{return [[cBlock retain] autorelease];} + +-(void)dealloc +{ + [nuBlock release]; + [cBlock release]; + [super dealloc]; +} + +@end + +//the caller gets ownership of the block +static id make_cblock (NuBlock *nuBlock, NSString *signature) +{ + void *funcptr = construct_block_handler(nuBlock, [signature UTF8String]); + + int i = 0xFFFF; + void(^cBlock)(void)=[^(void){printf("%i",i);} copy]; + +#ifdef __x86_64__ + /* this is what happens when a block is called on x86 64 + mov %rax,-0x18(%rbp) //the pointer to the block object is in rax + mov -0x18(%rbp),%rax + mov 0x10(%rax),%rax //the pointer to the block function is at +0x10 into the block object + mov -0x18(%rbp),%rdi //the first argument (this examples has no others) is always the pointer to the block object + callq *%rax + */ + //2*(sizeof(void*)) = 0x10 + *((void **)(id)cBlock + 2) = (void *)funcptr; +#else + /* this is what happens when a block is called on x86 32 + mov %eax,-0x14(%ebp) //the pointer to the block object is in eax + mov -0x14(%ebp),%eax + mov 0xc(%eax),%eax //the pointer to the block function is at +0xc into the block object + mov %eax,%edx + mov -0x14(%ebp),%eax //the first argument (this examples has no others) is always the pointer to the block object + mov %eax,(%esp) + call *%edx + */ + //3*(sizeof(void*)) = 0xc + *((void **)(id)cBlock + 3) = (void *)funcptr; +#endif + return cBlock; +} + +static void objc_calling_nu_block_handler(ffi_cif* cif, void* returnvalue, void** args, void* userdata) +{ + int argc = cif->nargs - 1; + //void *ptr = (void*)args[0] //don't need this first parameter + // see objc_calling_nu_method_handler + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NuBlock *block = ((NuBlock **)userdata)[1]; + //NSLog(@"----------------------------------------"); + //NSLog(@"calling block %@", [block stringValue]); + id arguments = [[NuCell alloc] init]; + id cursor = arguments; + int i; + for (i = 0; i < argc; i++) { + NuCell *nextCell = [[NuCell alloc] init]; + [cursor setCdr:nextCell]; + [nextCell release]; + cursor = [cursor cdr]; + id value = get_nu_value_from_objc_value(args[i+1], ((char **)userdata)[i+2]); + [cursor setCar:value]; + } + //NSLog(@"in nu method handler, using arguments %@", [arguments stringValue]); + id result = [block evalWithArguments:[arguments cdr] context:nil]; + //NSLog(@"in nu method handler, putting result %@ in %x with type %s", [result stringValue], (size_t) returnvalue, ((char **)userdata)[0]); + char *resultType = (((char **)userdata)[0])+1;// skip the first character, it's a flag + set_objc_value_from_nu_value(returnvalue, result, resultType); + [arguments release]; + if (pool) { + if (resultType[0] == '@') + [*((id *)returnvalue) retain]; + [pool release]; + if (resultType[0] == '@') + [*((id *)returnvalue) autorelease]; + } +} + +static char **generate_block_userdata(NuBlock *nuBlock, const char *signature) +{ + NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:signature]; + const char *return_type_string = [methodSignature methodReturnType]; + NSUInteger argument_count = [methodSignature numberOfArguments]; + char **userdata = (char **) malloc ((argument_count+3) * sizeof(char*)); + userdata[0] = (char *) malloc (2 + strlen(return_type_string)); + + //assume blocks never return retained results + sprintf(userdata[0], " %s", return_type_string); + + //so first element is return type, second is nuBlock + userdata[1] = (char *) nuBlock; + [nuBlock retain]; + int i; + for (i = 0; i < argument_count; i++) { + const char *argument_type_string = [methodSignature getArgumentTypeAtIndex:i]; + userdata[i+2] = strdup(argument_type_string); + } + userdata[argument_count+2] = NULL; + +#if 0 + NSLog(@"Userdata for block: %@, signature: %s", [nuBlock stringValue], signature); + for (int i = 0; i < argument_count+2; i++) + { if (i != 1) + NSLog(@"userdata[%i] = %s",i,userdata[i]); } +#endif + return userdata; +} + + +static void *construct_block_handler(NuBlock *block, const char *signature) +{ + char **userdata = generate_block_userdata(block, signature); + + int argument_count = 0; + while (userdata[argument_count] != 0) argument_count++; + argument_count-=1; //unlike a method call, c blocks have one, not two hidden args (see comments in make_cblock() +#if 0 + NSLog(@"using libffi to construct handler for nu block with %d arguments and signature %s", argument_count, signature); +#endif + if (argument_count < 0) { + NSLog(@"error in argument construction"); + return NULL; + } + + ffi_type **argument_types = (ffi_type **) malloc ((argument_count+1) * sizeof(ffi_type *)); + ffi_type *result_type = ffi_type_for_objc_type(userdata[0]+1); + + argument_types[0] = ffi_type_for_objc_type("^?"); + + for (int i = 1; i < argument_count; i++) + argument_types[i] = ffi_type_for_objc_type(userdata[i+1]); + argument_types[argument_count] = NULL; + ffi_cif *cif = (ffi_cif *)malloc(sizeof(ffi_cif)); + if (cif == NULL) { + NSLog(@"unable to prepare closure for signature %s (could not allocate memory for cif structure)", signature); + return NULL; + } + int status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, argument_count, result_type, argument_types); + if (status != FFI_OK) { + NSLog(@"unable to prepare closure for signature %s (ffi_prep_cif failed)", signature); + return NULL; + } + ffi_closure *closure = (ffi_closure *)mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (closure == (ffi_closure *) -1) { + NSLog(@"unable to prepare closure for signature %s (mmap failed with error %d)", signature, errno); + return NULL; + } + if (closure == NULL) { + NSLog(@"unable to prepare closure for signature %s (could not allocate memory for closure)", signature); + return NULL; + } + if (ffi_prep_closure(closure, cif, objc_calling_nu_block_handler, userdata) != FFI_OK) { + NSLog(@"unable to prepare closure for signature %s (ffi_prep_closure failed)", signature); + return NULL; + } + if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1) { + NSLog(@"unable to prepare closure for signature %s (mprotect failed with error %d)", signature, errno); + return NULL; + } + return (void*)closure; +} + +#endif //__BLOCKS__ + +#pragma mark - NuBridgeSupport.m + +#if !TARGET_OS_IPHONE + +static NSString *getTypeStringFromNode(id node) +{ + static BOOL use64BitTypes = (sizeof(void *) == 8); + if (use64BitTypes ) { + id type64Attribute = [node attributeForName:@"type64"]; + if (type64Attribute) + return [type64Attribute stringValue]; + } + return [[node attributeForName:@"type"] stringValue]; +} + +@implementation NuBridgeSupport + ++ (void)importLibrary:(NSString *) libraryPath +{ + //NSLog(@"importing library %@", libraryPath); + dlopen([libraryPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_LAZY | RTLD_GLOBAL); +} + ++ (void)importFramework:(NSString *) framework fromPath:(NSString *) path intoDictionary:(NSMutableDictionary *) BridgeSupport +{ + NSMutableDictionary *frameworks = [BridgeSupport valueForKey:@"frameworks"]; + if ([frameworks valueForKey:framework]) + return; + else + [frameworks setValue:framework forKey:framework]; + + NSString *xmlPath; // constants, enums, functions, and more are described in an XML file. + NSString *dylibPath; // sometimes a dynamic library is included to provide implementations of inline functions. + + if (path) { + xmlPath = [NSString stringWithFormat:@"%@/Resources/BridgeSupport/%@.bridgesupport", path, framework]; + dylibPath = [NSString stringWithFormat:@"%@/Resources/BridgeSupport/%@.dylib", path, framework]; + } + else { + xmlPath = [NSString stringWithFormat:@"/System/Library/Frameworks/%@.framework/Resources/BridgeSupport/%@.bridgesupport", framework, framework]; + dylibPath = [NSString stringWithFormat:@"/System/Library/Frameworks/%@.framework/Resources/BridgeSupport/%@.dylib", framework, framework]; + } + + if ([NSFileManager fileExistsNamed:dylibPath]) + [self importLibrary:dylibPath]; + + NSMutableDictionary *constants = [BridgeSupport valueForKey:@"constants"]; + NSMutableDictionary *enums = [BridgeSupport valueForKey:@"enums"]; + NSMutableDictionary *functions = [BridgeSupport valueForKey:@"functions"]; + + NSXMLDocument *xmlDocument = [[[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:xmlPath] options:0 error:NULL] autorelease]; + if (xmlDocument) { + id node; + NSEnumerator *childEnumerator = [[[xmlDocument rootElement] children] objectEnumerator]; + while ((node = [childEnumerator nextObject])) { + if ([[node name] isEqual:@"depends_on"]) { + id fileName = [[node attributeForName:@"path"] stringValue]; + id frameworkName = [[[fileName lastPathComponent] componentsSeparatedByString:@"."] objectAtIndex:0]; + [NuBridgeSupport importFramework:frameworkName fromPath:fileName intoDictionary:BridgeSupport]; + } + else if ([[node name] isEqual:@"constant"]) { + [constants setValue:getTypeStringFromNode(node) + forKey:[[node attributeForName:@"name"] stringValue]]; + } + else if ([[node name] isEqual:@"enum"]) { + [enums setValue:[NSNumber numberWithInt:[[[node attributeForName:@"value"] stringValue] intValue]] + forKey:[[node attributeForName:@"name"] stringValue]]; + } + else if ([[node name] isEqual:@"function"]) { + id name = [[node attributeForName:@"name"] stringValue]; + id argumentTypes = [NSMutableString string]; + id returnType = @"v"; + id child; + NSEnumerator *nodeChildEnumerator = [[node children] objectEnumerator]; + while ((child = [nodeChildEnumerator nextObject])) { + if ([[child name] isEqual:@"arg"]) { + id typeModifier = [child attributeForName:@"type_modifier"]; + if (typeModifier) { + [argumentTypes appendString:[typeModifier stringValue]]; + } + [argumentTypes appendString:getTypeStringFromNode(child)]; + } + else if ([[child name] isEqual:@"retval"]) { + returnType = getTypeStringFromNode(child); + } + else { + NSLog(@"unrecognized type #{[child XMLString]}"); + } + } + id signature = [NSString stringWithFormat:@"%@%@", returnType, argumentTypes]; + [functions setValue:signature forKey:name]; + } + } + } + else { + // don't complain about missing bridge support files... + //NSString *reason = [NSString stringWithFormat:@"unable to find BridgeSupport file for %@", framework]; + //[[NSException exceptionWithName:@"NuBridgeSupportMissing" reason:reason userInfo:nil] raise]; + } +} + ++ (void) prune +{ + NuSymbolTable *symbolTable = [NuSymbolTable sharedSymbolTable]; + id BridgeSupport = [[symbolTable symbolWithString:@"BridgeSupport"] value]; + [[BridgeSupport objectForKey:@"frameworks"] removeAllObjects]; + + id key; + for (int i = 0; i < 3; i++) { + id dictionary = [BridgeSupport objectForKey:(i == 0) ? @"constants" : (i == 1) ? @"enums" : @"functions"]; + id keyEnumerator = [[dictionary allKeys] objectEnumerator]; + while ((key = [keyEnumerator nextObject])) { + if (![symbolTable lookup:key]) + [dictionary removeObjectForKey:key]; + } + } +} + ++ (NSString *) stringValue +{ + NuSymbolTable *symbolTable = [NuSymbolTable sharedSymbolTable]; + id BridgeSupport = [[symbolTable symbolWithString:@"BridgeSupport"] value]; + + id result = [NSMutableString stringWithString:@"(global BridgeSupport\n"]; + id d, keyEnumerator, key; + + [result appendString:@" (dict\n"]; + d = [BridgeSupport objectForKey:@"constants"]; + [result appendString:@" constants:\n"]; + [result appendString:@" (dict"]; + keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; + while ((key = [keyEnumerator nextObject])) { + [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; + } + [result appendString:@")\n"]; + + d = [BridgeSupport objectForKey:@"enums"]; + [result appendString:@" enums:\n"]; + [result appendString:@" (dict"]; + keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; + while ((key = [keyEnumerator nextObject])) { + [result appendString:[NSString stringWithFormat:@"\n \"%@\" %@", key, [d objectForKey:key]]]; + } + [result appendString:@")\n"]; + + d = [BridgeSupport objectForKey:@"functions"]; + [result appendString:@" functions:\n"]; + [result appendString:@" (dict"]; + keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; + while ((key = [keyEnumerator nextObject])) { + [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; + } + [result appendString:@")\n"]; + + d = [BridgeSupport objectForKey:@"frameworks"]; + [result appendString:@" frameworks:\n"]; + [result appendString:@" (dict"]; + keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; + while ((key = [keyEnumerator nextObject])) { + [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; + } + [result appendString:@")))\n"]; + return result; +} + +@end +#endif \ No newline at end of file diff --git a/objc/NuCell.h b/objc/NuCell.h new file mode 100644 index 0000000..e907ead --- /dev/null +++ b/objc/NuCell.h @@ -0,0 +1,91 @@ +// +// NuCell.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @class NuCell + @abstract The building blocks of lists. + @discussion NuCells are used to build lists and accept several powerful messages for list manipulation. + In Lisp, these are called "cons" cells after the function used to create them. + + Each NuCell contains pointers to two objects, which for historical reasons are called its "car" and "cdr". + These pointers can point to objects of any Objective-C class, + which includes other NuCells. Typically, the car of a NuCell points to a member of a list and + its cdr points to another NuCell that is the head of the remainder of the list. + The cdr of the last element in a list is nil. + In Nu, nil is represented with the [NSNull null] object. + */ +@interface NuCell : NSObject + +/*! Create a new cell with a specifed car and cdr. */ ++ (id) cellWithCar:(id)car cdr:(id)cdr; +/*! Get the car of a NuCell. */ +- (id) car; +/*! Get the cdr of a NuCell. */ +- (id) cdr; +/*! Set the car of a NuCell. */ +- (void) setCar:(id) c; +/*! Set the cdr of a NuCell. */ +- (void) setCdr:(id) c; +/*! Get the last object in a list by traversing the list. Use this carefully. */ +- (id) lastObject; +/*! Get a string representation of a list. In many cases, this can be parsed to produce the original list. */ +- (NSMutableString *) stringValue; +/*! Treat the NuCell as the head of a list of Nu expressions and evaluate those expressions. */ +- (id) evalWithContext:(NSMutableDictionary *)context; +/*! Returns false. NuCells are not atoms. Also, nil is not an atom. But everything else is. */ +- (bool) atom; +/*! Get any comments that were associated with a NuCell in its Nu source file. */ +- (id) comments; +/*! Iterate over each element of the list headed by a NuCell, calling the specified block with the element as an argument. */ +- (id) each:(id) block; +/*! Iterate over each pair of elements of the list headed by a NuCell, calling the specified block with the two elements as arguments. */ +- (id) eachPair:(id) block; +/*! Iterate over each element of the list headed by a NuCell, calling the specified block with the element and its index as arguments. */ +- (id) eachWithIndex:(id) block; +/*! Iterate over each element of the list headed by a NuCell, returning a list containing the elements for which the provided block evaluates non-nil. */ +- (id) select:(id) block; +/*! Iterate over each element of the list headed by a NuCell, returning the first element for which the provided block evaluates non-nil. */ +- (id) find:(id) block; +/*! Iterate over each element of the list headed by a NuCell, applying the provided block to each element, and returning a list of the results. */ +- (id) map:(id) block; +/*! Iterate over each element of the list headed by a NuCell, using the provided block to combine elements into a single return value. */ +- (id) reduce:(id) block from:(id) initial; +/*! Get the length of a list beginning at a NuCell. */ +- (NSUInteger) length; +/*! Get the number of elements in a list. Synonymous with length. */ +- (NSUInteger) count; +/*! Get an array containing the elements of a list. */ +- (NSMutableArray *) array; + +- (void) setFile:(int) f line:(int) l; +- (int) file; +- (int) line; + +- (void)encodeWithCoder:(NSCoder *)coder; +- (id) initWithCoder:(NSCoder *)coder; + +@end + +/*! + @class NuCellWithComments + @abstract A cell with annotated comments. + @discussion To simplify programmatic analysis of Nu code, + the Nu parser can optionally attach the comments preceding a list element to an instance of this subclass of NuCell. + Comments can then be parsed with Nu code, typically to produce documentation. + */ +@interface NuCellWithComments : NuCell + +/*! Get a string containing the comments that preceded a list element. */ +- (id) comments; +/*! Set the comments string for a list element. */ +- (void) setComments:(id) comments; + +@end + diff --git a/objc/NuCell.m b/objc/NuCell.m new file mode 100644 index 0000000..1176c9a --- /dev/null +++ b/objc/NuCell.m @@ -0,0 +1,538 @@ +// +// NuCell.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuCell.h" +#import "NuInternals.h" +#import "NSString+Nu.h" +#import "NuException.h" +#import "NuBlock.h" + +@interface NuCell () +{ + id car; + id cdr; + int file; + int line; +} +@end + +@implementation NuCell + ++ (id) cellWithCar:(id)car cdr:(id)cdr +{ + NuCell *cell = [[self alloc] init]; + [cell setCar:car]; + [cell setCdr:cdr]; + return [cell autorelease]; +} + +- (id) init +{ + if ((self = [super init])) { + car = Nu__null; + cdr = Nu__null; + file = -1; + line = -1; + } + return self; +} + +- (void) dealloc +{ + [car release]; + [cdr release]; + [super dealloc]; +} + +- (bool) atom {return false;} + +- (id) car {return car;} + +- (id) cdr {return cdr;} + +- (void) setCar:(id) c +{ + [c retain]; + [car release]; + car = c; +} + +- (void) setCdr:(id) c +{ + [c retain]; + [cdr release]; + cdr = c; +} + +// additional accessors, for efficiency (from Nu) +- (id) caar {return [car car];} +- (id) cadr {return [car cdr];} +- (id) cdar {return [cdr car];} +- (id) cddr {return [cdr cdr];} +- (id) caaar {return [[car car] car];} +- (id) caadr {return [[car car] cdr];} +- (id) cadar {return [[car cdr] car];} +- (id) caddr {return [[car cdr] cdr];} +- (id) cdaar {return [[cdr car] car];} +- (id) cdadr {return [[cdr car] cdr];} +- (id) cddar {return [[cdr cdr] car];} +- (id) cdddr {return [[cdr cdr] cdr];} + +- (BOOL) isEqual:(id) other +{ + if (nu_objectIsKindOfClass(other, [NuCell class]) + && [[self car] isEqual:[other car]] && [[self cdr] isEqual:[other cdr]]) { + return YES; + } + else { + return NO; + } +} + +- (id) first +{ + return car; +} + +- (id) second +{ + return [cdr car]; +} + +- (id) third +{ + return [[cdr cdr] car]; +} + +- (id) fourth +{ + return [[[cdr cdr] cdr] car]; +} + +- (id) fifth +{ + return [[[[cdr cdr] cdr] cdr] car]; +} + +- (id) nth:(int) n +{ + if (n == 1) + return car; + id cursor = cdr; + int i; + for (i = 2; i < n; i++) { + cursor = [cursor cdr]; + if (cursor == Nu__null) return nil; + } + return [cursor car]; +} + +- (id) objectAtIndex:(int) n +{ + if (n < 0) + return nil; + else if (n == 0) + return car; + id cursor = cdr; + for (int i = 1; i < n; i++) { + cursor = [cursor cdr]; + if (cursor == Nu__null) return nil; + } + return [cursor car]; +} + +// When an unknown message is received by a cell, treat it as a call to objectAtIndex: +- (id) handleUnknownMessage:(NuCell *) method withContext:(NSMutableDictionary *) context +{ + if ([[method car] isKindOfClass:[NuSymbol class]]) { + NSString *methodName = [[method car] stringValue]; + NSUInteger length = [methodName length]; + if (([methodName characterAtIndex:0] == 'c') && ([methodName characterAtIndex:(length - 1)] == 'r')) { + id cursor = self; + BOOL valid = YES; + for (int i = 1; valid && (i < length - 1); i++) { + switch ([methodName characterAtIndex:i]) { + case 'd': cursor = [cursor cdr]; break; + case 'a': cursor = [cursor car]; break; + default: valid = NO; + } + } + if (valid) return cursor; + } + } + id m = [[method car] evalWithContext:context]; + if ([m isKindOfClass:[NSNumber class]]) { + int mm = [m intValue]; + if (mm < 0) { + // if the index is negative, index from the end of the array + mm += [self length]; + } + return [self objectAtIndex:mm]; + } + else { + return [super handleUnknownMessage:method withContext:context]; + } +} + +- (id) lastObject +{ + id cursor = self; + while ([cursor cdr] != Nu__null) { + cursor = [cursor cdr]; + } + return [cursor car]; +} + +- (NSMutableString *) stringValue +{ + NuCell *cursor = self; + NSMutableString *result = [NSMutableString stringWithString:@"("]; + int count = 0; + while (IS_NOT_NULL(cursor)) { + if (count > 0) + [result appendString:@" "]; + count++; + id item = [cursor car]; + if (nu_objectIsKindOfClass(item, [NuCell class])) { + [result appendString:[item stringValue]]; + } + else if (IS_NOT_NULL(item)) { + if ([item respondsToSelector:@selector(escapedStringRepresentation)]) { + [result appendString:[item escapedStringRepresentation]]; + } + else { + [result appendString:[item description]]; + } + } + else { + [result appendString:@"()"]; + } + cursor = [cursor cdr]; + // check for dotted pairs + if (IS_NOT_NULL(cursor) && !nu_objectIsKindOfClass(cursor, [NuCell class])) { + [result appendString:@" . "]; + if ([cursor respondsToSelector:@selector(escapedStringRepresentation)]) { + [result appendString:[((id) cursor) escapedStringRepresentation]]; + } + else { + [result appendString:[cursor description]]; + } + break; + } + } + [result appendString:@")"]; + return result; +} + +- (NSString *) description +{ + return [self stringValue]; +} + +- (void) addToException:(NuException*)e value:(id)value +{ + const char *parsedFilename = nu_parsedFilename(self->file); + + if (parsedFilename) { + NSString* filename = [NSString stringWithCString:parsedFilename encoding:NSUTF8StringEncoding]; + [e addFunction:value lineNumber:[self line] filename:filename]; + } + else { + [e addFunction:value lineNumber:[self line]]; + } +} + +- (id) evalWithContext:(NSMutableDictionary *)context +{ + id value = nil; + id result = nil; + + @try + { + value = [car evalWithContext:context]; + +#ifdef DARWIN + if (NU_LIST_EVAL_BEGIN_ENABLED()) { + if ((self->line != -1) && (self->file != -1)) { + NU_LIST_EVAL_BEGIN(nu_parsedFilename(self->file), self->line); + } + else { + NU_LIST_EVAL_BEGIN("", 0); + } + } +#endif + // to improve error reporting, add the currently-evaluating expression to the context + [context setObject:self forKey:[[NuSymbolTable sharedSymbolTable] symbolWithString:@"_expression"]]; + + result = [value evalWithArguments:cdr context:context]; + +#ifdef DARWIN + if (NU_LIST_EVAL_END_ENABLED()) { + if ((self->line != -1) && (self->file != -1)) { + NU_LIST_EVAL_END(nu_parsedFilename(self->file), self->line); + } + else { + NU_LIST_EVAL_END("", 0); + } + } +#endif + } + @catch (NuException* nuException) { + [self addToException:nuException value:[car stringValue]]; + @throw nuException; + } + @catch (NSException* e) { + if ( nu_objectIsKindOfClass(e, [NuBreakException class]) + || nu_objectIsKindOfClass(e, [NuContinueException class]) + || nu_objectIsKindOfClass(e, [NuReturnException class])) { + @throw e; + } + else { + NuException* nuException = [[NuException alloc] initWithName:[e name] + reason:[e reason] + userInfo:[e userInfo]]; + [self addToException:nuException value:[car stringValue]]; + @throw nuException; + } + } + + return result; +} + +- (id) each:(id) block +{ + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + id args = [[NuCell alloc] init]; + id cursor = self; + while (cursor && (cursor != Nu__null)) { + [args setCar:[cursor car]]; + [block evalWithArguments:args context:Nu__null]; + cursor = [cursor cdr]; + } + [args release]; + } + return self; +} + +- (id) eachPair:(id) block +{ + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + id args = [[NuCell alloc] init]; + [args setCdr:[[[NuCell alloc] init] autorelease]]; + id cursor = self; + while (cursor && (cursor != Nu__null)) { + [args setCar:[cursor car]]; + [[args cdr] setCar:[[cursor cdr] car]]; + [block evalWithArguments:args context:Nu__null]; + cursor = [[cursor cdr] cdr]; + } + [args release]; + } + return self; +} + +- (id) eachWithIndex:(id) block +{ + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + id args = [[NuCell alloc] init]; + [args setCdr:[[[NuCell alloc] init] autorelease]]; + id cursor = self; + int i = 0; + while (cursor && (cursor != Nu__null)) { + [args setCar:[cursor car]]; + [[args cdr] setCar:[NSNumber numberWithInt:i]]; + [block evalWithArguments:args context:Nu__null]; + cursor = [cursor cdr]; + i++; + } + [args release]; + } + return self; +} + +- (id) select:(id) block +{ + NuCell *parent = [[[NuCell alloc] init] autorelease]; + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + id args = [[NuCell alloc] init]; + id cursor = self; + id resultCursor = parent; + while (cursor && (cursor != Nu__null)) { + [args setCar:[cursor car]]; + id result = [block evalWithArguments:args context:Nu__null]; + if (nu_valueIsTrue(result)) { + [resultCursor setCdr:[NuCell cellWithCar:[cursor car] cdr:[resultCursor cdr]]]; + resultCursor = [resultCursor cdr]; + } + cursor = [cursor cdr]; + } + [args release]; + } + else + return Nu__null; + NuCell *selected = [parent cdr]; + return selected; +} + +- (id) find:(id) block +{ + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + id args = [[NuCell alloc] init]; + id cursor = self; + while (cursor && (cursor != Nu__null)) { + [args setCar:[cursor car]]; + id result = [block evalWithArguments:args context:Nu__null]; + if (nu_valueIsTrue(result)) { + [args release]; + return [cursor car]; + } + cursor = [cursor cdr]; + } + [args release]; + } + return Nu__null; +} + +- (id) map:(id) block +{ + NuCell *parent = [[[NuCell alloc] init] autorelease]; + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + id args = [[NuCell alloc] init]; + id cursor = self; + id resultCursor = parent; + while (cursor && (cursor != Nu__null)) { + [args setCar:[cursor car]]; + id result = [block evalWithArguments:args context:Nu__null]; + [resultCursor setCdr:[NuCell cellWithCar:result cdr:[resultCursor cdr]]]; + cursor = [cursor cdr]; + resultCursor = [resultCursor cdr]; + } + [args release]; + } + else + return Nu__null; + NuCell *result = [parent cdr]; + return result; +} + +- (id) mapSelector:(SEL) sel +{ + NuCell *parent = [[NuCell alloc] init]; + id args = [[NuCell alloc] init]; + id cursor = self; + id resultCursor = parent; + while (cursor && (cursor != Nu__null)) { + id object = [cursor car]; + id result = [object performSelector:sel]; + [resultCursor setCdr:[NuCell cellWithCar:result cdr:[resultCursor cdr]]]; + cursor = [cursor cdr]; + resultCursor = [resultCursor cdr]; + } + [args release]; + NuCell *result = [parent cdr]; + [parent release]; + return result; +} + +- (id) reduce:(id) block from:(id) initial +{ + id result = initial; + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + id args = [[NuCell alloc] init]; + [args setCdr:[[[NuCell alloc] init] autorelease]]; + id cursor = self; + while (cursor && (cursor != Nu__null)) { + [args setCar:result]; + [[args cdr] setCar:[cursor car]]; + result = [block evalWithArguments:args context:Nu__null]; + cursor = [cursor cdr]; + } + [args release]; + } + return result; +} + +- (NSUInteger) length +{ + int count = 0; + id cursor = self; + while (cursor && (cursor != Nu__null)) { + cursor = [cursor cdr]; + count++; + } + return count; +} + +- (NSMutableArray *) array +{ + NSMutableArray *a = [NSMutableArray array]; + id cursor = self; + while (cursor && cursor != Nu__null) { + [a addObject:[cursor car]]; + cursor = [cursor cdr]; + } + return a; +} + +- (NSUInteger) count +{ + return [self length]; +} + +- (id) comments {return nil;} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeObject:car]; + [coder encodeObject:cdr]; +} + +- (id) initWithCoder:(NSCoder *)coder +{ + if ((self = [super init])) { + car = [[coder decodeObject] retain]; + cdr = [[coder decodeObject] retain]; + } + return self; +} + +- (void) setFile:(int) f line:(int) l +{ + file = f; + line = l; +} + +- (int) file {return file;} +- (int) line {return line;} +@end + +@interface NuCellWithComments () +{ + id comments; +} +@end + +@implementation NuCellWithComments + +- (void) dealloc +{ + [comments release]; + [super dealloc]; +} + +- (id) comments {return comments;} + +- (void) setComments:(id) c +{ + [c retain]; + [comments release]; + comments = c; +} + +@end + diff --git a/objc/NuClass.h b/objc/NuClass.h new file mode 100644 index 0000000..1af884b --- /dev/null +++ b/objc/NuClass.h @@ -0,0 +1,67 @@ +// +// NuClass.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +@class NuBlock; +@class NuMethod; + +/*! + @class NuClass + @abstract A Nu wrapper for class representations in the Objective-C runtime. + @discussion NuClass provides an object wrapper for classes that are represented in the Objective-C runtime. + NuClass objects are used in the Nu language to manipulate and extend Objective-C classes. + */ +@interface NuClass : NSObject + +/*! Create a class wrapper for the specified class (used from Objective-C). */ ++ (NuClass *) classWithClass:(Class) class; +/*! Create a class wrapper for the named Objective-C class. */ ++ (NuClass *) classWithName:(NSString *)string; +/*! Initialize a class wrapper for the specified class (used from Objective-C). */ +- (id) initWithClass:(Class) class; +/*! Initialize a class wrapper for the named Objective-C class. */ +- (id) initWithClassNamed:(NSString *) name; +/*! Get the class corresponding to the NuClass wrapper (used from Objective-C). */ +- (Class) wrappedClass; +/*! Get an array of all classes known to the Objective-C runtime. + Beware, some of these classes may be deprecated, undocumented, or otherwise unsafe to use. */ ++ (NSArray *) all; +/*! Get the name of a class. */ +- (NSString *) name; +/*! Get an array containing NuMethod representations of the class methods of a class. */ +- (NSArray *) classMethods; +/*! Get an array containing NuMethod representations of the instance methods of a class. */ +- (NSArray *) instanceMethods; +/*! Get an array containing the names of the class methods of a class. */ +- (NSArray *) classMethodNames; +/*! Get an array containing the names of the instance methods of a class. */ +- (NSArray *) instanceMethodNames; +/*! Determine whether a class is derived from another class. */ +- (BOOL) isDerivedFromClass:(Class) parent; +/*! Compare a class with another class by name. This allows arrays of classes to be easily sorted. */ +- (NSComparisonResult) compare:(NuClass *) anotherClass; +/*! Get a class method by name. */ +- (NuMethod *) classMethodWithName:(NSString *) methodName; +/*! Get an instance method by name. */ +- (NuMethod *) instanceMethodWithName:(NSString *) methodName; +/*! Compare two classes for equality. */ +- (BOOL) isEqual:(NuClass *) anotherClass; +/*! Change the superclass of a class. Be careful with this. */ +- (void) setSuperclass:(NuClass *) newSuperclass; +/*! Add an instance method to a class with the specified name, type signature, and body. */ +- (id) addInstanceMethod:(NSString *) methodName signature:(NSString *)signature body:(NuBlock *) block; +/*! Add a class method to a class with the specified name, type signature, and body. */ +- (id) addClassMethod:(NSString *) methodName signature:(NSString *)signature body:(NuBlock *) block; +/*! Add an instance variable to the receiving class. This will cause problems if there are already instances of the receiving class. */ +- (id) addInstanceVariable:(NSString *)variableName signature:(NSString *) signature; + +- (BOOL) isRegistered; +- (void) setRegistered:(BOOL) value; +- (void) registerClass; +@end diff --git a/objc/NuClass.m b/objc/NuClass.m new file mode 100644 index 0000000..35432a5 --- /dev/null +++ b/objc/NuClass.m @@ -0,0 +1,289 @@ +// +// NuClass.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuClass.h" +#import "NuInternals.h" + +#import "NuProperty.h" +#import "NuEnumerable.h" +#import "NuMethod.h" + +#pragma mark - NuClass.m + +// getting a specific method... +// (set x (((Convert classMethods) select: (do (m) (eq (m name) "passRect:"))) objectAtIndex:0)) + +@interface NuClass () +{ + Class c; + BOOL isRegistered; +} +@end + +@implementation NuClass + ++ (NuClass *) classWithName:(NSString *)string +{ + const char *name = [string cStringUsingEncoding:NSUTF8StringEncoding]; + Class class = objc_getClass(name); + if (class) { + return [[[self alloc] initWithClass:class] autorelease]; + } + else { + return nil; + } +} + ++ (NuClass *) classWithClass:(Class) class +{ + if (class) { + return [[[self alloc] initWithClass:class] autorelease]; + } + else { + return nil; + } +} + +- (id) initWithClassNamed:(NSString *) string +{ + const char *name = [string cStringUsingEncoding:NSUTF8StringEncoding]; + Class class = objc_getClass(name); + return [self initWithClass: class]; +} + +- (id) initWithClass:(Class) class +{ + if ((self = [super init])) { + c = class; + isRegistered = YES; // unless we explicitly set otherwise + } + return self; +} + ++ (NSArray *) all +{ + NSMutableArray *array = [NSMutableArray array]; + int numClasses = objc_getClassList(NULL, 0); + if(numClasses > 0) { + Class *classes = (Class *) malloc( sizeof(Class) * numClasses ); + objc_getClassList(classes, numClasses); + int i = 0; + while (i < numClasses) { + NuClass *class = [[[NuClass alloc] initWithClass:classes[i]] autorelease]; + [array addObject:class]; + i++; + } + free(classes); + } + return array; +} + +- (NSString *) name +{ + // NSLog(@"calling NuClass name for object %@", self); + return [NSString stringWithCString:class_getName(c) encoding:NSUTF8StringEncoding]; +} + +- (NSString *) stringValue +{ + return [self name]; +} + +- (Class) wrappedClass +{ + return c; +} + +- (NSArray *) classMethods +{ + NSMutableArray *array = [NSMutableArray array]; + unsigned int method_count; + Method *method_list = class_copyMethodList(object_getClass([self wrappedClass]), &method_count); + int i; + for (i = 0; i < method_count; i++) { + [array addObject:[[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]]; + } + free(method_list); + [array sortUsingSelector:@selector(compare:)]; + return array; +} + +- (NSArray *) instanceMethods +{ + NSMutableArray *array = [NSMutableArray array]; + unsigned int method_count; + Method *method_list = class_copyMethodList([self wrappedClass], &method_count); + int i; + for (i = 0; i < method_count; i++) { + [array addObject:[[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]]; + } + free(method_list); + [array sortUsingSelector:@selector(compare:)]; + return array; +} + +/*! Get an array containing the names of the class methods of a class. */ +- (NSArray *) classMethodNames +{ + id methods = [self classMethods]; + return [methods mapSelector:@selector(name)]; +} + +/*! Get an array containing the names of the instance methods of a class. */ +- (NSArray *) instanceMethodNames +{ + id methods = [self instanceMethods]; + return [methods mapSelector:@selector(name)]; +} + +- (BOOL) isDerivedFromClass:(Class) parent +{ + Class myclass = [self wrappedClass]; + if (myclass == parent) + return true; + Class superclass = [myclass superclass]; + if (superclass) + return nu_objectIsKindOfClass(superclass, parent); + return false; +} + +- (NSComparisonResult) compare:(NuClass *) anotherClass +{ + return [[self name] compare:[anotherClass name]]; +} + +- (NuMethod *) classMethodWithName:(NSString *) methodName +{ + const char *methodNameString = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; + NuMethod *method = Nu__null; + unsigned int method_count; + Method *method_list = class_copyMethodList(object_getClass([self wrappedClass]), &method_count); + int i; + for (i = 0; i < method_count; i++) { + if (!strcmp(methodNameString, sel_getName(method_getName(method_list[i])))) { + method = [[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]; + } + } + free(method_list); + return method; +} + +- (NuMethod *) instanceMethodWithName:(NSString *) methodName +{ + const char *methodNameString = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; + NuMethod *method = Nu__null; + unsigned int method_count; + Method *method_list = class_copyMethodList([self wrappedClass], &method_count); + int i; + for (i = 0; i < method_count; i++) { + if (!strcmp(methodNameString, sel_getName(method_getName(method_list[i])))) { + method = [[[NuMethod alloc] initWithMethod:method_list[i]] autorelease]; + } + } + free(method_list); + return method; +} + +- (id) addInstanceMethod:(NSString *)methodName signature:(NSString *)signature body:(NuBlock *)block +{ + //NSLog(@"adding instance method %@", methodName); + return add_method_to_class(c, methodName, signature, block); +} + +- (id) addClassMethod:(NSString *)methodName signature:(NSString *)signature body:(NuBlock *)block +{ + NSLog(@"adding class method %@", methodName); + return add_method_to_class(object_getClass(c), /* c->isa, */ methodName, signature, block); +} + +- (id) addInstanceVariable:(NSString *)variableName signature:(NSString *)signature +{ + //NSLog(@"adding instance variable %@", variableName); + nu_class_addInstanceVariable_withSignature(c, [variableName cStringUsingEncoding:NSUTF8StringEncoding], [signature cStringUsingEncoding:NSUTF8StringEncoding]); + return Nu__null; +} + +- (BOOL) isEqual:(NuClass *) anotherClass +{ + return c == anotherClass->c; +} + +- (void) setSuperclass:(NuClass *) newSuperclass +{ + struct nu_objc_class + { + Class isa; + Class super_class; + // other stuff... + }; + ((struct nu_objc_class *) self->c)->super_class = newSuperclass->c; +} + +- (BOOL) isRegistered +{ + return isRegistered; +} + +- (void) setRegistered:(BOOL) value +{ + isRegistered = value; +} + +- (void) registerClass +{ + if (isRegistered == NO) { + objc_registerClassPair(c); + isRegistered = YES; + } +} + +- (id) handleUnknownMessage:(id) cdr withContext:(NSMutableDictionary *) context +{ + return [[self wrappedClass] handleUnknownMessage:cdr withContext:context]; +} + +- (NSArray *) instanceVariableNames { + NSMutableArray *names = [NSMutableArray array]; + + unsigned int ivarCount = 0; + // Ivar *ivarList = class_copyIvarList(c, &ivarCount); + + NSLog(@"%d ivars", ivarCount); + return names; +} + +- (BOOL) addPropertyWithName:(NSString *) name { + const objc_property_attribute_t attributes[10]; + unsigned int attributeCount = 0; + return class_addProperty(c, [name cStringUsingEncoding:NSUTF8StringEncoding], + attributes, + attributeCount); +} + +- (NuProperty *) propertyWithName:(NSString *) name { + objc_property_t property = class_getProperty(c, [name cStringUsingEncoding:NSUTF8StringEncoding]); + + return [NuProperty propertyWithProperty:(objc_property_t) property]; +} + +- (NSArray *) properties { + unsigned int property_count; + objc_property_t *property_list = class_copyPropertyList(c, &property_count); + + NSMutableArray *properties = [NSMutableArray array]; + for (int i = 0; i < property_count; i++) { + [properties addObject:[NuProperty propertyWithProperty:property_list[i]]]; + } + free(property_list); + return properties; +} + +//OBJC_EXPORT objc_property_t class_getProperty(Class cls, const char *name) + + +@end diff --git a/objc/NuEnumerable.h b/objc/NuEnumerable.h new file mode 100644 index 0000000..ab1eccd --- /dev/null +++ b/objc/NuEnumerable.h @@ -0,0 +1,41 @@ +// +// NuEnumerable.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +@class NuBlock; + +/*! + @class NuEnumerable + @abstract The NuEnumerable mixin class. + @discussion This class implements methods that act on enumerated collections of objects. + It is designed to be mixed into a class using the include method that Nu adds to NSObject. + The receiving class must have an objectEnumerator method that returns an NSEnumerator. + Some methods in this class take a callable object as an argument; callable objects are those + that have evalWithArguments:context: defined. + */ +@interface NuEnumerable : NSObject + +/*! Iterate over each member of a collection, evaluating the provided callable item for each member. */ +- (id) each:(id) callable; +/*! Iterate over each member of a collection, evaluating the provided block for each member. + The block is expected to take two arguments: the member and its index. */ +- (id) eachWithIndex:(NuBlock *) block; +/*! Iterate over each member of a collection, returning an array containing the elements for which the provided block evaluates non-nil. */ +- (NSArray *) select:(NuBlock *) block; +/*! Iterate over each member of a collection, returning the first element for which the provided block evaluates non-nil. */ +- (id) find:(NuBlock *) block; +/*! Iterate over each member of a collection, applying the provided block to each member, and returning an array of the results. */ +- (NSArray *) map:(id) callable; +/*! Iterate over each member of a collection, using the provided callable to combine members into a single return value. + */ +- (id) reduce:(id) callable from:(id) initial; +/*! Iterate over each member of a collection, applying the provided selector to each member, and returning an array of the results. */ +- (NSArray *) mapSelector:(SEL) selector; + +@end diff --git a/objc/NuEnumerable.m b/objc/NuEnumerable.m new file mode 100644 index 0000000..3c8758f --- /dev/null +++ b/objc/NuEnumerable.m @@ -0,0 +1,228 @@ +// +// NuEnumerable.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuEnumerable.h" +#import "NuInternals.h" +#import "NuCell.h" + +#pragma mark - NuEnumerable.m + +@interface NuEnumerable(Unimplemented) +- (id) objectEnumerator; +@end + +@implementation NuEnumerable + +- (id) each:(id) callable +{ + id args = [[NuCell alloc] init]; + if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { + NSEnumerator *enumerator = [self objectEnumerator]; + id object; + while ((object = [enumerator nextObject])) { + @try + { + [args setCar:object]; + [callable evalWithArguments:args context:nil]; + } + @catch (NuBreakException *exception) { + break; + } + @catch (NuContinueException *exception) { + // do nothing, just continue with the next loop iteration + } + @catch (id exception) { + [args release]; + @throw(exception); + } + } + } + [args release]; + return self; +} + +- (id) eachWithIndex:(NuBlock *) block +{ + id args = [[NuCell alloc] init]; + [args setCdr:[[[NuCell alloc] init] autorelease]]; + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + NSEnumerator *enumerator = [self objectEnumerator]; + id object; + int i = 0; + while ((object = [enumerator nextObject])) { + @try + { + [args setCar:object]; + [[args cdr] setCar:[NSNumber numberWithInt:i]]; + [block evalWithArguments:args context:nil]; + } + @catch (NuBreakException *exception) { + break; + } + @catch (NuContinueException *exception) { + // do nothing, just continue with the next loop iteration + } + @catch (id exception) { + [args release]; + @throw(exception); + } + i++; + } + } + [args release]; + return self; +} + +- (NSArray *) select +{ + NSMutableArray *selected = [NSMutableArray array]; + NSEnumerator *enumerator = [self objectEnumerator]; + id object; + while ((object = [enumerator nextObject])) { + if (nu_valueIsTrue(object)) { + [selected addObject:object]; + } + } + return selected; +} + +- (NSArray *) select:(NuBlock *) block +{ + NSMutableArray *selected = [NSMutableArray array]; + id args = [[NuCell alloc] init]; + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + NSEnumerator *enumerator = [self objectEnumerator]; + id object; + while ((object = [enumerator nextObject])) { + [args setCar:object]; + id result = [block evalWithArguments:args context:Nu__null]; + if (nu_valueIsTrue(result)) { + [selected addObject:object]; + } + } + } + [args release]; + return selected; +} + +- (id) find:(NuBlock *) block +{ + id args = [[NuCell alloc] init]; + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + NSEnumerator *enumerator = [self objectEnumerator]; + id object; + while ((object = [enumerator nextObject])) { + [args setCar:object]; + id result = [block evalWithArguments:args context:Nu__null]; + if (nu_valueIsTrue(result)) { + [args release]; + return object; + } + } + } + [args release]; + return Nu__null; +} + +- (NSArray *) map:(id) callable +{ + NSMutableArray *results = [NSMutableArray array]; + id args = [[NuCell alloc] init]; + if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { + NSEnumerator *enumerator = [self objectEnumerator]; + id object; + while ((object = [enumerator nextObject])) { + [args setCar:object]; + [results addObject:[callable evalWithArguments:args context:nil]]; + } + } + [args release]; + return results; +} + +- (NSArray *) mapWithIndex:(id) callable +{ + NSMutableArray *results = [NSMutableArray array]; + id args = [[NuCell alloc] init]; + [args setCdr:[[[NuCell alloc] init] autorelease]]; + if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { + NSEnumerator *enumerator = [self objectEnumerator]; + id object; + int i = 0; + while ((object = [enumerator nextObject])) { + [args setCar:object]; + [[args cdr] setCar:[NSNumber numberWithInt:i]]; + [results addObject:[callable evalWithArguments:args context:nil]]; + i++; + } + } + [args release]; + return results; +} + +- (NSArray *) mapSelector:(SEL) sel +{ + NSMutableArray *results = [NSMutableArray array]; + NSEnumerator *enumerator = [self objectEnumerator]; + id object; + while ((object = [enumerator nextObject])) { + // this will fail (crash!) if the selector returns any type other than an object. + [results addObject:[object performSelector:sel]]; + } + return results; +} + +- (id) reduce:(id) callable from:(id) initial +{ + id args = [[NuCell alloc] init]; + [args setCdr:[[[NuCell alloc] init] autorelease]]; + id result = initial; + if ([callable respondsToSelector:@selector(evalWithArguments:context:)]) { + NSEnumerator *enumerator = [self objectEnumerator]; + id object; + while ((object = [enumerator nextObject])) { + [args setCar:result]; + [[args cdr] setCar: object]; + result = [callable evalWithArguments:args context:nil]; + } + } + [args release]; + return result; +} + +- (id) maximum:(NuBlock *) block +{ + id bestObject = nil; + + id args = [[NuCell alloc] init]; + [args setCdr:[[[NuCell alloc] init] autorelease]]; + + if (nu_objectIsKindOfClass(block, [NuBlock class])) { + NSEnumerator *enumerator = [self objectEnumerator]; + id object; + while ((object = [enumerator nextObject])) { + if (!bestObject) { + bestObject = object; + } + else { + [args setCar:object]; + [[args cdr] setCar:bestObject]; + id result = [block evalWithArguments:args context:Nu__null]; + if (result && (result != Nu__null)) { + if ([result intValue] > 0) { + bestObject = object; + } + } + } + } + } + [args release]; + return bestObject; +} + +@end diff --git a/objc/NuException.h b/objc/NuException.h new file mode 100644 index 0000000..da71b03 --- /dev/null +++ b/objc/NuException.h @@ -0,0 +1,55 @@ +// +// NuException.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +#pragma mark - +#pragma mark Error Handling + +/*! + @class NuException + @abstract When something goes wrong in Nu. + @discussion A Nu Exception is a subclass of NSException, representing + errors during execution of Nu code. It has the ability to store trace information. + This information gets added during unwinding the stack by the NuCells. + */ +@interface NuException : NSException + ++ (void)setDefaultExceptionHandler; ++ (void)setVerbose:(BOOL)flag; + +/*! Create a NuException. */ +- (id)initWithName:(NSString *)name reason:(NSString *)reason userInfo:(NSDictionary *)userInfo; + +/*! Get the stack trace. */ +- (NSArray*)stackTrace; + +/*! Add to the stack trace. */ +- (NuException *)addFunction:(NSString *)function lineNumber:(int)line; +- (NuException *)addFunction:(NSString *)function lineNumber:(int)line filename:(NSString*)filename; + +/*! Get a string representation of the exception. */ +- (NSString *)stringValue; + +/*! Dump the exception to stdout. */ +- (NSString*)dump; + +/*! Dump leaving off some of the toplevel */ +- (NSString*)dumpExcludingTopLevelCount:(NSUInteger)count; + +@end + +@interface NuTraceInfo : NSObject + +- (id)initWithFunction:(NSString *)function lineNumber:(int)lineNumber filename:(NSString *)filename; +- (NSString *)filename; +- (int)lineNumber; +- (NSString *)function; + +@end + diff --git a/objc/NuException.m b/objc/NuException.m new file mode 100644 index 0000000..e55e479 --- /dev/null +++ b/objc/NuException.m @@ -0,0 +1,201 @@ +// +// NuException.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuException.h" + + +#pragma mark - NuException.m + +#define kFilenameTopLevel @"" + +@implementation NSException (NuStackTrace) + +- (NSString*)dump +{ + NSMutableString* dump = [NSMutableString stringWithString:@""]; + + // Print the system stack trace (10.6 only) + if ([self respondsToSelector:@selector(callStackSymbols)]) + { + [dump appendString:@"\nSystem stack trace:\n"]; + + NSArray* callStackSymbols = [self callStackSymbols]; + NSUInteger count = [callStackSymbols count]; + for (int i = 0; i < count; i++) + { + [dump appendString:[callStackSymbols objectAtIndex:i]]; + [dump appendString:@"\n"]; + } + } + + return dump; +} + +@end + + +static void Nu_defaultExceptionHandler(NSException* e) +{ + [e dump]; +} + +static BOOL NuException_verboseExceptionReporting = NO; + +@interface NuException () +{ + NSMutableArray* stackTrace; +} +@end + +@implementation NuException + ++ (void)setDefaultExceptionHandler +{ + NSSetUncaughtExceptionHandler(*Nu_defaultExceptionHandler); + +#ifdef IMPORT_EXCEPTION_HANDLING_FRAMEWORK + [[NSExceptionHandler defaultExceptionHandler] + setExceptionHandlingMask:(NSHandleUncaughtExceptionMask + | NSHandleUncaughtSystemExceptionMask + | NSHandleUncaughtRuntimeErrorMask + | NSHandleTopLevelExceptionMask + | NSHandleOtherExceptionMask)]; +#endif +} + ++ (void)setVerbose:(BOOL)flag +{ + NuException_verboseExceptionReporting = flag; +} + + +- (void) dealloc +{ + if (stackTrace) + { + [stackTrace removeAllObjects]; + [stackTrace release]; + } + [super dealloc]; +} + +- (id)initWithName:(NSString *)name reason:(NSString *)reason userInfo:(NSDictionary *)userInfo +{ + self = [super initWithName:name reason:reason userInfo:userInfo]; + stackTrace = [[NSMutableArray alloc] init]; + return self; +} + +- (NSArray*)stackTrace +{ + return stackTrace; +} + +- (NuException *)addFunction:(NSString *)function lineNumber:(int)line +{ + return [self addFunction:function lineNumber:line filename:kFilenameTopLevel]; +} + +- (NuException *)addFunction:(NSString *)function lineNumber:(int)line filename:(NSString *)filename +{ + NuTraceInfo* traceInfo = [[[NuTraceInfo alloc] initWithFunction:function + lineNumber:line + filename:filename] + autorelease]; + [stackTrace addObject:traceInfo]; + + return self; +} + +- (NSString *)stringValue +{ + return [self reason]; +} + + +- (NSString*)dumpExcludingTopLevelCount:(NSUInteger)topLevelCount +{ + NSMutableString* dump = [NSMutableString stringWithString:@"Nu uncaught exception: "]; + + [dump appendString:[NSString stringWithFormat:@"%@: %@\n", [self name], [self reason]]]; + + NSUInteger count = [stackTrace count] - topLevelCount; + for (int i = 0; i < count; i++) + { + NuTraceInfo* trace = [stackTrace objectAtIndex:i]; + + NSString* traceString = [NSString stringWithFormat:@" from %@:%d: in %@\n", + [trace filename], + [trace lineNumber], + [trace function]]; + + [dump appendString:traceString]; + } + + if (NuException_verboseExceptionReporting) + { + [dump appendString:[super dump]]; + } + + return dump; +} + +- (NSString*)dump +{ + return [self dumpExcludingTopLevelCount:0]; +} + +@end + +@interface NuTraceInfo () +{ + NSString* filename; + int lineNumber; + NSString* function; +} +@end + +@implementation NuTraceInfo + +- (id)initWithFunction:(NSString *)aFunction lineNumber:(int)aLine filename:(NSString *)aFilename +{ + self = [super init]; + + if (self) + { + filename = [aFilename retain]; + lineNumber = aLine; + function = [aFunction retain]; + } + return self; +} + +- (void)dealloc +{ + [filename release]; + [function release]; + + [super dealloc]; +} + +- (NSString *)filename +{ + return filename; +} + +- (int)lineNumber +{ + return lineNumber; +} + +- (NSString *)function +{ + return function; +} + +@end diff --git a/objc/NuHandler.h b/objc/NuHandler.h new file mode 100644 index 0000000..db3ca5e --- /dev/null +++ b/objc/NuHandler.h @@ -0,0 +1,35 @@ +// +// NuHandler.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +@class NuBlock; + +#pragma mark - NuHandler.h + +struct nu_handler_description +{ + IMP handler; + char **description; +}; + +/*! + @class NuHandlerWarehouse + @abstract Internal class used to store and vend method implementations on platforms that don't allow them to be constructed at runtime. + */ +@interface NuHandlerWarehouse : NSObject ++ (void) registerHandlers:(struct nu_handler_description *) description withCount:(int) count forReturnType:(NSString *) returnType; ++ (IMP) handlerWithSelector:(SEL)sel block:(NuBlock *)block signature:(const char *) signature userdata:(char **) userdata; +@end + +static void nu_handler(void *return_value, + struct nu_handler_description *description, + id receiver, + va_list ap); + + diff --git a/objc/NuHandler.m b/objc/NuHandler.m new file mode 100644 index 0000000..1510b21 --- /dev/null +++ b/objc/NuHandler.m @@ -0,0 +1,284 @@ +// +// NuHandler.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// + +#import "NuHandler.h" +#import "NuCell.h" +#import "NuInternals.h" +#import "NuBlock.h" + +#if TARGET_OS_IPHONE +#import +#endif + +static id collect_arguments(struct nu_handler_description *description, va_list ap) +{ + int i = 0; + char *type; + id arguments = [[NuCell alloc] init]; + id cursor = arguments; + while((type = description->description[2+i])) { + [cursor setCdr:[[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + // NSLog(@"argument type %d: %s", i, type); + if (!strcmp(type, "@")) { + [cursor setCar:va_arg(ap, id)]; + } + else if (!strcmp(type, "i")) { + int x = va_arg(ap, int); + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; + } + else if (!strcmp(type, "C")) { + // unsigned char is promoted to int in va_arg() + //unsigned char x = va_arg(ap, unsigned char); + int x = va_arg(ap, int); + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; + } + else if (!strcmp(type, "f")) { + // calling this w/ float crashes on intel + double x = (double) va_arg(ap, double); + //NSLog(@"argument is %f", *((float *) &x)); + ap = ap - sizeof(float); // messy, messy... + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; + } + else if (!strcmp(type, "d")) { + double x = va_arg(ap, double); + //NSLog(@"argument is %lf", x); + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; + } + else if (!strcmp(type, ":")) { + SEL x = va_arg(ap, SEL); + //NSLog(@"collect_arguments: [:] (SEL) = %@", NSStringFromSelector(x)); + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; + } + else if (!strcmp(type, "^@")) { + void *x = va_arg(ap, void *); + //NSLog(@"argument is %lf", x); + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; + } +#if TARGET_OS_IPHONE + else if (!strcmp(type, "{CGRect={CGPoint=ff}{CGSize=ff}}") + || (!strcmp(type, "{CGRect=\"origin\"{CGPoint=\"x\"f\"y\"f}\"size\"{CGSize=\"width\"f\"height\"f}}"))) { + CGRect x = va_arg(ap, CGRect); + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; + } +#else + else if (!strcmp(type, "{_NSRect={_NSPoint=dd}{_NSSize=dd}}")) { + NSRect x = va_arg(ap, NSRect); + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; + } + else if (!strcmp(type, "{CGRect={CGPoint=dd}{CGSize=dd}}")) { +#ifdef DARWIN + CGRect x = va_arg(ap, CGRect); + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; +#endif + } + else if (!strcmp(type, "{_NSPoint=dd}")) { + NSPoint x = va_arg(ap, NSPoint); + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; + } + else if (!strcmp(type, "{_NSSize=dd}")) { + NSSize x = va_arg(ap, NSSize); + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; + } + else if (!strcmp(type, "{_NSRange=QQ}")) { + NSRange x = va_arg(ap, NSRange); + [cursor setCar:get_nu_value_from_objc_value(&x, type)]; + } +#endif + else { + NSLog(@"unsupported argument type %s, see objc/handler.m to add support for it", type); + } + i++; + } + return arguments; +} + +// helper function called by method handlers +static void nu_handler(void *return_value, struct nu_handler_description *handler, id receiver, va_list ap) +{ + id result; + BOOL retained_through_autorelease = NO; + @autoreleasepool { + NuBlock *block = (NuBlock *) handler->description[1]; + // NSLog(@"handling %@", [block stringValue]); + id arguments = collect_arguments(handler, ap); + result = [block evalWithArguments:[arguments cdr] context:nil self:receiver]; + if (return_value) { + // if the call returns an object, retain the result so that it will survive the autorelease. + // we undo this retain once we're safely outside of the autorelease block. + if (handler->description[0][1] == '@') { + retained_through_autorelease = YES; + [result retain]; + // if the call is supposed to return a retained object, add an additional retain. + if (handler->description[0][0] == '!') { + // The static analyzer says this is a potential leak. + // It's intentional, we are returning from a method that should return a retained (+1) object. + [result retain]; + } + } + set_objc_value_from_nu_value(return_value, result, handler->description[0]+1); + } + [arguments release]; + } + if (retained_through_autorelease) { + // undo the object-preserving retain we made in the autorelease block above. + [result autorelease]; + } +} + +@interface NuHandlers : NSObject +{ +@public + struct nu_handler_description *handlers; + int handler_count; + int next_free_handler; +} + +@end + +@implementation NuHandlers +- (id) initWithHandlers:(struct nu_handler_description *) h count:(int) count +{ + if ((self = [super init])) { + handlers = h; + handler_count = count; + next_free_handler = 0; + } + return self; +} + +@end + +static IMP handler_returning_void(void *userdata) { + return imp_implementationWithBlock(^(id receiver, ...) { + struct nu_handler_description description; + description.handler = NULL; + description.description = userdata; + va_list ap; + va_start(ap, receiver); + nu_handler(0, &description, receiver, ap); + }); +} + +#define MAKE_HANDLER_WITH_TYPE(type) \ +static IMP handler_returning_ ## type (void* userdata) \ +{ \ +return imp_implementationWithBlock(^(id receiver, ...) { \ +struct nu_handler_description description; \ +description.handler = NULL; \ +description.description = userdata; \ +va_list ap; \ +va_start(ap, receiver); \ +type result; \ +nu_handler(&result, &description, receiver, ap); \ +return result; \ +}); \ +} + +MAKE_HANDLER_WITH_TYPE(id) +MAKE_HANDLER_WITH_TYPE(int) +MAKE_HANDLER_WITH_TYPE(bool) +MAKE_HANDLER_WITH_TYPE(float) +MAKE_HANDLER_WITH_TYPE(double) +#ifdef DARWIN +MAKE_HANDLER_WITH_TYPE(CGRect) +MAKE_HANDLER_WITH_TYPE(CGPoint) +MAKE_HANDLER_WITH_TYPE(CGSize) +#endif +#if !TARGET_OS_IPHONE +MAKE_HANDLER_WITH_TYPE(NSRect) +MAKE_HANDLER_WITH_TYPE(NSPoint) +MAKE_HANDLER_WITH_TYPE(NSSize) +#endif +MAKE_HANDLER_WITH_TYPE(NSRange) + +static NSMutableDictionary *handlerWarehouse = nil; + +@implementation NuHandlerWarehouse + ++ (void) registerHandlers:(struct nu_handler_description *) description withCount:(int) count forReturnType:(NSString *) returnType +{ + if (!handlerWarehouse) { + handlerWarehouse = [[NSMutableDictionary alloc] init]; + } + NuHandlers *handlers = [[NuHandlers alloc] initWithHandlers:description count:count]; + [handlerWarehouse setObject:handlers forKey:returnType]; + [handlers release]; +} + ++ (IMP) handlerWithSelector:(SEL)sel block:(NuBlock *)block signature:(const char *) signature userdata:(char **) userdata +{ + NSString *returnType = [NSString stringWithCString:userdata[0]+1 encoding:NSUTF8StringEncoding]; + if ([returnType isEqualToString:@"v"]) { + return handler_returning_void(userdata); + } + else if ([returnType isEqualToString:@"@"]) { + return handler_returning_id(userdata); + } + else if ([returnType isEqualToString:@"i"]) { + return handler_returning_int(userdata); + } + else if ([returnType isEqualToString:@"C"]) { + return handler_returning_bool(userdata); + } + else if ([returnType isEqualToString:@"f"]) { + return handler_returning_float(userdata); + } + else if ([returnType isEqualToString:@"d"]) { + return handler_returning_double(userdata); + } +#ifdef DARWIN + else if ([returnType isEqualToString:@"{CGRect={CGPoint=ff}{CGSize=ff}}"]) { + return handler_returning_CGRect(userdata); + } + else if ([returnType isEqualToString:@"{CGPoint=ff}"]) { + return handler_returning_CGPoint(userdata); + } + else if ([returnType isEqualToString:@"{CGSize=ff}"]) { + return handler_returning_CGSize(userdata); + } +#endif + else if ([returnType isEqualToString:@"{_NSRange=II}"]) { + return handler_returning_NSRange(userdata); + } +#if !TARGET_OS_IPHONE + else if ([returnType isEqualToString:@"{_NSRect={_NSPoint=dd}{_NSSize=dd}}"]) { + return handler_returning_NSRect(userdata); + } + else if ([returnType isEqualToString:@"{_NSPoint=dd}"]) { + return handler_returning_NSPoint(userdata); + } + else if ([returnType isEqualToString:@"{_NSSize=dd}"]) { + return handler_returning_NSSize(userdata); + } + else if ([returnType isEqualToString:@"{_NSRange=QQ}"]) { + return handler_returning_NSRange(userdata); + } +#endif + else { +#if TARGET_OS_IPHONE + // this is only a problem on iOS. + NSLog(@"UNKNOWN RETURN TYPE %@", returnType); +#endif + } + // the following is deprecated. Now that we can create IMPs from blocks, we don't need handler pools. + if (!handlerWarehouse) { + return NULL; + } + NuHandlers *handlers = [handlerWarehouse objectForKey:returnType]; + if (handlers) { + if (handlers->next_free_handler < handlers->handler_count) { + handlers->handlers[handlers->next_free_handler].description = userdata; + IMP handler = handlers->handlers[handlers->next_free_handler].handler; + handlers->next_free_handler++; + return handler; + } + } + return NULL; +} + +@end diff --git a/objc/NuInternals.h b/objc/NuInternals.h new file mode 100644 index 0000000..d1e603e --- /dev/null +++ b/objc/NuInternals.h @@ -0,0 +1,149 @@ +// +// NuInternals.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// + +#ifndef NuInternals_h +#define NuInternals_h + +#define NU_VERSION "2.0.1" +#define NU_VERSION_MAJOR 2 +#define NU_VERSION_MINOR 0 +#define NU_VERSION_TWEAK 1 +#define NU_RELEASE_DATE "2011-09-02" +#define NU_RELEASE_YEAR 2011 +#define NU_RELEASE_MONTH 09 +#define NU_RELEASE_DAY 02 + +#import "Nu.h" + +@class NuBlock; + +#define IS_NOT_NULL(xyz) ((xyz) && (((id) (xyz)) != Nu__null)) + + +extern NSMutableDictionary *nu_block_table; + +id Nu__null; + +// Execution contexts are NSMutableDictionaries that are keyed by +// symbols. Here we define two string keys that allow us to store +// some extra information in our contexts. + +// Use this key to get the symbol table from an execution context. +#define SYMBOLS_KEY @"symbols" + +// Use this key to get the parent context of an execution context. +#define PARENT_KEY @"parent" + +/*! + @class NuBreakException + @abstract Internal class used to implement the Nu break operator. + */ +@interface NuBreakException : NSException +@end + +/*! + @class NuContinueException + @abstract Internal class used to implement the Nu continue operator. + */ +@interface NuContinueException : NSException +@end + +/*! + @class NuReturnException + @abstract Internal class used to implement the Nu return operator. + */ +@interface NuReturnException : NSException +{ + id value; + id blockForReturn; +} + +- (id) value; +- (id) blockForReturn; +@end + +// use this to test a value for "truth" +bool nu_valueIsTrue(id value); + +// use this to get the filename for a NuCell created by the parser +const char *nu_parsedFilename(int i); + + + +id nu_calling_objc_method_handler(id target, Method m, NSMutableArray *args); + + +// We'd like for this to be in the ObjC2 API, but it isn't. +void nu_class_addInstanceVariable_withSignature(Class thisClass, const char *variableName, const char *signature); + +// These are handy. +IMP nu_class_replaceMethod(Class cls, SEL name, IMP imp, const char *types); +BOOL nu_copyInstanceMethod(Class destinationClass, Class sourceClass, SEL selector); +BOOL nu_objectIsKindOfClass(id object, Class class); +void nu_markEndOfObjCTypeString(char *type, size_t len); + +// This makes it safe to insert nil into container classes +void nu_swizzleContainerClasses(void); + +id add_method_to_class(Class c, NSString *methodName, NSString *signature, NuBlock *block); +id get_nu_value_from_objc_value(void *objc_value, const char *typeString); +int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *typeString); +void *value_buffer_for_objc_type(const char *typeString); +NSString *signature_for_identifier(NuCell *cell, NuSymbolTable *symbolTable); +id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *context, BOOL addClassMethod); +size_t size_of_objc_type(const char *typeString); + + +#pragma mark - DTrace macros + +/* + * Generated by dtrace(1M). + */ + +#ifndef _DTRACE_H +#define _DTRACE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define NU_STABILITY "___dtrace_stability$nu$v1$5_5_5_1_1_5_1_1_5_5_5_5_5_5_5" + +#define NU_TYPEDEFS "___dtrace_typedefs$nu$v1" + +#define NU_LIST_EVAL_BEGIN(arg0, arg1) \ +{ \ +__asm__ volatile(".reference " NU_TYPEDEFS); \ +__dtrace_probe$nu$list_eval_begin$v1$63686172202a$696e74((char *)arg0, arg1); \ +__asm__ volatile(".reference " NU_STABILITY); \ +} +#define NU_LIST_EVAL_BEGIN_ENABLED() \ +__dtrace_isenabled$nu$list_eval_begin$v1() +#define NU_LIST_EVAL_END(arg0, arg1) \ +{ \ +__asm__ volatile(".reference " NU_TYPEDEFS); \ +__dtrace_probe$nu$list_eval_end$v1$63686172202a$696e74((char *)arg0, arg1); \ +__asm__ volatile(".reference " NU_STABILITY); \ +} +#define NU_LIST_EVAL_END_ENABLED() \ +__dtrace_isenabled$nu$list_eval_end$v1() + + + extern void __dtrace_probe$nu$list_eval_begin$v1$63686172202a$696e74(char *, int); + extern int __dtrace_isenabled$nu$list_eval_begin$v1(void); + extern void __dtrace_probe$nu$list_eval_end$v1$63686172202a$696e74(char *, int); + extern int __dtrace_isenabled$nu$list_eval_end$v1(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DTRACE_H */ + +#endif /* NuInternals_h */ diff --git a/objc/NuMacro.h b/objc/NuMacro.h new file mode 100644 index 0000000..0d4a79e --- /dev/null +++ b/objc/NuMacro.h @@ -0,0 +1,105 @@ +// +// NuMacro.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + + +#import "NuSymbol.h" +#import "NuInternals.h" + +@class NuCell; + +/*! + @class NuMacro_0 + @abstract The Nu implementation of macros. + @discussion Macros allow Nu programmers to arbitrarily extend the Nu language. + + In Nu programs, macros are defined with the macro operator. + + Macros are like functions, but with two important differences: + + First, macro arguments are not evaluated before the macro is called. + It is up to the macro implementation to decide whether and how + many times to evaluate each argument. When a Nu macro is evaluated, + the margs name is defined and is bound to a list of + the arguments of the macro. + + Second, macro evaluation occurs in the context of the caller. + This means that a macro has access to all names defined in the + code that calls it, and that any name assignments made in a macro will + affect the names in the calling code. To avoid unintentional + name conflicts, any names in a macro body that begin with a double + underscore ("__") are replaced with automatically-generated symbols + that are guaranteed to be unique. In Lisp terminology, these generated + symbols are called "gensyms". + */ +@interface NuMacro_0 : NSObject + +/*! Construct a macro. */ ++ (id) macroWithName:(NSString *)name body:(NuCell *)body; +/*! Get the name of a macro. */ +- (NSString *) name; +/*! Get the body of a macro. */ +- (NuCell *) body; +/*! Get any gensyms in a macro. */ +- (NSSet *) gensyms; +/*! Initialize a macro. */ +- (id) initWithName:(NSString *)name body:(NuCell *)body; +/*! Get a string representation of a macro. */ +- (NSString *) stringValue; +/*! Evaluate a macro. */ +- (id) evalWithArguments:(id)margs context:(NSMutableDictionary *)calling_context; +/*! Expand a macro in its context. */ +- (id) expand1:(id)margs context:(NSMutableDictionary *)calling_context; +/*! Insert unique gensym'd variables. */ +- (id) body:(NuCell *) oldBody withGensymPrefix:(NSString *) prefix symbolTable:(NuSymbolTable *) symbolTable; +/*! Expand unquotes in macro body. */ +- (id) expandUnquotes:(id) oldBody withContext:(NSMutableDictionary *) context; + +@end + +/*! + @class NuMacro_1 + @abstract The Nu implementation of a Lisp-like macro operator. + @discussion Macros allow Nu programmers to arbitrarily extend the Nu language. + + The macro operator works similarly to the Nu macro-0 + operator, but differs in the following ways: + + macro accepts a parameter list much like a Nu function. + Nu's macro operator puts all of the parameter list into an + implicit variable named margs, which the body of the macro + must destructure manually. + + macro does not implicitly "quote" the body of the macro. + Instead the backquote (abbreviated as '`') + and bq-comma (abbreviated as ',') operators can be + used to write a macro body that more closely resembles the + generated code. + + For example, the following two macros are equivalent: + + (macro-0 inc! (set (unquote (car margs)) (+ (unquote (car margs)) 1))) + + (macro inc! (n) `(set ,n (+ ,n 1))) + */ +@interface NuMacro_1 : NuMacro_0 + +/*! Construct a macro. */ ++ (id) macroWithName:(NSString *)name parameters:(NuCell*)args body:(NuCell *)body; +/*! Initialize a macro. */ +- (id) initWithName:(NSString *)name parameters:(NuCell *)args body:(NuCell *)body; +/*! Get a string representation of a macro. */ +- (NSString *) stringValue; +/*! Evaluate a macro. */ +- (id) evalWithArguments:(id)margs context:(NSMutableDictionary *)calling_context; +/*! Expand a macro in its context. */ +- (id) expand1:(id)margs context:(NSMutableDictionary *)calling_context; + +@end + diff --git a/objc/NuMacro.m b/objc/NuMacro.m new file mode 100644 index 0000000..f6b49c4 --- /dev/null +++ b/objc/NuMacro.m @@ -0,0 +1,635 @@ +// +// NuMacro.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuMacro.h" +#import "NuMath.h" +#import "NSDictionary+Nu.h" +#import "NuCell.h" + +#pragma mark - NuMacro_0.m +@interface NuMacro_0 () +{ +@protected + NSString *name; + NuCell *body; + NSMutableSet *gensyms; +} +@end + +@implementation NuMacro_0 + ++ (id) macroWithName:(NSString *)n body:(NuCell *)b +{ + return [[[self alloc] initWithName:n body:b] autorelease]; +} + +- (void) dealloc +{ + [body release]; + [super dealloc]; +} + +- (NSString *) name +{ + return name; +} + +- (NuCell *) body +{ + return body; +} + +- (NSSet *) gensyms +{ + return gensyms; +} + +- (void) collectGensyms:(NuCell *)cell +{ + id car = [cell car]; + if ([car atom]) { + if (nu_objectIsKindOfClass(car, [NuSymbol class]) && [car isGensym]) { + [gensyms addObject:car]; + } + } + else if (car && (car != Nu__null)) { + [self collectGensyms:car]; + } + id cdr = [cell cdr]; + if (cdr && (cdr != Nu__null)) { + [self collectGensyms:cdr]; + } +} + +- (id) initWithName:(NSString *)n body:(NuCell *)b +{ + if ((self = [super init])) { + name = [n retain]; + body = [b retain]; + gensyms = [[NSMutableSet alloc] init]; + [self collectGensyms:body]; + } + return self; +} + +- (NSString *) stringValue +{ + return [NSString stringWithFormat:@"(macro-0 %@ %@)", name, [body stringValue]]; +} + +- (id) body:(NuCell *) oldBody withGensymPrefix:(NSString *) prefix symbolTable:(NuSymbolTable *) symbolTable +{ + NuCell *newBody = [[[NuCell alloc] init] autorelease]; + id car = [oldBody car]; + if (car == Nu__null) { + [newBody setCar:car]; + } + else if ([car atom]) { + if (nu_objectIsKindOfClass(car, [NuSymbol class]) && [car isGensym]) { + [newBody setCar:[symbolTable symbolWithString:[NSString stringWithFormat:@"%@%@", prefix, [car stringValue]]]]; + } + else if (nu_objectIsKindOfClass(car, [NSString class])) { + // Here we replace gensyms in interpolated strings. + // The current solution is workable but fragile; + // we just blindly replace the gensym names with their expanded names. + // It would be better to + // 1. only replace gensym names in interpolated expressions. + // 2. ensure substitutions never overlap. To do this, I think we should + // a. order gensyms by size and do the longest ones first. + // b. make the gensym transformation idempotent. + // That's for another day. + // For now, I just substitute each gensym name with its expansion. + // + NSMutableString *tempString = [NSMutableString stringWithString:car]; + //NSLog(@"checking %@", tempString); + NSEnumerator *gensymEnumerator = [gensyms objectEnumerator]; + NuSymbol *gensymSymbol; + while ((gensymSymbol = [gensymEnumerator nextObject])) { + //NSLog(@"gensym is %@", [gensymSymbol stringValue]); + [tempString replaceOccurrencesOfString:[gensymSymbol stringValue] + withString:[NSString stringWithFormat:@"%@%@", prefix, [gensymSymbol stringValue]] + options:0 range:NSMakeRange(0, [tempString length])]; + } + //NSLog(@"setting string to %@", tempString); + [newBody setCar:tempString]; + } + else { + [newBody setCar:car]; + } + } + else { + [newBody setCar:[self body:car withGensymPrefix:prefix symbolTable:symbolTable]]; + } + id cdr = [oldBody cdr]; + if (cdr && (cdr != Nu__null)) { + [newBody setCdr:[self body:cdr withGensymPrefix:prefix symbolTable:symbolTable]]; + } + else { + [newBody setCdr:cdr]; + } + return newBody; +} + +- (id) expandUnquotes:(id) oldBody withContext:(NSMutableDictionary *) context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + if (oldBody == [NSNull null]) + return oldBody; + id unquote = [symbolTable symbolWithString:@"unquote"]; + id car = [oldBody car]; + id cdr = [oldBody cdr]; + if ([car atom]) { + if (car == unquote) { + return [[cdr car] evalWithContext:context]; + } + else { + NuCell *newBody = [[[NuCell alloc] init] autorelease]; + [newBody setCar:car]; + [newBody setCdr:[self expandUnquotes:cdr withContext:context]]; + return newBody; + } + } + else { + NuCell *newBody = [[[NuCell alloc] init] autorelease]; + [newBody setCar:[self expandUnquotes:car withContext:context]]; + [newBody setCdr:[self expandUnquotes:cdr withContext:context]]; + return newBody; + } +} + + +- (id) expandAndEval:(id)cdr context:(NSMutableDictionary *)calling_context evalFlag:(BOOL)evalFlag +{ + NuSymbolTable *symbolTable = [calling_context objectForKey:SYMBOLS_KEY]; + + // save the current value of margs + id old_margs = [calling_context objectForKey:[symbolTable symbolWithString:@"margs"]]; + // set the arguments to the special variable "margs" + [calling_context setPossiblyNullObject:cdr forKey:[symbolTable symbolWithString:@"margs"]]; + // evaluate the body of the block in the calling context (implicit progn) + + // if the macro contains gensyms, give them a unique prefix + NSUInteger gensymCount = [[self gensyms] count]; + id gensymPrefix = nil; + if (gensymCount > 0) { + gensymPrefix = [NSString stringWithFormat:@"g%ld", [NuMath random]]; + } + + id bodyToEvaluate = (gensymCount == 0) + ? (id)body : [self body:body withGensymPrefix:gensymPrefix symbolTable:symbolTable]; + + // uncomment this to get the old (no gensym) behavior. + //bodyToEvaluate = body; + //NSLog(@"evaluating %@", [bodyToEvaluate stringValue]); + + id value = [self expandUnquotes:bodyToEvaluate withContext:calling_context]; + + if (evalFlag) + { + id cursor = value; + + while (cursor && (cursor != Nu__null)) { + value = [[cursor car] evalWithContext:calling_context]; + cursor = [cursor cdr]; + } + } + + // restore the old value of margs + if (old_margs == nil) { + [calling_context removeObjectForKey:[symbolTable symbolWithString:@"margs"]]; + } + else { + [calling_context setPossiblyNullObject:old_margs forKey:[symbolTable symbolWithString:@"margs"]]; + } + +#if 0 + // I would like to remove gensym values and symbols at the end of a macro's execution, + // but there is a problem with this: the gensym assignments could be used in a closure, + // and deleting them would cause that to break. See the testIvarAccessorMacro unit + // test for an example of this. So for now, the code below is disabled. + // + // remove the gensyms from the context; this also releases their assigned values + NSArray *gensymArray = [gensyms allObjects]; + for (int i = 0; i < gensymCount; i++) { + NuSymbol *gensymBase = [gensymArray objectAtIndex:i]; + NuSymbol *gensymSymbol = [symbolTable symbolWithString:[NSString stringWithFormat:@"%@%@", gensymPrefix, [gensymBase stringValue]]]; + [calling_context removeObjectForKey:gensymSymbol]; + [symbolTable removeSymbol:gensymSymbol]; + } +#endif + return value; +} + + +- (id) expand1:(id)cdr context:(NSMutableDictionary*)calling_context +{ + return [self expandAndEval:cdr context:calling_context evalFlag:NO]; +} + + +- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context +{ + return [self expandAndEval:cdr context:calling_context evalFlag:YES]; +} + +@end + +#pragma mark - NuMacro_1.m + +//#define MACRO1_DEBUG 1 + +// Following debug output on and off for this file only +#ifdef MACRO1_DEBUG +#define Macro1Debug(arg...) NSLog(arg) +#else +#define Macro1Debug(arg...) +#endif + +@interface NuMacro_1 () +{ + NuCell *parameters; +} +@end + +@implementation NuMacro_1 + ++ (id) macroWithName:(NSString *)n parameters:(NuCell*)p body:(NuCell *)b +{ + return [[[self alloc] initWithName:n parameters:p body:b] autorelease]; +} + +- (void) dealloc +{ + [parameters release]; + [super dealloc]; +} + +- (BOOL) findAtom:(id)atom inSequence:(id)sequence +{ + if (atom == nil || atom == Nu__null) + return NO; + + if (sequence == nil || sequence == Nu__null) + return NO; + + if ([[atom stringValue] isEqualToString:[sequence stringValue]]) + return YES; + + if ([sequence class] == [NuCell class]) { + return ( [self findAtom:atom inSequence:[sequence car]] + || [self findAtom:atom inSequence:[sequence cdr]]); + } + + return NO; +} + +- (id) initWithName:(NSString *)n parameters:(NuCell *)p body:(NuCell *)b +{ + if ((self = [super initWithName:n body:b])) { + parameters = [p retain]; + + if (([parameters length] == 1) + && ([[[parameters car] stringValue] isEqualToString:@"*args"])) { + // Skip the check + } + else { + BOOL foundArgs = [self findAtom:@"*args" inSequence:parameters]; + + if (foundArgs) { + printf("Warning: Overriding implicit variable '*args'.\n"); + } + } + } + return self; +} + +- (NSString *) stringValue +{ + return [NSString stringWithFormat:@"(macro %@ %@ %@)", name, [parameters stringValue], [body stringValue]]; +} + +- (void) dumpContext:(NSMutableDictionary*)context +{ +#ifdef MACRO1_DEBUG + NSArray* keys = [context allKeys]; + NSUInteger count = [keys count]; + for (int i = 0; i < count; i++) { + id key = [keys objectAtIndex:i]; + Macro1Debug(@"contextdump: %@ = %@ [%@]", key, + [[context objectForKey:key] stringValue], + [[context objectForKey:key] class]); + } +#endif +} + +- (void) restoreArgs:(id)old_args context:(NSMutableDictionary*)calling_context +{ + NuSymbolTable *symbolTable = [calling_context objectForKey:SYMBOLS_KEY]; + + if (old_args == nil) { + [calling_context removeObjectForKey:[symbolTable symbolWithString:@"*args"]]; + } + else { + [calling_context setPossiblyNullObject:old_args forKey:[symbolTable symbolWithString:@"*args"]]; + } +} + +- (void)restoreBindings:(id)bindings + forMaskedVariables:(NSMutableDictionary*)maskedVariables + fromContext:(NSMutableDictionary*)calling_context +{ + id plist = bindings; + + while (plist && (plist != Nu__null)) { + id param = [[plist car] car]; + + Macro1Debug(@"restoring bindings: looking up key: %@", + [param stringValue]); + + [calling_context removeObjectForKey:param]; + id pvalue = [maskedVariables objectForKey:param]; + + Macro1Debug(@"restoring calling context for: %@, value: %@", + [param stringValue], [pvalue stringValue]); + + if (pvalue) { + [calling_context setPossiblyNullObject:pvalue forKey:param]; + } + + plist = [plist cdr]; + } +} + +- (id) destructuringListAppend:(id)lhs withList:(id)rhs +{ + Macro1Debug(@"Append: lhs = %@ rhs = %@", [lhs stringValue], [rhs stringValue]); + + if (lhs == nil || lhs == Nu__null) + return rhs; + + if (rhs == nil || rhs == Nu__null) + return lhs; + + id cursor = lhs; + + while ( cursor + && (cursor != Nu__null) + && [cursor cdr] + && ([cursor cdr] != Nu__null)) { + cursor = [cursor cdr]; + } + + [cursor setCdr:rhs]; + + Macro1Debug(@"Append: result = %@", [lhs stringValue]); + + return lhs; +} + +- (id) mdestructure:(id)pattern withSequence:(id)sequence +{ + Macro1Debug(@"mdestructure: pat: %@ seq: %@", [pattern stringValue], [sequence stringValue]); + + // ((and (not pat) seq) + if ( ((pattern == nil) || (pattern == Nu__null)) + && !((sequence == Nu__null) || (sequence == nil))) { + [NSException raise:@"NuDestructureException" + format:@"Attempt to match empty pattern to non-empty object %@", [self stringValue]]; + } + // ((not pat) nil) + else if ((pattern == nil) || (pattern == Nu__null)) { + return nil; + } + // ((eq pat '_) '()) ; wildcard match produces no binding + else if ([[pattern stringValue] isEqualToString:@"_"]) { + return nil; + } + // ((symbol? pat) + // (let (seq (if (eq ((pat stringValue) characterAtIndex:0) '*') + // (then (list seq)) + // (else seq))) + // (list (list pat seq)))) + else if ([pattern class] == [NuSymbol class]) { + id result; + + if ([[pattern stringValue] characterAtIndex:0] == '*') { + // List-ify sequence + id l = [[[NuCell alloc] init] autorelease]; + [l setCar:sequence]; + result = l; + } + else { + result = sequence; + } + + // (list pattern sequence) + id p = [[[NuCell alloc] init] autorelease]; + id s = [[[NuCell alloc] init] autorelease]; + + [p setCar:pattern]; + [p setCdr:s]; + [s setCar:result]; + + // (list (list pattern sequence)) + id l = [[[NuCell alloc] init] autorelease]; + [l setCar:p]; + + return l; + } + // ((pair? pat) + // (if (and (symbol? (car pat)) + // (eq (((car pat) stringValue) characterAtIndex:0) '*')) + // (then (list (list (car pat) seq))) + // (else ((let ((bindings1 (mdestructure (car pat) (car seq))) + // (bindings2 (mdestructure (cdr pat) (cdr seq)))) + // (append bindings1 bindings2)))))) + else if ([pattern class] == [NuCell class]) { + if ( ([[pattern car] class] == [NuSymbol class]) + && ([[[pattern car] stringValue] characterAtIndex:0] == '*')) { + + id l1 = [[[NuCell alloc] init] autorelease]; + id l2 = [[[NuCell alloc] init] autorelease]; + id l3 = [[[NuCell alloc] init] autorelease]; + [l1 setCar:[pattern car]]; + [l1 setCdr:l2]; + [l2 setCar:sequence]; + [l3 setCar:l1]; + + return l3; + } + else { + if (sequence == nil || sequence == Nu__null) { + [NSException raise:@"NuDestructureException" + format:@"Attempt to match non-empty pattern to empty object"]; + } + + id b1 = [self mdestructure:[pattern car] withSequence:[sequence car]]; + id b2 = [self mdestructure:[pattern cdr] withSequence:[sequence cdr]]; + + id newList = [self destructuringListAppend:b1 withList:b2]; + + Macro1Debug(@"jsb: dbind: %@", [newList stringValue]); + return newList; + } + } + // (else (throw* "NuMatchException" + // "pattern is not nil, a symbol or a pair: #{pat}")))) + else { + [NSException raise:@"NuDestructureException" + format:@"Pattern is not nil, a symbol or a pair: %@", [pattern stringValue]]; + } + + // Just for aesthetics... + return nil; +} + +- (id) expandAndEval:(id)cdr context:(NSMutableDictionary*)calling_context evalFlag:(BOOL)evalFlag +{ + NuSymbolTable *symbolTable = [calling_context objectForKey:SYMBOLS_KEY]; + + NSMutableDictionary* maskedVariables = [[NSMutableDictionary alloc] init]; + + id plist; + + Macro1Debug(@"Dumping context:"); + Macro1Debug(@"---------------:"); +#ifdef MACRO1_DEBUG + [self dumpContext:calling_context]; +#endif + id old_args = [calling_context objectForKey:[symbolTable symbolWithString:@"*args"]]; + [calling_context setPossiblyNullObject:cdr forKey:[symbolTable symbolWithString:@"*args"]]; + + id destructure; + + @try + { + // Destructure the arguments + destructure = [self mdestructure:parameters withSequence:cdr]; + } + @catch (id exception) { + // Destructure failed...restore/remove *args + [self restoreArgs:old_args context:calling_context]; + + @throw; + } + + plist = destructure; + while (plist && (plist != Nu__null)) { + id parameter = [[plist car] car]; + id value = [[[plist car] cdr] car]; + Macro1Debug(@"Destructure: %@ = %@", [parameter stringValue], [value stringValue]); + + id pvalue = [calling_context objectForKey:parameter]; + + if (pvalue) { + Macro1Debug(@" Saving context: %@ = %@", + [parameter stringValue], + [pvalue stringValue]); + [maskedVariables setPossiblyNullObject:pvalue forKey:parameter]; + } + + [calling_context setPossiblyNullObject:value forKey:parameter]; + + plist = [plist cdr]; + } + + Macro1Debug(@"Dumping context (after destructure):"); + Macro1Debug(@"-----------------------------------:"); +#ifdef MACRO1_DEBUG + [self dumpContext:calling_context]; +#endif + // evaluate the body of the block in the calling context (implicit progn) + id value = Nu__null; + + // if the macro contains gensyms, give them a unique prefix + NSUInteger gensymCount = [[self gensyms] count]; + id gensymPrefix = nil; + if (gensymCount > 0) { + gensymPrefix = [NSString stringWithFormat:@"g%ld", [NuMath random]]; + } + + id bodyToEvaluate = (gensymCount == 0) + ? (id)body : [self body:body withGensymPrefix:gensymPrefix symbolTable:symbolTable]; + + // Macro1Debug(@"macro evaluating: %@", [bodyToEvaluate stringValue]); + // Macro1Debug(@"macro context: %@", [calling_context stringValue]); + + @try + { + // Macro expansion + id cursor = [self expandUnquotes:bodyToEvaluate withContext:calling_context]; + while (cursor && (cursor != Nu__null)) { + Macro1Debug(@"macro eval cursor: %@", [cursor stringValue]); + value = [[cursor car] evalWithContext:calling_context]; + Macro1Debug(@"macro expand value: %@", [value stringValue]); + cursor = [cursor cdr]; + } + + // Now that macro expansion is done, restore the masked calling context variables + [self restoreBindings:destructure + forMaskedVariables:maskedVariables + fromContext:calling_context]; + + [maskedVariables release]; + maskedVariables = nil; + + // Macro evaluation + // If we're just macro-expanding, don't do this step... + if (evalFlag) { + Macro1Debug(@"About to execute: %@", [value stringValue]); + value = [value evalWithContext:calling_context]; + Macro1Debug(@"macro eval value: %@", [value stringValue]); + } + + Macro1Debug(@"Dumping context at end:"); + Macro1Debug(@"----------------------:"); +#ifdef MACRO1_DEBUG + [self dumpContext:calling_context]; +#endif + // restore the old value of *args + [self restoreArgs:old_args context:calling_context]; + + Macro1Debug(@"macro result: %@", value); + } + @catch (id exception) { + if (maskedVariables) { + Macro1Debug(@"Caught exception in macro, restoring bindings"); + + [self restoreBindings:destructure + forMaskedVariables:maskedVariables + fromContext:calling_context]; + + Macro1Debug(@"Caught exception in macro, releasing maskedVariables"); + + [maskedVariables release]; + } + + Macro1Debug(@"Caught exception in macro, restoring masked arguments"); + + [self restoreArgs:old_args context:calling_context]; + + Macro1Debug(@"Caught exception in macro, rethrowing..."); + + @throw; + } + + return value; +} + +- (id) expand1:(id)cdr context:(NSMutableDictionary*)calling_context +{ + return [self expandAndEval:cdr context:calling_context evalFlag:NO]; +} + +- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)calling_context +{ + return [self expandAndEval:cdr context:calling_context evalFlag:YES]; +} + +@end + diff --git a/objc/NuMarkupOperator.h b/objc/NuMarkupOperator.h new file mode 100644 index 0000000..8f1b19a --- /dev/null +++ b/objc/NuMarkupOperator.h @@ -0,0 +1,36 @@ +// +// NuMarkupOperator.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import +#import "Nu.h" +#import "NuOperators.h" + +@interface NuMarkupOperator : NuOperator +{ + NSString *tag; + NSString *prefix; + NSMutableArray *tagIds; + NSMutableArray *tagClasses; + id contents; + BOOL empty; // aka a "void element" +} + ++ (id) operatorWithTag:(NSString *) _tag; ++ (id) operatorWithTag:(NSString *) _tag prefix:(NSString *) _prefix; ++ (id) operatorWithTag:(NSString *) _tag prefix:(NSString *) _prefix contents:(id) _contents; + +- (id) initWithTag:(NSString *) tag; +- (id) initWithTag:(NSString *) tag prefix:(NSString *) prefix contents:(id) contents; +- (void) setEmpty:(BOOL) e; + +- (NSString *) tag; +- (NSString *) prefix; +- (id) contents; +- (BOOL) empty; + +@end diff --git a/objc/NuMarkupOperator.m b/objc/NuMarkupOperator.m new file mode 100644 index 0000000..7ecc98d --- /dev/null +++ b/objc/NuMarkupOperator.m @@ -0,0 +1,207 @@ +// +// NuMarkupOperator.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "Nu.h" +#import "NuInternals.h" +#import "NuMarkupOperator.h" + +@implementation NuMarkupOperator + +static NSSet *voidHTMLElements = nil; +static NSDictionary *elementPrefixes = nil; + ++ (void) initialize { + voidHTMLElements = [[NSSet setWithObjects: + @"area", + @"base", + @"br", + @"col", + @"command", + @"embed", + @"hr", + @"img", + @"input", + @"keygen", + @"link", + @"meta", + @"param", + @"source", + @"track", + @"wbr", + nil] retain]; + elementPrefixes = [[NSDictionary dictionaryWithObjectsAndKeys: + @"", @"html", + nil] retain]; +} + ++ (id) operatorWithTag:(NSString *) _tag +{ + return [[[self alloc] initWithTag:_tag] autorelease]; +} + ++ (id) operatorWithTag:(NSString *) _tag prefix:(NSString *) _prefix +{ + return [[[self alloc] initWithTag:_tag prefix:_prefix contents:nil] autorelease]; +} + ++ (id) operatorWithTag:(NSString *) _tag prefix:(NSString *) _prefix contents:(id) _contents +{ + return [[[self alloc] initWithTag:_tag prefix:_prefix contents:_contents] autorelease]; +} + +- (id) initWithTag:(NSString *) _tag +{ + return [self initWithTag:_tag prefix:nil contents:nil]; +} + +- (id) initWithTag:(NSString *) _tag prefix:(NSString *) _prefix contents:(id) _contents +{ + self = [super init]; + + // Scan through the tag looking for "." or "#" characters. + // When we find them, we split the and use the following strings as class or id attributes. + if (_tag) { + NSScanner *scanner = [NSScanner scannerWithString:_tag]; + NSCharacterSet *scanSet = [NSCharacterSet characterSetWithCharactersInString:@".#"]; + NSString *token; + char typeFlag = 0; + while ([scanner scanUpToCharactersFromSet:scanSet intoString:&token]) { + if (typeFlag == 0) { + _tag = token; + } else if (typeFlag == '.') { + if (!tagClasses) { + tagClasses = [[NSMutableArray alloc] init]; + } + [tagClasses addObject:token]; + } else if (typeFlag == '#') { + if (!tagIds) { + tagIds = [[NSMutableArray alloc] init]; + } + [tagIds addObject:token]; + } + if ([scanner scanCharactersFromSet:scanSet intoString:&token]) { + if ([token length]) { + typeFlag = [token characterAtIndex:[token length] - 1]; + } else { + typeFlag = 0; + } + } + } + } + tag = _tag ? [_tag stringByReplacingOccurrencesOfString:@"=" withString:@":"] : nil; + [tag retain]; + prefix = _prefix ? _prefix : [elementPrefixes objectForKey:tag]; + if (!prefix) { + prefix = @""; + } + [prefix retain]; + contents = _contents ? _contents : [NSNull null]; + [contents retain]; + empty = [voidHTMLElements containsObject:tag]; + return self; +} + +- (void) dealloc +{ + [tag release]; + [prefix release]; + [contents release]; + [tagIds release]; + [tagClasses release]; + [super dealloc]; +} + +- (void) setEmpty:(BOOL) e +{ + empty = e; +} + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id t_symbol = [symbolTable symbolWithString:@"t"]; + + NSMutableString *body = [NSMutableString string]; + NSMutableString *attributes = [NSMutableString string]; + + static id NuSymbol = nil; + if (!NuSymbol) { + NuSymbol = NSClassFromString(@"NuSymbol"); + } + if (tagIds) { + for (int i = 0; i < [tagIds count]; i++) { + [attributes appendFormat:@" id=\"%@\"", [tagIds objectAtIndex:i]]; + } + } + if (tagClasses) { + for (int i = 0; i < [tagClasses count]; i++) { + [attributes appendFormat:@" class=\"%@\"", [tagClasses objectAtIndex:i]]; + } + } + for (int i = 0; i < 2; i++) { + id cursor = (i == 0) ? contents : cdr; + while (cursor && (cursor != [NSNull null])) { + id item = [cursor car]; + if ([item isKindOfClass:[NuSymbol class]] && [item isLabel]) { + cursor = [cursor cdr]; + if (cursor && (cursor != [NSNull null])) { + id value = [[cursor car] evalWithContext:context]; + id attributeName = [[item labelName] stringByReplacingOccurrencesOfString:@"=" withString:@":"]; + if ([value isEqual:[NSNull null]]) { + // omit attributes that are "false" + } else if ([value isEqual:t_symbol]) { + // boolean attributes with "true" are written without values + [attributes appendFormat:@" %@", attributeName]; + } else { + id stringValue = [value isEqual:[NSNull null]] ? @"" : [value stringValue]; + [attributes appendFormat:@" %@=\"%@\"", attributeName, stringValue]; + } + } + } + else { + id evaluatedItem = [item evalWithContext:context]; + if (!evaluatedItem || (evaluatedItem == [NSNull null])) { + // do nothing + } + else if ([evaluatedItem isKindOfClass:[NSString class]]) { + [body appendString:evaluatedItem]; + } + else if ([evaluatedItem isKindOfClass:[NSArray class]]) { + NSArray *evaluatedArray = (NSArray *) evaluatedItem; + int max = [evaluatedArray count]; + for (int i = 0; i < max; i++) { + id objectAtIndex = [evaluatedArray objectAtIndex:i]; + [body appendString:[objectAtIndex stringValue]]; + } + } + else { + [body appendString:[evaluatedItem stringValue]]; + } + } + if (cursor && (cursor != [NSNull null])) + cursor = [cursor cdr]; + } + } + + if (!tag) { + return body; + } + else if ([body length] || !empty) { + return [NSString stringWithFormat:@"%@<%@%@>%@", prefix, tag, attributes, body, tag]; + } + else { + return [NSString stringWithFormat:@"%@<%@%@/>", prefix, tag, attributes]; + } +} + +- (NSString *) tag {return tag;} +- (NSString *) prefix {return prefix;} +- (id) contents {return contents;} +- (BOOL) empty {return empty;} + +@end diff --git a/objc/NuMath.h b/objc/NuMath.h new file mode 100644 index 0000000..0d71310 --- /dev/null +++ b/objc/NuMath.h @@ -0,0 +1,43 @@ +// +// NuMath.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @class NuMath + @abstract A utility class that provides Nu access to common mathematical functions. + @discussion The NuMath class provides a few common mathematical functions as class methods. + */ +@interface NuMath : NSObject +/*! Get the square root of a number. */ ++ (double) sqrt: (double) x; +/*! Get the square of a number. */ ++ (double) square: (double) x; +/*! Get the cubed root of a number. */ ++ (double) cbrt: (double) x; +/*! Get the cosine of an angle. */ ++ (double) cos: (double) x; +/*! Get the sine of an angle. */ ++ (double) sin: (double) x; +/*! Get the largest integral value that is not greater than x.*/ ++ (double) floor: (double) x; +/*! Get the smallest integral value that is greater than or equal to x.*/ ++ (double) ceil: (double) x; +/*! Get the integral value nearest to x by always rounding half-way cases away from zero. */ ++ (double) round: (double) x; +/*! Raise x to the power of y */ ++ (double) raiseNumber: (double) x toPower: (double) y; +/*! Get the qouteint of x divided by y as an integer */ ++ (int) integerDivide:(int) x by:(int) y; +/*! Get the remainder of x divided by y as an integer */ ++ (int) integerMod:(int) x by:(int) y; +/*! Get a random integer. */ ++ (long) random; +/*! Seed the random number generator. */ ++ (void) srandom:(unsigned long) seed; +@end \ No newline at end of file diff --git a/objc/NuMath.m b/objc/NuMath.m new file mode 100644 index 0000000..2407d34 --- /dev/null +++ b/objc/NuMath.m @@ -0,0 +1,52 @@ +// +// NuMath.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuMath.h" + +@implementation NuMath + ++ (double) cos: (double) x {return cos(x);} ++ (double) sin: (double) x {return sin(x);} ++ (double) sqrt: (double) x {return sqrt(x);} ++ (double) cbrt: (double) x {return cbrt(x);} ++ (double) square: (double) x {return x*x;} ++ (double) exp: (double) x {return exp(x);} ++ (double) exp2: (double) x {return exp2(x);} ++ (double) log: (double) x {return log(x);} + +#ifdef FREEBSD ++ (double) log2: (double) x {return log10(x)/log10(2.0);} // not in FreeBSD +#else ++ (double) log2: (double) x {return log2(x);} +#endif + ++ (double) log10: (double) x {return log10(x);} + ++ (double) floor: (double) x {return floor(x);} ++ (double) ceil: (double) x {return ceil(x);} ++ (double) round: (double) x {return round(x);} + ++ (double) raiseNumber: (double) x toPower: (double) y {return pow(x, y);} ++ (int) integerDivide:(int) x by:(int) y {return x / y;} ++ (int) integerMod:(int) x by:(int) y {return x % y;} + ++ (double) abs: (double) x {return (x < 0) ? -x : x;} + ++ (long) random +{ + long r = random(); + return r; +} + ++ (void) srandom:(unsigned long) seed +{ + srandom((unsigned int) seed); +} + +@end + diff --git a/objc/NuMethod.h b/objc/NuMethod.h new file mode 100644 index 0000000..e451274 --- /dev/null +++ b/objc/NuMethod.h @@ -0,0 +1,41 @@ +// +// NuMethod.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import +#import +#import + +@class NuBlock; + +/*! + @class NuMethod + @abstract A Nu wrapper for method representations in the Objective-C runtime. + @discussion NuMethod provides an object wrapper for methods that are represented in the Objective-C runtime. + NuMethod objects are used in the Nu language to manipulate Objective-C methods. + */ +@interface NuMethod : NSObject + +/*! Initialize a NuMethod for a given Objective-C method (used from Objective-C) */ +- (id) initWithMethod:(Method) method; +/*! Get the name of a method. */ +- (NSString *) name; +/*! Get the number of arguments to a method. */ +- (int) argumentCount; +/*! Get the Objective-C type encoding of a method. This includes offset information. */ +- (NSString *) typeEncoding; +/*! Get the Objective-C type signature of a method. */ +- (NSString *) signature; +/*! Get the type encoding of a specified argument of a method. */ +- (NSString *) argumentType:(int) i; +/*! Get the encoded return type of a method. */ +- (NSString *) returnType; +/*! If a method is implemented with Nu, get its block. */ +- (NuBlock *) block; +/*! Compare a method with another method by name. This allows arrays of methods to be easily sorted. */ +- (NSComparisonResult) compare:(NuMethod *) anotherMethod; +@end \ No newline at end of file diff --git a/objc/NuMethod.m b/objc/NuMethod.m new file mode 100644 index 0000000..b5eee66 --- /dev/null +++ b/objc/NuMethod.m @@ -0,0 +1,105 @@ +// +// NuMethod.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + + + +#import "NuMethod.h" +#import "NuInternals.h" + + + +#pragma mark - NuMethod.m +@interface NuMethod () +{ + Method m; +} +@end + +@implementation NuMethod + +- (id) initWithMethod:(Method) method +{ + if ((self = [super init])) { + m = method; + } + return self; +} + +- (NSString *) name +{ + return m ? [NSString stringWithCString:(sel_getName(method_getName(m))) encoding:NSUTF8StringEncoding] : (NSString *) [NSNull null]; +} + +- (int) argumentCount +{ + return method_getNumberOfArguments(m); +} + +- (NSString *) typeEncoding +{ + return [NSString stringWithCString:method_getTypeEncoding(m) encoding:NSUTF8StringEncoding]; +} + +- (NSString *) signature +{ + const char *encoding = method_getTypeEncoding(m); + NSInteger len = strlen(encoding)+1; + char *signature = (char *) malloc (len * sizeof(char)); + method_getReturnType(m, signature, len); + NSInteger step = strlen(signature); + char *start = &signature[step]; + len -= step; + int argc = method_getNumberOfArguments(m); + int i; + for (i = 0; i < argc; i++) { + method_getArgumentType(m, i, start, len); + step = strlen(start); + start = &start[step]; + len -= step; + } + // printf("name:%s i:%d len:%d signature:%s\n", sel_getName(method_getName(m)), i, len, signature); + id result = [NSString stringWithCString:signature encoding:NSUTF8StringEncoding]; + free(signature); + return result; +} + +- (NSString *) argumentType:(int) i +{ + if (i >= method_getNumberOfArguments(m)) + return nil; + char *argumentType = method_copyArgumentType(m, i); + id result = [NSString stringWithCString:argumentType encoding:NSUTF8StringEncoding]; + free(argumentType); + return result; +} + +- (NSString *) returnType +{ + char *returnType = method_copyReturnType(m); + id result = [NSString stringWithCString:returnType encoding:NSUTF8StringEncoding]; + free(returnType); + return result; +} + +- (NuBlock *) block +{ + IMP imp = method_getImplementation(m); + NuBlock *block = nil; + if (nu_block_table) { + block = [nu_block_table objectForKey:[NSNumber numberWithUnsignedLong:(unsigned long) imp]]; + } + return block; +} + +- (NSComparisonResult) compare:(NuMethod *) anotherMethod +{ + return [[self name] compare:[anotherMethod name]]; +} + +@end + diff --git a/objc/NuObjCRuntime.h b/objc/NuObjCRuntime.h new file mode 100644 index 0000000..6cfd831 --- /dev/null +++ b/objc/NuObjCRuntime.h @@ -0,0 +1,10 @@ +// +// NuObjCRuntime.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + diff --git a/objc/NuObjCRuntime.m b/objc/NuObjCRuntime.m new file mode 100644 index 0000000..f29b7e9 --- /dev/null +++ b/objc/NuObjCRuntime.m @@ -0,0 +1,136 @@ +// +// NuObjCRuntime.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuObjCRuntime.h" +#import "NuInternals.h" + +#pragma mark - NuObjCRuntime.m + +IMP nu_class_replaceMethod(Class cls, SEL name, IMP imp, const char *types) +{ + if (class_addMethod(cls, name, imp, types)) { + return imp; + } else { + return class_replaceMethod(cls, name, imp, types); + } +} + +void nu_class_addInstanceVariable_withSignature(Class thisClass, const char *variableName, const char *signature) +{ + extern size_t size_of_objc_type(const char *typeString); + size_t size = size_of_objc_type(signature); + uint8_t alignment = log2(size); + BOOL result = class_addIvar(thisClass, variableName, size, alignment, signature); + if (!result) { + [NSException raise:@"NuAddIvarFailed" + format:@"failed to add instance variable %s to class %s", variableName, class_getName(thisClass)]; + } + //NSLog(@"adding ivar named %s to %s, result is %d", variableName, class_getName(thisClass), result); +} + +BOOL nu_copyInstanceMethod(Class destinationClass, Class sourceClass, SEL selector) +{ + Method m = class_getInstanceMethod(sourceClass, selector); + if (!m) { + return NO; + } + IMP imp = method_getImplementation(m); + if (!imp) { + return NO; + } + const char *signature = method_getTypeEncoding(m); + if (!signature) { + return NO; + } + BOOL result = (nu_class_replaceMethod(destinationClass, selector, imp, signature) != 0); + return result; +} + +BOOL nu_objectIsKindOfClass(id object, Class class) +{ + if (object == NULL) { + return NO; + } + Class classCursor = object_getClass(object); + while (classCursor) { + if (classCursor == class) { + return YES; + } + classCursor = class_getSuperclass(classCursor); + } + return NO; +} + +// This function attempts to recognize the return type from a method signature. +// It scans across the signature until it finds a complete return type string, +// then it inserts a null to mark the end of the string. +void nu_markEndOfObjCTypeString(char *type, size_t len) +{ + size_t i; + char final_char = 0; + char start_char = 0; + int depth = 0; + for (i = 0; i < len; i++) { + switch(type[i]) { + case '[': + case '{': + case '(': + // we want to scan forward to a closing character + if (!final_char) { + start_char = type[i]; + final_char = (start_char == '[') ? ']' : (start_char == '(') ? ')' : '}'; + depth = 1; + } + else if (type[i] == start_char) { + depth++; + } + break; + case ']': + case '}': + case ')': + if (type[i] == final_char) { + depth--; + if (depth == 0) { + if (i+1 < len) + type[i+1] = 0; + return; + } + } + break; + case 'b': // bitfields + if (depth == 0) { + // scan forward, reading all subsequent digits + i++; + while ((i < len) && (type[i] >= '0') && (type[i] <= '9')) + i++; + if (i+1 < len) + type[i+1] = 0; + return; + } + case '^': // pointer + case 'r': // const + case 'n': // in + case 'N': // inout + case 'o': // out + case 'O': // bycopy + case 'R': // byref + case 'V': // oneway + break; // keep going, these are all modifiers. + case 'c': case 'i': case 's': case 'l': case 'q': + case 'C': case 'I': case 'S': case 'L': case 'Q': + case 'f': case 'd': case 'B': case 'v': case '*': + case '@': case '#': case ':': case '?': default: + if (depth == 0) { + if (i+1 < len) + type[i+1] = 0; + return; + } + break; + } + } +} diff --git a/objc/NuOperators.h b/objc/NuOperators.h new file mode 100644 index 0000000..ba6d03c --- /dev/null +++ b/objc/NuOperators.h @@ -0,0 +1,34 @@ +// +// NuOperators.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + + +/*! + @class NuOperator + @abstract An abstract class for Nu operators. + @discussion Like everything else in Nu, operators are represented with objects. + Nu operators that are written in Objective-C are implemented with subclasses of this class. + Each operator is intended to have a singleton instance that is bound to a symbol + in a Nu symbol table. An operator is evaluated with a call to + its evalWithArguments:context: method. + When they implement functions, operators evaluate their arguments, + but many special forms exist that evaluate their arguments zero or multiple times. + */ +@interface NuOperator : NSObject + +/*! Evaluate an operator with a list of arguments and an execution context. + This method calls callWithArguments:context: and should not be overridden. + */ +- (id) evalWithArguments:(id) cdr context:(NSMutableDictionary *) context; +/*! Call an operator with a list of arguments and an execution context. + This method should be overridden by implementations of new operators. + */ +- (id) callWithArguments:(id) cdr context:(NSMutableDictionary *) context; + +@end diff --git a/objc/NuOperators.m b/objc/NuOperators.m new file mode 100644 index 0000000..fb6957d --- /dev/null +++ b/objc/NuOperators.m @@ -0,0 +1,2395 @@ +// +// NuOperators.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuOperators.h" +#import "NuInternals.h" +#import "NuRegex.h" +#import "NuMacro.h" +#import "NSBundle+Nu.h" +#import "NSDictionary+Nu.h" +#import "NSFileManager+Nu.h" +#import "NSArray+Nu.h" +#import "NuBridge.h" + +#if TARGET_OS_IPHONE +#import +#endif + + +#pragma mark - NuOperator.m + +@implementation NuBreakException +- (id) init +{ + return [super initWithName:@"NuBreakException" reason:@"A break operator was evaluated" userInfo:nil]; +} + +@end + +@implementation NuContinueException +- (id) init +{ + return [super initWithName:@"NuContinueException" reason:@"A continue operator was evaluated" userInfo:nil]; +} + +@end + +@implementation NuReturnException +- (id) initWithValue:(id) v +{ + if ((self = [super initWithName:@"NuReturnException" reason:@"A return operator was evaluated" userInfo:nil])) { + value = [v retain]; + blockForReturn = nil; + } + return self; +} + +- (id) initWithValue:(id) v blockForReturn:(id) b +{ + if ((self = [super initWithName:@"NuReturnException" reason:@"A return operator was evaluated" userInfo:nil])) { + value = [v retain]; + blockForReturn = b; // weak reference + } + return self; +} + +- (void) dealloc +{ + [value release]; + [super dealloc]; +} + +- (id) value +{ + return value; +} + +- (id) blockForReturn +{ + return blockForReturn; +} + +@end + +@implementation NuOperator : NSObject +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context {return nil;} +- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context {return [self callWithArguments:cdr context:context];} +@end + +@interface Nu_car_operator : NuOperator {} +@end + +@implementation Nu_car_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cadr = [cdr car]; + id value = [cadr evalWithContext:context]; + return ([value respondsToSelector:@selector(car)]) ? [value car] : Nu__null; +} + +@end + +@interface Nu_cdr_operator : NuOperator {} +@end + +@implementation Nu_cdr_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cadr = [cdr car]; + id value = [cadr evalWithContext:context]; + return ([value respondsToSelector:@selector(cdr)]) ? [value cdr] : Nu__null; +} + +@end + +@interface Nu_atom_operator : NuOperator {} +@end + +@implementation Nu_atom_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cadr = [cdr car]; + id value = [cadr evalWithContext:context]; + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + if ([value atom]) + return [symbolTable symbolWithString:@"t"]; + else + return Nu__null; +} + +@end + +@interface Nu_defined_operator : NuOperator {} +@end + +@implementation Nu_defined_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + bool is_defined = YES; + id cadr = [cdr car]; + @try + { + [cadr evalWithContext:context]; + } + @catch (id exception) { + // is this an undefined symbol exception? if not, throw it + if ([[exception name] isEqualToString:@"NuUndefinedSymbol"]) { + is_defined = NO; + } + else { + @throw(exception); + } + } + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + if (is_defined) + return [symbolTable symbolWithString:@"t"]; + else + return Nu__null; +} + +@end + +@interface Nu_eq_operator : NuOperator {} +@end + +@implementation Nu_eq_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id cursor = cdr; + id current = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + id next = [[cursor car] evalWithContext: context]; + if (![current isEqual:next]) + return Nu__null; + current = next; + cursor = [cursor cdr]; + } + return [symbolTable symbolWithString:@"t"]; +} + +@end + +@interface Nu_neq_operator : NuOperator {} +@end + +@implementation Nu_neq_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cadr = [cdr car]; + id caddr = [[cdr cdr] car]; + id value1 = [cadr evalWithContext:context]; + id value2 = [caddr evalWithContext:context]; + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + if ((value1 == nil) && (value2 == nil)) { + return Nu__null; + } + else if ([value1 isEqual:value2]) { + return Nu__null; + } + else { + return [symbolTable symbolWithString:@"t"]; + } +} + +@end + +@interface Nu_cons_operator : NuOperator {} +@end + +@implementation Nu_cons_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cadr = [cdr car]; + id cddr = [cdr cdr]; + id value1 = [cadr evalWithContext:context]; + id value2 = [cddr evalWithContext:context]; + id newCell = [[[NuCell alloc] init] autorelease]; + [newCell setCar:value1]; + [newCell setCdr:value2]; + return newCell; +} + +@end + +@interface Nu_append_operator : NuOperator {} +@end + +@implementation Nu_append_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id newList = Nu__null; + id cursor = nil; + id list_to_append = cdr; + while (list_to_append && (list_to_append != Nu__null)) { + id item_to_append = [[list_to_append car] evalWithContext:context]; + while (item_to_append && (item_to_append != Nu__null)) { + if (newList == Nu__null) { + newList = [[[NuCell alloc] init] autorelease]; + cursor = newList; + } + else { + [cursor setCdr: [[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + } + id item = [item_to_append car]; + [cursor setCar: item]; + item_to_append = [item_to_append cdr]; + } + list_to_append = [list_to_append cdr]; + } + return newList; +} + +@end + + +@interface Nu_apply_operator : NuOperator {} +@end + +@implementation Nu_apply_operator +- (id) prependCell:(id)item withSymbol:(id)symbol +{ + id qitem = [[[NuCell alloc] init] autorelease]; + [qitem setCar:symbol]; + [qitem setCdr:[[[NuCell alloc] init] autorelease]]; + [[qitem cdr] setCar:item]; + return qitem; +} + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id quoteSymbol = [symbolTable symbolWithString:@"quote"]; + + id fn = [cdr car]; + + // Arguments to fn can be anything, but last item must be a list + id qargs = Nu__null; + id qargs_cursor = Nu__null; + id cursor = [cdr cdr]; + + while (cursor && (cursor != Nu__null) && [cursor cdr] && ([cursor cdr] != Nu__null)) { + if (qargs == Nu__null) { + qargs = [[[NuCell alloc] init] autorelease]; + qargs_cursor = qargs; + } + else { + [qargs_cursor setCdr:[[[NuCell alloc] init] autorelease]]; + qargs_cursor = [qargs_cursor cdr]; + } + + id item = [[cursor car] evalWithContext:context]; + id qitem = [self prependCell:item withSymbol:quoteSymbol]; + [qargs_cursor setCar:qitem]; + cursor = [cursor cdr]; + } + + // The rest of the arguments are in a list + id args = [cursor evalWithContext:context]; + cursor = args; + + while (cursor && (cursor != Nu__null)) { + if (qargs == Nu__null) { + qargs = [[[NuCell alloc] init] autorelease]; + qargs_cursor = qargs; + } + else { + [qargs_cursor setCdr:[[[NuCell alloc] init] autorelease]]; + qargs_cursor = [qargs_cursor cdr]; + } + id item = [cursor car]; + + id qitem = [self prependCell:item withSymbol:quoteSymbol]; + [qargs_cursor setCar:qitem]; + cursor = [cursor cdr]; + } + + // Call the real function with the evaluated and quoted args + id expr = [[[NuCell alloc] init] autorelease]; + [expr setCar:fn]; + [expr setCdr:qargs]; + + id result = [expr evalWithContext:context]; + + return result; +} +@end + +@interface Nu_cond_operator : NuOperator {} +@end + +@implementation Nu_cond_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id pairs = cdr; + id value = Nu__null; + while (pairs != Nu__null) { + id condition = [[pairs car] car]; + id test = [condition evalWithContext:context]; + if (nu_valueIsTrue(test)) { + value = test; + id cursor = [[pairs car] cdr]; + while (cursor && (cursor != Nu__null)) { + value = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + } + return value; + } + pairs = [pairs cdr]; + } + return value; +} + +@end + +@interface Nu_case_operator : NuOperator {} +@end + +@implementation Nu_case_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id target = [[cdr car] evalWithContext:context]; + id cases = [cdr cdr]; + while ([cases cdr] != Nu__null) { + id condition = [[cases car] car]; + id result = [condition evalWithContext:context]; + if ([result isEqual:target]) { + id value = Nu__null; + id cursor = [[cases car] cdr]; + while (cursor && (cursor != Nu__null)) { + value = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + } + return value; + } + cases = [cases cdr]; + } + // or return the last one + id value = Nu__null; + id cursor = [[cases car] cdr]; + while (cursor && (cursor != Nu__null)) { + value = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + } + return value; +} + +@end + +@interface Nu_if_operator : NuOperator {} +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context flipped:(bool)flip; +@end + +@implementation Nu_if_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + return [self callWithArguments:cdr context:context flipped:NO]; +} + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context flipped:(bool)flip +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + //id thenSymbol = [symbolTable symbolWithString:@"then"]; + id elseSymbol = [symbolTable symbolWithString:@"else"]; + //id elseifSymbol = [symbolTable symbolWithString:@"elseif"]; + + id result = Nu__null; + id test = [[cdr car] evalWithContext:context]; + + bool testIsTrue = flip ^ nu_valueIsTrue(test); + bool noneIsTrue = !testIsTrue; + + id expressions = [cdr cdr]; + while (expressions && (expressions != Nu__null)) { + id nextExpression = [expressions car]; + if (nu_objectIsKindOfClass(nextExpression, [NuCell class])) { + /*if ([nextExpression car] == elseifSymbol) { + test = [[[[expressions car] cdr] car] evalWithContext:context]; + testIsTrue = noneIsTrue && nu_valueIsTrue(test); + noneIsTrue = noneIsTrue && !testIsTrue; + if (testIsTrue) + // skip the test: + result = [[[nextExpression cdr] cdr] evalWithContext:context]; + } + else */ + if ([nextExpression car] == elseSymbol) { + if (noneIsTrue) + result = [nextExpression evalWithContext:context]; + } + else { + if (testIsTrue) + result = [nextExpression evalWithContext:context]; + } + } + else { + /*if (nextExpression == elseifSymbol) { + test = [[[expressions cdr] car] evalWithContext:context]; + testIsTrue = noneIsTrue && nu_valueIsTrue(test); + noneIsTrue = noneIsTrue && !testIsTrue; + expressions = [expressions cdr]; // skip the test + } + else */ + if (nextExpression == elseSymbol) { + testIsTrue = noneIsTrue; + noneIsTrue = NO; + } + else { + if (testIsTrue) + result = [nextExpression evalWithContext:context]; + } + } + expressions = [expressions cdr]; + } + return result; +} + +@end + +@interface Nu_unless_operator : Nu_if_operator {} +@end + +@implementation Nu_unless_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + return [super callWithArguments:cdr context:context flipped:YES]; +} + +@end + +@interface Nu_while_operator : NuOperator {} +@end + +@implementation Nu_while_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id result = Nu__null; + id test = [[cdr car] evalWithContext:context]; + while (nu_valueIsTrue(test)) { + @try + { + id expressions = [cdr cdr]; + while (expressions && (expressions != Nu__null)) { + result = [[expressions car] evalWithContext:context]; + expressions = [expressions cdr]; + } + } + @catch (NuBreakException *exception) { + break; + } + @catch (NuContinueException *exception) { + // do nothing, just continue with the next loop iteration + } + @catch (id exception) { + @throw(exception); + } + test = [[cdr car] evalWithContext:context]; + } + return result; +} + +@end + +@interface Nu_until_operator : NuOperator {} +@end + +@implementation Nu_until_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id result = Nu__null; + id test = [[cdr car] evalWithContext:context]; + while (!nu_valueIsTrue(test)) { + @try + { + id expressions = [cdr cdr]; + while (expressions && (expressions != Nu__null)) { + result = [[expressions car] evalWithContext:context]; + expressions = [expressions cdr]; + } + } + @catch (NuBreakException *exception) { + break; + } + @catch (NuContinueException *exception) { + // do nothing, just continue with the next loop iteration + } + @catch (id exception) { + @throw(exception); + } + test = [[cdr car] evalWithContext:context]; + } + return result; +} + +@end + +@interface Nu_for_operator : NuOperator {} +@end + +@implementation Nu_for_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id result = Nu__null; + id controls = [cdr car]; // this could use some error checking! + id loopinit = [controls car]; + id looptest = [[controls cdr] car]; + id loopincr = [[[controls cdr] cdr] car]; + // initialize the loop + [loopinit evalWithContext:context]; + // evaluate the loop condition + id test = [looptest evalWithContext:context]; + while (nu_valueIsTrue(test)) { + @try + { + id expressions = [cdr cdr]; + while (expressions && (expressions != Nu__null)) { + result = [[expressions car] evalWithContext:context]; + expressions = [expressions cdr]; + } + } + @catch (NuBreakException *exception) { + break; + } + @catch (NuContinueException *exception) { + // do nothing, just continue with the next loop iteration + } + @catch (id exception) { + @throw(exception); + } + // perform the end of loop increment step + [loopincr evalWithContext:context]; + // evaluate the loop condition + test = [looptest evalWithContext:context]; + } + return result; +} + +@end + +@interface Nu_try_operator : NuOperator {} +@end + +@implementation Nu_try_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id catchSymbol = [symbolTable symbolWithString:@"catch"]; + id finallySymbol = [symbolTable symbolWithString:@"finally"]; + id result = Nu__null; + + @try + { + // evaluate all the expressions that are outside catch and finally blocks + id expressions = cdr; + while (expressions && (expressions != Nu__null)) { + id nextExpression = [expressions car]; + if (nu_objectIsKindOfClass(nextExpression, [NuCell class])) { + if (([nextExpression car] != catchSymbol) && ([nextExpression car] != finallySymbol)) { + result = [nextExpression evalWithContext:context]; + } + } + else { + result = [nextExpression evalWithContext:context]; + } + expressions = [expressions cdr]; + } + } + @catch (id thrownObject) { + // evaluate all the expressions that are in catch blocks + id expressions = cdr; + while (expressions && (expressions != Nu__null)) { + id nextExpression = [expressions car]; + if (nu_objectIsKindOfClass(nextExpression, [NuCell class])) { + if (([nextExpression car] == catchSymbol)) { + // this is a catch block. + // the first expression should be a list with a single symbol + // that's a name. we'll set that name to the thing we caught + id nameList = [[nextExpression cdr] car]; + id name = [nameList car]; + [context setValue:thrownObject forKey:name]; + // now we loop over the rest of the expressions and evaluate them one by one + id cursor = [[nextExpression cdr] cdr]; + while (cursor && (cursor != Nu__null)) { + result = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + } + } + } + expressions = [expressions cdr]; + } + } + @finally + { + // evaluate all the expressions that are in finally blocks + id expressions = cdr; + while (expressions && (expressions != Nu__null)) { + id nextExpression = [expressions car]; + if (nu_objectIsKindOfClass(nextExpression, [NuCell class])) { + if (([nextExpression car] == finallySymbol)) { + // this is a finally block + // loop over the rest of the expressions and evaluate them one by one + id cursor = [nextExpression cdr]; + while (cursor && (cursor != Nu__null)) { + result = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + } + } + } + expressions = [expressions cdr]; + } + } + return result; +} + +@end + +@interface Nu_throw_operator : NuOperator {} +@end + +@implementation Nu_throw_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id exception = [[cdr car] evalWithContext:context]; + @throw exception; + return exception; +} + +@end + +@interface Nu_synchronized_operator : NuOperator {} +@end + +@implementation Nu_synchronized_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + // NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + + id object = [[cdr car] evalWithContext:context]; + id result = Nu__null; + + @synchronized(object) { + // evaluate the rest of the expressions + id expressions = [cdr cdr]; + while (expressions && (expressions != Nu__null)) { + id nextExpression = [expressions car]; + result = [nextExpression evalWithContext:context]; + expressions = [expressions cdr]; + } + } + return result; +} + +@end + +@interface Nu_quote_operator : NuOperator {} +@end + +@implementation Nu_quote_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cadr = [cdr car]; + return cadr; +} + +@end + +@interface Nu_quasiquote_eval_operator : NuOperator {} +@end + +@implementation Nu_quasiquote_eval_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + // bqcomma is handled by Nu_quasiquote_operator. + // If we get here, it means someone called bq_comma + // outside of a backquote + [NSException raise:@"NuQuasiquoteEvalOutsideQuasiquote" + format:@"Comma must be inside a backquote"]; + + // Purely cosmetic... + return Nu__null; +} + +@end + +@interface Nu_quasiquote_splice_operator : NuOperator {} +@end + +@implementation Nu_quasiquote_splice_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + // bqcomma-at is handled by Nu_quasiquote_operator. + // If we get here, it means someone called bq_comma + // outside of a backquote + [NSException raise:@"NuQuasiquoteSpliceOutsideQuasiquote" + format:@"Comma-at must be inside a backquote"]; + + // Purely cosmetic... + return Nu__null; +} + +@end + +// Temporary use for debugging quasiquote functions... +#if 0 +#define QuasiLog(args...) NSLog(args) +#else +#define QuasiLog(args...) +#endif + +@interface Nu_quasiquote_operator : NuOperator {} +@end + +@implementation Nu_quasiquote_operator + +- (id) evalQuasiquote:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + + id quasiquote_eval = [[symbolTable symbolWithString:@"quasiquote-eval"] value]; + id quasiquote_splice = [[symbolTable symbolWithString:@"quasiquote-splice"] value]; + + QuasiLog(@"bq:Entered. callWithArguments cdr = %@", [cdr stringValue]); + + id result = Nu__null; + id result_cursor = Nu__null; + id cursor = cdr; + + while (cursor && (cursor != Nu__null)) { + id value; + QuasiLog(@"quasiquote: [cursor car] == %@", [[cursor car] stringValue]); + + if ([[cursor car] atom]) { + // Treat it as a quoted value + QuasiLog(@"quasiquote: Quoting cursor car: %@", [[cursor car] stringValue]); + value = [cursor car]; + } + else if ([cursor car] == Nu__null) { + QuasiLog(@" quasiquote: null-list"); + value = Nu__null; + } + else if ([[symbolTable lookup:[[[cursor car] car] stringValue]] value] == quasiquote_eval) { + QuasiLog(@"quasiquote-eval: Evaling: [[cursor car] cdr]: %@", [[[cursor car] cdr] stringValue]); + value = [[[cursor car] cdr] evalWithContext:context]; + QuasiLog(@" quasiquote-eval: Value: %@", [value stringValue]); + } + else if ([[symbolTable lookup:[[[cursor car] car] stringValue]] value] == quasiquote_splice) { + QuasiLog(@"quasiquote-splice: Evaling: [[cursor car] cdr]: %@", + [[[cursor car] cdr] stringValue]); + value = [[[cursor car] cdr] evalWithContext:context]; + QuasiLog(@" quasiquote-splice: Value: %@", [value stringValue]); + + if (value != Nu__null && [value atom]) { + [NSException raise:@"NuQuasiquoteSpliceNoListError" + format:@"An atom was passed to Quasiquote splicer. Splicing can only splice a list."]; + } + + id value_cursor = value; + + while (value_cursor && (value_cursor != Nu__null)) { + id value_item = [value_cursor car]; + + if (result_cursor == Nu__null) { + result_cursor = [[[NuCell alloc] init] autorelease]; + result = result_cursor; + } + else { + [result_cursor setCdr: [[[NuCell alloc] init] autorelease]]; + result_cursor = [result_cursor cdr]; + } + + [result_cursor setCar: value_item]; + value_cursor = [value_cursor cdr]; + } + + QuasiLog(@" quasiquote-splice-append: result: %@", [result stringValue]); + + cursor = [cursor cdr]; + + // Don't want to do the normal cursor handling at bottom of the loop + // in this case as we've already done it in the splicing above... + continue; + } + else { + QuasiLog(@"quasiquote: recursive callWithArguments: %@", [[cursor car] stringValue]); + value = [self evalQuasiquote:[cursor car] context:context]; + QuasiLog(@"quasiquote: leaving recursive call with value: %@", [value stringValue]); + } + + if (result == Nu__null) { + result = [[[NuCell alloc] init] autorelease]; + result_cursor = result; + } + else { + [result_cursor setCdr:[[[NuCell alloc] init] autorelease]]; + result_cursor = [result_cursor cdr]; + } + + [result_cursor setCar:value]; + + QuasiLog(@"quasiquote: result_cursor: %@", [result_cursor stringValue]); + QuasiLog(@"quasiquote: result: %@", [result stringValue]); + + cursor = [cursor cdr]; + } + QuasiLog(@"quasiquote: returning result = %@", [result stringValue]); + return result; +} + +#if 0 +@implementation Nu_append_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id newList = Nu__null; + id cursor = nil; + id list_to_append = cdr; + while (list_to_append && (list_to_append != Nu__null)) { + id item_to_append = [[list_to_append car] evalWithContext:context]; + while (item_to_append && (item_to_append != Nu__null)) { + if (newList == Nu__null) { + newList = [[[NuCell alloc] init] autorelease]; + cursor = newList; + } + else { + [cursor setCdr: [[[NuCell alloc] init] autorelease]]; + cursor = [cursor cdr]; + } + id item = [item_to_append car]; + [cursor setCar: item]; + item_to_append = [item_to_append cdr]; + } + list_to_append = [list_to_append cdr]; + } + return newList; +} + +@end +#endif + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + return [[self evalQuasiquote:cdr context:context] car]; +} + +@end + +@interface Nu_context_operator : NuOperator {} +@end + +@implementation Nu_context_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + return context; +} + +@end + +@interface Nu_set_operator : NuOperator {} +@end + +@implementation Nu_set_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + + NuSymbol *symbol = [cdr car]; + id value = [[cdr cdr] car]; + id result = [value evalWithContext:context]; + + char c = (char) [[symbol stringValue] characterAtIndex:0]; + if (c == '$') { + [symbol setValue:result]; + } + else if (c == '@') { + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id object = [context lookupObjectForKey:[symbolTable symbolWithString:@"self"]]; + id ivar = [[symbol stringValue] substringFromIndex:1]; + [object setValue:result forIvar:ivar]; + } + else { +#ifndef CLOSE_ON_VALUES + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id classSymbol = [symbolTable symbolWithString:@"_class"]; + id searchContext = context; + while (searchContext) { + if ([searchContext objectForKey:symbol]) { + [searchContext setPossiblyNullObject:result forKey:symbol]; + return result; + } + else if ([searchContext objectForKey:classSymbol]) { + break; + } + searchContext = [searchContext objectForKey:PARENT_KEY]; + } +#endif + [context setPossiblyNullObject:result forKey:symbol]; + } + return result; +} + +@end + +@interface Nu_local_operator : NuOperator {} +@end + +@implementation Nu_local_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + + NuSymbol *symbol = [cdr car]; + id value = [[cdr cdr] car]; + id result = [value evalWithContext:context]; + [context setPossiblyNullObject:result forKey:symbol]; + return result; +} + +@end + + +@interface Nu_global_operator : NuOperator {} +@end + +@implementation Nu_global_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + + NuSymbol *symbol = [cdr car]; + id value = [[cdr cdr] car]; + id result = [value evalWithContext:context]; + [symbol setValue:result]; + return result; +} + +@end + +@interface Nu_regex_operator : NuOperator {} +@end + +@implementation Nu_regex_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id value = [cdr car]; + value = [value evalWithContext:context]; + return [NSRegularExpression regexWithPattern:value]; +} + +@end + +@interface Nu_do_operator : NuOperator {} +@end + +@implementation Nu_do_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id args = [cdr car]; + id body = [cdr cdr]; + NuBlock *block = [[[NuBlock alloc] initWithParameters:args body:body context:context] autorelease]; + return block; +} + +@end + +@interface Nu_function_operator : NuOperator {} +@end + +@implementation Nu_function_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id symbol = [cdr car]; + id args = [[cdr cdr] car]; + id body = [[cdr cdr] cdr]; + NuBlock *block = [[[NuBlock alloc] initWithParameters:args body:body context:context] autorelease]; + // this defines the function in the calling context, lexical closures make recursion possible + [context setPossiblyNullObject:block forKey:symbol]; +#ifdef CLOSE_ON_VALUES + // in this case, we don't have closures, so we set this to allow recursion (but it creates a retain cycle) + [[block context] setPossiblyNullObject:block forKey:symbol]; +#endif + return block; +} + +@end + +@interface Nu_label_operator : NuOperator {} +@end + +@implementation Nu_label_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id symbol = [cdr car]; + id value = [[cdr cdr] car]; + value = [value evalWithContext:context]; + if (nu_objectIsKindOfClass(value, [NuBlock class])) { + //NSLog(@"setting context[%@] = %@", symbol, value); + [((NSMutableDictionary *)[value context]) setPossiblyNullObject:value forKey:symbol]; + } + return value; +} + +@end + +@interface Nu_macro_0_operator : NuOperator {} +@end + +@implementation Nu_macro_0_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id name = [cdr car]; + id body = [cdr cdr]; + + NuMacro_0 *macro = [[[NuMacro_0 alloc] initWithName:name body:body] autorelease]; + // this defines the function in the calling context + [context setPossiblyNullObject:macro forKey:name]; + return macro; +} + +@end + +@interface Nu_macro_1_operator : NuOperator {} +@end + +@implementation Nu_macro_1_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id name = [cdr car]; + id args = [[cdr cdr] car]; + id body = [[cdr cdr] cdr]; + + NuMacro_1 *macro = [[[NuMacro_1 alloc] initWithName:name parameters:args body:body] autorelease]; + // this defines the function in the calling context + [context setPossiblyNullObject:macro forKey:name]; + return macro; +} + +@end + +@interface Nu_macrox_operator : NuOperator {} +@end + +@implementation Nu_macrox_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id call = [cdr car]; + id name = [call car]; + id margs = [call cdr]; + + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id macro = [context objectForKey:[symbolTable symbolWithString:[name stringValue]]]; + + if (macro == nil) { + [NSException raise:@"NuMacroxWrongType" format:@"macrox was called on an object which is not a macro"]; + } + + id expanded = [macro expand1:margs context:context]; + return expanded; +} + +@end + +@interface Nu_list_operator : NuOperator {} +@end + +@implementation Nu_list_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id result = Nu__null; + id cursor = cdr; + id result_cursor = Nu__null; + while (cursor && (cursor != Nu__null)) { + if (result == Nu__null) { + result = [[[NuCell alloc] init] autorelease]; + result_cursor = result; + } + else { + [result_cursor setCdr:[[[NuCell alloc] init] autorelease]]; + result_cursor = [result_cursor cdr]; + } + id value = [[cursor car] evalWithContext:context]; + [result_cursor setCar:value]; + cursor = [cursor cdr]; + } + return result; +} + +@end + +@interface Nu_add_operator : NuOperator {} +@end + +@implementation Nu_add_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + if ([context objectForKey:[symbolTable symbolWithString:@"_class"]] && ![context objectForKey:[symbolTable symbolWithString:@"_method"]]) { + // we are inside a class declaration and outside a method declaration. + // treat this as a "cmethod" call + NuClass *classWrapper = [context objectForKey:[symbolTable symbolWithString:@"_class"]]; + [classWrapper registerClass]; + Class classToExtend = [classWrapper wrappedClass]; + return help_add_method_to_class(classToExtend, cdr, context, YES); + } + // otherwise, it's an addition + id firstArgument = [[cdr car] evalWithContext:context]; + if (nu_objectIsKindOfClass(firstArgument, [NSValue class])) { + double sum = [firstArgument doubleValue]; + id cursor = [cdr cdr]; + while (cursor && (cursor != Nu__null)) { + sum += [[[cursor car] evalWithContext:context] doubleValue]; + cursor = [cursor cdr]; + } + return [NSNumber numberWithDouble:sum]; + } + else { + NSMutableString *result = [NSMutableString stringWithString:[firstArgument stringValue]]; + id cursor = [cdr cdr]; + while (cursor && (cursor != Nu__null)) { + id carValue = [[cursor car] evalWithContext:context]; + if (carValue && (carValue != Nu__null)) { + [result appendString:[carValue stringValue]]; + } + cursor = [cursor cdr]; + } + return result; + } +} + +@end + +@interface Nu_multiply_operator : NuOperator {} +@end + +@implementation Nu_multiply_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + double product = 1; + id cursor = cdr; + while (cursor && (cursor != Nu__null)) { + product *= [[[cursor car] evalWithContext:context] doubleValue]; + cursor = [cursor cdr]; + } + return [NSNumber numberWithDouble:product]; +} + +@end + +@interface Nu_subtract_operator : NuOperator {} +@end + +@implementation Nu_subtract_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + if ([context objectForKey:[symbolTable symbolWithString:@"_class"]] && ![context objectForKey:[symbolTable symbolWithString:@"_method"]]) { + // we are inside a class declaration and outside a method declaration. + // treat this as an "imethod" call + NuClass *classWrapper = [context objectForKey:[symbolTable symbolWithString:@"_class"]]; + [classWrapper registerClass]; + Class classToExtend = [classWrapper wrappedClass]; + return help_add_method_to_class(classToExtend, cdr, context, NO); + } + // otherwise, it's a subtraction + id cursor = cdr; + double sum = [[[cursor car] evalWithContext:context] doubleValue]; + cursor = [cursor cdr]; + if (!cursor || (cursor == Nu__null)) { + // if there is just one operand, negate it + sum = -sum; + } + else { + // otherwise, subtract all the remaining operands from the first one + while (cursor && (cursor != Nu__null)) { + sum -= [[[cursor car] evalWithContext:context] doubleValue]; + cursor = [cursor cdr]; + } + } + return [NSNumber numberWithDouble:sum]; +} + +@end + +@interface Nu_exponentiation_operator : NuOperator {} +@end + +@implementation Nu_exponentiation_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cursor = cdr; + double result = [[[cursor car] evalWithContext:context] doubleValue]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + result = pow(result, [[[cursor car] evalWithContext:context] doubleValue]); + cursor = [cursor cdr]; + } + return [NSNumber numberWithDouble:result]; +} + +@end + +@interface Nu_divide_operator : NuOperator {} +@end + +@implementation Nu_divide_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cursor = cdr; + double product = [[[cursor car] evalWithContext:context] doubleValue]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + product /= [[[cursor car] evalWithContext:context] doubleValue]; + cursor = [cursor cdr]; + } + return [NSNumber numberWithDouble:product]; +} + +@end + +@interface Nu_modulus_operator : NuOperator {} +@end + +@implementation Nu_modulus_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cursor = cdr; + int product = [[[cursor car] evalWithContext:context] intValue]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + product %= [[[cursor car] evalWithContext:context] intValue]; + cursor = [cursor cdr]; + } + return [NSNumber numberWithInt:product]; +} + +@end + +@interface Nu_bitwiseand_operator : NuOperator {} +@end + +@implementation Nu_bitwiseand_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cursor = cdr; + long result = [[[cursor car] evalWithContext:context] longValue]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + result &= [[[cursor car] evalWithContext:context] longValue]; + cursor = [cursor cdr]; + } + return [NSNumber numberWithLong:result]; +} + +@end + +@interface Nu_bitwiseor_operator : NuOperator {} +@end + +@implementation Nu_bitwiseor_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cursor = cdr; + long result = [[[cursor car] evalWithContext:context] longValue]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + result |= [[[cursor car] evalWithContext:context] longValue]; + cursor = [cursor cdr]; + } + return [NSNumber numberWithLong:result]; +} + +@end + +@interface Nu_greaterthan_operator : NuOperator {} +@end + +@implementation Nu_greaterthan_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id cursor = cdr; + id current = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + id next = [[cursor car] evalWithContext:context]; + NSComparisonResult result = [current compare:next]; + if (result != NSOrderedDescending) + return Nu__null; + current = next; + cursor = [cursor cdr]; + } + return [symbolTable symbolWithString:@"t"]; +} + +@end + +@interface Nu_lessthan_operator : NuOperator {} +@end + +@implementation Nu_lessthan_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id cursor = cdr; + id current = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + id next = [[cursor car] evalWithContext:context]; + NSComparisonResult result = [current compare:next]; + if (result != NSOrderedAscending) + return Nu__null; + current = next; + cursor = [cursor cdr]; + } + return [symbolTable symbolWithString:@"t"]; +} + +@end + +@interface Nu_gte_operator : NuOperator {} +@end + +@implementation Nu_gte_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id cursor = cdr; + id current = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + id next = [[cursor car] evalWithContext:context]; + NSComparisonResult result = [current compare:next]; + if (result == NSOrderedAscending) + return Nu__null; + current = next; + cursor = [cursor cdr]; + } + return [symbolTable symbolWithString:@"t"]; +} + +@end + +@interface Nu_lte_operator : NuOperator {} +@end + +@implementation Nu_lte_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id cursor = cdr; + id current = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + while (cursor && (cursor != Nu__null)) { + id next = [[cursor car] evalWithContext:context]; + NSComparisonResult result = [current compare:next]; + if (result == NSOrderedDescending) + return Nu__null; + current = next; + cursor = [cursor cdr]; + } + return [symbolTable symbolWithString:@"t"]; +} + +@end + +@interface Nu_leftshift_operator : NuOperator {} +@end + +@implementation Nu_leftshift_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + long result = [[[cdr car] evalWithContext:context] longValue]; + result = result << [[[[cdr cdr] car] evalWithContext:context] longValue]; + return [NSNumber numberWithLong:result]; +} + +@end + +@interface Nu_rightshift_operator : NuOperator {} +@end + +@implementation Nu_rightshift_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + long result = [[[cdr car] evalWithContext:context] longValue]; + result = result >> [[[[cdr cdr] car] evalWithContext:context] longValue]; + return [NSNumber numberWithLong:result]; +} + +@end + +@interface Nu_and_operator : NuOperator {} +@end + +@implementation Nu_and_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cursor = cdr; + id value = Nu__null; + while (cursor && (cursor != Nu__null)) { + value = [[cursor car] evalWithContext:context]; + if (!nu_valueIsTrue(value)) + return Nu__null; + cursor = [cursor cdr]; + } + return value; +} + +@end + +@interface Nu_or_operator : NuOperator {} +@end + +@implementation Nu_or_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cursor = cdr; + while (cursor && (cursor != Nu__null)) { + id value = [[cursor car] evalWithContext:context]; + if (nu_valueIsTrue(value)) + return value; + cursor = [cursor cdr]; + } + return Nu__null; +} + +@end + +@interface Nu_not_operator : NuOperator {} +@end + +@implementation Nu_not_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id cursor = cdr; + if (cursor && (cursor != Nu__null)) { + id value = [[cursor car] evalWithContext:context]; + return nu_valueIsTrue(value) ? Nu__null : [symbolTable symbolWithString:@"t"]; + } + return Nu__null; +} + +@end + +#if !TARGET_OS_IPHONE +@interface NuConsoleViewController : NSObject {} +- (void) write:(id) string; +@end +#endif + +@interface Nu_puts_operator : NuOperator {} +@end + +@implementation Nu_puts_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ +#if !TARGET_OS_IPHONE + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + NuConsoleViewController *console = (NuConsoleViewController*) + [[symbolTable symbolWithString:@"$$console"] value]; +#endif + NSString *string; + id cursor = cdr; + while (cursor && (cursor != Nu__null)) { + id value = [[cursor car] evalWithContext:context]; + if (value) { + string = [value stringValue]; +#if !TARGET_OS_IPHONE + if (console && (console != Nu__null)) { + [console write:string]; + [console write:[NSString carriageReturn]]; + } + else { +#endif + printf("%s\n", [string cStringUsingEncoding:NSUTF8StringEncoding]); +#if !TARGET_OS_IPHONE + } +#endif + } + cursor = [cursor cdr]; + } + return Nu__null;; +} + +@end + +#if !TARGET_OS_IPHONE +@interface Nu_gets_operator : NuOperator {} +@end + +@implementation Nu_gets_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + char *input = readline(""); + NSString *result = [NSString stringWithUTF8String: input]; + return result; +} + +@end +#endif + +@interface Nu_print_operator : NuOperator {} +@end + +@implementation Nu_print_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ +#if !TARGET_OS_IPHONE + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + NuConsoleViewController *console = (NuConsoleViewController*)[[symbolTable symbolWithString:@"$$console"] value]; +#endif + NSString *string; + id cursor = cdr; + while (cursor && (cursor != Nu__null)) { + string = [[[cursor car] evalWithContext:context] stringValue]; +#if !TARGET_OS_IPHONE + if (console && (console != Nu__null)) { + [console write:string]; + } + else { +#endif + printf("%s", [string cStringUsingEncoding:NSUTF8StringEncoding]); +#if !TARGET_OS_IPHONE + } +#endif + cursor = [cursor cdr]; + } + return Nu__null;; +} + +@end + +@interface Nu_call_operator : NuOperator {} +@end + +@implementation Nu_call_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id function = [[cdr car] evalWithContext:context]; + id arguments = [cdr cdr]; + id value = [function callWithArguments:arguments context:context]; + return value; +} + +@end + +@interface Nu_send_operator : NuOperator {} +@end + +@implementation Nu_send_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id target = [[cdr car] evalWithContext:context]; + id message = [cdr cdr]; + id value = [target sendMessage:message withContext:context]; + return value; +} + +@end + +@interface Nu_progn_operator : NuOperator {} +@end + +@implementation Nu_progn_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id value = Nu__null; + id cursor = cdr; + while (cursor && (cursor != Nu__null)) { + value = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + } + return value; +} + +@end + +@interface Nu_eval_operator : NuOperator {} +@end + +@implementation Nu_eval_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id value = [[[cdr car] evalWithContext:context] evalWithContext:context]; + return value; +} + +@end + +#ifdef LINUX +id loadNuLibraryFile(NSString *nuFileName, id parser, id context, id symbolTable) +{ + NSString *fullPath = [NSString stringWithFormat:@"/usr/local/share/libNu/%@.nu", nuFileName]; + if ([NSFileManager fileExistsNamed:fullPath]) { + NSString *string = [NSString stringWithContentsOfFile:fullPath]; + id value = Nu__null; + if (string) { + id body = [parser parse:string asIfFromFilename:[fullPath cStringUsingEncoding:NSUTF8StringEncoding]]; + value = [body evalWithContext:context]; + return [symbolTable symbolWithString:@"t"]; + } + else { + return nil; + } + } + else { + return nil; + } +} +#endif + +@interface Nu_load_operator : NuOperator {} +@end + +@implementation Nu_load_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id parser = [context lookupObjectForKey:[symbolTable symbolWithString:@"_parser"]]; + id resourceName = [[cdr car] evalWithContext:context]; + + // does the resourceName contain a colon? if so, it's a framework:nu-source-file pair. + NSArray *split = [resourceName componentsSeparatedByString:@":"]; + if ([split count] == 2) { + id frameworkName = [split objectAtIndex:0]; + id nuFileName = [split objectAtIndex:1]; +#ifdef LINUX + if ([frameworkName isEqual:@"Nu"]) { + if (loadNuLibraryFile(nuFileName, parser, context, symbolTable) == nil) { + [NSException raise:@"NuLoadFailed" format:@"unable to load %@", nuFileName]; + } + else { + return [symbolTable symbolWithString:@"t"]; + } + } +#endif + + NSBundle *framework = [NSBundle frameworkWithName:frameworkName]; + if ([framework loadNuFile:nuFileName withContext:context]) + return [symbolTable symbolWithString:@"t"]; + else { + [NSException raise:@"NuLoadFailed" format:@"unable to load %@", resourceName]; + return nil; + } + } + else { + // first try to find a file at the specified path + id fileName = [resourceName stringByExpandingTildeInPath]; + if (![NSFileManager fileExistsNamed:fileName]) { + // if that failed, try looking for a Nu_ source file in the current directory, + // first with and then without the ".nu" suffix + fileName = [NSString stringWithFormat:@"./%@.nu", resourceName]; + if (![NSFileManager fileExistsNamed: fileName]) { + fileName = [NSString stringWithFormat:@"./%@", resourceName]; + if (![NSFileManager fileExistsNamed: fileName]) fileName = nil; + } + } + if (fileName) { + NSString *string = [NSString stringWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:NULL]; + if (string) { + id body = [parser parse:string asIfFromFilename:[fileName cStringUsingEncoding:NSUTF8StringEncoding]]; + [body evalWithContext:context]; + return [symbolTable symbolWithString:@"t"]; + } + else { + [NSException raise:@"NuLoadFailed" format:@"unable to load %@", fileName]; + return nil; + } + } + + // if that failed, try to load the file the main application bundle + if ([[NSBundle mainBundle] loadNuFile:resourceName withContext:context]) { + return [symbolTable symbolWithString:@"t"]; + } + + // next, try the main Nu bundle + if ([Nu loadNuFile:resourceName fromBundleWithIdentifier:@"nu.programming.framework" withContext:context]) { + return [symbolTable symbolWithString:@"t"]; + } + + // if no file was found, try to load a framework with the given name + if ([NSBundle frameworkWithName:resourceName]) { +#ifdef LINUX + // if we're on Linux, call this a second (redundant) time because GNUstep seems to sometimes fail to properly load on the first call. + [NSBundle frameworkWithName:resourceName]; +#endif + return [symbolTable symbolWithString:@"t"]; + } + +#ifdef LINUX + if (loadNuLibraryFile(resourceName, parser, context, symbolTable)) { + return [symbolTable symbolWithString:@"t"]; + } +#endif + + [NSException raise:@"NuLoadFailed" format:@"unable to load %@", resourceName]; + return nil; + } +} + +@end + +@interface Nu_let_operator : NuOperator {} +@end + +@implementation Nu_let_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + id arg_names = [[NuCell alloc] init]; + id arg_values = [[NuCell alloc] init]; + + id cursor = [cdr car]; + if ((cursor != [NSNull null]) && [[cursor car] atom]) { + [arg_names setCar:[cursor car]]; + [arg_values setCar:[[cursor cdr] car]]; + } + else { + id arg_name_cursor = arg_names; + id arg_value_cursor = arg_values; + while (cursor && (cursor != Nu__null)) { + [arg_name_cursor setCar:[[cursor car] car]]; + [arg_value_cursor setCar:[[[cursor car] cdr] car]]; + cursor = [cursor cdr]; + if (cursor && (cursor != Nu__null)) { + [arg_name_cursor setCdr:[[[NuCell alloc] init] autorelease]]; + [arg_value_cursor setCdr:[[[NuCell alloc] init] autorelease]]; + arg_name_cursor = [arg_name_cursor cdr]; + arg_value_cursor = [arg_value_cursor cdr]; + } + } + } + id body = [cdr cdr]; + NuBlock *block = [[NuBlock alloc] initWithParameters:arg_names body:body context:context]; + id result = [[block evalWithArguments:arg_values context:context] retain]; + [block release]; + + [arg_names release]; + [arg_values release]; + [pool drain]; + [result autorelease]; + return result; +} + +@end + +@interface Nu_class_operator : NuOperator {} +@end + +@implementation Nu_class_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id className = [cdr car]; + id body; +#if defined(__x86_64__) || TARGET_OS_IPHONE + Class newClass = nil; +#endif + + NuClass *childClass; + //NSLog(@"class name: %@", className); + if ([cdr cdr] + && ([cdr cdr] != Nu__null) + && [[[cdr cdr] car] isEqual: [symbolTable symbolWithString:@"is"]] + ) { + id parentName = [[[cdr cdr] cdr] car]; + //NSLog(@"parent name: %@", [parentName stringValue]); + Class parentClass = NSClassFromString([parentName stringValue]); + if (!parentClass) + [NSException raise:@"NuUndefinedSuperclass" format:@"undefined superclass %@", [parentName stringValue]]; + +#if defined(__x86_64__) || TARGET_OS_IPHONE + + newClass = objc_allocateClassPair(parentClass, [[className stringValue] cStringUsingEncoding:NSUTF8StringEncoding], 0); + childClass = [NuClass classWithClass:newClass]; + [childClass setRegistered:NO]; + //NSLog(@"created class %@", [childClass name]); + // it seems dangerous to call this here. Maybe it's better to wait until the new class is registered. + if ([parentClass respondsToSelector:@selector(inheritedByClass:)]) { + [parentClass inheritedByClass:childClass]; + } + + if (!childClass) { + // This class may have already been defined previously + // (perhaps by loading the same .nu file twice). + // If so, the above call to objc_allocateClassPair() returns nil. + // So if childClass is nil, it may be that the class was + // already defined, so we'll try to find it and use it. + Class existingClass = NSClassFromString([className stringValue]); + if (existingClass) { + childClass = [NuClass classWithClass:existingClass]; + //if (childClass) + // NSLog(@"Warning: attempting to re-define existing class: %@. Ignoring.", [className stringValue]); + } + } + +#else + [parentClass createSubclassNamed:[className stringValue]]; + childClass = [NuClass classWithName:[className stringValue]]; +#endif + body = [[[cdr cdr] cdr] cdr]; + } + else { + childClass = [NuClass classWithName:[className stringValue]]; + body = [cdr cdr]; + } + if (!childClass) + [NSException raise:@"NuUndefinedClass" format:@"undefined class %@", [className stringValue]]; + id result = nil; + if (body && (body != Nu__null)) { + NuBlock *block = [[NuBlock alloc] initWithParameters:Nu__null body:body context:context]; + [[block context] + setPossiblyNullObject:childClass + forKey:[symbolTable symbolWithString:@"_class"]]; + result = [block evalWithArguments:Nu__null context:Nu__null]; + [block release]; + } +#if defined(__x86_64__) || TARGET_OS_IPHONE + if (newClass && ([childClass isRegistered] == NO)) { + [childClass registerClass]; + } +#endif + return result; +} + +@end + +@interface Nu_cmethod_operator : NuOperator {} +@end + +@implementation Nu_cmethod_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NSLog(@"The cmethod operator is deprecated. Please replace it with '+' in your code."); + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + NuClass *classWrapper = [context objectForKey:[symbolTable symbolWithString:@"_class"]]; + [classWrapper registerClass]; + Class classToExtend = [classWrapper wrappedClass]; + if (!classToExtend) + [NSException raise:@"NuMisplacedDeclaration" format:@"class method declaration with no enclosing class declaration"]; + return help_add_method_to_class(classToExtend, cdr, context, YES); +} + +@end + +@interface Nu_imethod_operator : NuOperator {} +@end + +@implementation Nu_imethod_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NSLog(@"The imethod operator is deprecated. Please replace it with '-' in your code."); + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + NuClass *classWrapper = [context objectForKey:[symbolTable symbolWithString:@"_class"]]; + [classWrapper registerClass]; + Class classToExtend = [classWrapper wrappedClass]; + if (!classToExtend) + [NSException raise:@"NuMisplacedDeclaration" format:@"instance method declaration with no enclosing class declaration"]; + return help_add_method_to_class(classToExtend, cdr, context, NO); +} + +@end + +@interface Nu_ivar_operator : NuOperator {} +@end + +@implementation Nu_ivar_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + NuClass *classWrapper = [context objectForKey:[symbolTable symbolWithString:@"_class"]]; + // this will only work if the class is unregistered... + if ([classWrapper isRegistered]) { + [NSException raise:@"NuIvarAddedTooLate" format:@"explicit instance variables must be added when a class is created and before any method declarations"]; + } + Class classToExtend = [classWrapper wrappedClass]; + if (!classToExtend) + [NSException raise:@"NuMisplacedDeclaration" format:@"instance variable declaration with no enclosing class declaration"]; + id cursor = cdr; + while (cursor && (cursor != Nu__null)) { + id variableType = [cursor car]; + cursor = [cursor cdr]; + id variableName = [cursor car]; + cursor = [cursor cdr]; + NSString *signature = signature_for_identifier(variableType, symbolTable); + nu_class_addInstanceVariable_withSignature(classToExtend, + [[variableName stringValue] cStringUsingEncoding:NSUTF8StringEncoding], + [signature cStringUsingEncoding:NSUTF8StringEncoding]); + //NSLog(@"adding ivar %@ with signature %@", [variableName stringValue], signature); + } + return Nu__null; +} + +@end + +@interface Nu_ivars_operator : NuOperator {} +@end + +@implementation Nu_ivars_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NSLog(@"The ivars operator is unnecessary. Please remove it from your source."); + return Nu__null; +} + +@end + +@interface Nu_ivar_accessors_operator : NuOperator {} +@end + +@implementation Nu_ivar_accessors_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + NSLog(@"The ivar-accessors operator is unnecessary. Please remove it from your source."); + return Nu__null; +} + +@end + +@interface Nu_system_operator : NuOperator {} +@end + +@implementation Nu_system_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id cursor = cdr; + NSMutableString *command = [NSMutableString string]; + while (cursor && (cursor != [NSNull null])) { + [command appendString:[[[cursor car] evalWithContext:context] stringValue]]; + cursor = [cursor cdr]; + } + const char *commandString = [command cStringUsingEncoding:NSUTF8StringEncoding]; + int result = system(commandString) >> 8; // this needs an explanation + return [NSNumber numberWithInt:result]; +} + +@end + +@interface Nu_exit_operator : NuOperator {} +@end + +@implementation Nu_exit_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + if (cdr && (cdr != Nu__null)) { + int status = [[[cdr car] evalWithContext:context] intValue]; + exit(status); + } + else { + exit (0); + } + return Nu__null; // we'll never get here. +} + +@end + +@interface Nu_sleep_operator : NuOperator {} +@end + +@implementation Nu_sleep_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + int result = -1; + if (cdr && (cdr != Nu__null)) { + int seconds = [[[cdr car] evalWithContext:context] intValue]; + result = sleep(seconds); + } + else { + [NSException raise: @"NuArityError" format:@"sleep expects 1 argument, got 0"]; + } + return [NSNumber numberWithInt:result]; +} + +@end + +@interface Nu_uname_operator : NuOperator {} +@end + +@implementation Nu_uname_operator +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + if (!cdr || (cdr == Nu__null)) { +#if TARGET_OS_IPHONE + return @"iOS"; +#else +#ifdef DARWIN + return @"Darwin"; +#else + return @"Linux"; +#endif +#endif + } + if ([[[cdr car] stringValue] isEqualToString:@"systemName"]) { +#if TARGET_OS_IPHONE + return [[UIDevice currentDevice] systemName]; +#else + return @"Macintosh"; +#endif + } + return nil; +} + +@end + +@interface Nu_help_operator : NuOperator {} +@end + +@implementation Nu_help_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id object = [[cdr car] evalWithContext:context]; + return [object help]; +} + +@end + +@interface Nu_break_operator : NuOperator {} +@end + +@implementation Nu_break_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + @throw [[[NuBreakException alloc] init] autorelease]; + return nil; // unreached +} + +@end + +@interface Nu_continue_operator : NuOperator {} +@end + +@implementation Nu_continue_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + @throw [[[NuContinueException alloc] init] autorelease]; + return nil; // unreached +} + +@end + +@interface Nu_return_operator : NuOperator {} +@end + +@implementation Nu_return_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id value = nil; + if (cdr && cdr != Nu__null) { + value = [[cdr car] evalWithContext:context]; + } + @throw [[[NuReturnException alloc] initWithValue:value] autorelease]; + return nil; // unreached +} + +@end + +@interface Nu_return_from_operator : NuOperator {} +@end + +@implementation Nu_return_from_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id block = nil; + id value = nil; + id cursor = cdr; + if (cursor && cursor != Nu__null) { + block = [[cursor car] evalWithContext:context]; + cursor = [cursor cdr]; + } + if (cursor && cursor != Nu__null) { + value = [[cursor car] evalWithContext:context]; + } + @throw [[[NuReturnException alloc] initWithValue:value blockForReturn:block] autorelease]; + return nil; // unreached +} + +@end + +@interface Nu_version_operator : NuOperator {} +@end + +@implementation Nu_version_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + return [NSString stringWithFormat:@"Nu %s (%s)", NU_VERSION, NU_RELEASE_DATE]; +} + +@end + +@interface Nu_min_operator : NuOperator {} +@end + +@implementation Nu_min_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + if (cdr == Nu__null) + [NSException raise: @"NuArityError" format:@"min expects at least 1 argument, got 0"]; + id smallest = [[cdr car] evalWithContext:context]; + id cursor = [cdr cdr]; + while (cursor && (cursor != Nu__null)) { + id nextValue = [[cursor car] evalWithContext:context]; + if([smallest compare:nextValue] == 1) { + smallest = nextValue; + } + cursor = [cursor cdr]; + } + return smallest; +} + +@end + +@interface Nu_max_operator : NuOperator {} +@end + +@implementation Nu_max_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + if (cdr == Nu__null) + [NSException raise: @"NuArityError" format:@"max expects at least 1 argument, got 0"]; + id biggest = [[cdr car] evalWithContext:context]; + id cursor = [cdr cdr]; + while (cursor && (cursor != Nu__null)) { + id nextValue = [[cursor car] evalWithContext:context]; + if([biggest compare:nextValue] == -1) { + biggest = nextValue; + } + cursor = [cursor cdr]; + } + return biggest; +} + +@end + +static id evaluatedArguments(id cdr, NSMutableDictionary *context) +{ + NuCell *evaluatedArguments = nil; + id cursor = cdr; + id outCursor = nil; + while (cursor && (cursor != Nu__null)) { + id nextValue = [[cursor car] evalWithContext:context]; + id newCell = [[[NuCell alloc] init] autorelease]; + [newCell setCar:nextValue]; + if (!outCursor) { + evaluatedArguments = newCell; + } + else { + [outCursor setCdr:newCell]; + } + outCursor = newCell; + cursor = [cursor cdr]; + } + return evaluatedArguments; +} + +@interface Nu_array_operator : NuOperator {} +@end + +@implementation Nu_array_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + return [NSArray arrayWithList:evaluatedArguments(cdr, context)]; +} + +@end + +@interface Nu_dict_operator : NuOperator {} +@end + +@implementation Nu_dict_operator + +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + return [NSDictionary dictionaryWithList:evaluatedArguments(cdr, context)]; +} + +@end + +@interface Nu_parse_operator : NuOperator {} +@end + +@implementation Nu_parse_operator + +// parse operator; parses a string into Nu code objects +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + id parser = [[[NuParser alloc] init] autorelease]; + return [parser parse:[[cdr car] evalWithContext:context]]; +} + +@end + +@interface Nu_signature_operator : NuOperator {} +@end + +@implementation Nu_signature_operator + +// signature operator; basically gives access to the static signature_for_identifier function from within Nu code +- (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + return signature_for_identifier( [[cdr car] evalWithContext:context],[NuSymbolTable sharedSymbolTable]); +} + +@end + +#define install(name, class) [(NuSymbol *) [symbolTable symbolWithString:name] setValue:[[[class alloc] init] autorelease]] + +void load_builtins(NuSymbolTable *symbolTable); + +void load_builtins(NuSymbolTable *symbolTable) +{ + [(NuSymbol *) [symbolTable symbolWithString:@"t"] setValue:[symbolTable symbolWithString:@"t"]]; + [(NuSymbol *) [symbolTable symbolWithString:@"nil"] setValue:Nu__null]; + [(NuSymbol *) [symbolTable symbolWithString:@"YES"] setValue:[NSNumber numberWithBool:YES]]; + [(NuSymbol *) [symbolTable symbolWithString:@"NO"] setValue:[NSNumber numberWithBool:NO]]; + + install(@"car", Nu_car_operator); + install(@"cdr", Nu_cdr_operator); + install(@"first", Nu_car_operator); + install(@"rest", Nu_cdr_operator); + install(@"head", Nu_car_operator); + install(@"tail", Nu_cdr_operator); + install(@"atom", Nu_atom_operator); + install(@"defined", Nu_defined_operator); + + install(@"eq", Nu_eq_operator); + install(@"==", Nu_eq_operator); + install(@"ne", Nu_neq_operator); + install(@"!=", Nu_neq_operator); + install(@"gt", Nu_greaterthan_operator); + install(@">", Nu_greaterthan_operator); + install(@"lt", Nu_lessthan_operator); + install(@"<", Nu_lessthan_operator); + install(@"ge", Nu_gte_operator); + install(@">=", Nu_gte_operator); + install(@"le", Nu_lte_operator); + install(@"<=", Nu_lte_operator); + + install(@"cons", Nu_cons_operator); + install(@"append", Nu_append_operator); + install(@"apply", Nu_apply_operator); + + install(@"cond", Nu_cond_operator); + install(@"case", Nu_case_operator); + install(@"if", Nu_if_operator); + install(@"unless", Nu_unless_operator); + install(@"while", Nu_while_operator); + install(@"until", Nu_until_operator); + install(@"for", Nu_for_operator); + install(@"break", Nu_break_operator); + install(@"continue", Nu_continue_operator); + install(@"return", Nu_return_operator); + install(@"return-from", Nu_return_from_operator); + + install(@"try", Nu_try_operator); + + install(@"throw", Nu_throw_operator); + install(@"synchronized", Nu_synchronized_operator); + + install(@"quote", Nu_quote_operator); + install(@"eval", Nu_eval_operator); + + install(@"context", Nu_context_operator); + install(@"set", Nu_set_operator); + install(@"global", Nu_global_operator); + install(@"local", Nu_local_operator); + + install(@"regex", Nu_regex_operator); + + install(@"function", Nu_function_operator); + install(@"def", Nu_function_operator); + + install(@"progn", Nu_progn_operator); + install(@"then", Nu_progn_operator); + install(@"else", Nu_progn_operator); + + install(@"macro", Nu_macro_1_operator); + install(@"macrox", Nu_macrox_operator); + + install(@"quasiquote", Nu_quasiquote_operator); + install(@"quasiquote-eval", Nu_quasiquote_eval_operator); + install(@"quasiquote-splice", Nu_quasiquote_splice_operator); + + install(@"+", Nu_add_operator); + install(@"-", Nu_subtract_operator); + install(@"*", Nu_multiply_operator); + install(@"/", Nu_divide_operator); + install(@"**", Nu_exponentiation_operator); + install(@"%", Nu_modulus_operator); + + install(@"&", Nu_bitwiseand_operator); + install(@"|", Nu_bitwiseor_operator); + install(@"<<", Nu_leftshift_operator); + install(@">>", Nu_rightshift_operator); + + install(@"&&", Nu_and_operator); + install(@"||", Nu_or_operator); + + install(@"and", Nu_and_operator); + install(@"or", Nu_or_operator); + install(@"not", Nu_not_operator); + + install(@"min", Nu_min_operator); + install(@"max", Nu_max_operator); + + install(@"list", Nu_list_operator); + + install(@"do", Nu_do_operator); + +#if !TARGET_OS_IPHONE + install(@"gets", Nu_gets_operator); +#endif + install(@"puts", Nu_puts_operator); + install(@"print", Nu_print_operator); + + install(@"let", Nu_let_operator); + + install(@"load", Nu_load_operator); + + install(@"uname", Nu_uname_operator); + install(@"system", Nu_system_operator); + install(@"exit", Nu_exit_operator); + install(@"sleep", Nu_sleep_operator); + + install(@"class", Nu_class_operator); + install(@"imethod", Nu_imethod_operator); + install(@"cmethod", Nu_cmethod_operator); + install(@"ivar", Nu_ivar_operator); + install(@"ivars", Nu_ivars_operator); + install(@"ivar-accessors", Nu_ivar_accessors_operator); + + install(@"call", Nu_call_operator); + install(@"send", Nu_send_operator); + + install(@"array", Nu_array_operator); + install(@"dict", Nu_dict_operator); + install(@"parse", Nu_parse_operator); + + install(@"help", Nu_help_operator); + install(@"?", Nu_help_operator); + install(@"version", Nu_version_operator); + + install(@"signature", Nu_signature_operator); + + // set some commonly-used globals + [(NuSymbol *) [symbolTable symbolWithString:@"NSUTF8StringEncoding"] + setValue:[NSNumber numberWithInt:NSUTF8StringEncoding]]; + + [(NuSymbol *) [symbolTable symbolWithString:@"NSLog"] // let's make this an operator someday + setValue:[NuBridgedFunction functionWithName:@"NSLog" signature:@"v@"]]; +} diff --git a/objc/NuParser.h b/objc/NuParser.h new file mode 100644 index 0000000..dbd55cf --- /dev/null +++ b/objc/NuParser.h @@ -0,0 +1,58 @@ +// +// NuParser.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +#pragma mark - +#pragma mark Parsing + + + +#import "NuSymbol.h" + +/*! + @class NuParser + @abstract A Nu language parser. + @discussion Instances of this class are used to parse and evaluate Nu source text. + */ +@interface NuParser : NSObject + +/*! Get the symbol table used by a parser. */ +- (NuSymbolTable *) symbolTable; +/*! Get the top-level evaluation context that a parser uses for evaluation. */ +- (NSMutableDictionary *) context; +/*! Parse Nu source into an expression, returning the NuCell at the top of the resulting expression. + Since parsing may produce multiple expressions, the top-level NuCell is a Nu progn operator. + */ +- (id) parse:(NSString *)string; +/*! Call -parse: while specifying the name of the source file for the string to be parsed. */ +- (id) parse:(NSString *)string asIfFromFilename:(const char *) filename; +/*! Evaluate a parsed Nu expression in the parser's evaluation context. */ +- (id) eval: (id) code; +/*! Parse Nu source text and evaluate it in the parser's evalation context. */ +- (NSString *) parseEval:(NSString *)string; +/*! Get the value of a name or expression in the parser's context. */ +- (id) valueForKey:(NSString *)string; +/*! Set the value of a name in the parser's context. */ +- (void) setValue:(id)value forKey:(NSString *)string; +/*! Returns true if the parser is currently parsing an incomplete Nu expression. + Presumably the rest of the expression will be passed in with a future + invocation of the parse: method. + */ +- (BOOL) incomplete; +/*! Reset the parse set after an error */ +- (void) reset; + +#if !TARGET_OS_IPHONE +/*! Run a parser interactively at the console (Terminal.app). */ +- (int) interact; +/*! Run the main handler for a console(Terminal.app)-oriented Nu shell. */ ++ (int) main; +#endif + +@end \ No newline at end of file diff --git a/objc/NuParser.m b/objc/NuParser.m new file mode 100644 index 0000000..80469f9 --- /dev/null +++ b/objc/NuParser.m @@ -0,0 +1,1098 @@ +// +// NuParser.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuParser.h" +#import "Nu.h" +#import "NuInternals.h" +#import "NuStack.h" +#import "NSString+Nu.h" +#import "NSDictionary+Nu.h" +#import "NuException.h" +#import "NuCell.h" + +#define PARSE_NORMAL 0 +#define PARSE_COMMENT 1 +#define PARSE_STRING 2 +#define PARSE_HERESTRING 3 +#define PARSE_REGEX 4 + +#define MAX_FILES 1024 +static char *filenames[MAX_FILES]; +static int filecount = 0; + +// Turn debug output on and off for this file only +//#define PARSER_DEBUG 1 + +#ifdef PARSER_DEBUG +#define ParserDebug(arg...) NSLog(arg) +#else +#define ParserDebug(arg...) +#endif + +const char *nu_parsedFilename(int i) +{ + return (i < 0) ? NULL: filenames[i]; +} + +@interface NuParser(Internal) +- (int) depth; +- (int) parens; +- (int) state; +- (NuCell *) root; +- (NuStack *) opens; +- (NSString *) stringValue; +- (const char *) cStringUsingEncoding:(NSStringEncoding) encoding; +- (id) init; +- (void) openList; +- (void) closeList; +- (void) addAtom:(id)atom; +- (void) quoteNextElement; +- (void) quasiquoteNextElement; +- (void) quasiquoteEvalNextElement; +- (void) quasiquoteSpliceNextElement; +- (int) interact; +@end + +static id atomWithString(NSString *string, NuSymbolTable *symbolTable) +{ + const char *cstring = [string cStringUsingEncoding:NSUTF8StringEncoding]; + char *endptr; + // If the string can be converted to a long, it's an NSNumber. + long lvalue = strtol(cstring, &endptr, 0); + if (*endptr == 0) { + return [NSNumber numberWithLong:lvalue]; + } + // If the string can be converted to a double, it's an NSNumber. + double dvalue = strtod(cstring, &endptr); + if (*endptr == 0) { + return [NSNumber numberWithDouble:dvalue]; + } + // Otherwise, it's a symbol. + NuSymbol *symbol = [symbolTable symbolWithString:string]; + return symbol; +} + +static id regexWithString(NSString *string) +{ + // If the first character of the string is a forward slash, it's a regular expression literal. + if (([string characterAtIndex:0] == '/') && ([string length] > 1)) { + NSUInteger lastSlash = [string length]; + NSInteger i = lastSlash-1; + while (i > 0) { + if ([string characterAtIndex:i] == '/') { + lastSlash = i; + break; + } + i--; + } + // characters after the last slash specify options. + NSInteger options = 0; + NSInteger j; + for (j = lastSlash+1; j < [string length]; j++) { + unichar c = [string characterAtIndex:j]; + switch (c) { + case 'i': options += NSRegularExpressionCaseInsensitive; break; + case 's': options += NSRegularExpressionDotMatchesLineSeparators; break; + case 'x': options += NSRegularExpressionAllowCommentsAndWhitespace; break; + case 'm': options += NSRegularExpressionAnchorsMatchLines; break; // multiline + default: + [NSException raise:@"NuParseError" format:@"unsupported regular expression option character: %C", c]; + } + } + NSString *pattern = [string substringWithRange:NSMakeRange(1, lastSlash-1)]; + return [NSRegularExpression regularExpressionWithPattern:pattern + options:options + error:NULL]; + } + else { + return nil; + } +} + +#define NU_MAX_PARSER_MACRO_DEPTH 1000 + +@interface NuParser () +{ + int state; + int start; + int depth; + int parens; + int column; + + NSMutableArray* readerMacroStack; + int readerMacroDepth[NU_MAX_PARSER_MACRO_DEPTH]; + + int filenum; + int linenum; + int parseEscapes; + + NuCell *root; + NuCell *current; + bool addToCar; + NSMutableString *hereString; + bool hereStringOpened; + NuStack *stack; + NuStack *opens; + NuSymbolTable *symbolTable; + NSMutableDictionary *context; + NSMutableString *partial; + NSMutableString *comments; + NSString *pattern; // used for herestrings +} +@end + +@implementation NuParser + ++ (const char *) filename:(int)i +{ + if ((i < 0) || (i >= filecount)) + return ""; + else + return filenames[i]; +} + +- (void) setFilename:(const char *) name +{ + if (name == NULL) + filenum = -1; + else { + filenames[filecount] = strdup(name); + filenum = filecount; + filecount++; + } + linenum = 1; +} + +- (const char *) filename +{ + if (filenum == -1) + return NULL; + else + return filenames[filenum]; +} + +- (BOOL) incomplete +{ + return (depth > 0) || (state == PARSE_REGEX) || (state == PARSE_HERESTRING); +} + +- (int) depth +{ + return depth; +} + +- (int) parens +{ + return parens; +} + +- (int) state +{ + return state; +} + +- (NuCell *) root +{ + return [root cdr]; +} + +- (NuStack *) opens +{ + return opens; +} + +- (NSMutableDictionary *) context +{ + return context; +} + +- (NuSymbolTable *) symbolTable +{ + return symbolTable; +} + +- (NSString *) stringValue +{ + return [self description]; +} + +- (const char *) cStringUsingEncoding:(NSStringEncoding) encoding +{ + return [[self stringValue] cStringUsingEncoding:encoding]; +} + +- (void) reset +{ + state = PARSE_NORMAL; + [partial setString:@""]; + depth = 0; + parens = 0; + + [readerMacroStack removeAllObjects]; + + int i; + for (i = 0; i < NU_MAX_PARSER_MACRO_DEPTH; i++) { + readerMacroDepth[i] = 0; + } + + [root release]; + root = current = [[NuCell alloc] init]; + [root setFile:filenum line:linenum]; + [root setCar:[symbolTable symbolWithString:@"progn"]]; + addToCar = false; + [stack release]; + stack = [[NuStack alloc] init]; +} + +- (id) init +{ + if (Nu__null == 0) Nu__null = [NSNull null]; + if ((self = [super init])) { + + filenum = -1; + linenum = 1; + column = 0; + opens = [[NuStack alloc] init]; + // attach to symbol table (or create one if we want a separate table per parser) + symbolTable = [[NuSymbolTable sharedSymbolTable] retain]; + // create top-level context + context = [[NSMutableDictionary alloc] init]; + + readerMacroStack = [[NSMutableArray alloc] init]; + + [context setPossiblyNullObject:self forKey:[symbolTable symbolWithString:@"_parser"]]; + [context setPossiblyNullObject:symbolTable forKey:SYMBOLS_KEY]; + + partial = [[NSMutableString alloc] initWithString:@""]; + + [self reset]; + } + return self; +} + +- (void) close +{ + // break this retain cycle so the parser can be deleted. + [context setPossiblyNullObject:[NSNull null] forKey:[symbolTable symbolWithString:@"_parser"]]; +} + +- (void) dealloc +{ + [opens release]; + [context release]; + [symbolTable release]; + [root release]; + [stack release]; + [comments release]; + [readerMacroStack release]; + [pattern release]; + [partial release]; + [super dealloc]; +} + +- (void) addAtomCell:(id)atom +{ + ParserDebug(@"addAtomCell: depth = %d atom = %@", depth, [atom stringValue]); + + // when we have two consecutive labels, concatenate them. + // this allows us to have ':' characters inside labels. + if ([atom isKindOfClass:[NuSymbol class]] && [atom isLabel]) { + id currentCar = [current car]; + if ([currentCar isKindOfClass:[NuSymbol class]] && [currentCar isLabel]) { + NuSymbol *combinedLabel = [symbolTable symbolWithString:[[currentCar stringValue] stringByAppendingString:[atom stringValue]]]; + [current setCar:combinedLabel]; + return; + } + } + + NuCell *newCell; + if (comments) { + NuCellWithComments *newCellWithComments = [[[NuCellWithComments alloc] init] autorelease]; + [newCellWithComments setComments:comments]; + newCell = newCellWithComments; + [comments release]; + comments = nil; + } + else { + newCell = [[[NuCell alloc] init] autorelease]; + [newCell setFile:filenum line:linenum]; + } + if (addToCar) { + [current setCar:newCell]; + [stack push:current]; + } + else { + [current setCdr:newCell]; + } + current = newCell; + [current setCar:atom]; + addToCar = false; +} + +- (void) openListCell +{ + ParserDebug(@"openListCell: depth = %d", depth); + + depth++; + NuCell *newCell = [[[NuCell alloc] init] autorelease]; + [newCell setFile:filenum line:linenum]; + if (addToCar) { + [current setCar:newCell]; + [stack push:current]; + } + else { + [current setCdr:newCell]; + } + current = newCell; + + addToCar = true; +} + +- (void) openList +{ + ParserDebug(@"openList: depth = %d", depth); + + while ([readerMacroStack count] > 0) { + ParserDebug(@" openList: readerMacro"); + + [self openListCell]; + ++readerMacroDepth[depth]; + ParserDebug(@" openList: ++RMD[%d] = %d", depth, readerMacroDepth[depth]); + [self addAtomCell: + [symbolTable symbolWithString: + [readerMacroStack objectAtIndex:0]]]; + + [readerMacroStack removeObjectAtIndex:0]; + } + + [self openListCell]; +} + +- (void) addAtom:(id)atom +{ + ParserDebug(@"addAtom: depth = %d atom: %@", depth, [atom stringValue]); + + while ([readerMacroStack count] > 0) { + ParserDebug(@" addAtom: readerMacro"); + [self openListCell]; + ++readerMacroDepth[depth]; + ParserDebug(@" addAtom: ++RMD[%d] = %d", depth, readerMacroDepth[depth]); + [self addAtomCell: + [symbolTable symbolWithString:[readerMacroStack objectAtIndex:0]]]; + + [readerMacroStack removeObjectAtIndex:0]; + } + + [self addAtomCell:atom]; + + while (readerMacroDepth[depth] > 0) { + --readerMacroDepth[depth]; + ParserDebug(@" addAtom: --RMD[%d] = %d", depth, readerMacroDepth[depth]); + [self closeList]; + } +} + +- (void) closeListCell +{ + ParserDebug(@"closeListCell: depth = %d", depth); + + --depth; + + if (addToCar) { + [current setCar:[NSNull null]]; + } + else { + [current setCdr:[NSNull null]]; + current = [stack pop]; + } + addToCar = false; + + while (readerMacroDepth[depth] > 0) { + --readerMacroDepth[depth]; + ParserDebug(@" closeListCell: --RMD[%d] = %d", depth, readerMacroDepth[depth]); + [self closeList]; + } +} + +- (void) closeList +{ + ParserDebug(@"closeList: depth = %d", depth); + + [self closeListCell]; +} + +-(void) openReaderMacro:(NSString*) operator +{ + [readerMacroStack addObject:operator]; +} + +-(void) quoteNextElement +{ + [self openReaderMacro:@"quote"]; +} + +-(void) quasiquoteNextElement +{ + [self openReaderMacro:@"quasiquote"]; +} + +-(void) quasiquoteEvalNextElement +{ + [self openReaderMacro:@"quasiquote-eval"]; +} + +-(void) quasiquoteSpliceNextElement +{ + [self openReaderMacro:@"quasiquote-splice"]; +} + +static int nu_octal_digit_value(unichar c) +{ + int x = (c - '0'); + if ((x >= 0) && (x <= 7)) + return x; + [NSException raise:@"NuParseError" format:@"invalid octal character: %C", c]; + return 0; +} + +static unichar nu_hex_digit_value(unichar c) +{ + int x = (c - '0'); + if ((x >= 0) && (x <= 9)) + return x; + x = (c - 'A'); + if ((x >= 0) && (x <= 5)) + return x + 10; + x = (c - 'a'); + if ((x >= 0) && (x <= 5)) + return x + 10; + [NSException raise:@"NuParseError" format:@"invalid hex character: %C", c]; + return 0; +} + +static unichar nu_octal_digits_to_unichar(unichar c0, unichar c1, unichar c2) +{ + return nu_octal_digit_value(c0)*64 + nu_octal_digit_value(c1)*8 + nu_octal_digit_value(c2); +} + +static unichar nu_hex_digits_to_unichar(unichar c1, unichar c2) +{ + return nu_hex_digit_value(c1)*16 + nu_hex_digit_value(c2); +} + +static unichar nu_unicode_digits_to_unichar(unichar c1, unichar c2, unichar c3, unichar c4) +{ + unichar value = nu_hex_digit_value(c1)*4096 + nu_hex_digit_value(c2)*256 + nu_hex_digit_value(c3)*16 + nu_hex_digit_value(c4); + return value; +} + +static NSUInteger nu_parse_escape_sequences(NSString *string, NSUInteger i, NSUInteger imax, NSMutableString *partial) +{ + i++; + unichar c = [string characterAtIndex:i]; + switch(c) { + case 'n': [partial appendCharacter:0x0a]; break; + case 'r': [partial appendCharacter:0x0d]; break; + case 'f': [partial appendCharacter:0x0c]; break; + case 't': [partial appendCharacter:0x09]; break; + case 'b': [partial appendCharacter:0x08]; break; + case 'a': [partial appendCharacter:0x07]; break; + case 'e': [partial appendCharacter:0x1b]; break; + case 's': [partial appendCharacter:0x20]; break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + // octal. expect two more digits (\nnn). + if (imax < i+2) { + [NSException raise:@"NuParseError" format:@"not enough characters for octal constant"]; + } + char c1 = [string characterAtIndex:++i]; + char c2 = [string characterAtIndex:++i]; + [partial appendCharacter:nu_octal_digits_to_unichar(c, c1, c2)]; + break; + } + case 'x': + { + // hex. expect two more digits (\xnn). + if (imax < i+2) { + [NSException raise:@"NuParseError" format:@"not enough characters for hex constant"]; + } + char c1 = [string characterAtIndex:++i]; + char c2 = [string characterAtIndex:++i]; + [partial appendCharacter:nu_hex_digits_to_unichar(c1, c2)]; + break; + } + case 'u': + { + // unicode. expect four more digits (\unnnn) + if (imax < i+4) { + [NSException raise:@"NuParseError" format:@"not enough characters for unicode constant"]; + } + char c1 = [string characterAtIndex:++i]; + char c2 = [string characterAtIndex:++i]; + char c3 = [string characterAtIndex:++i]; + char c4 = [string characterAtIndex:++i]; + [partial appendCharacter:nu_unicode_digits_to_unichar(c1, c2, c3, c4)]; + break; + } + case 'c': case 'C': + { + // control character. Unsupported, fall through to default. + } + case 'M': + { + // meta character. Unsupported, fall through to default. + } + default: + [partial appendCharacter:c]; + } + return i; +} + +-(id) parse:(NSString*)string +{ + if (!string) return [NSNull null]; // don't crash, at least. + + column = 0; + if (state != PARSE_REGEX) + [partial setString:@""]; + else + [partial autorelease]; + + NSUInteger i = 0; + NSUInteger imax = [string length]; + for (i = 0; i < imax; i++) { + column++; + unichar stri = [string characterAtIndex:i]; + switch (state) { + case PARSE_NORMAL: + switch(stri) { + case '(': + ParserDebug(@"Parser: ( %d on line %d", column, linenum); + [opens push:[NSNumber numberWithInt:column]]; + parens++; + if ([partial length] == 0) { + [self openList]; + } + break; + case ')': + ParserDebug(@"Parser: ) %d on line %d", column, linenum); + [opens pop]; + parens--; + if (parens < 0) parens = 0; + if ([partial length] > 0) { + [self addAtom:atomWithString(partial, symbolTable)]; + [partial setString:@""]; + } + if (depth > 0) { + [self closeList]; + } + else { + [NSException raise:@"NuParseError" format:@"no open sexpr"]; + } + break; + case '"': + { + state = PARSE_STRING; + parseEscapes = YES; + [partial setString:@""]; + break; + } + case '-': + case '+': + { + if ((i+1 < imax) && ([string characterAtIndex:i+1] == '"')) { + state = PARSE_STRING; + parseEscapes = (stri == '+'); + [partial setString:@""]; + i++; + } + else { + [partial appendCharacter:stri]; + } + break; + } + case '/': + { + if (i+1 < imax) { + unichar nextc = [string characterAtIndex:i+1]; + if (nextc == ' ') { + [partial appendCharacter:stri]; + } + else { + state = PARSE_REGEX; + [partial setString:@""]; + [partial appendCharacter:'/']; + } + } + else { + [partial appendCharacter:stri]; + } + break; + } + case ':': + [partial appendCharacter:':']; + // ordinarily we break symbols on trailing colons. + // one exception: we don't do it when the symbol begins with an ampersand. + // that's because these symbols are usually markup generators, and + // sometimes we want to generate markup tags that contain colons. + if ([partial characterAtIndex:0] != '&') { + [self addAtom:atomWithString(partial, symbolTable)]; + [partial setString:@""]; + } + break; + case '\'': + { + // try to parse a character literal. + // if that doesn't work, then interpret the quote as the quote operator. + bool isACharacterLiteral = false; + int characterLiteralValue; + if (i + 2 < imax) { + if ([string characterAtIndex:i+1] != '\\') { + if ([string characterAtIndex:i+2] == '\'') { + isACharacterLiteral = true; + characterLiteralValue = [string characterAtIndex:i+1]; + i = i + 2; + } + else if ((i + 5 < imax) && + isalnum([string characterAtIndex:i+1]) && + isalnum([string characterAtIndex:i+2]) && + isalnum([string characterAtIndex:i+3]) && + isalnum([string characterAtIndex:i+4]) && + ([string characterAtIndex:i+5] == '\'')) { + characterLiteralValue = + ((([string characterAtIndex:i+1]*256 + + [string characterAtIndex:i+2])*256 + + [string characterAtIndex:i+3])*256 + + [string characterAtIndex:i+4]); + isACharacterLiteral = true; + i = i + 5; + } + } + else { + // look for an escaped character + NSUInteger newi = nu_parse_escape_sequences(string, i+1, imax, partial); + if ([partial length] > 0) { + isACharacterLiteral = true; + characterLiteralValue = [partial characterAtIndex:0]; + [partial setString:@""]; + i = newi; + // make sure that we have a closing single-quote + if ((i + 1 < imax) && ([string characterAtIndex:i+1] == '\'')) { + i = i + 1;// move past the closing single-quote + } + else { + [NSException raise:@"NuParseError" format:@"missing close quote from character literal"]; + } + } + } + } + if (isACharacterLiteral) { + [self addAtom:[NSNumber numberWithInt:characterLiteralValue]]; + } + else { + [self quoteNextElement]; + } + break; + } + case '`': + { + [self quasiquoteNextElement]; + break; + } + case ',': + { + if ((i + 1 < imax) && ([string characterAtIndex:i+1] == '@')) { + [self quasiquoteSpliceNextElement]; + i = i + 1; + } + else { + [self quasiquoteEvalNextElement]; + } + break; + } + case '\n': // end of line + column = 0; + linenum++; + case ' ': // end of token + case '\t': + case 0: // end of string + if ([partial length] > 0) { + [self addAtom:atomWithString(partial, symbolTable)]; + [partial setString:@""]; + } + break; + case ';': + case '#': + if ((stri == '#') && ([partial length] > 0)) { + // this allows us to include '#' in symbols (but not as the first character) + [partial appendCharacter:'#']; + } else { + if ([partial length]) { + NuSymbol *symbol = [symbolTable symbolWithString:partial]; + [self addAtom:symbol]; + [partial setString:@""]; + } + state = PARSE_COMMENT; + } + break; + case '<': + if ((i+3 < imax) && ([string characterAtIndex:i+1] == '<') + && (([string characterAtIndex:i+2] == '-') || ([string characterAtIndex:i+2] == '+'))) { + // parse a here string + state = PARSE_HERESTRING; + parseEscapes = ([string characterAtIndex:i+2] == '+'); + // get the tag to match + NSUInteger j = i+3; + while ((j < imax) && ([string characterAtIndex:j] != '\n')) { + j++; + } + [pattern release]; + pattern = [[string substringWithRange:NSMakeRange(i+3, j-(i+3))] retain]; + //NSLog(@"herestring pattern: %@", pattern); + [partial setString:@""]; + // skip the newline + i = j; + //NSLog(@"parsing herestring that ends with %@ from %@", pattern, [string substringFromIndex:i]); + hereString = nil; + hereStringOpened = true; + break; + } + // if this is not a here string, fall through to the general handler + default: + [partial appendCharacter:stri]; + } + break; + case PARSE_HERESTRING: + //NSLog(@"pattern %@", pattern); + if ((stri == [pattern characterAtIndex:0]) && + (i + [pattern length] < imax) && + ([pattern isEqual:[string substringWithRange:NSMakeRange(i, [pattern length])]])) { + // everything up to here is the string + NSString *string = [[[NSString alloc] initWithString:partial] autorelease]; + [partial setString:@""]; + if (!hereString) + hereString = [[[NSMutableString alloc] init] autorelease]; + else + [hereString appendString:@"\n"]; + [hereString appendString:string]; + if (hereString == nil) + hereString = [NSMutableString string]; + //NSLog(@"got herestring **%@**", hereString); + [self addAtom:hereString]; + // to continue, set i to point to the next character after the tag + i = i + [pattern length] - 1; + //NSLog(@"continuing parsing with:%s", &str[i+1]); + //NSLog(@"ok------------"); + state = PARSE_NORMAL; + start = -1; + } + else { + if (parseEscapes && (stri == '\\')) { + // parse escape sequencs in here strings + i = nu_parse_escape_sequences(string, i, imax, partial); + } + else { + [partial appendCharacter:stri]; + } + } + break; + case PARSE_STRING: + switch(stri) { + case '"': + { + state = PARSE_NORMAL; + NSString *string = [NSString stringWithString:partial]; + //NSLog(@"parsed string:%@:", string); + [self addAtom:string]; + [partial setString:@""]; + break; + } + case '\n': + { + column = 0; + linenum++; + NSString *string = [[NSString alloc] initWithString:partial]; + [NSException raise:@"NuParseError" format:@"partial string (terminated by newline): %@", string]; + [partial setString:@""]; + break; + } + case '\\': + { // parse escape sequences in strings + if (parseEscapes) { + i = nu_parse_escape_sequences(string, i, imax, partial); + } + else { + [partial appendCharacter:stri]; + } + break; + } + default: + { + [partial appendCharacter:stri]; + } + } + break; + case PARSE_REGEX: + switch(stri) { + case '/': // that's the end of it + { + [partial appendCharacter:'/']; + i++; + // add any remaining option characters + while (i < imax) { + unichar nextc = [string characterAtIndex:i]; + if ((nextc >= 'a') && (nextc <= 'z')) { + [partial appendCharacter:nextc]; + i++; + } + else { + i--; // back up to revisit this character + break; + } + } + [self addAtom:regexWithString(partial)]; + [partial setString:@""]; + state = PARSE_NORMAL; + break; + } + case '\\': + { + [partial appendCharacter:stri]; + i++; + [partial appendCharacter:[string characterAtIndex:i]]; + break; + } + default: + { + [partial appendCharacter:stri]; + } + } + break; + case PARSE_COMMENT: + switch(stri) { + case '\n': + { + if (!comments) comments = [[NSMutableString alloc] init]; + else [comments appendString:@"\n"]; + [comments appendString:[[[NSString alloc] initWithString:partial] autorelease]]; + [partial setString:@""]; + column = 0; + linenum++; + state = PARSE_NORMAL; + break; + } + default: + { + [partial appendCharacter:stri]; + } + } + } + } + // close off anything that is still being scanned. + if (state == PARSE_NORMAL) { + if ([partial length] > 0) { + [self addAtom:atomWithString(partial, symbolTable)]; + } + [partial setString:@""]; + } + else if (state == PARSE_COMMENT) { + if (!comments) comments = [[NSMutableString alloc] init]; + [comments appendString:[[[NSString alloc] initWithString:partial] autorelease]]; + [partial setString:@""]; + column = 0; + linenum++; + state = PARSE_NORMAL; + } + else if (state == PARSE_STRING) { + [NSException raise:@"NuParseError" format:@"partial string (terminated by newline): %@", partial]; + } + else if (state == PARSE_HERESTRING) { + if (hereStringOpened) { + hereStringOpened = false; + } + else { + if (hereString) { + [hereString appendString:@"\n"]; + } + else { + hereString = [[NSMutableString alloc] init]; + } + [hereString appendString:partial]; + [partial setString:@""]; + } + } + else if (state == PARSE_REGEX) { + // we stay in this state and leave the regex open. + [partial appendCharacter:'\n']; + [partial retain]; + } + if ([self incomplete]) { + return [NSNull null]; + } + else { + NuCell *expressions = root; + root = nil; + [self reset]; + [expressions autorelease]; + return expressions; + } +} + +- (id) parse:(NSString *)string asIfFromFilename:(const char *) filename; +{ + [self setFilename:filename]; + id result = [self parse:string]; + [self setFilename:NULL]; + return result; +} + +- (void) newline +{ + linenum++; +} + +- (id) eval: (id) code +{ + return [code evalWithContext:context]; +} + +- (id) valueForKey:(NSString *)string +{ + return [self eval:[self parse:string]]; +} + +- (void) setValue:(id)value forKey:(NSString *)string +{ + [context setObject:value forKey:[symbolTable symbolWithString:string]]; +} + +- (NSString *) parseEval:(NSString *)string +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NuCell *expressions = [self parse:string]; + id result = [[expressions evalWithContext:context] stringValue]; + [result retain]; + [pool drain]; + [result autorelease]; + return result; +} + +#if !TARGET_OS_IPHONE +- (int) interact +{ + printf("Nu Shell.\n"); + + char* homedir = getenv("HOME"); + char history_file[FILENAME_MAX]; + int valid_history_file = 0; + + if (homedir) { // Not likely, but could be NULL + // Since we're getting something from the shell environment, + // try to be safe about it + int n = snprintf(history_file, FILENAME_MAX, "%s/.nush_history", homedir); + if (n <= FILENAME_MAX) { + read_history(history_file); + valid_history_file = 1; + } + } + + const char *unbufferedIO = getenv("NSUnbufferedIO"); + if (unbufferedIO && !strcmp(unbufferedIO, "YES")) { + system("stty -echo"); // Turn off echoing to avoid duplicated input. Surely there's a better way to do this. + puts("It looks like you are running in the Xcode debugger console. Beware: command history is broken."); + } + + do { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + char *prompt = ([self incomplete] ? "- " : "% "); +#ifdef IPHONENOREADLINE + puts(prompt); + char line[1024]; // careful + int count = gets(line); +#else + char *line = readline(prompt); + if (line && *line && strcmp(line, "quit")) + add_history (line); +#endif + if(!line || !strcmp(line, "quit")) { + break; + } + else { + id progn = nil; + + @try + { + progn = [[self parse:[NSString stringWithCString:line encoding:NSUTF8StringEncoding]] retain]; + } + @catch (NuException* nuException) { + printf("%s\n", [[nuException dump] cStringUsingEncoding:NSUTF8StringEncoding]); + [self reset]; + } + @catch (id exception) { + printf("%s: %s\n", + [[exception name] cStringUsingEncoding:NSUTF8StringEncoding], + [[exception reason] cStringUsingEncoding:NSUTF8StringEncoding]); + [self reset]; + } + + if (progn && (progn != [NSNull null])) { + id cursor = [progn cdr]; + while (cursor && (cursor != [NSNull null])) { + if ([cursor car] != [NSNull null]) { + id expression = [cursor car]; + //printf("evaluating %s\n", [[expression stringValue] cStringUsingEncoding:NSUTF8StringEncoding]); + + @try + { + id result = [expression evalWithContext:context]; + if (result) { + id stringToDisplay; + if ([result respondsToSelector:@selector(escapedStringRepresentation)]) { + stringToDisplay = [result escapedStringRepresentation]; + } + else { + stringToDisplay = [result stringValue]; + } + printf("%s\n", [stringToDisplay cStringUsingEncoding:NSUTF8StringEncoding]); + } + } + @catch (NuException* nuException) { + printf("%s\n", [[nuException dump] cStringUsingEncoding:NSUTF8StringEncoding]); + } + @catch (id exception) { + printf("%s: %s\n", + [[exception name] cStringUsingEncoding:NSUTF8StringEncoding], + [[exception reason] cStringUsingEncoding:NSUTF8StringEncoding]); + } + } + cursor = [cursor cdr]; + } + } + [progn release]; + } + [pool release]; + } while(1); + + if (valid_history_file) { + write_history(history_file); + } + + return 0; +} +#endif ++ (int) main +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NuParser *parser = [Nu sharedParser]; + int result = [parser interact]; + [pool drain]; + return result; +} + +@end diff --git a/objc/NuPointer.h b/objc/NuPointer.h new file mode 100644 index 0000000..b6633f7 --- /dev/null +++ b/objc/NuPointer.h @@ -0,0 +1,35 @@ +// +// NuPointer.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import +#pragma mark - +#pragma mark Wrapping access to items and objects in memory + +/*! + @class NuPointer + @abstract The Nu pointer wrapper. + @discussion The NuPointer class provides a wrapper for pointers to arbitrary locations in memory. + */ +@interface NuPointer : NSObject + +/*! Get the value of the pointer. Don't call this from Nu. */ +- (void *) pointer; +/*! Set the pointer. Used by the bridge to create NuReference objects from pointers. Don't call this from Nu. */ +- (void) setPointer:(void *) pointer; +/*! Set the type of a pointer. This should be an Objective-C type encoding that begins with a "^". */ +- (void) setTypeString:(NSString *) typeString; +/*! Get an Objective-C type string describing the pointer target. */ +- (NSString *) typeString; +/*! Assume the pointer is a pointer to an Objective-C object. Get the object. You had better be right, or this will crash. */ +- (id) object; +/*! Get the value of the pointed-to object, using the typeString to determine the correct type */ +- (id) value; +/*! Helper function, used internally to reserve space for data of a specified type. */ +- (void) allocateSpaceForTypeString:(NSString *) s; +@end + diff --git a/objc/NuPointer.m b/objc/NuPointer.m new file mode 100644 index 0000000..95d9e31 --- /dev/null +++ b/objc/NuPointer.m @@ -0,0 +1,90 @@ +// +// NuPointer.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuPointer.h" +#import "NuInternals.h" + +#pragma mark - NuPointer.m + +@interface NuPointer () +{ + void *pointer; + NSString *typeString; + bool thePointerIsMine; +} +@end + +@implementation NuPointer + +- (id) init +{ + if ((self = [super init])) { + pointer = 0; + typeString = nil; + thePointerIsMine = NO; + } + return self; +} + +- (void *) pointer {return pointer;} + +- (void) setPointer:(void *) p +{ + pointer = p; +} + +- (NSString *) typeString {return typeString;} + +- (id) object +{ + return pointer; +} + +- (void) setTypeString:(NSString *) s +{ + [s retain]; + [typeString release]; + typeString = s; +} + +- (void) allocateSpaceForTypeString:(NSString *) s +{ + if (thePointerIsMine) + free(pointer); + [self setTypeString:s]; + const char *type = [s cStringUsingEncoding:NSUTF8StringEncoding]; + while (*type && (*type != '^')) + type++; + if (*type) + type++; + //NSLog(@"allocating space for type %s", type); + pointer = value_buffer_for_objc_type(type); + thePointerIsMine = YES; +} + +- (void) dealloc +{ + [typeString release]; + if (thePointerIsMine) + free(pointer); + [super dealloc]; +} + +- (id) value +{ + const char *type = [typeString cStringUsingEncoding:NSUTF8StringEncoding]; + while (*type && (*type != '^')) + type++; + if (*type) + type++; + //NSLog(@"getting value for type %s", type); + return get_nu_value_from_objc_value(pointer, type); +} + +@end + diff --git a/objc/NuProfiler.h b/objc/NuProfiler.h new file mode 100644 index 0000000..bd04ad9 --- /dev/null +++ b/objc/NuProfiler.h @@ -0,0 +1,15 @@ +// +// NuProfiler.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +@interface NuProfiler : NSObject + ++ (NuProfiler *) defaultProfiler; + +@end \ No newline at end of file diff --git a/objc/NuProfiler.m b/objc/NuProfiler.m new file mode 100644 index 0000000..f915490 --- /dev/null +++ b/objc/NuProfiler.m @@ -0,0 +1,142 @@ +// +// NuProfiler.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuProfiler.h" + + +#ifdef DARWIN +#import +#import +#endif + +@interface NuProfileStackElement : NSObject +{ +@public + NSString *name; + uint64_t start; + NuProfileStackElement *parent; +} + +@end + +@interface NuProfileTimeSlice : NSObject +{ +@public + float time; + int count; +} + +@end + +@implementation NuProfileStackElement + +- (NSString *) name {return name;} +- (uint64_t) start {return start;} +- (NuProfileStackElement *) parent {return parent;} + +- (NSString *) description +{ + return [NSString stringWithFormat:@"name:%@ start:%llx", name, start]; +} + +@end + +@implementation NuProfileTimeSlice + +- (float) time {return time;} +- (int) count {return count;} + +- (NSString *) description +{ + return [NSString stringWithFormat:@"time:%f count:%d", time, count]; +} + +@end + +@interface NuProfiler () +{ + NSMutableDictionary *sections; + NuProfileStackElement *stack; +} +@end + +@implementation NuProfiler + +static NuProfiler *defaultProfiler = nil; + ++ (NuProfiler *) defaultProfiler +{ + if (!defaultProfiler) + defaultProfiler = [[NuProfiler alloc] init]; + return defaultProfiler; +} + +- (NuProfiler *) init +{ + self = [super init]; + sections = [[NSMutableDictionary alloc] init]; + stack = nil; + return self; +} + +- (void) start:(NSString *) name +{ +#ifdef DARWIN + NuProfileStackElement *stackElement = [[NuProfileStackElement alloc] init]; + stackElement->name = [name retain]; + stackElement->start = mach_absolute_time(); + stackElement->parent = stack; + stack = stackElement; +#endif +} + +- (void) stop +{ +#ifdef DARWIN + if (stack) { + uint64_t current_time = mach_absolute_time(); + uint64_t time_delta = current_time - stack->start; + struct mach_timebase_info info; + mach_timebase_info(&info); + float timeDelta = 1e-9 * time_delta * (double) info.numer / info.denom; + //NSNumber *delta = [NSNumber numberWithFloat:timeDelta]; + NuProfileTimeSlice *entry = [sections objectForKey:stack->name]; + if (!entry) { + entry = [[[NuProfileTimeSlice alloc] init] autorelease]; + entry->count = 1; + entry->time = timeDelta; + [sections setObject:entry forKey:stack->name]; + } + else { + entry->count++; + entry->time += timeDelta; + } + [stack->name release]; + NuProfileStackElement *top = stack; + stack = stack->parent; + [top release]; + } +#endif +} + +- (NSMutableDictionary *) sections +{ + return sections; +} + +- (void) reset +{ + [sections removeAllObjects]; + while (stack) { + NuProfileStackElement *top = stack; + stack = stack->parent; + [top release]; + } +} + +@end diff --git a/objc/NuProperty.h b/objc/NuProperty.h new file mode 100644 index 0000000..7f66abd --- /dev/null +++ b/objc/NuProperty.h @@ -0,0 +1,25 @@ +// +// NuProperty.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import +#import +#import + +/*! + @class NuProperty + @abstract Wrapper for Objective-C properties. + @discussion Preliminary and incomplete. + */ +@interface NuProperty : NSObject + +/*! Create a property wrapper for the specified property (used from Objective-C). */ ++ (NuProperty *) propertyWithProperty:(objc_property_t) property; +/*! Initialize a property wrapper for the specified property (used from Objective-C). */ +- (id) initWithProperty:(objc_property_t) property; + +@end \ No newline at end of file diff --git a/objc/NuProperty.m b/objc/NuProperty.m new file mode 100644 index 0000000..6d4c2d9 --- /dev/null +++ b/objc/NuProperty.m @@ -0,0 +1,39 @@ +// +// NuProperty.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// +#import +#import "NuProperty.h" + +#pragma mark - NuProperty.m + +@interface NuProperty () +{ + objc_property_t p; +} +@end + +@implementation NuProperty + ++ (NuProperty *) propertyWithProperty:(objc_property_t) property { + return [[[self alloc] initWithProperty:property] autorelease]; +} + +- (id) initWithProperty:(objc_property_t) property +{ + if ((self = [super init])) { + p = property; + } + return self; +} + +- (NSString *) name +{ + return [NSString stringWithCString:property_getName(p) encoding:NSUTF8StringEncoding]; +} + +@end + diff --git a/objc/NuReference.h b/objc/NuReference.h new file mode 100644 index 0000000..5b96d3a --- /dev/null +++ b/objc/NuReference.h @@ -0,0 +1,43 @@ +// +// NuReference.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @class NuReference + @abstract The Nu object wrapper. + @discussion The NuReference class provides a wrapper for pointers to Objective-C objects. + NuReference objects are used in the Nu language to capture arguments that are returned by value from Objective-C methods. + For example, the following Nu method uses a NuReference to capture a returned-by-reference NSError: + +
+ + (- (id) save is
+   (set perror ((NuReference alloc) init))
+   (set result ((self managedObjectContext) save:perror))
+   (unless result
+     (NSLog "error: #{((perror value) localizedDescription)}"))
+   result) +
+
+ */ +@interface NuReference : NSObject + +/*! Get the value of the referenced object. */ +- (id) value; +/*! Set the value of the referenced object. */ +- (void) setValue:(id) value; +/*! Set the pointer for a reference. Used by the bridge to create NuReference objects from pointers. Don't call this from Nu. */ +- (void) setPointer:(id *) pointer; +/*! Get a pointer to the referenced object. Used by the bridge to Objective-C to convert NuReference objects to pointers. + Don't call this from Nu. + */ +- (id *) pointerToReferencedObject; +/*! Retain the referenced object. Used by the bridge to Objective-C to retain values returned by reference. */ +- (void) retainReferencedObject; +@end \ No newline at end of file diff --git a/objc/NuReference.m b/objc/NuReference.m new file mode 100644 index 0000000..a329147 --- /dev/null +++ b/objc/NuReference.m @@ -0,0 +1,76 @@ +// +// NuReference.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuReference.h" + +#pragma mark - NuReference.m + +@interface NuReference () +{ + id *pointer; + bool thePointerIsMine; +} +@end + +@implementation NuReference + +- (id) init +{ + if ((self = [super init])) { + pointer = 0; + thePointerIsMine = false; + } + return self; +} + +- (id) value {return pointer ? *pointer : nil;} + +- (void) setValue:(id) v +{ + if (!pointer) { + pointer = (id *) malloc (sizeof (id)); + *pointer = nil; + thePointerIsMine = true; + } + [v retain]; + [(*pointer) release]; + (*pointer) = v; +} + +- (void) setPointer:(id *) p +{ + if (thePointerIsMine) { + free(pointer); + thePointerIsMine = false; + } + pointer = p; +} + +- (id *) pointerToReferencedObject +{ + if (!pointer) { + pointer = (id *) malloc (sizeof (id)); + *pointer = nil; + thePointerIsMine = true; + } + return pointer; +} + +- (void) retainReferencedObject +{ + [(*pointer) retain]; +} + +- (void) dealloc +{ + if (thePointerIsMine) + free(pointer); + [super dealloc]; +} + +@end diff --git a/objc/NuRegex.h b/objc/NuRegex.h new file mode 100644 index 0000000..397aca6 --- /dev/null +++ b/objc/NuRegex.h @@ -0,0 +1,92 @@ +// +// NuRegex.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +#pragma mark - +#pragma mark Regular Expressions + +// Let's make NSRegularExpression and NSTextCheckingResult look like our previous classes, NuRegex and NuRegexMatch + +@interface NSTextCheckingResult (NuRegexMatch) +/*! + @method regex + The regular expression used to make this match. */ +- (NSRegularExpression *)regex; + +/*! + @method count + The number of capturing subpatterns, including the pattern itself. */ +- (NSUInteger)count; + +/*! + @method group + Returns the part of the target string that matched the pattern. */ +- (NSString *)group; + +/*! + @method groupAtIndex: + Returns the part of the target string that matched the subpattern at the given index or nil if it wasn't matched. The subpatterns are indexed in order of their opening parentheses, 0 is the entire pattern, 1 is the first capturing subpattern, and so on. */ +- (NSString *)groupAtIndex:(int)idx; + +/*! + @method string + Returns the target string. */ +- (NSString *)string; + +@end + +@interface NSRegularExpression (NuRegex) + +/*! + @method regexWithPattern: + Creates a new regex using the given pattern string. Returns nil if the pattern string is invalid. */ ++ (id)regexWithPattern:(NSString *)pattern; + +/*! + @method regexWithPattern:options: + Creates a new regex using the given pattern string and option flags. Returns nil if the pattern string is invalid. */ ++ (id)regexWithPattern:(NSString *)pattern options:(int)options; + +/*! + @method initWithPattern: + Initializes the regex using the given pattern string. Returns nil if the pattern string is invalid. */ +- (id)initWithPattern:(NSString *)pattern; + +/*! + @method initWithPattern:options: + Initializes the regex using the given pattern string and option flags. Returns nil if the pattern string is invalid. */ +- (id)initWithPattern:(NSString *)pattern options:(int)options; + +/*! + @method findInString: + Calls findInString:range: using the full range of the target string. */ +- (NSTextCheckingResult *)findInString:(NSString *)string; + +/*! + @method findInString:range: + Returns an NuRegexMatch for the first occurrence of the regex in the given range of the target string or nil if none is found. */ +- (NSTextCheckingResult *)findInString:(NSString *)string range:(NSRange)range; + +/*! + @method findAllInString: + Calls findAllInString:range: using the full range of the target string. */ +- (NSArray *)findAllInString:(NSString *)string; + +/*! + @method findAllInString:range: + Returns an array of all non-overlapping occurrences of the regex in the given range of the target string. The members of the array are NuRegexMatches. */ +- (NSArray *)findAllInString:(NSString *)string range:(NSRange)range; + +/*! + @method replaceWithString:inString: + Calls replaceWithString:inString:limit: with no limit. */ +- (NSString *)replaceWithString:(NSString *)rep inString:(NSString *)str; + +@end + diff --git a/objc/NuRegex.m b/objc/NuRegex.m new file mode 100644 index 0000000..3ea7447 --- /dev/null +++ b/objc/NuRegex.m @@ -0,0 +1,172 @@ +// +// NuRegex.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuRegex.h" +#import "Nu.h" + +#pragma mark - NuRegex.m + +@implementation NSTextCheckingResult (NuRegexMatch) +/*! + @method regex + The regular expression used to make this match. */ +- (NSRegularExpression *)regex { + return [self regularExpression]; +} + +/*! + @method count + The number of capturing subpatterns, including the pattern itself. */ +- (NSUInteger)count { + return [self numberOfRanges]; +} + +/*! + @method group + Returns the part of the target string that matched the pattern. */ +- (NSString *)group { + return [self groupAtIndex:0]; +} + +/*! + @method groupAtIndex: + Returns the part of the target string that matched the subpattern at the given index or nil if it wasn't matched. The subpatterns are indexed in order of their opening parentheses, 0 is the entire pattern, 1 is the first capturing subpattern, and so on. */ +- (NSString *)groupAtIndex:(int)i { + NSRange range = [self rangeAtIndex:i]; + NSString *string = [self associatedObjectForKey:@"string"]; + if (string && (range.location != NSNotFound)) { + return [string substringWithRange:range]; + } else { + return nil; + } +} + +/*! + @method string + Returns the target string. */ +- (NSString *)string { + return [self associatedObjectForKey:@"string"]; +} + +@end + +@implementation NSRegularExpression (NuRegex) + +/*! + @method regexWithPattern: + Creates a new regex using the given pattern string. Returns nil if the pattern string is invalid. */ ++ (id)regexWithPattern:(NSString *)pattern { + return [self regularExpressionWithPattern:pattern + options:0 + error:NULL]; +} + +/*! + @method regexWithPattern:options: + Creates a new regex using the given pattern string and option flags. Returns nil if the pattern string is invalid. */ ++ (id)regexWithPattern:(NSString *)pattern options:(int)options { + return [self regularExpressionWithPattern:pattern + options:options + error:NULL]; +} + +/*! + @method initWithPattern: + Initializes the regex using the given pattern string. Returns nil if the pattern string is invalid. */ +- (id)initWithPattern:(NSString *)pattern { + return [self initWithPattern:pattern + options:0 + error:NULL]; +} + +/*! + @method initWithPattern:options: + Initializes the regex using the given pattern string and option flags. Returns nil if the pattern string is invalid. */ +- (id)initWithPattern:(NSString *)pattern options:(int)optionFlags { + return [self initWithPattern:pattern + options:optionFlags + error:NULL]; +} + + +/*! + @method findInString: + Calls findInString:range: using the full range of the target string. */ +- (NSTextCheckingResult *)findInString:(NSString *)string { + NSTextCheckingResult *result = [self firstMatchInString:string + options:0 + range:NSMakeRange(0,[string length])]; + if (result) { + [result setRetainedAssociatedObject:string forKey:@"string"]; + } + return result; +} + +/*! + @method findInString:range: + Returns an NuRegexMatch for the first occurrence of the regex in the given range of the target string or nil if none is found. */ +- (NSTextCheckingResult *)findInString:(NSString *)string range:(NSRange)range { + NSTextCheckingResult *result = [self firstMatchInString:string + options:0 + range:range]; + if (result) { + [result setRetainedAssociatedObject:string forKey:@"string"]; + } + return result; +} + +/*! + @method findAllInString: + Calls findAllInString:range: using the full range of the target string. */ +- (NSArray *)findAllInString:(NSString *)string { + NSArray *result = [self matchesInString:string + options:0 + range:NSMakeRange(0, [string length])]; + if (result) { + for (NSObject *match in result) { + [match setRetainedAssociatedObject:string forKey:@"string"]; + } + } + return result; +} + +/*! + @method findAllInString:range: + Returns an array of all non-overlapping occurrences of the regex in the given range of the target string. The members of the array are NuRegexMatches. */ +- (NSArray *)findAllInString:(NSString *)string range:(NSRange)range { + NSArray *result = [self matchesInString:string options:0 range:range]; + if (result) { + for (NSObject *match in result) { + [match setRetainedAssociatedObject:string forKey:@"string"]; + } + } + return result; +} + +/*! + @method replaceWithString:inString: + Calls replaceWithString:inString:limit: with no limit. */ +- (NSString *)replaceWithString:(NSString *)replacement inString:(NSString *)string { + return [self stringByReplacingMatchesInString:string + options:0 + range:NSMakeRange(0, [string length]) + withTemplate:replacement]; + +} + +#ifdef LINUX +- (BOOL) isEqual:(NSRegularExpression *)other +{ + return ([other isKindOfClass:[NSRegularExpression class]] && + [[self pattern] isEqual:[other pattern]] && + ([self options] == [other options])); +} +#endif + +@end + diff --git a/objc/NuStack.h b/objc/NuStack.h new file mode 100644 index 0000000..3b6e62c --- /dev/null +++ b/objc/NuStack.h @@ -0,0 +1,25 @@ +// +// NuStack.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @class NuStack + @abstract A stack class. + @discussion A simple stack class used by the Nu parser. + */ +@interface NuStack : NSObject + +/*! Push an object onto the stack. */ +- (void) push:(id) object; +/*! Pop an object from the top of the stack. Return nil if the stack is empty. */ +- (id) pop; +/*! Return the current stack depth. */ +- (NSUInteger) depth; + +@end \ No newline at end of file diff --git a/objc/NuStack.m b/objc/NuStack.m new file mode 100644 index 0000000..df2d1d1 --- /dev/null +++ b/objc/NuStack.m @@ -0,0 +1,72 @@ +// +// NuStack.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuStack.h" + +@interface NuStack () +{ + NSMutableArray *storage; +} +@end + +@implementation NuStack +- (id) init +{ + if ((self = [super init])) { + storage = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void) dealloc +{ + [storage release]; + [super dealloc]; +} + +- (void) push:(id) object +{ + [storage addObject:object]; +} + +- (id) pop +{ + if ([storage count] > 0) { + id object = [[storage lastObject] retain]; + [storage removeLastObject]; + [object autorelease]; + return object; + } + else { + return nil; + } +} + +- (NSUInteger) depth +{ + return [storage count]; +} + +- (id) top +{ + return [storage lastObject]; +} + +- (id) objectAtIndex:(int) i +{ + return [storage objectAtIndex:i]; +} + +- (void) dump +{ + for (NSInteger i = [storage count]-1; i >= 0; i--) { + NSLog(@"stack: %@", [storage objectAtIndex:i]); + } +} + +@end diff --git a/objc/NuSuper.h b/objc/NuSuper.h new file mode 100644 index 0000000..a7a7af0 --- /dev/null +++ b/objc/NuSuper.h @@ -0,0 +1,36 @@ +// +// NuSuper.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @class NuSuper + @abstract The Nu superclass proxy, an implementation detail used by Nu methods. + @discussion Instances of this class in Nu methods act as proxies for object superclasses. + Each time a Nu implementation of a method is called, + a NuSuper instance is created and inserted into the method's execution context with the name "super". + This allows method implementations to send messages to superclass implementations. + Typically, there is no need to directly interact with this class from Nu. + */ +@interface NuSuper : NSObject + +/*! Create a NuSuper proxy for an object with a specified class. + Note that the object class must be explicitly specified. + This is necessary to allow proper chaining of message sends + to super when multilevel methods are used (typically for initialization), + each calling the superclass version of itself. */ ++ (NuSuper *) superWithObject:(id) o ofClass:(Class) c; +/*! Initialize a NuSuper proxy for an object with a specified class. */ +- (NuSuper *) initWithObject:(id) o ofClass:(Class) c; +/*! Evalute a list headed by a NuSuper proxy. If non-null, the remainder + of the list is treated as a message that is sent to the object, + but treating the object as if it is an instance of its immediate superclass. + This is equivalent to sending a message to "super" in Objective-C. */ +- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context; + +@end \ No newline at end of file diff --git a/objc/NuSuper.m b/objc/NuSuper.m new file mode 100644 index 0000000..58af9f9 --- /dev/null +++ b/objc/NuSuper.m @@ -0,0 +1,80 @@ +// +// NuSuper.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuSuper.h" +#import "Nu.h" +#import "NuInternals.h" +#import "NuCell.h" + +#pragma mark - NuSuper.m + +@interface NuSuper () +{ + id object; + Class class; +} +@end + +@implementation NuSuper + +- (NuSuper *) initWithObject:(id) o ofClass:(Class) c +{ + if ((self = [super init])) { + object = o; // weak reference + class = c; // weak reference + } + return self; +} + ++ (NuSuper *) superWithObject:(id) o ofClass:(Class) c +{ + return [[[self alloc] initWithObject:o ofClass:c] autorelease]; +} + +- (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context +{ + // By themselves, Objective-C objects evaluate to themselves. + if (!cdr || (cdr == [NSNull null])) + return object; + + //NSLog(@"messaging super with %@", [cdr stringValue]); + // But when they're at the head of a list, the list is converted to a message and sent to the object + + NSMutableArray *args = [[NSMutableArray alloc] init]; + id cursor = cdr; + id selector = [cursor car]; + NSMutableString *selectorString = [NSMutableString stringWithString:[selector stringValue]]; + cursor = [cursor cdr]; + while (cursor && (cursor != [NSNull null])) { + [args addObject:[[cursor car] evalWithContext:context]]; + cursor = [cursor cdr]; + if (cursor && (cursor != [NSNull null])) { + [selectorString appendString:[[cursor car] stringValue]]; + cursor = [cursor cdr]; + } + } + SEL sel = sel_getUid([selectorString cStringUsingEncoding:NSUTF8StringEncoding]); + + // we're going to send the message to the handler of its superclass instead of one defined for its class. + Class c = class_getSuperclass(class); + Method m = class_getInstanceMethod(c, sel); + if (!m) m = class_getClassMethod(c, sel); + + id result; + if (m) { + result = nu_calling_objc_method_handler(object, m, args); + } + else { + NSLog(@"can't find function in superclass!"); + result = self; + } + [args release]; + return result; +} + +@end \ No newline at end of file diff --git a/objc/NuSwizzles.h b/objc/NuSwizzles.h new file mode 100644 index 0000000..0d8456f --- /dev/null +++ b/objc/NuSwizzles.h @@ -0,0 +1,9 @@ +// +// NuSwizzles.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import diff --git a/objc/NuSwizzles.m b/objc/NuSwizzles.m new file mode 100644 index 0000000..5791fb3 --- /dev/null +++ b/objc/NuSwizzles.m @@ -0,0 +1,80 @@ +// +// NuSwizzles.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "Nu.h" +#import "NuSwizzles.h" +#import "NuInternals.h" +#import "NuClass.h" + +#pragma mark - NuSwizzles.m + +@interface NSCFDictionarySwizzles : NSObject {} +@end + +@implementation NSCFDictionarySwizzles + +- (void)nuSetObject:(id)anObject forKey:(id)aKey +{ + [self nuSetObject:((anObject == nil) ? (id)[NSNull null] : anObject) forKey:aKey]; +} + +@end + +@interface NSCFArraySwizzles : NSObject {} +@end + +@implementation NSCFArraySwizzles + +- (void)nuAddObject:(id)anObject +{ + [self nuAddObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; +} + +- (void)nuInsertObject:(id)anObject atIndex:(int)index +{ + [self nuInsertObject:((anObject == nil) ? (id)[NSNull null] : anObject) atIndex:index]; +} + +- (void)nuReplaceObjectAtIndex:(int)index withObject:(id)anObject +{ + [self nuReplaceObjectAtIndex:index withObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; +} + +@end + +@interface NSCFSetSwizzles : NSObject {} +@end + +@implementation NSCFSetSwizzles + +- (void)nuAddObject:(id)anObject +{ + [self nuAddObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; +} + +@end + +void nu_swizzleContainerClasses() +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + Class NSCFDictionary = NSClassFromString(@"NSCFDictionary"); + Class NSCFArray = NSClassFromString(@"NSCFArray"); + Class NSCFSet = NSClassFromString(@"NSCFSet"); + [NSCFDictionary include:[NuClass classWithName:@"NSCFDictionarySwizzles"]]; + [NSCFArray include:[NuClass classWithName:@"NSCFArraySwizzles"]]; + [NSCFSet include:[NuClass classWithName:@"NSCFSetSwizzles"]]; + [NSCFDictionary exchangeInstanceMethod:@selector(setObject:forKey:) withMethod:@selector(nuSetObject:forKey:)]; + [NSCFArray exchangeInstanceMethod:@selector(addObject:) withMethod:@selector(nuAddObject:)]; + [NSCFArray exchangeInstanceMethod:@selector(insertObject:atIndex:) withMethod:@selector(nuInsertObject:atIndex:)]; + [NSCFArray exchangeInstanceMethod:@selector(replaceObjectAtIndex:withObject:) withMethod:@selector(nuReplaceObjectAtIndex:withObject:)]; + [NSCFSet exchangeInstanceMethod:@selector(addObject:) withMethod:@selector(nuAddObject:)]; + [pool drain]; +} + + + diff --git a/objc/NuSymbol.h b/objc/NuSymbol.h new file mode 100644 index 0000000..dee861a --- /dev/null +++ b/objc/NuSymbol.h @@ -0,0 +1,64 @@ +// +// NuSymbol.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +/*! + @class NuSymbol + @abstract The Nu symbol class. + @discussion Instances of NuSymbol are used to uniquely represent strings in parsed Nu expressions. + NuSymbol objects are used as keys in local evaluation contexts (typically of type NSMutableDictionary) + and each NuSymbol may also have a global value bound to it. + Symbols ending in a colon (':') are considered "labels" which evaluate to themselves without error, + and when a label is found at the head of the list, + the list is considered to be a special type of list called a property list (no relation to ObjC plists). + Each member of a property list is evaluated and the resulting list is returned with no further evaluation. + */ +@interface NuSymbol : NSObject + +/*! Get the global value of a symbol. */ +- (id) value; +/*! Set the global value of a symbol. */ +- (void) setValue:(id)v; +/*! Get an object of type NSString representing the symbol. */ +- (NSString *) stringValue; +/*! Returns true if a symbol is a label. */ +- (bool) isLabel; +/*! Returns true if a symbol is to be replaced by a generated symbol (which only occurs during macro evaluation). */ +- (bool) isGensym; +/*! If a symbol is a label, get a string representing its name. This string omits the final colon (':'). */ +- (NSString *) labelName; +/*! Evaluate a symbol in a specified context. */ +- (id) evalWithContext:(NSMutableDictionary *) context; +/*! Compare a symbol with another symbol by name. This allows arrays of symbols to be easily sorted. */ +- (NSComparisonResult) compare:(NuSymbol *) anotherSymbol; +/*! Get a description of a symbol. This is equivalent to a call to stringValue. */ +- (NSString *) description; + +@end + +/*! + @class NuSymbolTable + @abstract The Nu symbol table class. + @discussion Instances of NuSymbolTable manage collections of NuSymbol objects. + By default, one NuSymbolTable object is shared by all NuParser objects and execution contexts in a process. + */ +@interface NuSymbolTable : NSObject + +/*! Get the shared NuSymbolTable object. */ ++ (NuSymbolTable *) sharedSymbolTable; +/*! Get a symbol with the specified string. */ +- (NuSymbol *) symbolWithString:(NSString *)string; +/*! Lookup a symbol in a symbol table. */ +- (NuSymbol *) lookup:(NSString *) string; +/*! Get an array containing all of the symbols in a symbol table. */ +- (NSArray *) all; +/*! Remove a symbol from the symbol table */ +- (void) removeSymbol:(NuSymbol *) symbol; +@end + diff --git a/objc/NuSymbol.m b/objc/NuSymbol.m new file mode 100644 index 0000000..867b533 --- /dev/null +++ b/objc/NuSymbol.m @@ -0,0 +1,289 @@ +// +// NuSymbol.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuSymbol.h" +#import "NuInternals.h" +#import "NSDictionary+Nu.h" +#import "NuBridge.h" + +#pragma mark - NuSymbol.m + +@interface NuSymbol () +{ + NuSymbolTable *table; + id value; +@public // only for use by the symbol table + bool isLabel; + bool isGensym; // in macro evaluation, symbol is replaced with an automatically-generated unique symbol. + NSString *stringValue; // let's keep this for efficiency +} +- (void) _setStringValue:(NSString *) string; +@end + +@interface NuSymbolTable () +{ + NSMutableDictionary *symbol_table; +} +@end + +void load_builtins(NuSymbolTable *); + +static NuSymbolTable *sharedSymbolTable = 0; + + +@implementation NuSymbolTable + ++ (NuSymbolTable *) sharedSymbolTable +{ + if (!sharedSymbolTable) { + sharedSymbolTable = [[self alloc] init]; + load_builtins(sharedSymbolTable); + } + return sharedSymbolTable; +} + +- (void) dealloc +{ + NSLog(@"WARNING: deleting a symbol table. Leaking stored symbols."); + [super dealloc]; +} + +// Designated initializer +- (NuSymbol *) symbolWithString:(NSString *)string +{ + if (!symbol_table) symbol_table = [[NSMutableDictionary alloc] init]; + + // If the symbol is already in the table, return it. + NuSymbol *symbol; + symbol = [symbol_table objectForKey:string]; + if (symbol) { + return symbol; + } + + // If not, create it. + symbol = [[[NuSymbol alloc] init] autorelease]; // keep construction private + [symbol _setStringValue:string]; + + // Put the new symbol in the symbol table and return it. + [symbol_table setObject:symbol forKey:string]; + return symbol; +} + +- (NuSymbol *) lookup:(NSString *) string +{ + return [symbol_table objectForKey:string]; +} + +- (NSArray *) all +{ + return [symbol_table allValues]; +} + +- (void) removeSymbol:(NuSymbol *) symbol +{ + [symbol_table removeObjectForKey:[symbol stringValue]]; +} + +@end + +#import "NuMarkupOperator.h" + +@implementation NuSymbol + +- (void) _setStringValue:(NSString *) string { + self->stringValue = [string copy]; + + const char *cstring = [string cStringUsingEncoding:NSUTF8StringEncoding]; + NSUInteger len = strlen(cstring); + self->isLabel = (cstring[len - 1] == ':'); + self->isGensym = (len > 2) && (cstring[0] == '_') && (cstring[1] == '_'); +} + +- (void) dealloc +{ + [stringValue release]; + [super dealloc]; +} + +- (BOOL) isEqual: (NuSymbol *)other +{ + return (self == other) ? 1l : 0l; +} + +- (id) value +{ + return value; +} + +- (void) setValue:(id)v +{ + [v retain]; + [value release]; + value = v; +} + +- (NSString *) description +{ + return stringValue; +} + +- (NSString *) stringValue +{ + return stringValue; +} + +- (int) intValue +{ + return (value == [NSNull null]) ? 0 : 1; +} + +- (bool) isGensym +{ + return isGensym; +} + +- (bool) isLabel +{ + return isLabel; +} + +- (NSString *) labelName +{ + if (isLabel) + return [[self stringValue] substringToIndex:[[self stringValue] length] - 1]; + else + return [self stringValue]; +} + +- (NSString *) labelValue +{ + if (isLabel) + return [[self stringValue] substringToIndex:[[self stringValue] length] - 1]; + else + return [self stringValue]; +} + +- (id) evalWithContext:(NSMutableDictionary *)context +{ + + char c = (char) [[self stringValue] characterAtIndex:0]; + // If the symbol is a class instance variable, find "self" and ask it for the ivar value. + if (c == '@') { + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + id object = [context lookupObjectForKey:[symbolTable symbolWithString:@"self"]]; + if (!object) return [NSNull null]; + id ivarName = [[self stringValue] substringFromIndex:1]; + id result = [object valueForIvar:ivarName]; + return result ? result : (id) [NSNull null]; + } + + // Next, try to find the symbol in the local evaluation context. + id valueInContext = [context lookupObjectForKey:self]; + if (valueInContext) + return valueInContext; + +#if 0 + // if it's not there, try the next context up + id parentContext = [context objectForKey:@"context"]; + if (parentContext) { + valueInContext = [parentContext objectForKey:self]; + if (valueInContext) + return valueInContext; + } +#endif + + // Next, return the global value assigned to the value. + if (value) + return value; + + // If the symbol is a label (ends in ':'), then it will evaluate to itself. + if (isLabel) + return self; + + // If the symbol is still unknown, try to find a class with this name. + id className = [self stringValue]; + // the symbol should retain its value. + value = [[NuClass classWithName:className] retain]; + if (value) + return value; + + // Undefined globals evaluate to null. + if (c == '$') + return [NSNull null]; + + // Now we try looking in the bridge support dictionaries. + NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; + NuSymbol *bridgeSupportSymbol = [symbolTable symbolWithString:@"BridgeSupport"]; + NSDictionary *bridgeSupport = bridgeSupportSymbol ? [bridgeSupportSymbol value] : nil; + if (bridgeSupport) { + // is it an enum? + id enumValue = [[bridgeSupport valueForKey:@"enums"] valueForKey:[self stringValue]]; + if (enumValue) { + value = enumValue; + return value; + } + // is it a constant? + id constantSignature = [[bridgeSupport valueForKey:@"constants"] valueForKey:[self stringValue]]; + if (constantSignature) { + value = [[NuBridgedConstant constantWithName:[self stringValue] signature:constantSignature] retain]; + return value; + } + // is it a function? + id functionSignature = [[bridgeSupport valueForKey:@"functions"] valueForKey:[self stringValue]]; + if (functionSignature) { + value = [[NuBridgedFunction functionWithName:[self stringValue] signature:functionSignature] retain]; + return value; + } + } + + // Automatically create markup operators + if ([[self stringValue] characterAtIndex:0] == '&') { + NuMarkupOperator *newOperator = [NuMarkupOperator operatorWithTag:[[self stringValue] substringFromIndex:1]]; + [self setValue:newOperator]; + return newOperator; + } + + // Still-undefined symbols throw an exception. + NSMutableString *errorDescription = [NSMutableString stringWithFormat:@"undefined symbol %@", [self stringValue]]; + id expression = [context lookupObjectForKey:[symbolTable symbolWithString:@"_expression"]]; + if (expression) { + [errorDescription appendFormat:@" while evaluating expression %@", [expression stringValue]]; + const char *filename = nu_parsedFilename([expression file]); + if (filename) { + [errorDescription appendFormat:@" at %s:%d", filename, [expression line]]; + } + } + [NSException raise:@"NuUndefinedSymbol" format:@"%@", errorDescription]; + return [NSNull null]; +} + +- (NSComparisonResult) compare:(NuSymbol *) anotherSymbol +{ + return [stringValue compare:anotherSymbol->stringValue]; +} + +- (id) copyWithZone:(NSZone *) zone +{ + // Symbols are unique, so we don't copy them, but we retain them again since copies are automatically retained. + return [self retain]; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeObject:[self stringValue]]; +} + +- (id) initWithCoder:(NSCoder *)coder +{ + [super init]; + [self autorelease]; + return [[[NuSymbolTable sharedSymbolTable] symbolWithString:[coder decodeObject]] retain]; +} + +@end + diff --git a/objc/NuTestHelper.h b/objc/NuTestHelper.h new file mode 100644 index 0000000..4a3a22e --- /dev/null +++ b/objc/NuTestHelper.h @@ -0,0 +1,13 @@ +// +// NuTestHelper.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +@interface NuTestHelper : NSObject + +@end diff --git a/objc/NuTestHelper.m b/objc/NuTestHelper.m new file mode 100644 index 0000000..b5adcba --- /dev/null +++ b/objc/NuTestHelper.m @@ -0,0 +1,150 @@ +// +// NuTestHelper.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import +#import "Nu.h" + +#import "NuTestHelper.h" +#ifdef DARWIN +#import +#endif + +#pragma mark - NuTestHelper.m + +static BOOL verbose_helper = false; + +@protocol NuTestProxy + +#ifdef DARWIN +- (CGRect) CGRectValue; +- (CGPoint) CGPointValue; +- (CGSize) CGSizeValue; +#endif +- (NSRange) NSRangeValue; + +@end + +static int deallocationCount = 0; + +@implementation NuTestHelper + ++ (void) cycle +{ + NuTestHelper *object = [[NuTestHelper alloc] init]; + //Class before = object->isa; + objc_setAssociatedObject(object, @"number", @"123", OBJC_ASSOCIATION_RETAIN); + //Class after = object->isa; + //SEL cxx_destruct = sel_registerName(".cxx_destruct"); + //NSLog(@"class %@ %@", before, after); + //NSLog(@"responds? %d", [object respondsToSelector:cxx_destruct]); + [object release]; +} + ++ (void) setVerbose:(BOOL) v +{ + verbose_helper = v; +} + ++ (BOOL) verbose +{ + return verbose_helper; +} + ++ (id) helperInObjCUsingAllocInit +{ + id object = [[[NuTestHelper alloc] init] autorelease]; + return object; +} + ++ (id) helperInObjCUsingNew +{ + id object = [NuTestHelper new]; + // the GNUstep runtime returns nil from this call. + [object autorelease]; + return object; +} + +- (id) init +{ + if (verbose_helper) + NSLog(@"(NuTestHelper init %p)", self); + return [super init]; +} + +- (id) retain +{ + if (verbose_helper) + NSLog(@"(NuTestHelper retain %p)", self); + return [super retain]; +} + +- (oneway void) release +{ + if (verbose_helper) + NSLog(@"(NuTestHelper release %p)", self); + [super release]; +} + +- (id) autorelease +{ + if (verbose_helper) + NSLog(@"(NuTestHelper autorelease %p)", self); + return [super autorelease]; +} + +- (void) dealloc +{ + if (verbose_helper) + NSLog(@"(NuTestHelper dealloc %p)", self); + deallocationCount++; + [super dealloc]; +} + +- (void) finalize +{ + if (verbose_helper) + NSLog(@"(NuTestHelper finalize %p)", self); + deallocationCount++; + [super finalize]; +} + ++ (void) resetDeallocationCount +{ +#if !TARGET_OS_IPHONE + [[NSGarbageCollector defaultCollector] collectExhaustively]; +#endif + deallocationCount = 0; +} + ++ (int) deallocationCount +{ +#if !TARGET_OS_IPHONE + [[NSGarbageCollector defaultCollector] collectExhaustively]; +#endif + return deallocationCount; +} + +#ifdef DARWIN ++ (CGRect) getCGRectFromProxy:(id) proxy { + return [proxy CGRectValue]; +} + ++ (CGPoint) getCGPointFromProxy:(id) proxy { + return [proxy CGPointValue]; +} + ++ (CGSize) getCGSizeFromProxy:(id) proxy { + return [proxy CGSizeValue]; +} +#endif + ++ (NSRange) getNSRangeFromProxy:(id) proxy { + return [proxy NSRangeValue]; +} + +@end \ No newline at end of file From f01d0bb5382f82a3683d2ec6f11af433b3026eba Mon Sep 17 00:00:00 2001 From: Tim Burks Date: Sun, 24 Apr 2016 20:58:48 -0700 Subject: [PATCH 03/26] Expand bridging classes into separate files. --- Xcode/Nu.xcodeproj/project.pbxproj | 40 +++ objc/Nu.m | 1 + objc/NuBridge.h | 129 +------- objc/NuBridge.m | 502 +---------------------------- objc/NuBridgeSupport.h | 25 ++ objc/NuBridgeSupport.m | 178 ++++++++++ objc/NuBridgedBlock.h | 41 +++ objc/NuBridgedBlock.m | 215 ++++++++++++ objc/NuBridgedConstant.h | 25 ++ objc/NuBridgedConstant.m | 28 ++ objc/NuBridgedFunction.h | 64 ++++ objc/NuBridgedFunction.m | 126 ++++++++ objc/NuOperators.m | 1 + objc/NuSymbol.m | 2 + 14 files changed, 758 insertions(+), 619 deletions(-) create mode 100644 objc/NuBridgeSupport.h create mode 100644 objc/NuBridgeSupport.m create mode 100644 objc/NuBridgedBlock.h create mode 100644 objc/NuBridgedBlock.m create mode 100644 objc/NuBridgedConstant.h create mode 100644 objc/NuBridgedConstant.m create mode 100644 objc/NuBridgedFunction.h create mode 100644 objc/NuBridgedFunction.m diff --git a/Xcode/Nu.xcodeproj/project.pbxproj b/Xcode/Nu.xcodeproj/project.pbxproj index d3c1ee1..947c09a 100644 --- a/Xcode/Nu.xcodeproj/project.pbxproj +++ b/Xcode/Nu.xcodeproj/project.pbxproj @@ -117,6 +117,18 @@ 2217EC6A1CCDBF390082837B /* NuBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC671CCDBF390082837B /* NuBridge.m */; }; 225F62CD13B04256002DD16B /* ffi.S in Sources */ = {isa = PBXBuildFile; fileRef = 225F62C413B04256002DD16B /* ffi.S */; }; 225F62D313B04256002DD16B /* ffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 225F62CA13B04256002DD16B /* ffi.c */; }; + 22716B131CCDC9FD00E7ACDD /* NuBridgedFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 22716B111CCDC9FD00E7ACDD /* NuBridgedFunction.h */; }; + 22716B141CCDC9FD00E7ACDD /* NuBridgedFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B121CCDC9FD00E7ACDD /* NuBridgedFunction.m */; }; + 22716B151CCDC9FD00E7ACDD /* NuBridgedFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B121CCDC9FD00E7ACDD /* NuBridgedFunction.m */; }; + 22716B181CCDCB6F00E7ACDD /* NuBridgedConstant.h in Headers */ = {isa = PBXBuildFile; fileRef = 22716B161CCDCB6F00E7ACDD /* NuBridgedConstant.h */; }; + 22716B191CCDCB6F00E7ACDD /* NuBridgedConstant.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B171CCDCB6F00E7ACDD /* NuBridgedConstant.m */; }; + 22716B1A1CCDCB6F00E7ACDD /* NuBridgedConstant.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B171CCDCB6F00E7ACDD /* NuBridgedConstant.m */; }; + 22716B1D1CCDCC0F00E7ACDD /* NuBridgedBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 22716B1B1CCDCC0F00E7ACDD /* NuBridgedBlock.h */; }; + 22716B1E1CCDCC0F00E7ACDD /* NuBridgedBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B1C1CCDCC0F00E7ACDD /* NuBridgedBlock.m */; }; + 22716B1F1CCDCC0F00E7ACDD /* NuBridgedBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B1C1CCDCC0F00E7ACDD /* NuBridgedBlock.m */; }; + 22716B221CCDCCD900E7ACDD /* NuBridgeSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 22716B201CCDCCD900E7ACDD /* NuBridgeSupport.h */; }; + 22716B231CCDCCD900E7ACDD /* NuBridgeSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B211CCDCCD900E7ACDD /* NuBridgeSupport.m */; }; + 22716B241CCDCCD900E7ACDD /* NuBridgeSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B211CCDCCD900E7ACDD /* NuBridgeSupport.m */; }; 2283074411DDBEA700A5C690 /* Nu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Nu.framework */; }; 22B3B3B613B033D400B3AB31 /* test.html in Resources */ = {isa = PBXBuildFile; fileRef = 22B3B38813B033D400B3AB31 /* test.html */; }; 22B3B3B713B033D400B3AB31 /* test_array.nu in Resources */ = {isa = PBXBuildFile; fileRef = 22B3B38913B033D400B3AB31 /* test_array.nu */; }; @@ -299,6 +311,14 @@ 225F62BE13B04256002DD16B /* ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi.h; sourceTree = ""; }; 225F62C413B04256002DD16B /* ffi.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = ffi.S; sourceTree = ""; }; 225F62CA13B04256002DD16B /* ffi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi.c; sourceTree = ""; }; + 22716B111CCDC9FD00E7ACDD /* NuBridgedFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuBridgedFunction.h; sourceTree = ""; }; + 22716B121CCDC9FD00E7ACDD /* NuBridgedFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuBridgedFunction.m; sourceTree = ""; }; + 22716B161CCDCB6F00E7ACDD /* NuBridgedConstant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuBridgedConstant.h; sourceTree = ""; }; + 22716B171CCDCB6F00E7ACDD /* NuBridgedConstant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuBridgedConstant.m; sourceTree = ""; }; + 22716B1B1CCDCC0F00E7ACDD /* NuBridgedBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuBridgedBlock.h; sourceTree = ""; }; + 22716B1C1CCDCC0F00E7ACDD /* NuBridgedBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuBridgedBlock.m; sourceTree = ""; }; + 22716B201CCDCCD900E7ACDD /* NuBridgeSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuBridgeSupport.h; sourceTree = ""; }; + 22716B211CCDCCD900E7ACDD /* NuBridgeSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuBridgeSupport.m; sourceTree = ""; }; 2283073111DDBE3100A5C690 /* nush */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = nush; sourceTree = BUILT_PRODUCTS_DIR; }; 229FABE113C0129400CEFCF5 /* Nu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Nu.h; sourceTree = ""; }; 22B3B38813B033D400B3AB31 /* test.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = test.html; sourceTree = ""; }; @@ -640,6 +660,14 @@ 2217EBBD1CCD8BDF0082837B /* NuSymbol.m */, 2217EBC11CCD8CE30082837B /* NuTestHelper.h */, 2217EBC21CCD8CE30082837B /* NuTestHelper.m */, + 22716B111CCDC9FD00E7ACDD /* NuBridgedFunction.h */, + 22716B121CCDC9FD00E7ACDD /* NuBridgedFunction.m */, + 22716B161CCDCB6F00E7ACDD /* NuBridgedConstant.h */, + 22716B171CCDCB6F00E7ACDD /* NuBridgedConstant.m */, + 22716B1B1CCDCC0F00E7ACDD /* NuBridgedBlock.h */, + 22716B1C1CCDCC0F00E7ACDD /* NuBridgedBlock.m */, + 22716B201CCDCCD900E7ACDD /* NuBridgeSupport.h */, + 22716B211CCDCCD900E7ACDD /* NuBridgeSupport.m */, ); name = objc; path = ../objc; @@ -694,6 +722,7 @@ files = ( 2217EC681CCDBF390082837B /* NuBridge.h in Headers */, 2217EC401CCDAED00082837B /* NSArray+Nu.h in Headers */, + 22716B1D1CCDCC0F00E7ACDD /* NuBridgedBlock.h in Headers */, 2217EBC81CCD8DF00082837B /* NuSwizzles.h in Headers */, 2217EBE11CCD921B0082837B /* NuReference.h in Headers */, 2217EC091CCDA4990082837B /* NuMacro.h in Headers */, @@ -708,8 +737,10 @@ 2217EC041CCDA3870082837B /* NuMethod.h in Headers */, 2217EC541CCDB0D40082837B /* NSData+Nu.h in Headers */, 2217EBB81CCD89E60082837B /* NuMarkupOperator.h in Headers */, + 22716B131CCDC9FD00E7ACDD /* NuBridgedFunction.h in Headers */, 2217EC3B1CCDAE010082837B /* NuException.h in Headers */, 2217EC221CCDA9A00082837B /* NuMath.h in Headers */, + 22716B221CCDCCD900E7ACDD /* NuBridgeSupport.h in Headers */, 2217EC311CCDAC600082837B /* NSBundle+Nu.h in Headers */, 2217EBFA1CCDA27A0082837B /* NSObject+Nu.h in Headers */, 2217EC131CCDA65F0082837B /* NuBlock.h in Headers */, @@ -718,6 +749,7 @@ 2217EC2C1CCDAB700082837B /* NSDictionary+Nu.h in Headers */, 2217EBE61CCD92AC0082837B /* NuProperty.h in Headers */, 2217EBF51CCDA0420082837B /* NuOperators.h in Headers */, + 22716B181CCDCB6F00E7ACDD /* NuBridgedConstant.h in Headers */, 2217EC181CCDA7350082837B /* NuCell.h in Headers */, 2217EC0E1CCDA5390082837B /* NuHandler.h in Headers */, 2217EBDC1CCD915B0082837B /* NuRegex.h in Headers */, @@ -936,6 +968,7 @@ 2217EBDE1CCD915B0082837B /* NuRegex.m in Sources */, 2217EC331CCDAC600082837B /* NSBundle+Nu.m in Sources */, 2217EC561CCDB0D40082837B /* NSData+Nu.m in Sources */, + 22716B1A1CCDCB6F00E7ACDD /* NuBridgedConstant.m in Sources */, 22EE2C0613A4731600895861 /* main.m in Sources */, 2217EC061CCDA3870082837B /* NuMethod.m in Sources */, 2217EBCA1CCD8DF00082837B /* NuSwizzles.m in Sources */, @@ -952,6 +985,7 @@ 2217EC5B1CCDB1240082837B /* NSDate+Nu.m in Sources */, 2217EC381CCDAD3B0082837B /* NuEnumerable.m in Sources */, 2217EBCF1CCD8E760082837B /* NuSuper.m in Sources */, + 22716B1F1CCDCC0F00E7ACDD /* NuBridgedBlock.m in Sources */, 2217EBF21CCD9E7F0082837B /* NuPointer.m in Sources */, 2217EC241CCDA9A00082837B /* NuMath.m in Sources */, 2217EC011CCDA3300082837B /* NuObjCRuntime.m in Sources */, @@ -959,6 +993,7 @@ 225F62CD13B04256002DD16B /* ffi.S in Sources */, 2217EBE31CCD921B0082837B /* NuReference.m in Sources */, 2217EC4C1CCDAFE00082837B /* NSNull+Nu.m in Sources */, + 22716B241CCDCCD900E7ACDD /* NuBridgeSupport.m in Sources */, 2217EBD91CCD90310082837B /* NuParser.m in Sources */, 2217EC511CCDB0770082837B /* NSNumber+Nu.m in Sources */, 2217EC0B1CCDA4990082837B /* NuMacro.m in Sources */, @@ -967,6 +1002,7 @@ 2217EC3D1CCDAE010082837B /* NuException.m in Sources */, 2217EBED1CCD9DFE0082837B /* NuProfiler.m in Sources */, 2217EBC01CCD8BDF0082837B /* NuSymbol.m in Sources */, + 22716B151CCDC9FD00E7ACDD /* NuBridgedFunction.m in Sources */, 225F62D313B04256002DD16B /* ffi.c in Sources */, 2217EC471CCDAF2A0082837B /* NSSet+Nu.m in Sources */, 2217EC421CCDAED00082837B /* NSArray+Nu.m in Sources */, @@ -983,18 +1019,22 @@ 2217EC501CCDB0770082837B /* NSNumber+Nu.m in Sources */, 2217EC411CCDAED00082837B /* NSArray+Nu.m in Sources */, 2217EC051CCDA3870082837B /* NuMethod.m in Sources */, + 22716B231CCDCCD900E7ACDD /* NuBridgeSupport.m in Sources */, 2217EBC41CCD8CE30082837B /* NuTestHelper.m in Sources */, 2217EBEC1CCD9DFE0082837B /* NuProfiler.m in Sources */, 2217EC5A1CCDB1240082837B /* NSDate+Nu.m in Sources */, 2217EBD31CCD8F960082837B /* NuStack.m in Sources */, 2217EBF11CCD9E7F0082837B /* NuPointer.m in Sources */, 2217EC321CCDAC600082837B /* NSBundle+Nu.m in Sources */, + 22716B141CCDC9FD00E7ACDD /* NuBridgedFunction.m in Sources */, 2217EBE71CCD92AC0082837B /* NuProperty.m in Sources */, 2217EC141CCDA65F0082837B /* NuBlock.m in Sources */, 2217EC641CCDB2610082837B /* NSMethodSignature+Nu.m in Sources */, 2217EC551CCDB0D40082837B /* NSData+Nu.m in Sources */, 2217EBE21CCD921B0082837B /* NuReference.m in Sources */, + 22716B191CCDCB6F00E7ACDD /* NuBridgedConstant.m in Sources */, 2217EC461CCDAF2A0082837B /* NSSet+Nu.m in Sources */, + 22716B1E1CCDCC0F00E7ACDD /* NuBridgedBlock.m in Sources */, 2217EC231CCDA9A00082837B /* NuMath.m in Sources */, 2217EC3C1CCDAE010082837B /* NuException.m in Sources */, 2217EC4B1CCDAFE00082837B /* NSNull+Nu.m in Sources */, diff --git a/objc/Nu.m b/objc/Nu.m index 51cbc21..90a8fec 100644 --- a/objc/Nu.m +++ b/objc/Nu.m @@ -70,6 +70,7 @@ #import "NuEnumerable.h" #import "NuException.h" #import "NuBridge.h" +#import "NuBridgedFunction.h" #ifdef LINUX id loadNuLibraryFile(NSString *nuFileName, id parser, id context, id symbolTable); diff --git a/objc/NuBridge.h b/objc/NuBridge.h index da7e8b2..bb748ee 100644 --- a/objc/NuBridge.h +++ b/objc/NuBridge.h @@ -11,113 +11,20 @@ #import "NuBlock.h" #import "NuCell.h" -#pragma mark - -#pragma mark Callables: Functions, Macros, Operators - -#pragma mark - -#pragma mark Bridging C - -/*! - @class NuBridgedFunction - @abstract The Nu wrapper for imported C functions. - @discussion Instances of this class wrap functions imported from C. - - Because NuBridgedFunction is a subclass of NuOperator, Nu expressions that - begin with NuBridgedFunction instances are treated as operator calls. - - In general, operators may or may not evaluate their arguments, - but for NuBridgedFunctions, all arguments are evaluated. - The resulting values are then passed to the bridged C function - using the foreign function interface (libFFI). - - The C function's return value is converted into a Nu object and returned. - - Here is an example showing the use of this class from Nu. - The example imports and calls the C function NSApplicationMain. - -
- - (set NSApplicationMain
-     (NuBridgedFunction
-         functionWithName:"NSApplicationMain"
-         signature:"ii^*"))

- (NSApplicationMain 0 nil) -
-
- - The signature string used to create a NuBridgedFunction must be a valid Objective-C type signature. - In the future, convenience methods may be added to make those signatures easier to generate. - But in practice, this has not been much of a problem. - */ - -#import "NuOperators.h" - - -@interface NuBridgedFunction : NuOperator +#import +#if TARGET_OS_IPHONE +#import "ffi.h" +#else +#ifdef DARWIN +#import +#else +#import +#endif +#endif -/*! Create a wrapper for a C function with the specified name and signature. - The function is looked up using the dlsym() function and the wrapper is - constructed using libFFI. If the result of this method is assigned to a - symbol, that symbol may be used as the name of the bridged function. - */ -+ (NuBridgedFunction *) functionWithName:(NSString *)name signature:(NSString *)signature; -/*! Initialize a wrapper for a C function with the specified name and signature. - The function is looked up using the dlsym() function and the wrapper is - constructed using libFFI. If the result of this method is assigned to a - symbol, that symbol may be used as the name of the bridged function. - */ -- (NuBridgedFunction *) initWithName:(NSString *)name signature:(NSString *)signature; -/*! Evaluate a bridged function with the specified arguments and context. - Arguments must be in a Nu list. - */ -- (id) evalWithArguments:(id)arguments context:(NSMutableDictionary *)context; -@end -/*! - @class NuBridgedConstant - @abstract The Nu wrapper for imported C constants. - @discussion This class can be used to import constants defined in C code. - The signature string used to import a constant must be a valid Objective-C type signature. - */ -@interface NuBridgedConstant : NSObject {} -/*! Look up the value of a constant with specified name and type. - The function is looked up using the dlsym() function. - The returned value is of the type specified by the signature argument. - */ -+ (id) constantWithName:(NSString *) name signature:(NSString *) signature; +ffi_type *ffi_type_for_objc_type(const char *typeString); -@end - -#ifdef __BLOCKS__ -/*! - @class NuBridgedBlock - @abstract Generates a C block that wraps a nu block - @discussion This class makes a C block that wraps a nu block using a supplied - Objective-C-style function signature. This works by copying a dummy c block and - then writing over its function pointer with a libFFI-generated closure function. - */ -@interface NuBridgedBlock : NSObject - -/*! Returns a C block that wraps the supplied nu block using the supplied - Objective-C-style function signature. - */ -+(id)cBlockWithNuBlock:(NuBlock*)nb signature:(NSString*)sig; - -/*! Initializes a NuBridgedBlock object using a NuBlock and an Objective-C-style - function signature. A C block is generated during the initialization. - */ --(id)initWithNuBlock:(NuBlock*)nb signature:(NSString*)sig; - -/*! Returns the NuBlock associated with the NuBridgedBlock object. - */ --(NuBlock*)nuBlock; - -/*! Returns the C block generated by the NuBridgedBlock object. - */ --(id)cBlock; - -@end -#endif //__BLOCKS__ #import "NuMethod.h" @@ -126,17 +33,3 @@ #import "NuClass.h" -#if !TARGET_OS_IPHONE -/*! - @class NuBridgeSupport - @abstract A reader for Apple's BridgeSupport files. - @discussion Methods of this class are used to read Apple's BridgeSupport files. - */ -@interface NuBridgeSupport : NSObject -/*! Import a dynamic library at the specified path. */ -+ (void)importLibrary:(NSString *) libraryPath; -/*! Import a BridgeSupport description of a framework from a specified path. Store the results in the specified dictionary. */ -+ (void)importFramework:(NSString *) framework fromPath:(NSString *) path intoDictionary:(NSMutableDictionary *) BridgeSupport; - -@end -#endif \ No newline at end of file diff --git a/objc/NuBridge.m b/objc/NuBridge.m index 8092795..b6af5e0 100644 --- a/objc/NuBridge.m +++ b/objc/NuBridge.m @@ -212,7 +212,7 @@ static char get_typeChar_from_typeString(const char *typeString) return typeChar; } -static ffi_type *ffi_type_for_objc_type(const char *typeString) +ffi_type *ffi_type_for_objc_type(const char *typeString) { char typeChar = get_typeChar_from_typeString(typeString); switch (typeChar) { @@ -1257,137 +1257,6 @@ id add_method_to_class(Class c, NSString *methodName, NSString *signature, NuBlo return [NSNull null]; } -@interface NuBridgedFunction () -{ - char *name; - char *signature; - void *function; -} -@end - -@implementation NuBridgedFunction - -- (void) dealloc -{ - free(name); - free(signature); - [super dealloc]; -} - -- (NuBridgedFunction *) initWithName:(NSString *)n signature:(NSString *)s -{ - name = strdup([n cStringUsingEncoding:NSUTF8StringEncoding]); - signature = strdup([s cStringUsingEncoding:NSUTF8StringEncoding]); - function = dlsym(RTLD_DEFAULT, name); - if (!function) { - [NSException raise:@"NuCantFindBridgedFunction" - format:@"%s\n%s\n%s\n", dlerror(), - "If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set.", - "In Xcode, check the 'Preserve Private External Symbols' checkbox."]; - } - return self; -} - -+ (NuBridgedFunction *) functionWithName:(NSString *)name signature:(NSString *)signature -{ - const char *function_name = [name cStringUsingEncoding:NSUTF8StringEncoding]; - void *function = dlsym(RTLD_DEFAULT, function_name); - if (!function) { - [NSException raise:@"NuCantFindBridgedFunction" - format:@"%s\n%s\n%s\n", dlerror(), - "If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set.", - "In Xcode, check the 'Preserve Private External Symbols' checkbox."]; - } - NuBridgedFunction *wrapper = [[[NuBridgedFunction alloc] initWithName:name signature:signature] autorelease]; - return wrapper; -} - -- (id) evalWithArguments:(id) cdr context:(NSMutableDictionary *) context -{ - //NSLog(@"----------------------------------------"); - //NSLog(@"calling C function %s with signature %s", name, signature); - id result; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - char *return_type_identifier = strdup(signature); - nu_markEndOfObjCTypeString(return_type_identifier, strlen(return_type_identifier)); - - int argument_count = 0; - char *argument_type_identifiers[100]; - char *cursor = &signature[strlen(return_type_identifier)]; - while (*cursor != 0) { - argument_type_identifiers[argument_count] = strdup(cursor); - nu_markEndOfObjCTypeString(argument_type_identifiers[argument_count], strlen(cursor)); - cursor = &cursor[strlen(argument_type_identifiers[argument_count])]; - argument_count++; - } - //NSLog(@"calling return type is %s", return_type_identifier); - int i; - for (i = 0; i < argument_count; i++) { - // NSLog(@"argument %d type is %s", i, argument_type_identifiers[i]); - } - - ffi_cif *cif = (ffi_cif *)malloc(sizeof(ffi_cif)); - - ffi_type *result_type = ffi_type_for_objc_type(return_type_identifier); - ffi_type **argument_types = (argument_count == 0) ? NULL : (ffi_type **) malloc (argument_count * sizeof(ffi_type *)); - for (i = 0; i < argument_count; i++) - argument_types[i] = ffi_type_for_objc_type(argument_type_identifiers[i]); - - int status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, argument_count, result_type, argument_types); - if (status != FFI_OK) { - NSLog (@"failed to prepare cif structure"); - return [NSNull null]; - } - - id arg_cursor = cdr; - void *result_value = value_buffer_for_objc_type(return_type_identifier); - void **argument_values = (void **) (argument_count ? malloc (argument_count * sizeof(void *)) : NULL); - - for (i = 0; i < argument_count; i++) { - argument_values[i] = value_buffer_for_objc_type( argument_type_identifiers[i]); - id arg_value = [[arg_cursor car] evalWithContext:context]; - set_objc_value_from_nu_value(argument_values[i], arg_value, argument_type_identifiers[i]); - arg_cursor = [arg_cursor cdr]; - } - ffi_call(cif, FFI_FN(function), result_value, argument_values); - result = get_nu_value_from_objc_value(result_value, return_type_identifier); - - // free the value structures - for (i = 0; i < argument_count; i++) { - free(argument_values[i]); - free(argument_type_identifiers[i]); - } - free(argument_values); - free(result_value); - free(return_type_identifier); - free(argument_types); - free(cif); - - [result retain]; - [pool drain]; - [result autorelease]; - return result; -} - -@end - -@implementation NuBridgedConstant - -+ (id) constantWithName:(NSString *) name signature:(NSString *) signature -{ - const char *constant_name = [name cStringUsingEncoding:NSUTF8StringEncoding]; - void *constant = dlsym(RTLD_DEFAULT, constant_name); - if (!constant) { - NSLog(@"%s", dlerror()); - NSLog(@"If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set."); - NSLog(@"In Xcode, check the 'Preserve Private External Symbols' checkbox."); - return nil; - } - return get_nu_value_from_objc_value(constant, [signature cStringUsingEncoding:NSUTF8StringEncoding]); -} - -@end static NuSymbol *oneway_symbol, *in_symbol, *out_symbol, *inout_symbol, *bycopy_symbol, *byref_symbol, *const_symbol, @@ -1725,372 +1594,3 @@ id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *co return nil; } } - -#ifdef __BLOCKS__ - -static id make_cblock (NuBlock *nuBlock, NSString *signature); -static void objc_calling_nu_block_handler(ffi_cif* cif, void* returnvalue, void** args, void* userdata); -static char **generate_block_userdata(NuBlock *nuBlock, const char *signature); -static void *construct_block_handler(NuBlock *block, const char *signature); - -@interface NuBridgedBlock () -{ - NuBlock *nuBlock; - id cBlock; -} -@end - -@implementation NuBridgedBlock - -+(id)cBlockWithNuBlock:(NuBlock*)nb signature:(NSString*)sig -{ - return [[[[self alloc] initWithNuBlock:nb signature:sig] autorelease] cBlock]; -} - --(id)initWithNuBlock:(NuBlock*)nb signature:(NSString*)sig -{ - nuBlock = [nb retain]; - cBlock = make_cblock(nb,sig); - - return self; -} - --(NuBlock*)nuBlock -{return [[nuBlock retain] autorelease];} - --(id)cBlock -{return [[cBlock retain] autorelease];} - --(void)dealloc -{ - [nuBlock release]; - [cBlock release]; - [super dealloc]; -} - -@end - -//the caller gets ownership of the block -static id make_cblock (NuBlock *nuBlock, NSString *signature) -{ - void *funcptr = construct_block_handler(nuBlock, [signature UTF8String]); - - int i = 0xFFFF; - void(^cBlock)(void)=[^(void){printf("%i",i);} copy]; - -#ifdef __x86_64__ - /* this is what happens when a block is called on x86 64 - mov %rax,-0x18(%rbp) //the pointer to the block object is in rax - mov -0x18(%rbp),%rax - mov 0x10(%rax),%rax //the pointer to the block function is at +0x10 into the block object - mov -0x18(%rbp),%rdi //the first argument (this examples has no others) is always the pointer to the block object - callq *%rax - */ - //2*(sizeof(void*)) = 0x10 - *((void **)(id)cBlock + 2) = (void *)funcptr; -#else - /* this is what happens when a block is called on x86 32 - mov %eax,-0x14(%ebp) //the pointer to the block object is in eax - mov -0x14(%ebp),%eax - mov 0xc(%eax),%eax //the pointer to the block function is at +0xc into the block object - mov %eax,%edx - mov -0x14(%ebp),%eax //the first argument (this examples has no others) is always the pointer to the block object - mov %eax,(%esp) - call *%edx - */ - //3*(sizeof(void*)) = 0xc - *((void **)(id)cBlock + 3) = (void *)funcptr; -#endif - return cBlock; -} - -static void objc_calling_nu_block_handler(ffi_cif* cif, void* returnvalue, void** args, void* userdata) -{ - int argc = cif->nargs - 1; - //void *ptr = (void*)args[0] //don't need this first parameter - // see objc_calling_nu_method_handler - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NuBlock *block = ((NuBlock **)userdata)[1]; - //NSLog(@"----------------------------------------"); - //NSLog(@"calling block %@", [block stringValue]); - id arguments = [[NuCell alloc] init]; - id cursor = arguments; - int i; - for (i = 0; i < argc; i++) { - NuCell *nextCell = [[NuCell alloc] init]; - [cursor setCdr:nextCell]; - [nextCell release]; - cursor = [cursor cdr]; - id value = get_nu_value_from_objc_value(args[i+1], ((char **)userdata)[i+2]); - [cursor setCar:value]; - } - //NSLog(@"in nu method handler, using arguments %@", [arguments stringValue]); - id result = [block evalWithArguments:[arguments cdr] context:nil]; - //NSLog(@"in nu method handler, putting result %@ in %x with type %s", [result stringValue], (size_t) returnvalue, ((char **)userdata)[0]); - char *resultType = (((char **)userdata)[0])+1;// skip the first character, it's a flag - set_objc_value_from_nu_value(returnvalue, result, resultType); - [arguments release]; - if (pool) { - if (resultType[0] == '@') - [*((id *)returnvalue) retain]; - [pool release]; - if (resultType[0] == '@') - [*((id *)returnvalue) autorelease]; - } -} - -static char **generate_block_userdata(NuBlock *nuBlock, const char *signature) -{ - NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:signature]; - const char *return_type_string = [methodSignature methodReturnType]; - NSUInteger argument_count = [methodSignature numberOfArguments]; - char **userdata = (char **) malloc ((argument_count+3) * sizeof(char*)); - userdata[0] = (char *) malloc (2 + strlen(return_type_string)); - - //assume blocks never return retained results - sprintf(userdata[0], " %s", return_type_string); - - //so first element is return type, second is nuBlock - userdata[1] = (char *) nuBlock; - [nuBlock retain]; - int i; - for (i = 0; i < argument_count; i++) { - const char *argument_type_string = [methodSignature getArgumentTypeAtIndex:i]; - userdata[i+2] = strdup(argument_type_string); - } - userdata[argument_count+2] = NULL; - -#if 0 - NSLog(@"Userdata for block: %@, signature: %s", [nuBlock stringValue], signature); - for (int i = 0; i < argument_count+2; i++) - { if (i != 1) - NSLog(@"userdata[%i] = %s",i,userdata[i]); } -#endif - return userdata; -} - - -static void *construct_block_handler(NuBlock *block, const char *signature) -{ - char **userdata = generate_block_userdata(block, signature); - - int argument_count = 0; - while (userdata[argument_count] != 0) argument_count++; - argument_count-=1; //unlike a method call, c blocks have one, not two hidden args (see comments in make_cblock() -#if 0 - NSLog(@"using libffi to construct handler for nu block with %d arguments and signature %s", argument_count, signature); -#endif - if (argument_count < 0) { - NSLog(@"error in argument construction"); - return NULL; - } - - ffi_type **argument_types = (ffi_type **) malloc ((argument_count+1) * sizeof(ffi_type *)); - ffi_type *result_type = ffi_type_for_objc_type(userdata[0]+1); - - argument_types[0] = ffi_type_for_objc_type("^?"); - - for (int i = 1; i < argument_count; i++) - argument_types[i] = ffi_type_for_objc_type(userdata[i+1]); - argument_types[argument_count] = NULL; - ffi_cif *cif = (ffi_cif *)malloc(sizeof(ffi_cif)); - if (cif == NULL) { - NSLog(@"unable to prepare closure for signature %s (could not allocate memory for cif structure)", signature); - return NULL; - } - int status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, argument_count, result_type, argument_types); - if (status != FFI_OK) { - NSLog(@"unable to prepare closure for signature %s (ffi_prep_cif failed)", signature); - return NULL; - } - ffi_closure *closure = (ffi_closure *)mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (closure == (ffi_closure *) -1) { - NSLog(@"unable to prepare closure for signature %s (mmap failed with error %d)", signature, errno); - return NULL; - } - if (closure == NULL) { - NSLog(@"unable to prepare closure for signature %s (could not allocate memory for closure)", signature); - return NULL; - } - if (ffi_prep_closure(closure, cif, objc_calling_nu_block_handler, userdata) != FFI_OK) { - NSLog(@"unable to prepare closure for signature %s (ffi_prep_closure failed)", signature); - return NULL; - } - if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1) { - NSLog(@"unable to prepare closure for signature %s (mprotect failed with error %d)", signature, errno); - return NULL; - } - return (void*)closure; -} - -#endif //__BLOCKS__ - -#pragma mark - NuBridgeSupport.m - -#if !TARGET_OS_IPHONE - -static NSString *getTypeStringFromNode(id node) -{ - static BOOL use64BitTypes = (sizeof(void *) == 8); - if (use64BitTypes ) { - id type64Attribute = [node attributeForName:@"type64"]; - if (type64Attribute) - return [type64Attribute stringValue]; - } - return [[node attributeForName:@"type"] stringValue]; -} - -@implementation NuBridgeSupport - -+ (void)importLibrary:(NSString *) libraryPath -{ - //NSLog(@"importing library %@", libraryPath); - dlopen([libraryPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_LAZY | RTLD_GLOBAL); -} - -+ (void)importFramework:(NSString *) framework fromPath:(NSString *) path intoDictionary:(NSMutableDictionary *) BridgeSupport -{ - NSMutableDictionary *frameworks = [BridgeSupport valueForKey:@"frameworks"]; - if ([frameworks valueForKey:framework]) - return; - else - [frameworks setValue:framework forKey:framework]; - - NSString *xmlPath; // constants, enums, functions, and more are described in an XML file. - NSString *dylibPath; // sometimes a dynamic library is included to provide implementations of inline functions. - - if (path) { - xmlPath = [NSString stringWithFormat:@"%@/Resources/BridgeSupport/%@.bridgesupport", path, framework]; - dylibPath = [NSString stringWithFormat:@"%@/Resources/BridgeSupport/%@.dylib", path, framework]; - } - else { - xmlPath = [NSString stringWithFormat:@"/System/Library/Frameworks/%@.framework/Resources/BridgeSupport/%@.bridgesupport", framework, framework]; - dylibPath = [NSString stringWithFormat:@"/System/Library/Frameworks/%@.framework/Resources/BridgeSupport/%@.dylib", framework, framework]; - } - - if ([NSFileManager fileExistsNamed:dylibPath]) - [self importLibrary:dylibPath]; - - NSMutableDictionary *constants = [BridgeSupport valueForKey:@"constants"]; - NSMutableDictionary *enums = [BridgeSupport valueForKey:@"enums"]; - NSMutableDictionary *functions = [BridgeSupport valueForKey:@"functions"]; - - NSXMLDocument *xmlDocument = [[[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:xmlPath] options:0 error:NULL] autorelease]; - if (xmlDocument) { - id node; - NSEnumerator *childEnumerator = [[[xmlDocument rootElement] children] objectEnumerator]; - while ((node = [childEnumerator nextObject])) { - if ([[node name] isEqual:@"depends_on"]) { - id fileName = [[node attributeForName:@"path"] stringValue]; - id frameworkName = [[[fileName lastPathComponent] componentsSeparatedByString:@"."] objectAtIndex:0]; - [NuBridgeSupport importFramework:frameworkName fromPath:fileName intoDictionary:BridgeSupport]; - } - else if ([[node name] isEqual:@"constant"]) { - [constants setValue:getTypeStringFromNode(node) - forKey:[[node attributeForName:@"name"] stringValue]]; - } - else if ([[node name] isEqual:@"enum"]) { - [enums setValue:[NSNumber numberWithInt:[[[node attributeForName:@"value"] stringValue] intValue]] - forKey:[[node attributeForName:@"name"] stringValue]]; - } - else if ([[node name] isEqual:@"function"]) { - id name = [[node attributeForName:@"name"] stringValue]; - id argumentTypes = [NSMutableString string]; - id returnType = @"v"; - id child; - NSEnumerator *nodeChildEnumerator = [[node children] objectEnumerator]; - while ((child = [nodeChildEnumerator nextObject])) { - if ([[child name] isEqual:@"arg"]) { - id typeModifier = [child attributeForName:@"type_modifier"]; - if (typeModifier) { - [argumentTypes appendString:[typeModifier stringValue]]; - } - [argumentTypes appendString:getTypeStringFromNode(child)]; - } - else if ([[child name] isEqual:@"retval"]) { - returnType = getTypeStringFromNode(child); - } - else { - NSLog(@"unrecognized type #{[child XMLString]}"); - } - } - id signature = [NSString stringWithFormat:@"%@%@", returnType, argumentTypes]; - [functions setValue:signature forKey:name]; - } - } - } - else { - // don't complain about missing bridge support files... - //NSString *reason = [NSString stringWithFormat:@"unable to find BridgeSupport file for %@", framework]; - //[[NSException exceptionWithName:@"NuBridgeSupportMissing" reason:reason userInfo:nil] raise]; - } -} - -+ (void) prune -{ - NuSymbolTable *symbolTable = [NuSymbolTable sharedSymbolTable]; - id BridgeSupport = [[symbolTable symbolWithString:@"BridgeSupport"] value]; - [[BridgeSupport objectForKey:@"frameworks"] removeAllObjects]; - - id key; - for (int i = 0; i < 3; i++) { - id dictionary = [BridgeSupport objectForKey:(i == 0) ? @"constants" : (i == 1) ? @"enums" : @"functions"]; - id keyEnumerator = [[dictionary allKeys] objectEnumerator]; - while ((key = [keyEnumerator nextObject])) { - if (![symbolTable lookup:key]) - [dictionary removeObjectForKey:key]; - } - } -} - -+ (NSString *) stringValue -{ - NuSymbolTable *symbolTable = [NuSymbolTable sharedSymbolTable]; - id BridgeSupport = [[symbolTable symbolWithString:@"BridgeSupport"] value]; - - id result = [NSMutableString stringWithString:@"(global BridgeSupport\n"]; - id d, keyEnumerator, key; - - [result appendString:@" (dict\n"]; - d = [BridgeSupport objectForKey:@"constants"]; - [result appendString:@" constants:\n"]; - [result appendString:@" (dict"]; - keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; - while ((key = [keyEnumerator nextObject])) { - [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; - } - [result appendString:@")\n"]; - - d = [BridgeSupport objectForKey:@"enums"]; - [result appendString:@" enums:\n"]; - [result appendString:@" (dict"]; - keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; - while ((key = [keyEnumerator nextObject])) { - [result appendString:[NSString stringWithFormat:@"\n \"%@\" %@", key, [d objectForKey:key]]]; - } - [result appendString:@")\n"]; - - d = [BridgeSupport objectForKey:@"functions"]; - [result appendString:@" functions:\n"]; - [result appendString:@" (dict"]; - keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; - while ((key = [keyEnumerator nextObject])) { - [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; - } - [result appendString:@")\n"]; - - d = [BridgeSupport objectForKey:@"frameworks"]; - [result appendString:@" frameworks:\n"]; - [result appendString:@" (dict"]; - keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; - while ((key = [keyEnumerator nextObject])) { - [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; - } - [result appendString:@")))\n"]; - return result; -} - -@end -#endif \ No newline at end of file diff --git a/objc/NuBridgeSupport.h b/objc/NuBridgeSupport.h new file mode 100644 index 0000000..7f0bfe1 --- /dev/null +++ b/objc/NuBridgeSupport.h @@ -0,0 +1,25 @@ +// +// NuBridgeSupport.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import +#import "NuBridge.h" + +#if !TARGET_OS_IPHONE +/*! + @class NuBridgeSupport + @abstract A reader for Apple's BridgeSupport files. + @discussion Methods of this class are used to read Apple's BridgeSupport files. + */ +@interface NuBridgeSupport : NSObject +/*! Import a dynamic library at the specified path. */ ++ (void)importLibrary:(NSString *) libraryPath; +/*! Import a BridgeSupport description of a framework from a specified path. Store the results in the specified dictionary. */ ++ (void)importFramework:(NSString *) framework fromPath:(NSString *) path intoDictionary:(NSMutableDictionary *) BridgeSupport; + +@end +#endif \ No newline at end of file diff --git a/objc/NuBridgeSupport.m b/objc/NuBridgeSupport.m new file mode 100644 index 0000000..ef11781 --- /dev/null +++ b/objc/NuBridgeSupport.m @@ -0,0 +1,178 @@ +// +// NuBridgeSupport.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuBridgeSupport.h" +#import "NuInternals.h" + +#pragma mark - NuBridgeSupport.m + +#if !TARGET_OS_IPHONE + +static NSString *getTypeStringFromNode(id node) +{ + static BOOL use64BitTypes = (sizeof(void *) == 8); + if (use64BitTypes ) { + id type64Attribute = [node attributeForName:@"type64"]; + if (type64Attribute) + return [type64Attribute stringValue]; + } + return [[node attributeForName:@"type"] stringValue]; +} + +@implementation NuBridgeSupport + ++ (void)importLibrary:(NSString *) libraryPath +{ + //NSLog(@"importing library %@", libraryPath); + dlopen([libraryPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_LAZY | RTLD_GLOBAL); +} + ++ (void)importFramework:(NSString *) framework fromPath:(NSString *) path intoDictionary:(NSMutableDictionary *) BridgeSupport +{ + NSMutableDictionary *frameworks = [BridgeSupport valueForKey:@"frameworks"]; + if ([frameworks valueForKey:framework]) + return; + else + [frameworks setValue:framework forKey:framework]; + + NSString *xmlPath; // constants, enums, functions, and more are described in an XML file. + NSString *dylibPath; // sometimes a dynamic library is included to provide implementations of inline functions. + + if (path) { + xmlPath = [NSString stringWithFormat:@"%@/Resources/BridgeSupport/%@.bridgesupport", path, framework]; + dylibPath = [NSString stringWithFormat:@"%@/Resources/BridgeSupport/%@.dylib", path, framework]; + } + else { + xmlPath = [NSString stringWithFormat:@"/System/Library/Frameworks/%@.framework/Resources/BridgeSupport/%@.bridgesupport", framework, framework]; + dylibPath = [NSString stringWithFormat:@"/System/Library/Frameworks/%@.framework/Resources/BridgeSupport/%@.dylib", framework, framework]; + } + + if ([NSFileManager fileExistsNamed:dylibPath]) + [self importLibrary:dylibPath]; + + NSMutableDictionary *constants = [BridgeSupport valueForKey:@"constants"]; + NSMutableDictionary *enums = [BridgeSupport valueForKey:@"enums"]; + NSMutableDictionary *functions = [BridgeSupport valueForKey:@"functions"]; + + NSXMLDocument *xmlDocument = [[[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:xmlPath] options:0 error:NULL] autorelease]; + if (xmlDocument) { + id node; + NSEnumerator *childEnumerator = [[[xmlDocument rootElement] children] objectEnumerator]; + while ((node = [childEnumerator nextObject])) { + if ([[node name] isEqual:@"depends_on"]) { + id fileName = [[node attributeForName:@"path"] stringValue]; + id frameworkName = [[[fileName lastPathComponent] componentsSeparatedByString:@"."] objectAtIndex:0]; + [NuBridgeSupport importFramework:frameworkName fromPath:fileName intoDictionary:BridgeSupport]; + } + else if ([[node name] isEqual:@"constant"]) { + [constants setValue:getTypeStringFromNode(node) + forKey:[[node attributeForName:@"name"] stringValue]]; + } + else if ([[node name] isEqual:@"enum"]) { + [enums setValue:[NSNumber numberWithInt:[[[node attributeForName:@"value"] stringValue] intValue]] + forKey:[[node attributeForName:@"name"] stringValue]]; + } + else if ([[node name] isEqual:@"function"]) { + id name = [[node attributeForName:@"name"] stringValue]; + id argumentTypes = [NSMutableString string]; + id returnType = @"v"; + id child; + NSEnumerator *nodeChildEnumerator = [[node children] objectEnumerator]; + while ((child = [nodeChildEnumerator nextObject])) { + if ([[child name] isEqual:@"arg"]) { + id typeModifier = [child attributeForName:@"type_modifier"]; + if (typeModifier) { + [argumentTypes appendString:[typeModifier stringValue]]; + } + [argumentTypes appendString:getTypeStringFromNode(child)]; + } + else if ([[child name] isEqual:@"retval"]) { + returnType = getTypeStringFromNode(child); + } + else { + NSLog(@"unrecognized type #{[child XMLString]}"); + } + } + id signature = [NSString stringWithFormat:@"%@%@", returnType, argumentTypes]; + [functions setValue:signature forKey:name]; + } + } + } + else { + // don't complain about missing bridge support files... + //NSString *reason = [NSString stringWithFormat:@"unable to find BridgeSupport file for %@", framework]; + //[[NSException exceptionWithName:@"NuBridgeSupportMissing" reason:reason userInfo:nil] raise]; + } +} + ++ (void) prune +{ + NuSymbolTable *symbolTable = [NuSymbolTable sharedSymbolTable]; + id BridgeSupport = [[symbolTable symbolWithString:@"BridgeSupport"] value]; + [[BridgeSupport objectForKey:@"frameworks"] removeAllObjects]; + + id key; + for (int i = 0; i < 3; i++) { + id dictionary = [BridgeSupport objectForKey:(i == 0) ? @"constants" : (i == 1) ? @"enums" : @"functions"]; + id keyEnumerator = [[dictionary allKeys] objectEnumerator]; + while ((key = [keyEnumerator nextObject])) { + if (![symbolTable lookup:key]) + [dictionary removeObjectForKey:key]; + } + } +} + ++ (NSString *) stringValue +{ + NuSymbolTable *symbolTable = [NuSymbolTable sharedSymbolTable]; + id BridgeSupport = [[symbolTable symbolWithString:@"BridgeSupport"] value]; + + id result = [NSMutableString stringWithString:@"(global BridgeSupport\n"]; + id d, keyEnumerator, key; + + [result appendString:@" (dict\n"]; + d = [BridgeSupport objectForKey:@"constants"]; + [result appendString:@" constants:\n"]; + [result appendString:@" (dict"]; + keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; + while ((key = [keyEnumerator nextObject])) { + [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; + } + [result appendString:@")\n"]; + + d = [BridgeSupport objectForKey:@"enums"]; + [result appendString:@" enums:\n"]; + [result appendString:@" (dict"]; + keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; + while ((key = [keyEnumerator nextObject])) { + [result appendString:[NSString stringWithFormat:@"\n \"%@\" %@", key, [d objectForKey:key]]]; + } + [result appendString:@")\n"]; + + d = [BridgeSupport objectForKey:@"functions"]; + [result appendString:@" functions:\n"]; + [result appendString:@" (dict"]; + keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; + while ((key = [keyEnumerator nextObject])) { + [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; + } + [result appendString:@")\n"]; + + d = [BridgeSupport objectForKey:@"frameworks"]; + [result appendString:@" frameworks:\n"]; + [result appendString:@" (dict"]; + keyEnumerator = [[[d allKeys] sortedArrayUsingSelector:@selector(compare:)] objectEnumerator]; + while ((key = [keyEnumerator nextObject])) { + [result appendString:[NSString stringWithFormat:@"\n \"%@\" \"%@\"", key, [d objectForKey:key]]]; + } + [result appendString:@")))\n"]; + return result; +} + +@end +#endif \ No newline at end of file diff --git a/objc/NuBridgedBlock.h b/objc/NuBridgedBlock.h new file mode 100644 index 0000000..da72bb6 --- /dev/null +++ b/objc/NuBridgedBlock.h @@ -0,0 +1,41 @@ +// +// NuBridgedBlock.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import +#import "NuInternals.h" + +#ifdef __BLOCKS__ +/*! + @class NuBridgedBlock + @abstract Generates a C block that wraps a nu block + @discussion This class makes a C block that wraps a nu block using a supplied + Objective-C-style function signature. This works by copying a dummy c block and + then writing over its function pointer with a libFFI-generated closure function. + */ +@interface NuBridgedBlock : NSObject + +/*! Returns a C block that wraps the supplied nu block using the supplied + Objective-C-style function signature. + */ ++(id)cBlockWithNuBlock:(NuBlock*)nb signature:(NSString*)sig; + +/*! Initializes a NuBridgedBlock object using a NuBlock and an Objective-C-style + function signature. A C block is generated during the initialization. + */ +-(id)initWithNuBlock:(NuBlock*)nb signature:(NSString*)sig; + +/*! Returns the NuBlock associated with the NuBridgedBlock object. + */ +-(NuBlock*)nuBlock; + +/*! Returns the C block generated by the NuBridgedBlock object. + */ +-(id)cBlock; + +@end +#endif //__BLOCKS__ diff --git a/objc/NuBridgedBlock.m b/objc/NuBridgedBlock.m new file mode 100644 index 0000000..d38d5dd --- /dev/null +++ b/objc/NuBridgedBlock.m @@ -0,0 +1,215 @@ +// +// NuBridgedBlock.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuBridgedBlock.h" +#import "NuInternals.h" +#import "NuBridge.h" + +#import +#import + +#ifdef __BLOCKS__ + +static id make_cblock (NuBlock *nuBlock, NSString *signature); +static void objc_calling_nu_block_handler(ffi_cif* cif, void* returnvalue, void** args, void* userdata); +static char **generate_block_userdata(NuBlock *nuBlock, const char *signature); +static void *construct_block_handler(NuBlock *block, const char *signature); + +@interface NuBridgedBlock () +{ + NuBlock *nuBlock; + id cBlock; +} +@end + +@implementation NuBridgedBlock + ++(id)cBlockWithNuBlock:(NuBlock*)nb signature:(NSString*)sig +{ + return [[[[self alloc] initWithNuBlock:nb signature:sig] autorelease] cBlock]; +} + +-(id)initWithNuBlock:(NuBlock*)nb signature:(NSString*)sig +{ + nuBlock = [nb retain]; + cBlock = make_cblock(nb,sig); + + return self; +} + +-(NuBlock*)nuBlock +{return [[nuBlock retain] autorelease];} + +-(id)cBlock +{return [[cBlock retain] autorelease];} + +-(void)dealloc +{ + [nuBlock release]; + [cBlock release]; + [super dealloc]; +} + +@end + +//the caller gets ownership of the block +static id make_cblock (NuBlock *nuBlock, NSString *signature) +{ + void *funcptr = construct_block_handler(nuBlock, [signature UTF8String]); + + int i = 0xFFFF; + void(^cBlock)(void)=[^(void){printf("%i",i);} copy]; + +#ifdef __x86_64__ + /* this is what happens when a block is called on x86 64 + mov %rax,-0x18(%rbp) //the pointer to the block object is in rax + mov -0x18(%rbp),%rax + mov 0x10(%rax),%rax //the pointer to the block function is at +0x10 into the block object + mov -0x18(%rbp),%rdi //the first argument (this examples has no others) is always the pointer to the block object + callq *%rax + */ + //2*(sizeof(void*)) = 0x10 + *((void **)(id)cBlock + 2) = (void *)funcptr; +#else + /* this is what happens when a block is called on x86 32 + mov %eax,-0x14(%ebp) //the pointer to the block object is in eax + mov -0x14(%ebp),%eax + mov 0xc(%eax),%eax //the pointer to the block function is at +0xc into the block object + mov %eax,%edx + mov -0x14(%ebp),%eax //the first argument (this examples has no others) is always the pointer to the block object + mov %eax,(%esp) + call *%edx + */ + //3*(sizeof(void*)) = 0xc + *((void **)(id)cBlock + 3) = (void *)funcptr; +#endif + return cBlock; +} + +static void objc_calling_nu_block_handler(ffi_cif* cif, void* returnvalue, void** args, void* userdata) +{ + int argc = cif->nargs - 1; + //void *ptr = (void*)args[0] //don't need this first parameter + // see objc_calling_nu_method_handler + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NuBlock *block = ((NuBlock **)userdata)[1]; + //NSLog(@"----------------------------------------"); + //NSLog(@"calling block %@", [block stringValue]); + id arguments = [[NuCell alloc] init]; + id cursor = arguments; + int i; + for (i = 0; i < argc; i++) { + NuCell *nextCell = [[NuCell alloc] init]; + [cursor setCdr:nextCell]; + [nextCell release]; + cursor = [cursor cdr]; + id value = get_nu_value_from_objc_value(args[i+1], ((char **)userdata)[i+2]); + [cursor setCar:value]; + } + //NSLog(@"in nu method handler, using arguments %@", [arguments stringValue]); + id result = [block evalWithArguments:[arguments cdr] context:nil]; + //NSLog(@"in nu method handler, putting result %@ in %x with type %s", [result stringValue], (size_t) returnvalue, ((char **)userdata)[0]); + char *resultType = (((char **)userdata)[0])+1;// skip the first character, it's a flag + set_objc_value_from_nu_value(returnvalue, result, resultType); + [arguments release]; + if (pool) { + if (resultType[0] == '@') + [*((id *)returnvalue) retain]; + [pool release]; + if (resultType[0] == '@') + [*((id *)returnvalue) autorelease]; + } +} + +static char **generate_block_userdata(NuBlock *nuBlock, const char *signature) +{ + NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:signature]; + const char *return_type_string = [methodSignature methodReturnType]; + NSUInteger argument_count = [methodSignature numberOfArguments]; + char **userdata = (char **) malloc ((argument_count+3) * sizeof(char*)); + userdata[0] = (char *) malloc (2 + strlen(return_type_string)); + + //assume blocks never return retained results + sprintf(userdata[0], " %s", return_type_string); + + //so first element is return type, second is nuBlock + userdata[1] = (char *) nuBlock; + [nuBlock retain]; + int i; + for (i = 0; i < argument_count; i++) { + const char *argument_type_string = [methodSignature getArgumentTypeAtIndex:i]; + userdata[i+2] = strdup(argument_type_string); + } + userdata[argument_count+2] = NULL; + +#if 0 + NSLog(@"Userdata for block: %@, signature: %s", [nuBlock stringValue], signature); + for (int i = 0; i < argument_count+2; i++) + { if (i != 1) + NSLog(@"userdata[%i] = %s",i,userdata[i]); } +#endif + return userdata; +} + + +static void *construct_block_handler(NuBlock *block, const char *signature) +{ + char **userdata = generate_block_userdata(block, signature); + + int argument_count = 0; + while (userdata[argument_count] != 0) argument_count++; + argument_count-=1; //unlike a method call, c blocks have one, not two hidden args (see comments in make_cblock() +#if 0 + NSLog(@"using libffi to construct handler for nu block with %d arguments and signature %s", argument_count, signature); +#endif + if (argument_count < 0) { + NSLog(@"error in argument construction"); + return NULL; + } + + ffi_type **argument_types = (ffi_type **) malloc ((argument_count+1) * sizeof(ffi_type *)); + ffi_type *result_type = ffi_type_for_objc_type(userdata[0]+1); + + argument_types[0] = ffi_type_for_objc_type("^?"); + + for (int i = 1; i < argument_count; i++) + argument_types[i] = ffi_type_for_objc_type(userdata[i+1]); + argument_types[argument_count] = NULL; + ffi_cif *cif = (ffi_cif *)malloc(sizeof(ffi_cif)); + if (cif == NULL) { + NSLog(@"unable to prepare closure for signature %s (could not allocate memory for cif structure)", signature); + return NULL; + } + int status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, argument_count, result_type, argument_types); + if (status != FFI_OK) { + NSLog(@"unable to prepare closure for signature %s (ffi_prep_cif failed)", signature); + return NULL; + } + ffi_closure *closure = (ffi_closure *)mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (closure == (ffi_closure *) -1) { + NSLog(@"unable to prepare closure for signature %s (mmap failed with error %d)", signature, errno); + return NULL; + } + if (closure == NULL) { + NSLog(@"unable to prepare closure for signature %s (could not allocate memory for closure)", signature); + return NULL; + } + if (ffi_prep_closure(closure, cif, objc_calling_nu_block_handler, userdata) != FFI_OK) { + NSLog(@"unable to prepare closure for signature %s (ffi_prep_closure failed)", signature); + return NULL; + } + if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1) { + NSLog(@"unable to prepare closure for signature %s (mprotect failed with error %d)", signature, errno); + return NULL; + } + return (void*)closure; +} + +#endif //__BLOCKS__ \ No newline at end of file diff --git a/objc/NuBridgedConstant.h b/objc/NuBridgedConstant.h new file mode 100644 index 0000000..9abffde --- /dev/null +++ b/objc/NuBridgedConstant.h @@ -0,0 +1,25 @@ +// +// NuBridgedConstant.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + + +/*! + @class NuBridgedConstant + @abstract The Nu wrapper for imported C constants. + @discussion This class can be used to import constants defined in C code. + The signature string used to import a constant must be a valid Objective-C type signature. + */ +@interface NuBridgedConstant : NSObject {} +/*! Look up the value of a constant with specified name and type. + The function is looked up using the dlsym() function. + The returned value is of the type specified by the signature argument. + */ ++ (id) constantWithName:(NSString *) name signature:(NSString *) signature; + +@end diff --git a/objc/NuBridgedConstant.m b/objc/NuBridgedConstant.m new file mode 100644 index 0000000..bf1eea0 --- /dev/null +++ b/objc/NuBridgedConstant.m @@ -0,0 +1,28 @@ +// +// NuBridgedConstant.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuBridgedConstant.h" +#import "NuBridge.h" +#import "NuInternals.h" + +@implementation NuBridgedConstant + ++ (id) constantWithName:(NSString *) name signature:(NSString *) signature +{ + const char *constant_name = [name cStringUsingEncoding:NSUTF8StringEncoding]; + void *constant = dlsym(RTLD_DEFAULT, constant_name); + if (!constant) { + NSLog(@"%s", dlerror()); + NSLog(@"If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set."); + NSLog(@"In Xcode, check the 'Preserve Private External Symbols' checkbox."); + return nil; + } + return get_nu_value_from_objc_value(constant, [signature cStringUsingEncoding:NSUTF8StringEncoding]); +} + +@end diff --git a/objc/NuBridgedFunction.h b/objc/NuBridgedFunction.h new file mode 100644 index 0000000..05a25b1 --- /dev/null +++ b/objc/NuBridgedFunction.h @@ -0,0 +1,64 @@ +// +// NuBridgedFunction.h +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import + +#import "NuOperators.h" + +/*! + @class NuBridgedFunction + @abstract The Nu wrapper for imported C functions. + @discussion Instances of this class wrap functions imported from C. + + Because NuBridgedFunction is a subclass of NuOperator, Nu expressions that + begin with NuBridgedFunction instances are treated as operator calls. + + In general, operators may or may not evaluate their arguments, + but for NuBridgedFunctions, all arguments are evaluated. + The resulting values are then passed to the bridged C function + using the foreign function interface (libFFI). + + The C function's return value is converted into a Nu object and returned. + + Here is an example showing the use of this class from Nu. + The example imports and calls the C function NSApplicationMain. + +
+ + (set NSApplicationMain
+     (NuBridgedFunction
+         functionWithName:"NSApplicationMain"
+         signature:"ii^*"))

+ (NSApplicationMain 0 nil) +
+
+ + The signature string used to create a NuBridgedFunction must be a valid Objective-C type signature. + In the future, convenience methods may be added to make those signatures easier to generate. + But in practice, this has not been much of a problem. + */ + +@interface NuBridgedFunction : NuOperator + +/*! Create a wrapper for a C function with the specified name and signature. + The function is looked up using the dlsym() function and the wrapper is + constructed using libFFI. If the result of this method is assigned to a + symbol, that symbol may be used as the name of the bridged function. + */ ++ (NuBridgedFunction *) functionWithName:(NSString *)name signature:(NSString *)signature; +/*! Initialize a wrapper for a C function with the specified name and signature. + The function is looked up using the dlsym() function and the wrapper is + constructed using libFFI. If the result of this method is assigned to a + symbol, that symbol may be used as the name of the bridged function. + */ +- (NuBridgedFunction *) initWithName:(NSString *)name signature:(NSString *)signature; +/*! Evaluate a bridged function with the specified arguments and context. + Arguments must be in a Nu list. + */ +- (id) evalWithArguments:(id)arguments context:(NSMutableDictionary *)context; +@end \ No newline at end of file diff --git a/objc/NuBridgedFunction.m b/objc/NuBridgedFunction.m new file mode 100644 index 0000000..8feb3d6 --- /dev/null +++ b/objc/NuBridgedFunction.m @@ -0,0 +1,126 @@ +// +// NuBridgedFunction.m +// Nu +// +// Created by Tim Burks on 4/24/16. +// +// + +#import "NuBridgedFunction.h" +#import "NuBridge.h" +#import "NuInternals.h" + +@interface NuBridgedFunction () +{ + char *name; + char *signature; + void *function; +} +@end + +@implementation NuBridgedFunction + +- (void) dealloc +{ + free(name); + free(signature); + [super dealloc]; +} + +- (NuBridgedFunction *) initWithName:(NSString *)n signature:(NSString *)s +{ + name = strdup([n cStringUsingEncoding:NSUTF8StringEncoding]); + signature = strdup([s cStringUsingEncoding:NSUTF8StringEncoding]); + function = dlsym(RTLD_DEFAULT, name); + if (!function) { + [NSException raise:@"NuCantFindBridgedFunction" + format:@"%s\n%s\n%s\n", dlerror(), + "If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set.", + "In Xcode, check the 'Preserve Private External Symbols' checkbox."]; + } + return self; +} + ++ (NuBridgedFunction *) functionWithName:(NSString *)name signature:(NSString *)signature +{ + const char *function_name = [name cStringUsingEncoding:NSUTF8StringEncoding]; + void *function = dlsym(RTLD_DEFAULT, function_name); + if (!function) { + [NSException raise:@"NuCantFindBridgedFunction" + format:@"%s\n%s\n%s\n", dlerror(), + "If you are using a release build, try rebuilding with the KEEP_PRIVATE_EXTERNS variable set.", + "In Xcode, check the 'Preserve Private External Symbols' checkbox."]; + } + NuBridgedFunction *wrapper = [[[NuBridgedFunction alloc] initWithName:name signature:signature] autorelease]; + return wrapper; +} + +- (id) evalWithArguments:(id) cdr context:(NSMutableDictionary *) context +{ + //NSLog(@"----------------------------------------"); + //NSLog(@"calling C function %s with signature %s", name, signature); + id result; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + char *return_type_identifier = strdup(signature); + nu_markEndOfObjCTypeString(return_type_identifier, strlen(return_type_identifier)); + + int argument_count = 0; + char *argument_type_identifiers[100]; + char *cursor = &signature[strlen(return_type_identifier)]; + while (*cursor != 0) { + argument_type_identifiers[argument_count] = strdup(cursor); + nu_markEndOfObjCTypeString(argument_type_identifiers[argument_count], strlen(cursor)); + cursor = &cursor[strlen(argument_type_identifiers[argument_count])]; + argument_count++; + } + //NSLog(@"calling return type is %s", return_type_identifier); + int i; + for (i = 0; i < argument_count; i++) { + // NSLog(@"argument %d type is %s", i, argument_type_identifiers[i]); + } + + ffi_cif *cif = (ffi_cif *)malloc(sizeof(ffi_cif)); + + ffi_type *result_type = ffi_type_for_objc_type(return_type_identifier); + ffi_type **argument_types = (argument_count == 0) ? NULL : (ffi_type **) malloc (argument_count * sizeof(ffi_type *)); + for (i = 0; i < argument_count; i++) + argument_types[i] = ffi_type_for_objc_type(argument_type_identifiers[i]); + + int status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, argument_count, result_type, argument_types); + if (status != FFI_OK) { + NSLog (@"failed to prepare cif structure"); + return [NSNull null]; + } + + id arg_cursor = cdr; + void *result_value = value_buffer_for_objc_type(return_type_identifier); + void **argument_values = (void **) (argument_count ? malloc (argument_count * sizeof(void *)) : NULL); + + for (i = 0; i < argument_count; i++) { + argument_values[i] = value_buffer_for_objc_type( argument_type_identifiers[i]); + id arg_value = [[arg_cursor car] evalWithContext:context]; + set_objc_value_from_nu_value(argument_values[i], arg_value, argument_type_identifiers[i]); + arg_cursor = [arg_cursor cdr]; + } + ffi_call(cif, FFI_FN(function), result_value, argument_values); + result = get_nu_value_from_objc_value(result_value, return_type_identifier); + + // free the value structures + for (i = 0; i < argument_count; i++) { + free(argument_values[i]); + free(argument_type_identifiers[i]); + } + free(argument_values); + free(result_value); + free(return_type_identifier); + free(argument_types); + free(cif); + + [result retain]; + [pool drain]; + [result autorelease]; + return result; +} + +@end diff --git a/objc/NuOperators.m b/objc/NuOperators.m index fb6957d..ca15218 100644 --- a/objc/NuOperators.m +++ b/objc/NuOperators.m @@ -15,6 +15,7 @@ #import "NSFileManager+Nu.h" #import "NSArray+Nu.h" #import "NuBridge.h" +#import "NuBridgedFunction.h" #if TARGET_OS_IPHONE #import diff --git a/objc/NuSymbol.m b/objc/NuSymbol.m index 867b533..b57a611 100644 --- a/objc/NuSymbol.m +++ b/objc/NuSymbol.m @@ -10,6 +10,8 @@ #import "NuInternals.h" #import "NSDictionary+Nu.h" #import "NuBridge.h" +#import "NuBridgedFunction.h" +#import "NuBridgedConstant.h" #pragma mark - NuSymbol.m From 9806965016577cd595685a95a8a1183409e69a82 Mon Sep 17 00:00:00 2001 From: Tim Burks Date: Sun, 24 Apr 2016 21:20:29 -0700 Subject: [PATCH 04/26] Restructure some includes. --- objc/NSNumber+Nu.m | 1 + objc/NSObject+Nu.m | 2 ++ objc/NSString+Nu.m | 1 + objc/Nu.m | 1 + objc/NuBlock.m | 1 + objc/NuBridge.h | 11 +---------- objc/NuBridge.m | 3 +++ objc/NuEnumerable.m | 1 + objc/NuMarkupOperator.m | 1 + objc/NuOperators.m | 1 + objc/NuSymbol.m | 1 + 11 files changed, 14 insertions(+), 10 deletions(-) diff --git a/objc/NSNumber+Nu.m b/objc/NSNumber+Nu.m index b5085f3..3f94132 100644 --- a/objc/NSNumber+Nu.m +++ b/objc/NSNumber+Nu.m @@ -9,6 +9,7 @@ #import "NSNumber+Nu.h" #import "NuInternals.h" #import "NuBlock.h" +#import "NuCell.h" @implementation NSNumber(Nu) diff --git a/objc/NSObject+Nu.m b/objc/NSObject+Nu.m index 09a65cd..54c9846 100644 --- a/objc/NSObject+Nu.m +++ b/objc/NSObject+Nu.m @@ -11,6 +11,8 @@ #import "NSDictionary+Nu.h" #import "NuEnumerable.h" #import "NuMethod.h" +#import "NuClass.h" +#import "NuCell.h" @protocol NuCanSetAction - (void) setAction:(SEL) action; diff --git a/objc/NSString+Nu.m b/objc/NSString+Nu.m index f414f6d..f2056b9 100644 --- a/objc/NSString+Nu.m +++ b/objc/NSString+Nu.m @@ -10,6 +10,7 @@ #import "NuInternals.h" #import "NSDictionary+Nu.h" #import "NSData+Nu.h" +#import "NuCell.h" @interface NuStringEnumerator : NSEnumerator { diff --git a/objc/Nu.m b/objc/Nu.m index 90a8fec..69eb5a6 100644 --- a/objc/Nu.m +++ b/objc/Nu.m @@ -71,6 +71,7 @@ #import "NuException.h" #import "NuBridge.h" #import "NuBridgedFunction.h" +#import "NuClass.h" #ifdef LINUX id loadNuLibraryFile(NSString *nuFileName, id parser, id context, id symbolTable); diff --git a/objc/NuBlock.m b/objc/NuBlock.m index 85cd9ce..fbfe562 100644 --- a/objc/NuBlock.m +++ b/objc/NuBlock.m @@ -11,6 +11,7 @@ #import "NuSuper.h" #import "NSDictionary+Nu.h" #import "NuCell.h" +#import "NuClass.h" @interface NuBlock () { diff --git a/objc/NuBridge.h b/objc/NuBridge.h index bb748ee..f6bf166 100644 --- a/objc/NuBridge.h +++ b/objc/NuBridge.h @@ -23,13 +23,4 @@ #endif -ffi_type *ffi_type_for_objc_type(const char *typeString); - - -#import "NuMethod.h" - -#pragma mark - -#pragma mark Interacting with the Objective-C Runtime - -#import "NuClass.h" - +ffi_type *ffi_type_for_objc_type(const char *typeString); \ No newline at end of file diff --git a/objc/NuBridge.m b/objc/NuBridge.m index b6af5e0..eed3cfb 100644 --- a/objc/NuBridge.m +++ b/objc/NuBridge.m @@ -43,6 +43,9 @@ #import "NuHandler.h" #import "NuReference.h" #import "NuPointer.h" +#import "NuClass.h" +#import "NSMethodSignature+Nu.h" +#import "NSDictionary+Nu.h" /* * types: diff --git a/objc/NuEnumerable.m b/objc/NuEnumerable.m index 3c8758f..84d7f19 100644 --- a/objc/NuEnumerable.m +++ b/objc/NuEnumerable.m @@ -9,6 +9,7 @@ #import "NuEnumerable.h" #import "NuInternals.h" #import "NuCell.h" +#import "NuBlock.h" #pragma mark - NuEnumerable.m diff --git a/objc/NuMarkupOperator.m b/objc/NuMarkupOperator.m index 7ecc98d..c1477cb 100644 --- a/objc/NuMarkupOperator.m +++ b/objc/NuMarkupOperator.m @@ -9,6 +9,7 @@ #import "Nu.h" #import "NuInternals.h" #import "NuMarkupOperator.h" +#import "NuCell.h" @implementation NuMarkupOperator diff --git a/objc/NuOperators.m b/objc/NuOperators.m index ca15218..8e380ea 100644 --- a/objc/NuOperators.m +++ b/objc/NuOperators.m @@ -16,6 +16,7 @@ #import "NSArray+Nu.h" #import "NuBridge.h" #import "NuBridgedFunction.h" +#import "NuClass.h" #if TARGET_OS_IPHONE #import diff --git a/objc/NuSymbol.m b/objc/NuSymbol.m index b57a611..b4c1df1 100644 --- a/objc/NuSymbol.m +++ b/objc/NuSymbol.m @@ -12,6 +12,7 @@ #import "NuBridge.h" #import "NuBridgedFunction.h" #import "NuBridgedConstant.h" +#import "NuClass.h" #pragma mark - NuSymbol.m From 4d37d30842fb8f069bd8c297216bb55fa77c79f7 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Wed, 13 Jul 2016 18:06:25 +0200 Subject: [PATCH 05/26] Modernization Going to modern libffi as submodule NuTouch Library Target Show errors in NuApp 64bit structs need to be implemented --- .gitignore | 1 + .gitmodules | 4 + Nu.xcworkspace/contents.xcworkspacedata | 10 + Xcode/Info.plist | 2 +- Xcode/Nu.xcodeproj/project.pbxproj | 359 +++++-- Xcode/NuApp/NuApp-Info.plist | 2 +- Xcode/NuApp/NuAppDelegate.m | 27 +- libffi | 1 + libffi/LICENSE | 21 - libffi/README.markdown | 28 - libffi/ffi.S | 759 -------------- libffi/ffi.c | 1257 ----------------------- libffi/ffi.h | 952 ----------------- objc/NuInternals.h | 2 +- 14 files changed, 290 insertions(+), 3135 deletions(-) create mode 100644 .gitmodules create mode 100644 Nu.xcworkspace/contents.xcworkspacedata create mode 160000 libffi delete mode 100644 libffi/LICENSE delete mode 100644 libffi/README.markdown delete mode 100644 libffi/ffi.S delete mode 100644 libffi/ffi.c delete mode 100644 libffi/ffi.h diff --git a/.gitignore b/.gitignore index e9dc46c..4d06f56 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ Nu.framework libNu.a examples/*/*.app xcuserdata +*.xcscmblueprint diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..762f422 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "libffi"] + path = libffi + url = https://github.com/ksjogo/libffi.git + branch = master diff --git a/Nu.xcworkspace/contents.xcworkspacedata b/Nu.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..d5fec2d --- /dev/null +++ b/Nu.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Xcode/Info.plist b/Xcode/Info.plist index 2ed73e7..c86810c 100644 --- a/Xcode/Info.plist +++ b/Xcode/Info.plist @@ -9,7 +9,7 @@ CFBundleIconFile CFBundleIdentifier - nu.programming.framework + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Xcode/Nu.xcodeproj/project.pbxproj b/Xcode/Nu.xcodeproj/project.pbxproj index 947c09a..c1abc27 100644 --- a/Xcode/Nu.xcodeproj/project.pbxproj +++ b/Xcode/Nu.xcodeproj/project.pbxproj @@ -9,126 +9,84 @@ /* Begin PBXBuildFile section */ 2217EBB81CCD89E60082837B /* NuMarkupOperator.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBB61CCD89E60082837B /* NuMarkupOperator.h */; }; 2217EBB91CCD89E60082837B /* NuMarkupOperator.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBB71CCD89E60082837B /* NuMarkupOperator.m */; }; - 2217EBBA1CCD8AAC0082837B /* NuMarkupOperator.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBB71CCD89E60082837B /* NuMarkupOperator.m */; }; 2217EBBE1CCD8BDF0082837B /* NuSymbol.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBBC1CCD8BDF0082837B /* NuSymbol.h */; }; 2217EBBF1CCD8BDF0082837B /* NuSymbol.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBBD1CCD8BDF0082837B /* NuSymbol.m */; }; - 2217EBC01CCD8BDF0082837B /* NuSymbol.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBBD1CCD8BDF0082837B /* NuSymbol.m */; }; 2217EBC31CCD8CE30082837B /* NuTestHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBC11CCD8CE30082837B /* NuTestHelper.h */; }; 2217EBC41CCD8CE30082837B /* NuTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBC21CCD8CE30082837B /* NuTestHelper.m */; }; - 2217EBC51CCD8CE30082837B /* NuTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBC21CCD8CE30082837B /* NuTestHelper.m */; }; 2217EBC81CCD8DF00082837B /* NuSwizzles.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBC61CCD8DF00082837B /* NuSwizzles.h */; }; 2217EBC91CCD8DF00082837B /* NuSwizzles.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBC71CCD8DF00082837B /* NuSwizzles.m */; }; - 2217EBCA1CCD8DF00082837B /* NuSwizzles.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBC71CCD8DF00082837B /* NuSwizzles.m */; }; 2217EBCD1CCD8E760082837B /* NuSuper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBCB1CCD8E760082837B /* NuSuper.h */; }; 2217EBCE1CCD8E760082837B /* NuSuper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBCC1CCD8E760082837B /* NuSuper.m */; }; - 2217EBCF1CCD8E760082837B /* NuSuper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBCC1CCD8E760082837B /* NuSuper.m */; }; 2217EBD21CCD8F960082837B /* NuStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBD01CCD8F960082837B /* NuStack.h */; }; 2217EBD31CCD8F960082837B /* NuStack.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBD11CCD8F960082837B /* NuStack.m */; }; - 2217EBD41CCD8F960082837B /* NuStack.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBD11CCD8F960082837B /* NuStack.m */; }; 2217EBD71CCD90310082837B /* NuParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBD51CCD90310082837B /* NuParser.h */; }; 2217EBD81CCD90310082837B /* NuParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBD61CCD90310082837B /* NuParser.m */; }; - 2217EBD91CCD90310082837B /* NuParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBD61CCD90310082837B /* NuParser.m */; }; 2217EBDC1CCD915B0082837B /* NuRegex.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBDA1CCD915B0082837B /* NuRegex.h */; }; 2217EBDD1CCD915B0082837B /* NuRegex.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBDB1CCD915B0082837B /* NuRegex.m */; }; - 2217EBDE1CCD915B0082837B /* NuRegex.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBDB1CCD915B0082837B /* NuRegex.m */; }; 2217EBE11CCD921B0082837B /* NuReference.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBDF1CCD921B0082837B /* NuReference.h */; }; 2217EBE21CCD921B0082837B /* NuReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBE01CCD921B0082837B /* NuReference.m */; }; - 2217EBE31CCD921B0082837B /* NuReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBE01CCD921B0082837B /* NuReference.m */; }; 2217EBE61CCD92AC0082837B /* NuProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBE41CCD92AC0082837B /* NuProperty.h */; }; 2217EBE71CCD92AC0082837B /* NuProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBE51CCD92AC0082837B /* NuProperty.m */; }; - 2217EBE81CCD92AC0082837B /* NuProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBE51CCD92AC0082837B /* NuProperty.m */; }; 2217EBEB1CCD9DFE0082837B /* NuProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBE91CCD9DFE0082837B /* NuProfiler.h */; }; 2217EBEC1CCD9DFE0082837B /* NuProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBEA1CCD9DFE0082837B /* NuProfiler.m */; }; - 2217EBED1CCD9DFE0082837B /* NuProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBEA1CCD9DFE0082837B /* NuProfiler.m */; }; 2217EBF01CCD9E7F0082837B /* NuPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBEE1CCD9E7F0082837B /* NuPointer.h */; }; 2217EBF11CCD9E7F0082837B /* NuPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBEF1CCD9E7F0082837B /* NuPointer.m */; }; - 2217EBF21CCD9E7F0082837B /* NuPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBEF1CCD9E7F0082837B /* NuPointer.m */; }; 2217EBF51CCDA0420082837B /* NuOperators.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBF31CCDA0420082837B /* NuOperators.h */; }; 2217EBF61CCDA0420082837B /* NuOperators.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBF41CCDA0420082837B /* NuOperators.m */; }; - 2217EBF71CCDA0420082837B /* NuOperators.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBF41CCDA0420082837B /* NuOperators.m */; }; 2217EBFA1CCDA27A0082837B /* NSObject+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBF81CCDA27A0082837B /* NSObject+Nu.h */; }; 2217EBFB1CCDA27A0082837B /* NSObject+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBF91CCDA27A0082837B /* NSObject+Nu.m */; }; - 2217EBFC1CCDA27A0082837B /* NSObject+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBF91CCDA27A0082837B /* NSObject+Nu.m */; }; 2217EBFF1CCDA3300082837B /* NuObjCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EBFD1CCDA3300082837B /* NuObjCRuntime.h */; }; 2217EC001CCDA3300082837B /* NuObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBFE1CCDA3300082837B /* NuObjCRuntime.m */; }; - 2217EC011CCDA3300082837B /* NuObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBFE1CCDA3300082837B /* NuObjCRuntime.m */; }; 2217EC041CCDA3870082837B /* NuMethod.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC021CCDA3870082837B /* NuMethod.h */; }; 2217EC051CCDA3870082837B /* NuMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC031CCDA3870082837B /* NuMethod.m */; }; - 2217EC061CCDA3870082837B /* NuMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC031CCDA3870082837B /* NuMethod.m */; }; 2217EC091CCDA4990082837B /* NuMacro.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC071CCDA4990082837B /* NuMacro.h */; }; 2217EC0A1CCDA4990082837B /* NuMacro.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC081CCDA4990082837B /* NuMacro.m */; }; - 2217EC0B1CCDA4990082837B /* NuMacro.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC081CCDA4990082837B /* NuMacro.m */; }; 2217EC0E1CCDA5390082837B /* NuHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC0C1CCDA5390082837B /* NuHandler.h */; }; 2217EC0F1CCDA5390082837B /* NuHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC0D1CCDA5390082837B /* NuHandler.m */; }; - 2217EC101CCDA5390082837B /* NuHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC0D1CCDA5390082837B /* NuHandler.m */; }; 2217EC131CCDA65F0082837B /* NuBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC111CCDA65F0082837B /* NuBlock.h */; }; 2217EC141CCDA65F0082837B /* NuBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC121CCDA65F0082837B /* NuBlock.m */; }; - 2217EC151CCDA65F0082837B /* NuBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC121CCDA65F0082837B /* NuBlock.m */; }; 2217EC181CCDA7350082837B /* NuCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC161CCDA7350082837B /* NuCell.h */; }; 2217EC191CCDA7350082837B /* NuCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC171CCDA7350082837B /* NuCell.m */; }; - 2217EC1A1CCDA7350082837B /* NuCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC171CCDA7350082837B /* NuCell.m */; }; 2217EC1D1CCDA8340082837B /* NuClass.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC1B1CCDA8340082837B /* NuClass.h */; }; 2217EC1E1CCDA8340082837B /* NuClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC1C1CCDA8340082837B /* NuClass.m */; }; - 2217EC1F1CCDA8340082837B /* NuClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC1C1CCDA8340082837B /* NuClass.m */; }; 2217EC221CCDA9A00082837B /* NuMath.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC201CCDA9A00082837B /* NuMath.h */; }; 2217EC231CCDA9A00082837B /* NuMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC211CCDA9A00082837B /* NuMath.m */; }; - 2217EC241CCDA9A00082837B /* NuMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC211CCDA9A00082837B /* NuMath.m */; }; 2217EC271CCDAA850082837B /* NSString+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC251CCDAA850082837B /* NSString+Nu.h */; }; 2217EC281CCDAA850082837B /* NSString+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC261CCDAA850082837B /* NSString+Nu.m */; }; - 2217EC291CCDAA850082837B /* NSString+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC261CCDAA850082837B /* NSString+Nu.m */; }; 2217EC2C1CCDAB700082837B /* NSDictionary+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC2A1CCDAB700082837B /* NSDictionary+Nu.h */; }; 2217EC2D1CCDAB700082837B /* NSDictionary+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC2B1CCDAB700082837B /* NSDictionary+Nu.m */; }; - 2217EC2E1CCDAB700082837B /* NSDictionary+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC2B1CCDAB700082837B /* NSDictionary+Nu.m */; }; 2217EC311CCDAC600082837B /* NSBundle+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC2F1CCDAC600082837B /* NSBundle+Nu.h */; }; 2217EC321CCDAC600082837B /* NSBundle+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC301CCDAC600082837B /* NSBundle+Nu.m */; }; - 2217EC331CCDAC600082837B /* NSBundle+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC301CCDAC600082837B /* NSBundle+Nu.m */; }; 2217EC361CCDAD3B0082837B /* NuEnumerable.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC341CCDAD3B0082837B /* NuEnumerable.h */; }; 2217EC371CCDAD3B0082837B /* NuEnumerable.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC351CCDAD3B0082837B /* NuEnumerable.m */; }; - 2217EC381CCDAD3B0082837B /* NuEnumerable.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC351CCDAD3B0082837B /* NuEnumerable.m */; }; 2217EC3B1CCDAE010082837B /* NuException.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC391CCDAE010082837B /* NuException.h */; }; 2217EC3C1CCDAE010082837B /* NuException.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC3A1CCDAE010082837B /* NuException.m */; }; - 2217EC3D1CCDAE010082837B /* NuException.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC3A1CCDAE010082837B /* NuException.m */; }; 2217EC401CCDAED00082837B /* NSArray+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC3E1CCDAED00082837B /* NSArray+Nu.h */; }; 2217EC411CCDAED00082837B /* NSArray+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC3F1CCDAED00082837B /* NSArray+Nu.m */; }; - 2217EC421CCDAED00082837B /* NSArray+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC3F1CCDAED00082837B /* NSArray+Nu.m */; }; 2217EC451CCDAF2A0082837B /* NSSet+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC431CCDAF2A0082837B /* NSSet+Nu.h */; }; 2217EC461CCDAF2A0082837B /* NSSet+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC441CCDAF2A0082837B /* NSSet+Nu.m */; }; - 2217EC471CCDAF2A0082837B /* NSSet+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC441CCDAF2A0082837B /* NSSet+Nu.m */; }; 2217EC4A1CCDAFE00082837B /* NSNull+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC481CCDAFE00082837B /* NSNull+Nu.h */; }; 2217EC4B1CCDAFE00082837B /* NSNull+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC491CCDAFE00082837B /* NSNull+Nu.m */; }; - 2217EC4C1CCDAFE00082837B /* NSNull+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC491CCDAFE00082837B /* NSNull+Nu.m */; }; 2217EC4F1CCDB0770082837B /* NSNumber+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC4D1CCDB0770082837B /* NSNumber+Nu.h */; }; 2217EC501CCDB0770082837B /* NSNumber+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC4E1CCDB0770082837B /* NSNumber+Nu.m */; }; - 2217EC511CCDB0770082837B /* NSNumber+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC4E1CCDB0770082837B /* NSNumber+Nu.m */; }; 2217EC541CCDB0D40082837B /* NSData+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC521CCDB0D40082837B /* NSData+Nu.h */; }; 2217EC551CCDB0D40082837B /* NSData+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC531CCDB0D40082837B /* NSData+Nu.m */; }; - 2217EC561CCDB0D40082837B /* NSData+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC531CCDB0D40082837B /* NSData+Nu.m */; }; 2217EC591CCDB1240082837B /* NSDate+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC571CCDB1240082837B /* NSDate+Nu.h */; }; 2217EC5A1CCDB1240082837B /* NSDate+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC581CCDB1240082837B /* NSDate+Nu.m */; }; - 2217EC5B1CCDB1240082837B /* NSDate+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC581CCDB1240082837B /* NSDate+Nu.m */; }; 2217EC5E1CCDB19C0082837B /* NSFileManager+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC5C1CCDB19C0082837B /* NSFileManager+Nu.h */; }; 2217EC5F1CCDB19C0082837B /* NSFileManager+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC5D1CCDB19C0082837B /* NSFileManager+Nu.m */; }; - 2217EC601CCDB19C0082837B /* NSFileManager+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC5D1CCDB19C0082837B /* NSFileManager+Nu.m */; }; 2217EC631CCDB2610082837B /* NSMethodSignature+Nu.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC611CCDB2610082837B /* NSMethodSignature+Nu.h */; }; 2217EC641CCDB2610082837B /* NSMethodSignature+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC621CCDB2610082837B /* NSMethodSignature+Nu.m */; }; - 2217EC651CCDB2610082837B /* NSMethodSignature+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC621CCDB2610082837B /* NSMethodSignature+Nu.m */; }; 2217EC681CCDBF390082837B /* NuBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 2217EC661CCDBF390082837B /* NuBridge.h */; }; 2217EC691CCDBF390082837B /* NuBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC671CCDBF390082837B /* NuBridge.m */; }; - 2217EC6A1CCDBF390082837B /* NuBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC671CCDBF390082837B /* NuBridge.m */; }; - 225F62CD13B04256002DD16B /* ffi.S in Sources */ = {isa = PBXBuildFile; fileRef = 225F62C413B04256002DD16B /* ffi.S */; }; - 225F62D313B04256002DD16B /* ffi.c in Sources */ = {isa = PBXBuildFile; fileRef = 225F62CA13B04256002DD16B /* ffi.c */; }; 22716B131CCDC9FD00E7ACDD /* NuBridgedFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 22716B111CCDC9FD00E7ACDD /* NuBridgedFunction.h */; }; 22716B141CCDC9FD00E7ACDD /* NuBridgedFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B121CCDC9FD00E7ACDD /* NuBridgedFunction.m */; }; - 22716B151CCDC9FD00E7ACDD /* NuBridgedFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B121CCDC9FD00E7ACDD /* NuBridgedFunction.m */; }; 22716B181CCDCB6F00E7ACDD /* NuBridgedConstant.h in Headers */ = {isa = PBXBuildFile; fileRef = 22716B161CCDCB6F00E7ACDD /* NuBridgedConstant.h */; }; 22716B191CCDCB6F00E7ACDD /* NuBridgedConstant.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B171CCDCB6F00E7ACDD /* NuBridgedConstant.m */; }; - 22716B1A1CCDCB6F00E7ACDD /* NuBridgedConstant.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B171CCDCB6F00E7ACDD /* NuBridgedConstant.m */; }; 22716B1D1CCDCC0F00E7ACDD /* NuBridgedBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 22716B1B1CCDCC0F00E7ACDD /* NuBridgedBlock.h */; }; 22716B1E1CCDCC0F00E7ACDD /* NuBridgedBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B1C1CCDCC0F00E7ACDD /* NuBridgedBlock.m */; }; - 22716B1F1CCDCC0F00E7ACDD /* NuBridgedBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B1C1CCDCC0F00E7ACDD /* NuBridgedBlock.m */; }; 22716B221CCDCCD900E7ACDD /* NuBridgeSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 22716B201CCDCCD900E7ACDD /* NuBridgeSupport.h */; }; 22716B231CCDCCD900E7ACDD /* NuBridgeSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B211CCDCCD900E7ACDD /* NuBridgeSupport.m */; }; - 22716B241CCDCCD900E7ACDD /* NuBridgeSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B211CCDCCD900E7ACDD /* NuBridgeSupport.m */; }; 2283074411DDBEA700A5C690 /* Nu.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Nu.framework */; }; 22B3B3B613B033D400B3AB31 /* test.html in Resources */ = {isa = PBXBuildFile; fileRef = 22B3B38813B033D400B3AB31 /* test.html */; }; 22B3B3B713B033D400B3AB31 /* test_array.nu in Resources */ = {isa = PBXBuildFile; fileRef = 22B3B38913B033D400B3AB31 /* test_array.nu */; }; @@ -210,7 +168,6 @@ 22B3B41613B033EE00B3AB31 /* test.nu in Resources */ = {isa = PBXBuildFile; fileRef = 22B3B3F513B033EE00B3AB31 /* test.nu */; }; 22B3B41713B033EE00B3AB31 /* test.nu in Resources */ = {isa = PBXBuildFile; fileRef = 22B3B3F513B033EE00B3AB31 /* test.nu */; }; 22B3B47313B0359300B3AB31 /* Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B3B41D13B0359300B3AB31 /* Nu.m */; }; - 22B3B47413B0359300B3AB31 /* Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B3B41D13B0359300B3AB31 /* Nu.m */; }; 22B3B50313B0386600B3AB31 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22B3B50213B0386600B3AB31 /* UIKit.framework */; }; 22B3B50513B0388C00B3AB31 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22B3B50413B0388C00B3AB31 /* Foundation.framework */; }; 22B3B50713B038D000B3AB31 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22B3B50613B038D000B3AB31 /* Foundation.framework */; }; @@ -218,6 +175,49 @@ 22EE2C0413A4731600895861 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 22EE2C0213A4731600895861 /* InfoPlist.strings */; }; 22EE2C0613A4731600895861 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 22EE2C0513A4731600895861 /* main.m */; }; 22EE2C0A13A4731600895861 /* NuAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 22EE2C0913A4731600895861 /* NuAppDelegate.m */; }; + 43B5D4101D3668A600D1E1FD /* libNuTouch.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 43B5D4021D36686B00D1E1FD /* libNuTouch.a */; }; + 43DCFCB31D369D8200CB6E63 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 43DCFCB21D369D8200CB6E63 /* libffi.a */; }; + 43DCFCB91D37938100CB6E63 /* NSArray+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC3F1CCDAED00082837B /* NSArray+Nu.m */; }; + 43DCFCBB1D37938100CB6E63 /* NSBundle+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC301CCDAC600082837B /* NSBundle+Nu.m */; }; + 43DCFCBD1D37938100CB6E63 /* NSData+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC531CCDB0D40082837B /* NSData+Nu.m */; }; + 43DCFCBF1D37938100CB6E63 /* NSDate+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC581CCDB1240082837B /* NSDate+Nu.m */; }; + 43DCFCC11D37938100CB6E63 /* NSDictionary+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC2B1CCDAB700082837B /* NSDictionary+Nu.m */; }; + 43DCFCC31D37938100CB6E63 /* NSFileManager+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC5D1CCDB19C0082837B /* NSFileManager+Nu.m */; }; + 43DCFCC51D37938100CB6E63 /* NSMethodSignature+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC621CCDB2610082837B /* NSMethodSignature+Nu.m */; }; + 43DCFCC71D37938200CB6E63 /* NSNull+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC491CCDAFE00082837B /* NSNull+Nu.m */; }; + 43DCFCC91D37938200CB6E63 /* NSNumber+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC4E1CCDB0770082837B /* NSNumber+Nu.m */; }; + 43DCFCCB1D37938200CB6E63 /* NSObject+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBF91CCDA27A0082837B /* NSObject+Nu.m */; }; + 43DCFCCD1D37938200CB6E63 /* NSSet+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC441CCDAF2A0082837B /* NSSet+Nu.m */; }; + 43DCFCCF1D37938200CB6E63 /* NSString+Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC261CCDAA850082837B /* NSString+Nu.m */; }; + 43DCFCD11D37938200CB6E63 /* Nu.m in Sources */ = {isa = PBXBuildFile; fileRef = 22B3B41D13B0359300B3AB31 /* Nu.m */; }; + 43DCFCD31D37938200CB6E63 /* NuBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC121CCDA65F0082837B /* NuBlock.m */; }; + 43DCFCD51D37938200CB6E63 /* NuBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC671CCDBF390082837B /* NuBridge.m */; }; + 43DCFCD71D37938200CB6E63 /* NuCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC171CCDA7350082837B /* NuCell.m */; }; + 43DCFCD91D37938200CB6E63 /* NuClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC1C1CCDA8340082837B /* NuClass.m */; }; + 43DCFCDB1D37938200CB6E63 /* NuEnumerable.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC351CCDAD3B0082837B /* NuEnumerable.m */; }; + 43DCFCDD1D37938200CB6E63 /* NuException.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC3A1CCDAE010082837B /* NuException.m */; }; + 43DCFCDF1D37938200CB6E63 /* NuHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC0D1CCDA5390082837B /* NuHandler.m */; }; + 43DCFCE21D37938200CB6E63 /* NuMacro.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC081CCDA4990082837B /* NuMacro.m */; }; + 43DCFCE41D37938200CB6E63 /* NuMarkupOperator.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBB71CCD89E60082837B /* NuMarkupOperator.m */; }; + 43DCFCE61D37938200CB6E63 /* NuMath.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC211CCDA9A00082837B /* NuMath.m */; }; + 43DCFCE81D37938200CB6E63 /* NuMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EC031CCDA3870082837B /* NuMethod.m */; }; + 43DCFCEA1D37938200CB6E63 /* NuObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBFE1CCDA3300082837B /* NuObjCRuntime.m */; }; + 43DCFCEC1D37938200CB6E63 /* NuOperators.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBF41CCDA0420082837B /* NuOperators.m */; }; + 43DCFCEE1D37938200CB6E63 /* NuParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBD61CCD90310082837B /* NuParser.m */; }; + 43DCFCF01D37938200CB6E63 /* NuPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBEF1CCD9E7F0082837B /* NuPointer.m */; }; + 43DCFCF21D37938200CB6E63 /* NuProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBEA1CCD9DFE0082837B /* NuProfiler.m */; }; + 43DCFCF41D37938200CB6E63 /* NuProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBE51CCD92AC0082837B /* NuProperty.m */; }; + 43DCFCF61D37938200CB6E63 /* NuReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBE01CCD921B0082837B /* NuReference.m */; }; + 43DCFCF81D37938200CB6E63 /* NuRegex.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBDB1CCD915B0082837B /* NuRegex.m */; }; + 43DCFCFA1D37938200CB6E63 /* NuStack.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBD11CCD8F960082837B /* NuStack.m */; }; + 43DCFCFC1D37938200CB6E63 /* NuSuper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBCC1CCD8E760082837B /* NuSuper.m */; }; + 43DCFCFE1D37938200CB6E63 /* NuSwizzles.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBC71CCD8DF00082837B /* NuSwizzles.m */; }; + 43DCFD001D37938200CB6E63 /* NuSymbol.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBBD1CCD8BDF0082837B /* NuSymbol.m */; }; + 43DCFD021D37938200CB6E63 /* NuTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2217EBC21CCD8CE30082837B /* NuTestHelper.m */; }; + 43DCFD041D37938200CB6E63 /* NuBridgedFunction.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B121CCDC9FD00E7ACDD /* NuBridgedFunction.m */; }; + 43DCFD061D37938200CB6E63 /* NuBridgedConstant.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B171CCDCB6F00E7ACDD /* NuBridgedConstant.m */; }; + 43DCFD081D37938200CB6E63 /* NuBridgedBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B1C1CCDCC0F00E7ACDD /* NuBridgedBlock.m */; }; + 43DCFD0A1D37938200CB6E63 /* NuBridgeSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 22716B211CCDCCD900E7ACDD /* NuBridgeSupport.m */; }; 4F43427C1420476C00AC1BFD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F43427B1420476C00AC1BFD /* main.m */; }; 56E07744170B028400FF0A4B /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 56E07743170B028400FF0A4B /* Default-568h@2x.png */; }; 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; @@ -233,6 +233,19 @@ }; /* End PBXContainerItemProxy section */ +/* Begin PBXCopyFilesBuildPhase section */ + 43B5D4001D36686B00D1E1FD /* Copy Files */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + name = "Copy Files"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 2217EBB61CCD89E60082837B /* NuMarkupOperator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuMarkupOperator.h; sourceTree = ""; }; @@ -308,9 +321,6 @@ 2217EC621CCDB2610082837B /* NSMethodSignature+Nu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMethodSignature+Nu.m"; sourceTree = ""; }; 2217EC661CCDBF390082837B /* NuBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuBridge.h; sourceTree = ""; }; 2217EC671CCDBF390082837B /* NuBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuBridge.m; sourceTree = ""; }; - 225F62BE13B04256002DD16B /* ffi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ffi.h; sourceTree = ""; }; - 225F62C413B04256002DD16B /* ffi.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = ffi.S; sourceTree = ""; }; - 225F62CA13B04256002DD16B /* ffi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ffi.c; sourceTree = ""; }; 22716B111CCDC9FD00E7ACDD /* NuBridgedFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuBridgedFunction.h; sourceTree = ""; }; 22716B121CCDC9FD00E7ACDD /* NuBridgedFunction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NuBridgedFunction.m; sourceTree = ""; }; 22716B161CCDCB6F00E7ACDD /* NuBridgedConstant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NuBridgedConstant.h; sourceTree = ""; }; @@ -396,6 +406,8 @@ 22EE2C0813A4731600895861 /* NuAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NuAppDelegate.h; sourceTree = ""; }; 22EE2C0913A4731600895861 /* NuAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NuAppDelegate.m; sourceTree = ""; }; 32DBCF5E0370ADEE00C91783 /* Nu_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Nu_Prefix.pch; sourceTree = ""; }; + 43B5D4021D36686B00D1E1FD /* libNuTouch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libNuTouch.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 43DCFCB21D369D8200CB6E63 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libffi.a; path = "../libffi/build/Debug-iphoneos/libffi.a"; sourceTree = ""; }; 4F43427B1420476C00AC1BFD /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ../main/main.m; sourceTree = ""; }; 56E07743170B028400FF0A4B /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -415,11 +427,20 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 43B5D4101D3668A600D1E1FD /* libNuTouch.a in Frameworks */, 22B3B50513B0388C00B3AB31 /* Foundation.framework in Frameworks */, 22B3B50313B0386600B3AB31 /* UIKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; + 43B5D3FF1D36686B00D1E1FD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 43DCFCB31D369D8200CB6E63 /* libffi.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8DC2EF560486A6940098B216 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -437,6 +458,7 @@ 8DC2EF5B0486A6940098B216 /* Nu.framework */, 2283073111DDBE3100A5C690 /* nush */, 22EE2BF413A4731600895861 /* NuApp.app */, + 43B5D4021D36686B00D1E1FD /* libNuTouch.a */, ); name = Products; sourceTree = ""; @@ -448,7 +470,6 @@ 22B3B41C13B0359300B3AB31 /* objc */, 22B3B3E413B033EE00B3AB31 /* nu */, 22B3B38713B033D400B3AB31 /* test */, - 225F62B913B04256002DD16B /* libffi */, 22B3B50B13B03CF400B3AB31 /* Targets */, 034768DFFF38A50411DB9C8B /* Products */, ); @@ -492,17 +513,6 @@ path = ..; sourceTree = ""; }; - 225F62B913B04256002DD16B /* libffi */ = { - isa = PBXGroup; - children = ( - 225F62BE13B04256002DD16B /* ffi.h */, - 225F62C413B04256002DD16B /* ffi.S */, - 225F62CA13B04256002DD16B /* ffi.c */, - ); - name = libffi; - path = ../libffi; - sourceTree = ""; - }; 22B3B38713B033D400B3AB31 /* test */ = { isa = PBXGroup; children = ( @@ -684,6 +694,7 @@ 22B3B50B13B03CF400B3AB31 /* Targets */ = { isa = PBXGroup; children = ( + 43DCFCB41D369D9400CB6E63 /* NuTouch */, 0867D69AFE84028FC02AAC07 /* Nu.framework */, 22B3B50913B03B6600B3AB31 /* nush */, 22EE2BFF13A4731600895861 /* NuApp */, @@ -713,6 +724,14 @@ name = "Supporting Files"; sourceTree = ""; }; + 43DCFCB41D369D9400CB6E63 /* NuTouch */ = { + isa = PBXGroup; + children = ( + 43DCFCB21D369D8200CB6E63 /* libffi.a */, + ); + name = NuTouch; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -800,6 +819,23 @@ productReference = 22EE2BF413A4731600895861 /* NuApp.app */; productType = "com.apple.product-type.application"; }; + 43B5D4011D36686B00D1E1FD /* NuTouch */ = { + isa = PBXNativeTarget; + buildConfigurationList = 43B5D4081D36686B00D1E1FD /* Build configuration list for PBXNativeTarget "NuTouch" */; + buildPhases = ( + 43DCFCB51D37934200CB6E63 /* Sources */, + 43B5D3FF1D36686B00D1E1FD /* Frameworks */, + 43B5D4001D36686B00D1E1FD /* Copy Files */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NuTouch; + productName = NuTouch; + productReference = 43B5D4021D36686B00D1E1FD /* libNuTouch.a */; + productType = "com.apple.product-type.library.static"; + }; 8DC2EF4F0486A6940098B216 /* Nu */ = { isa = PBXNativeTarget; buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "Nu" */; @@ -825,7 +861,12 @@ 0867D690FE84028FC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0450; + LastUpgradeCheck = 0720; + TargetAttributes = { + 43B5D4011D36686B00D1E1FD = { + CreatedOnToolsVersion = 7.2.1; + }; + }; }; buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "Nu" */; compatibilityVersion = "Xcode 3.2"; @@ -846,6 +887,7 @@ 8DC2EF4F0486A6940098B216 /* Nu */, 2283073011DDBE3100A5C690 /* nush */, 22EE2BF313A4731600895861 /* NuApp */, + 43B5D4011D36686B00D1E1FD /* NuTouch */, ); }; /* End PBXProject section */ @@ -963,51 +1005,56 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2217EBFC1CCDA27A0082837B /* NSObject+Nu.m in Sources */, - 2217EBBA1CCD8AAC0082837B /* NuMarkupOperator.m in Sources */, - 2217EBDE1CCD915B0082837B /* NuRegex.m in Sources */, - 2217EC331CCDAC600082837B /* NSBundle+Nu.m in Sources */, - 2217EC561CCDB0D40082837B /* NSData+Nu.m in Sources */, - 22716B1A1CCDCB6F00E7ACDD /* NuBridgedConstant.m in Sources */, 22EE2C0613A4731600895861 /* main.m in Sources */, - 2217EC061CCDA3870082837B /* NuMethod.m in Sources */, - 2217EBCA1CCD8DF00082837B /* NuSwizzles.m in Sources */, 22EE2C0A13A4731600895861 /* NuAppDelegate.m in Sources */, - 2217EC1F1CCDA8340082837B /* NuClass.m in Sources */, - 22B3B47413B0359300B3AB31 /* Nu.m in Sources */, - 2217EC651CCDB2610082837B /* NSMethodSignature+Nu.m in Sources */, - 2217EBE81CCD92AC0082837B /* NuProperty.m in Sources */, - 2217EBC51CCD8CE30082837B /* NuTestHelper.m in Sources */, - 2217EC6A1CCDBF390082837B /* NuBridge.m in Sources */, - 2217EC151CCDA65F0082837B /* NuBlock.m in Sources */, - 2217EC601CCDB19C0082837B /* NSFileManager+Nu.m in Sources */, - 2217EC2E1CCDAB700082837B /* NSDictionary+Nu.m in Sources */, - 2217EC5B1CCDB1240082837B /* NSDate+Nu.m in Sources */, - 2217EC381CCDAD3B0082837B /* NuEnumerable.m in Sources */, - 2217EBCF1CCD8E760082837B /* NuSuper.m in Sources */, - 22716B1F1CCDCC0F00E7ACDD /* NuBridgedBlock.m in Sources */, - 2217EBF21CCD9E7F0082837B /* NuPointer.m in Sources */, - 2217EC241CCDA9A00082837B /* NuMath.m in Sources */, - 2217EC011CCDA3300082837B /* NuObjCRuntime.m in Sources */, - 2217EBD41CCD8F960082837B /* NuStack.m in Sources */, - 225F62CD13B04256002DD16B /* ffi.S in Sources */, - 2217EBE31CCD921B0082837B /* NuReference.m in Sources */, - 2217EC4C1CCDAFE00082837B /* NSNull+Nu.m in Sources */, - 22716B241CCDCCD900E7ACDD /* NuBridgeSupport.m in Sources */, - 2217EBD91CCD90310082837B /* NuParser.m in Sources */, - 2217EC511CCDB0770082837B /* NSNumber+Nu.m in Sources */, - 2217EC0B1CCDA4990082837B /* NuMacro.m in Sources */, - 2217EBF71CCDA0420082837B /* NuOperators.m in Sources */, - 2217EC291CCDAA850082837B /* NSString+Nu.m in Sources */, - 2217EC3D1CCDAE010082837B /* NuException.m in Sources */, - 2217EBED1CCD9DFE0082837B /* NuProfiler.m in Sources */, - 2217EBC01CCD8BDF0082837B /* NuSymbol.m in Sources */, - 22716B151CCDC9FD00E7ACDD /* NuBridgedFunction.m in Sources */, - 225F62D313B04256002DD16B /* ffi.c in Sources */, - 2217EC471CCDAF2A0082837B /* NSSet+Nu.m in Sources */, - 2217EC421CCDAED00082837B /* NSArray+Nu.m in Sources */, - 2217EC1A1CCDA7350082837B /* NuCell.m in Sources */, - 2217EC101CCDA5390082837B /* NuHandler.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43DCFCB51D37934200CB6E63 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 43DCFCB91D37938100CB6E63 /* NSArray+Nu.m in Sources */, + 43DCFCBB1D37938100CB6E63 /* NSBundle+Nu.m in Sources */, + 43DCFCBD1D37938100CB6E63 /* NSData+Nu.m in Sources */, + 43DCFCBF1D37938100CB6E63 /* NSDate+Nu.m in Sources */, + 43DCFCC11D37938100CB6E63 /* NSDictionary+Nu.m in Sources */, + 43DCFCC31D37938100CB6E63 /* NSFileManager+Nu.m in Sources */, + 43DCFCC51D37938100CB6E63 /* NSMethodSignature+Nu.m in Sources */, + 43DCFCC71D37938200CB6E63 /* NSNull+Nu.m in Sources */, + 43DCFCC91D37938200CB6E63 /* NSNumber+Nu.m in Sources */, + 43DCFCCB1D37938200CB6E63 /* NSObject+Nu.m in Sources */, + 43DCFCCD1D37938200CB6E63 /* NSSet+Nu.m in Sources */, + 43DCFCCF1D37938200CB6E63 /* NSString+Nu.m in Sources */, + 43DCFCD11D37938200CB6E63 /* Nu.m in Sources */, + 43DCFCD31D37938200CB6E63 /* NuBlock.m in Sources */, + 43DCFCD51D37938200CB6E63 /* NuBridge.m in Sources */, + 43DCFCD71D37938200CB6E63 /* NuCell.m in Sources */, + 43DCFCD91D37938200CB6E63 /* NuClass.m in Sources */, + 43DCFCDB1D37938200CB6E63 /* NuEnumerable.m in Sources */, + 43DCFCDD1D37938200CB6E63 /* NuException.m in Sources */, + 43DCFCDF1D37938200CB6E63 /* NuHandler.m in Sources */, + 43DCFCE21D37938200CB6E63 /* NuMacro.m in Sources */, + 43DCFCE41D37938200CB6E63 /* NuMarkupOperator.m in Sources */, + 43DCFCE61D37938200CB6E63 /* NuMath.m in Sources */, + 43DCFCE81D37938200CB6E63 /* NuMethod.m in Sources */, + 43DCFCEA1D37938200CB6E63 /* NuObjCRuntime.m in Sources */, + 43DCFCEC1D37938200CB6E63 /* NuOperators.m in Sources */, + 43DCFCEE1D37938200CB6E63 /* NuParser.m in Sources */, + 43DCFCF01D37938200CB6E63 /* NuPointer.m in Sources */, + 43DCFCF21D37938200CB6E63 /* NuProfiler.m in Sources */, + 43DCFCF41D37938200CB6E63 /* NuProperty.m in Sources */, + 43DCFCF61D37938200CB6E63 /* NuReference.m in Sources */, + 43DCFCF81D37938200CB6E63 /* NuRegex.m in Sources */, + 43DCFCFA1D37938200CB6E63 /* NuStack.m in Sources */, + 43DCFCFC1D37938200CB6E63 /* NuSuper.m in Sources */, + 43DCFCFE1D37938200CB6E63 /* NuSwizzles.m in Sources */, + 43DCFD001D37938200CB6E63 /* NuSymbol.m in Sources */, + 43DCFD021D37938200CB6E63 /* NuTestHelper.m in Sources */, + 43DCFD041D37938200CB6E63 /* NuBridgedFunction.m in Sources */, + 43DCFD061D37938200CB6E63 /* NuBridgedConstant.m in Sources */, + 43DCFD081D37938200CB6E63 /* NuBridgedBlock.m in Sources */, + 43DCFD0A1D37938200CB6E63 /* NuBridgeSupport.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1112,6 +1159,7 @@ INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Library/Frameworks"; LIBRARY_SEARCH_PATHS = ""; + PRODUCT_BUNDLE_IDENTIFIER = nu.programming.framework; PRODUCT_NAME = Nu; WRAPPER_EXTENSION = framework; }; @@ -1138,6 +1186,7 @@ INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Library/Frameworks"; LIBRARY_SEARCH_PATHS = ""; + PRODUCT_BUNDLE_IDENTIFIER = nu.programming.framework; PRODUCT_NAME = Nu; WRAPPER_EXTENSION = framework; }; @@ -1146,7 +1195,7 @@ 1DEB91B208733DA50010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_GC = unsupported; GCC_OPTIMIZATION_LEVEL = 0; @@ -1171,7 +1220,6 @@ 1DEB91B308733DA50010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_GC = unsupported; GCC_PRECOMPILE_PREFIX_HEADER = NO; @@ -1241,7 +1289,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_ENABLE_OBJC_ARC = NO; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; @@ -1265,9 +1312,10 @@ "$(SRCROOT)/../objc", ); INFOPLIST_FILE = "NuApp/NuApp-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = "com.radtastical.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1279,7 +1327,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_ENABLE_OBJC_ARC = NO; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; @@ -1301,10 +1348,11 @@ "$(SRCROOT)/../objc", ); INFOPLIST_FILE = "NuApp/NuApp-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 5.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; LIBRARY_SEARCH_PATHS = "$(inherited)"; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; - OTHER_LDFLAGS = ""; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = "com.radtastical.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -1313,6 +1361,88 @@ }; name = Release; }; + 43B5D4091D36686B00D1E1FD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + HEADER_SEARCH_PATHS = ( + ../libffi/darwin_common/include, + ../libffi/darwin_ios/include, + ); + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 43B5D40A1D36686B00D1E1FD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + HEADER_SEARCH_PATHS = ( + ../libffi/darwin_common/include, + ../libffi/darwin_ios/include, + ); + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1352,6 +1482,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 43B5D4081D36686B00D1E1FD /* Build configuration list for PBXNativeTarget "NuTouch" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 43B5D4091D36686B00D1E1FD /* Debug */, + 43B5D40A1D36686B00D1E1FD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 0867D690FE84028FC02AAC07 /* Project object */; diff --git a/Xcode/NuApp/NuApp-Info.plist b/Xcode/NuApp/NuApp-Info.plist index 1c822bd..955a746 100644 --- a/Xcode/NuApp/NuApp-Info.plist +++ b/Xcode/NuApp/NuApp-Info.plist @@ -11,7 +11,7 @@ CFBundleIconFile CFBundleIdentifier - com.radtastical.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Xcode/NuApp/NuAppDelegate.m b/Xcode/NuApp/NuAppDelegate.m index 3d737b7..968d94c 100644 --- a/Xcode/NuApp/NuAppDelegate.m +++ b/Xcode/NuApp/NuAppDelegate.m @@ -10,16 +10,26 @@ #import "Nu.h" +#import + +@class ViewController; + @implementation NuAppDelegate @synthesize window; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; - self.window.backgroundColor = [UIColor greenColor]; - self.window.rootViewController = [[UIViewController alloc] init]; + CGRect frame = [[UIScreen mainScreen] bounds]; + self.window = [[[UIWindow alloc] initWithFrame:frame] autorelease]; [self.window makeKeyAndVisible]; - + UIViewController *viewController = [[UIViewController alloc] init]; + self.window.rootViewController = viewController; + UIView *view = [[UIView alloc] initWithFrame:frame]; + viewController.view = view; + UILabel *label = [[UILabel alloc] initWithFrame:frame]; + label.textAlignment = NSTextAlignmentCenter; + [view addSubview:label]; + NuInit(); [[Nu sharedParser] parseEval:@"(load \"nu\")"]; @@ -45,7 +55,14 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( } [regex release]; NSLog(@"running tests"); - [[Nu sharedParser] parseEval:@"(NuTestCase runAllTests)"]; + int failures = [[[Nu sharedParser] parseEval:@"(NuTestCase runAllTests)"] intValue]; + if (failures == 0) { + view.backgroundColor = [UIColor greenColor]; + label.text = @"Everything Nu!"; + } else { + view.backgroundColor = [UIColor redColor]; + label.text = [NSString stringWithFormat:@"%d failures!",failures]; + } NSLog(@"ok"); return YES; } diff --git a/libffi b/libffi new file mode 160000 index 0000000..5a3bf17 --- /dev/null +++ b/libffi @@ -0,0 +1 @@ +Subproject commit 5a3bf17e2b28cddfb48edb74c83f768c77f79912 diff --git a/libffi/LICENSE b/libffi/LICENSE deleted file mode 100644 index 064f4fa..0000000 --- a/libffi/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -libffi - Copyright (c) 1996-2008 Red Hat, Inc and others. -See source files for details. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -``Software''), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libffi/README.markdown b/libffi/README.markdown deleted file mode 100644 index cd44964..0000000 --- a/libffi/README.markdown +++ /dev/null @@ -1,28 +0,0 @@ -libffi for the iPhone -= - -**[libffi](http://sourceware.org/libffi/)** allows calling any C-function or ObjC method at runtime. - -**libffi-iphone** is a stripped down version of libffi, tailored just for the iPhone. **libffi-iphone** includes source code for both the iPhone simulator and the iPhone itself. - -Calling functions -- -Works just like libffi. - -Creating ffi closures, new functions created and called at runtime -- -ffi closures don't work on the iPhone, as mprotect is disabled. - -You can however retarget existing functions if you have a function pool. See [Tim Burks' post about Nu's method pool](http://stackoverflow.com/questions/219653/ruby-on-iphone), see [JSCocoa's Burks Pool](http://github.com/parmanoir/jscocoa/blob/master/JSCocoa/iPhone/BurksPool.m) for another implementation. - -To retarget an ObjC pool method, use the method's hidden _cmd argument (the current selector) and [self class]. This will tell you which method of which class is being called. - -License -- -**libffi-iphone** uses **libffi**'s license. - -Hey -- -Problems, questions
-Patrick Geiller
-[parmanoir@gmail.com](mailto:parmanoir@gmail.com) diff --git a/libffi/ffi.S b/libffi/ffi.S deleted file mode 100644 index c89514d..0000000 --- a/libffi/ffi.S +++ /dev/null @@ -1,759 +0,0 @@ -#import "TargetConditionals.h" - -/* This file is mangled from the original to compile using Apple's AS, not GAS */ -#if !TARGET_IPHONE_SIMULATOR - -#define __SOFTFP__ - -/* ----------------------------------------------------------------------- - sysv.S - Copyright (c) 1998, 2008 Red Hat, Inc. - - ARM Foreign Function Interface - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -#define LIBFFI_ASM -#include "ffi.h" -#ifdef HAVE_MACHINE_ASM_H -#include -#else -#ifdef __USER_LABEL_PREFIX__ -#define CONCAT1(a, b) CONCAT2(a, b) -#define CONCAT2(a, b) a ## b - -/* Use the right prefix for global labels. */ -#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) -#else -#define CNAME(x) x -#endif -#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): -#endif - -#ifdef __ELF__ -#define LSYM(x) .x -#else -#define LSYM(x) x -#endif - -/* We need a better way of testing for this, but for now, this is all - we can do. */ -@ This selects the minimum architecture level required. -#define __ARM_ARCH__ 3 - -#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) -# undef __ARM_ARCH__ -# define __ARM_ARCH__ 4 -#endif - -#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ - || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ - || defined(__ARM_ARCH_5TEJ__) -# undef __ARM_ARCH__ -# define __ARM_ARCH__ 5 -#endif - -#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ - || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ - || defined(__ARM_ARCH_6ZK__) -# undef __ARM_ARCH__ -# define __ARM_ARCH__ 6 -#endif - -#if __ARM_ARCH__ >= 5 -# define call_reg(x) blx x -#elif defined (__ARM_ARCH_4T__) -# define call_reg(x) mov lr, pc ; bx x -# if defined(__thumb__) || defined(__THUMB_INTERWORK__) -# define __INTERWORKING__ -# endif -#else -# define call_reg(x) mov lr, pc ; mov pc, x -#endif - -/* Conditionally compile unwinder directives. */ -#ifdef __ARM_EABI__ -#define UNWIND -#else -#define UNWIND @ -#endif - -/* -#if defined(__thumb__) && !defined(__THUMB_INTERWORK__) -.macro ARM_FUNC_START name - .text - .align 0 - .thumb - .thumb_func - ENTRY(\name) - bx pc - nop - .arm - UNWIND .fnstart -_L__\name: -.endm -#else -.macro ARM_FUNC_START name - .text - .align 0 - .arm - ENTRY(\name) - UNWIND .fnstart -.endm -#endif -*/ -/* -.macro RETLDM regs=, cond=, dirn=ia -#if defined (__INTERWORKING__) - .ifc "\regs","" - ldr\cond lr, [sp], #4 - .else - ldm\cond\dirn sp!, {\regs, lr} - .endif - bx\cond lr -#else - .ifc "\regs","" - ldr\cond pc, [sp], #4 - .else - ldm\cond\dirn sp!, {\regs, pc} - .endif -#endif -.endm -*/ - - @ r0: ffi_prep_args - @ r1: &ecif - @ r2: cif->bytes - @ r3: fig->flags - @ sp+0: ecif.rvalue - @ sp+4: fn - - .text - .align 4 - .globl _ffi_call_SYSV -_ffi_call_SYSV: - UNWIND .fnstart - @ Save registers - stmfd sp!, {r0-r3, fp, lr} - UNWIND .save {r0-r3, fp, lr} - mov fp, sp - - UNWIND .setfp fp, sp - - @ Make room for all of the new args. - sub sp, fp, r2 - - @ Place all of the ffi_prep_args in position - mov ip, r0 - mov r0, sp - @ r1 already set - - @ Call ffi_prep_args(stack, &ecif) - call_reg(ip) - - @ move first 4 parameters in registers - ldmia sp, {r0-r3} - - @ and adjust stack - ldr ip, [fp, #8] - cmp ip, #16 - movhs ip, #16 - add sp, sp, ip - - @ call (fn) (...) - ldr ip, [fp, #28] - call_reg(ip) - - @ Remove the space we pushed for the args - mov sp, fp - - @ Load r2 with the pointer to storage for the return value - ldr r2, [sp, #24] - - @ Load r3 with the return type code - ldr r3, [sp, #12] - - @ If the return value pointer is NULL, assume no return value. - cmp r2, #0 - beq LSYM(Lepilogue) - -@ return INT - cmp r3, #FFI_TYPE_INT -#ifdef __SOFTFP__ - cmpne r3, #FFI_TYPE_FLOAT -#endif - streq r0, [r2] - beq LSYM(Lepilogue) - - @ return INT64 - cmp r3, #FFI_TYPE_SINT64 -#ifdef __SOFTFP__ - cmpne r3, #FFI_TYPE_DOUBLE -#endif - stmiaeq r2, {r0, r1} - -#ifndef __SOFTFP__ - beq LSYM(Lepilogue) - -@ return FLOAT - cmp r3, #FFI_TYPE_FLOAT - stfeqs f0, [r2] - beq LSYM(Lepilogue) - -@ return DOUBLE or LONGDOUBLE - cmp r3, #FFI_TYPE_DOUBLE - stfeqd f0, [r2] -#endif - -LSYM(Lepilogue): - ldmia sp!, {r0-r3,fp, pc} - - -.ffi_call_SYSV_end: - UNWIND .fnend -// .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) - -/* - unsigned int FFI_HIDDEN - ffi_closure_SYSV_inner (closure, respp, args) - ffi_closure *closure; - void **respp; - void *args; -*/ - - .text - .align 0 - .globl _ffi_closure_SYSV -_ffi_closure_SYSV: - - UNWIND .pad #16 - add ip, sp, #16 - stmfd sp!, {ip, lr} - UNWIND .save {r0, lr} - add r2, sp, #8 -// .pad #16 - sub sp, sp, #16 - str sp, [sp, #8] - add r1, sp, #8 - bl _ffi_closure_SYSV_inner - - cmp r0, #FFI_TYPE_INT - beq .Lretint - - cmp r0, #FFI_TYPE_FLOAT -#ifdef __SOFTFP__ - beq .Lretint -#else - beq .Lretfloat -#endif - - cmp r0, #FFI_TYPE_DOUBLE -#ifdef __SOFTFP__ - beq .Lretlonglong -#else - beq .Lretdouble -#endif - - cmp r0, #FFI_TYPE_LONGDOUBLE -#ifdef __SOFTFP__ - beq .Lretlonglong -#else - beq .Lretlongdouble -#endif - - cmp r0, #FFI_TYPE_SINT64 - beq .Lretlonglong -.Lclosure_epilogue: - add sp, sp, #16 - ldmfd sp, {sp, pc} -.Lretint: - ldr r0, [sp] - b .Lclosure_epilogue -.Lretlonglong: - ldr r0, [sp] - ldr r1, [sp, #4] - b .Lclosure_epilogue - -#ifndef __SOFTFP__ -.Lretfloat: - ldfs f0, [sp] - b .Lclosure_epilogue -.Lretdouble: - ldfd f0, [sp] - b .Lclosure_epilogue -.Lretlongdouble: - ldfd f0, [sp] - b .Lclosure_epilogue -#endif - -.ffi_closure_SYSV_end: - UNWIND .fnend -// .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) - -#if defined __ELF__ && defined __linux__ - .section .note.GNU-stack,"",%progbits -#endif - - - -#endif - - -#if TARGET_IPHONE_SIMULATOR - -/* ----------------------------------------------------------------------- - darwin.S - Copyright (c) 1996, 1998, 2001, 2002, 2003, 2005 Red Hat, Inc. - Copyright (C) 2008 Free Software Foundation, Inc. - - X86 Foreign Function Interface - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -#ifndef __x86_64__ - -#define LIBFFI_ASM -#include "ffi.h" - -.text - -.globl _ffi_prep_args - - .align 4 -.globl _ffi_call_SYSV - -_ffi_call_SYSV: -.LFB1: - pushl %ebp -.LCFI0: - movl %esp,%ebp -.LCFI1: - subl $8,%esp - /* Make room for all of the new args. */ - movl 16(%ebp),%ecx - subl %ecx,%esp - - movl %esp,%eax - - /* Place all of the ffi_prep_args in position */ - subl $8,%esp - pushl 12(%ebp) - pushl %eax - call *8(%ebp) - - /* Return stack to previous state and call the function */ - addl $16,%esp - - call *28(%ebp) - - /* Load %ecx with the return type code */ - movl 20(%ebp),%ecx - - /* Protect %esi. We're going to pop it in the epilogue. */ - pushl %esi - - /* If the return value pointer is NULL, assume no return value. */ - cmpl $0,24(%ebp) - jne 0f - - /* Even if there is no space for the return value, we are - obliged to handle floating-point values. */ - cmpl $FFI_TYPE_FLOAT,%ecx - jne noretval - fstp %st(0) - - jmp epilogue -0: - .align 4 - call 1f -.Lstore_table: - .long noretval-.Lstore_table /* FFI_TYPE_VOID */ - .long retint-.Lstore_table /* FFI_TYPE_INT */ - .long retfloat-.Lstore_table /* FFI_TYPE_FLOAT */ - .long retdouble-.Lstore_table /* FFI_TYPE_DOUBLE */ - .long retlongdouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */ - .long retuint8-.Lstore_table /* FFI_TYPE_UINT8 */ - .long retsint8-.Lstore_table /* FFI_TYPE_SINT8 */ - .long retuint16-.Lstore_table /* FFI_TYPE_UINT16 */ - .long retsint16-.Lstore_table /* FFI_TYPE_SINT16 */ - .long retint-.Lstore_table /* FFI_TYPE_UINT32 */ - .long retint-.Lstore_table /* FFI_TYPE_SINT32 */ - .long retint64-.Lstore_table /* FFI_TYPE_UINT64 */ - .long retint64-.Lstore_table /* FFI_TYPE_SINT64 */ - .long retstruct-.Lstore_table /* FFI_TYPE_STRUCT */ - .long retint-.Lstore_table /* FFI_TYPE_POINTER */ - .long retstruct1b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_1B */ - .long retstruct2b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_2B */ -1: - pop %esi - add (%esi, %ecx, 4), %esi - jmp *%esi - - /* Sign/zero extend as appropriate. */ -retsint8: - movsbl %al, %eax - jmp retint - -retsint16: - movswl %ax, %eax - jmp retint - -retuint8: - movzbl %al, %eax - jmp retint - -retuint16: - movzwl %ax, %eax - jmp retint - -retfloat: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - fstps (%ecx) - jmp epilogue - -retdouble: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - fstpl (%ecx) - jmp epilogue - -retlongdouble: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - fstpt (%ecx) - jmp epilogue - -retint64: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - movl %eax,0(%ecx) - movl %edx,4(%ecx) - jmp epilogue - -retstruct1b: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - movb %al,0(%ecx) - jmp epilogue - -retstruct2b: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - movw %ax,0(%ecx) - jmp epilogue - -retint: - /* Load %ecx with the pointer to storage for the return value */ - movl 24(%ebp),%ecx - movl %eax,0(%ecx) - -retstruct: - /* Nothing to do! */ - -noretval: -epilogue: - popl %esi - movl %ebp,%esp - popl %ebp - ret - -.LFE1: -.ffi_call_SYSV_end: - - .align 4 -FFI_HIDDEN (ffi_closure_SYSV) -.globl _ffi_closure_SYSV - -_ffi_closure_SYSV: -.LFB2: - pushl %ebp -.LCFI2: - movl %esp, %ebp -.LCFI3: - subl $40, %esp - leal -24(%ebp), %edx - movl %edx, -12(%ebp) /* resp */ - leal 8(%ebp), %edx - movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */ - leal -12(%ebp), %edx - movl %edx, (%esp) /* &resp */ - movl %ebx, 8(%esp) -.LCFI7: - call L_ffi_closure_SYSV_inner$stub - movl 8(%esp), %ebx - movl -12(%ebp), %ecx - cmpl $FFI_TYPE_INT, %eax - je .Lcls_retint - - /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, - FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ - cmpl $FFI_TYPE_UINT64, %eax - jge 0f - cmpl $FFI_TYPE_UINT8, %eax - jge .Lcls_retint - -0: cmpl $FFI_TYPE_FLOAT, %eax - je .Lcls_retfloat - cmpl $FFI_TYPE_DOUBLE, %eax - je .Lcls_retdouble - cmpl $FFI_TYPE_LONGDOUBLE, %eax - je .Lcls_retldouble - cmpl $FFI_TYPE_SINT64, %eax - je .Lcls_retllong - cmpl $FFI_TYPE_SMALL_STRUCT_1B, %eax - je .Lcls_retstruct1b - cmpl $FFI_TYPE_SMALL_STRUCT_2B, %eax - je .Lcls_retstruct2b - cmpl $FFI_TYPE_STRUCT, %eax - je .Lcls_retstruct -.Lcls_epilogue: - movl %ebp, %esp - popl %ebp - ret -.Lcls_retint: - movl (%ecx), %eax - jmp .Lcls_epilogue -.Lcls_retfloat: - flds (%ecx) - jmp .Lcls_epilogue -.Lcls_retdouble: - fldl (%ecx) - jmp .Lcls_epilogue -.Lcls_retldouble: - fldt (%ecx) - jmp .Lcls_epilogue -.Lcls_retllong: - movl (%ecx), %eax - movl 4(%ecx), %edx - jmp .Lcls_epilogue -.Lcls_retstruct1b: - movsbl (%ecx), %eax - jmp .Lcls_epilogue -.Lcls_retstruct2b: - movswl (%ecx), %eax - jmp .Lcls_epilogue -.Lcls_retstruct: - lea -8(%ebp),%esp - movl %ebp, %esp - popl %ebp - ret $4 -.LFE2: - - -#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3) -#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) -#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) -#define CIF_FLAGS_OFFSET 20 - - .align 4 -FFI_HIDDEN (ffi_closure_raw_SYSV) -.globl _ffi_closure_raw_SYSV - -_ffi_closure_raw_SYSV: -.LFB3: - pushl %ebp -.LCFI4: - movl %esp, %ebp -.LCFI5: - pushl %esi -.LCFI6: - subl $36, %esp - movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */ - movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */ - movl %edx, 12(%esp) /* user_data */ - leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */ - movl %edx, 8(%esp) /* raw_args */ - leal -24(%ebp), %edx - movl %edx, 4(%esp) /* &res */ - movl %esi, (%esp) /* cif */ - call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */ - movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */ - cmpl $FFI_TYPE_INT, %eax - je .Lrcls_retint - - /* Handle FFI_TYPE_UINT8, FFI_TYPE_SINT8, FFI_TYPE_UINT16, - FFI_TYPE_SINT16, FFI_TYPE_UINT32, FFI_TYPE_SINT32. */ - cmpl $FFI_TYPE_UINT64, %eax - jge 0f - cmpl $FFI_TYPE_UINT8, %eax - jge .Lrcls_retint -0: - cmpl $FFI_TYPE_FLOAT, %eax - je .Lrcls_retfloat - cmpl $FFI_TYPE_DOUBLE, %eax - je .Lrcls_retdouble - cmpl $FFI_TYPE_LONGDOUBLE, %eax - je .Lrcls_retldouble - cmpl $FFI_TYPE_SINT64, %eax - je .Lrcls_retllong -.Lrcls_epilogue: - addl $36, %esp - popl %esi - popl %ebp - ret -.Lrcls_retint: - movl -24(%ebp), %eax - jmp .Lrcls_epilogue -.Lrcls_retfloat: - flds -24(%ebp) - jmp .Lrcls_epilogue -.Lrcls_retdouble: - fldl -24(%ebp) - jmp .Lrcls_epilogue -.Lrcls_retldouble: - fldt -24(%ebp) - jmp .Lrcls_epilogue -.Lrcls_retllong: - movl -24(%ebp), %eax - movl -20(%ebp), %edx - jmp .Lrcls_epilogue -.LFE3: - -.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5 -L_ffi_closure_SYSV_inner$stub: - .indirect_symbol _ffi_closure_SYSV_inner - hlt ; hlt ; hlt ; hlt ; hlt - - -.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support -EH_frame1: - .set L$set$0,LECIE1-LSCIE1 - .long L$set$0 -LSCIE1: - .long 0x0 - .byte 0x1 - .ascii "zR\0" - .byte 0x1 - .byte 0x7c - .byte 0x8 - .byte 0x1 - .byte 0x10 - .byte 0xc - .byte 0x5 - .byte 0x4 - .byte 0x88 - .byte 0x1 - .align 2 -LECIE1: -.globl _ffi_call_SYSV.eh -_ffi_call_SYSV.eh: -LSFDE1: - .set L$set$1,LEFDE1-LASFDE1 - .long L$set$1 -LASFDE1: - .long LASFDE1-EH_frame1 - .long .LFB1-. - .set L$set$2,.LFE1-.LFB1 - .long L$set$2 - .byte 0x0 - .byte 0x4 - .set L$set$3,.LCFI0-.LFB1 - .long L$set$3 - .byte 0xe - .byte 0x8 - .byte 0x84 - .byte 0x2 - .byte 0x4 - .set L$set$4,.LCFI1-.LCFI0 - .long L$set$4 - .byte 0xd - .byte 0x4 - .align 2 -LEFDE1: -.globl _ffi_closure_SYSV.eh -_ffi_closure_SYSV.eh: -LSFDE2: - .set L$set$5,LEFDE2-LASFDE2 - .long L$set$5 -LASFDE2: - .long LASFDE2-EH_frame1 - .long .LFB2-. - .set L$set$6,.LFE2-.LFB2 - .long L$set$6 - .byte 0x0 - .byte 0x4 - .set L$set$7,.LCFI2-.LFB2 - .long L$set$7 - .byte 0xe - .byte 0x8 - .byte 0x84 - .byte 0x2 - .byte 0x4 - .set L$set$8,.LCFI3-.LCFI2 - .long L$set$8 - .byte 0xd - .byte 0x4 - .align 2 -LEFDE2: - -.globl _ffi_closure_raw_SYSV.eh -_ffi_closure_raw_SYSV.eh: -LSFDE3: - .set L$set$10,LEFDE3-LASFDE3 - .long L$set$10 -LASFDE3: - .long LASFDE3-EH_frame1 - .long .LFB3-. - .set L$set$11,.LFE3-.LFB3 - .long L$set$11 - .byte 0x0 - .byte 0x4 - .set L$set$12,.LCFI4-.LFB3 - .long L$set$12 - .byte 0xe - .byte 0x8 - .byte 0x84 - .byte 0x2 - .byte 0x4 - .set L$set$13,.LCFI5-.LCFI4 - .long L$set$13 - .byte 0xd - .byte 0x4 - .byte 0x4 - .set L$set$14,.LCFI6-.LCFI5 - .long L$set$14 - .byte 0x85 - .byte 0x3 - .align 2 -LEFDE3: - -#endif /* ifndef __x86_64__ */ - -#endif \ No newline at end of file diff --git a/libffi/ffi.c b/libffi/ffi.c deleted file mode 100644 index bb22942..0000000 --- a/libffi/ffi.c +++ /dev/null @@ -1,1257 +0,0 @@ -/* ----------------------------------------------------------------------- - types.c - Copyright (c) 1996, 1998 Red Hat, Inc. - - Predefined ffi_types needed by libffi. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -/* Hide the basic type definitions from the header file, so that we - can redefine them here as "const". */ -#define LIBFFI_HIDE_BASIC_TYPES - -#include "ffi.h" -#include -#include - -/* ----------------------------------------------------------------------- - ffi_common.h - Copyright (c) 1996 Red Hat, Inc. - Copyright (C) 2007 Free Software Foundation, Inc - - Common internal definitions and macros. Only necessary for building - libffi. - ----------------------------------------------------------------------- */ - -#ifdef __cplusplus -extern "C" { -#endif - -void bcopy(const void *s1, void *s2, size_t n); -#define memcpy(d, s, n) bcopy ((s), (d), (n)) - -#if defined(FFI_DEBUG) -#include -#endif - -#ifdef FFI_DEBUG - void ffi_assert(char *expr, char *file, int line); - void ffi_stop_here(void); - void ffi_type_test(ffi_type *a, char *file, int line); - -#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) -#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) -#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) -#else -#define FFI_ASSERT(x) -#define FFI_ASSERT_AT(x, f, l) -#define FFI_ASSERT_VALID_TYPE(x) -#endif - -#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) -#define ALIGN_DOWN(v, a) (((size_t) (v)) & -a) - - /* Perform machine dependent cif processing */ - ffi_status ffi_prep_cif_machdep(ffi_cif *cif); - - /* Extended cif, used in callback from assembly routine */ - typedef struct - { - ffi_cif *cif; - void *rvalue; - void **avalue; - } extended_cif; - - /* Terse sized type definitions. */ - typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); - typedef signed int SINT8 __attribute__((__mode__(__QI__))); - typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); - typedef signed int SINT16 __attribute__((__mode__(__HI__))); - typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); - typedef signed int SINT32 __attribute__((__mode__(__SI__))); - typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); - typedef signed int SINT64 __attribute__((__mode__(__DI__))); - - typedef float FLOAT32; - - void ffi_prep_args(char *stack, extended_cif *ecif); - -#ifdef __cplusplus -} -#endif - -/* Type definitions */ - -#define FFI_TYPEDEF(name, type, id) \ -struct struct_align_##name { \ - char c; \ - type x; \ -}; \ -const ffi_type ffi_type_##name = { \ - sizeof(type), \ - offsetof(struct struct_align_##name, x), \ - id, NULL \ -} - -/* Size and alignment are fake here. They must not be 0. */ -const ffi_type ffi_type_void = { - 1, 1, FFI_TYPE_VOID, NULL -}; - -FFI_TYPEDEF(uint8, UINT8, FFI_TYPE_UINT8); -FFI_TYPEDEF(sint8, SINT8, FFI_TYPE_SINT8); -FFI_TYPEDEF(uint16, UINT16, FFI_TYPE_UINT16); -FFI_TYPEDEF(sint16, SINT16, FFI_TYPE_SINT16); -FFI_TYPEDEF(uint32, UINT32, FFI_TYPE_UINT32); -FFI_TYPEDEF(sint32, SINT32, FFI_TYPE_SINT32); -FFI_TYPEDEF(uint64, UINT64, FFI_TYPE_UINT64); -FFI_TYPEDEF(sint64, SINT64, FFI_TYPE_SINT64); -FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER); -FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT); -FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE); - -/* ----------------------------------------------------------------------- - raw_api.c - Copyright (c) 1999, 2008 Red Hat, Inc. - - Author: Kresten Krab Thorup - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -/* This file defines generic functions for use with the raw api. */ - -#include - -size_t -ffi_raw_size (ffi_cif *cif) -{ - size_t result = 0; - int i; - - ffi_type **at = cif->arg_types; - - for (i = cif->nargs-1; i >= 0; i--, at++) - { - if ((*at)->type == FFI_TYPE_STRUCT) - result += ALIGN (sizeof (void*), FFI_SIZEOF_ARG); - else - result += ALIGN ((*at)->size, FFI_SIZEOF_ARG); - } - - return result; -} - - -void -ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args) -{ - unsigned i; - ffi_type **tp = cif->arg_types; - - /* assume little endian */ - for (i = 0; i < cif->nargs; i++, tp++, args++) - { - if ((*tp)->type == FFI_TYPE_STRUCT) - { - *args = (raw++)->ptr; - } - else - { - *args = (void*) raw; - raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*); - } - } -} - -void -ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw) -{ - unsigned i; - ffi_type **tp = cif->arg_types; - - for (i = 0; i < cif->nargs; i++, tp++, args++) - { - switch ((*tp)->type) - { - case FFI_TYPE_UINT8: - (raw++)->uint = *(UINT8*) (*args); - break; - - case FFI_TYPE_SINT8: - (raw++)->sint = *(SINT8*) (*args); - break; - - case FFI_TYPE_UINT16: - (raw++)->uint = *(UINT16*) (*args); - break; - - case FFI_TYPE_SINT16: - (raw++)->sint = *(SINT16*) (*args); - break; - -#if FFI_SIZEOF_ARG >= 4 - case FFI_TYPE_UINT32: - (raw++)->uint = *(UINT32*) (*args); - break; - - case FFI_TYPE_SINT32: - (raw++)->sint = *(SINT32*) (*args); - break; -#endif - - case FFI_TYPE_STRUCT: - (raw++)->ptr = *args; - break; - - case FFI_TYPE_POINTER: - (raw++)->ptr = **(void***) args; - break; - - default: - memcpy ((void*) raw->data, (void*)*args, (*tp)->size); - raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; - } - } -} - -#if !FFI_NATIVE_RAW_API - - -/* This is a generic definition of ffi_raw_call, to be used if the - * native system does not provide a machine-specific implementation. - * Having this, allows code to be written for the raw API, without - * the need for system-specific code to handle input in that format; - * these following couple of functions will handle the translation forth - * and back automatically. */ - -void ffi_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *raw) -{ - void **avalue = (void**) alloca (cif->nargs * sizeof (void*)); - ffi_raw_to_ptrarray (cif, raw, avalue); - ffi_call (cif, fn, rvalue, avalue); -} - -#if FFI_CLOSURES /* base system provides closures */ - -static void -ffi_translate_args (ffi_cif *cif, void *rvalue, - void **avalue, void *user_data) -{ - ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif)); - ffi_raw_closure *cl = (ffi_raw_closure*)user_data; - - ffi_ptrarray_to_raw (cif, avalue, raw); - (*cl->fun) (cif, rvalue, raw, cl->user_data); -} - -ffi_status -ffi_prep_raw_closure_loc (ffi_raw_closure* cl, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data, - void *codeloc) -{ - ffi_status status; - - status = ffi_prep_closure_loc ((ffi_closure*) cl, - cif, - &ffi_translate_args, - codeloc, - codeloc); - if (status == FFI_OK) - { - cl->fun = fun; - cl->user_data = user_data; - } - - return status; -} - -#endif /* FFI_CLOSURES */ -#endif /* !FFI_NATIVE_RAW_API */ - -#if FFI_CLOSURES - -/* Again, here is the generic version of ffi_prep_raw_closure, which - * will install an intermediate "hub" for translation of arguments from - * the pointer-array format, to the raw format */ - -ffi_status -ffi_prep_raw_closure (ffi_raw_closure* cl, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data) -{ - return ffi_prep_raw_closure_loc (cl, cif, fun, user_data, cl); -} - -#endif /* FFI_CLOSURES */ - -/* ----------------------------------------------------------------------- - prep_cif.c - Copyright (c) 1996, 1998, 2007 Red Hat, Inc. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -/* Round up to FFI_SIZEOF_ARG. */ - -#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) - -/* Perform machine independent initialization of aggregate type - specifications. */ - -static ffi_status initialize_aggregate(ffi_type *arg) -{ - ffi_type **ptr; - - FFI_ASSERT(arg != NULL); - - FFI_ASSERT(arg->elements != NULL); - FFI_ASSERT(arg->size == 0); - FFI_ASSERT(arg->alignment == 0); - - ptr = &(arg->elements[0]); - - while ((*ptr) != NULL) - { - if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) - return FFI_BAD_TYPEDEF; - - /* Perform a sanity check on the argument type */ - FFI_ASSERT_VALID_TYPE(*ptr); - - arg->size = ALIGN(arg->size, (*ptr)->alignment); - arg->size += (*ptr)->size; - - arg->alignment = (arg->alignment > (*ptr)->alignment) ? - arg->alignment : (*ptr)->alignment; - - ptr++; - } - - /* Structure size includes tail padding. This is important for - structures that fit in one register on ABIs like the PowerPC64 - Linux ABI that right justify small structs in a register. - It's also needed for nested structure layout, for example - struct A { long a; char b; }; struct B { struct A x; char y; }; - should find y at an offset of 2*sizeof(long) and result in a - total size of 3*sizeof(long). */ - arg->size = ALIGN (arg->size, arg->alignment); - - if (arg->size == 0) - return FFI_BAD_TYPEDEF; - else - return FFI_OK; -} - -#ifndef __CRIS__ -/* The CRIS ABI specifies structure elements to have byte - alignment only, so it completely overrides this functions, - which assumes "natural" alignment and padding. */ - -/* Perform machine independent ffi_cif preparation, then call - machine dependent routine. */ - -ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, - ffi_type *rtype, ffi_type **atypes) -{ - unsigned bytes = 0; - unsigned int i; - ffi_type **ptr; - - FFI_ASSERT(cif != NULL); - FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); - - cif->abi = abi; - cif->arg_types = atypes; - cif->nargs = nargs; - cif->rtype = rtype; - - cif->flags = 0; - - /* Initialize the return type if necessary */ - if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) - return FFI_BAD_TYPEDEF; - - /* Perform a sanity check on the return type */ - FFI_ASSERT_VALID_TYPE(cif->rtype); - - /* x86-64 stack space allocation is handled in prep_machdep. */ -#if !defined __x86_64__ - /* Make space for the return structure pointer */ - if (cif->rtype->type == FFI_TYPE_STRUCT -#ifdef X86_DARWIN - && (cif->rtype->size > 8) -#endif - ) - bytes = STACK_ARG_SIZE(sizeof(void*)); -#endif - - for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) - { - - /* Initialize any uninitialized aggregate type definitions */ - if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) - return FFI_BAD_TYPEDEF; - - /* Perform a sanity check on the argument type, do this - check after the initialization. */ - FFI_ASSERT_VALID_TYPE(*ptr); - -#if !defined __x86_64__ - { - /* Add any padding if necessary */ - if (((*ptr)->alignment - 1) & bytes) - bytes = ALIGN(bytes, (*ptr)->alignment); - - bytes += STACK_ARG_SIZE((*ptr)->size); - } -#endif - } - - cif->bytes = bytes; - - /* Perform machine dependent cif processing */ - return ffi_prep_cif_machdep(cif); -} -#endif /* not __CRIS__ */ - -#if FFI_CLOSURES - -ffi_status -ffi_prep_closure (ffi_closure* closure, - ffi_cif* cif, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data) -{ - return ffi_prep_closure_loc (closure, cif, fun, user_data, closure); -} - -#endif - -#if !TARGET_IPHONE_SIMULATOR - -#ifdef __arm__ -extern void __clear_cache (void *beg, void *end); -#endif - -//extern void __clear_cache (void *start, void *end) { -// sys_icache_invalidate(start, end-start); -//} - -/* ----------------------------------------------------------------------- - ffi.c - Copyright (c) 1998, 2008 Red Hat, Inc. - - ARM Foreign Function Interface - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -/* ffi_prep_args is called by the assembly routine once stack space - has been allocated for the function's arguments */ - -void ffi_prep_args(char *stack, extended_cif *ecif) -{ - register unsigned int i; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; - - argp = stack; - - if ( ecif->cif->flags == FFI_TYPE_STRUCT ) { - *(void **) argp = ecif->rvalue; - argp += 4; - } - - p_argv = ecif->avalue; - - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - (i != 0); - i--, p_arg++) - { - size_t z; - - /* Align if necessary */ - if (((*p_arg)->alignment - 1) & (unsigned) argp) { - argp = (char *) ALIGN(argp, (*p_arg)->alignment); - } - - if ((*p_arg)->type == FFI_TYPE_STRUCT) - argp = (char *) ALIGN(argp, 4); - - z = (*p_arg)->size; - if (z < sizeof(int)) - { - z = sizeof(int); - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); - break; - - case FFI_TYPE_UINT8: - *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); - break; - - case FFI_TYPE_SINT16: - *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); - break; - - case FFI_TYPE_UINT16: - *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); - break; - - case FFI_TYPE_STRUCT: - memcpy(argp, *p_argv, (*p_arg)->size); - break; - - default: - FFI_ASSERT(0); - } - } - else if (z == sizeof(int)) - { - *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); - } - else - { - memcpy(argp, *p_argv, z); - } - p_argv++; - argp += z; - } - - return; -} - -/* Perform machine dependent cif processing */ -ffi_status ffi_prep_cif_machdep(ffi_cif *cif) -{ - /* Round the stack up to a multiple of 8 bytes. This isn't needed - everywhere, but it is on some platforms, and it doesn't harm anything - when it isn't needed. */ - cif->bytes = (cif->bytes + 7) & ~7; - - /* Set the return type flag */ - switch (cif->rtype->type) - { - case FFI_TYPE_VOID: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: - cif->flags = (unsigned) cif->rtype->type; - break; - - case FFI_TYPE_SINT64: - case FFI_TYPE_UINT64: - cif->flags = (unsigned) FFI_TYPE_SINT64; - break; - - case FFI_TYPE_STRUCT: - if (cif->rtype->size <= 4) - /* A Composite Type not larger than 4 bytes is returned in r0. */ - cif->flags = (unsigned)FFI_TYPE_INT; - else - /* A Composite Type larger than 4 bytes, or whose size cannot - be determined statically ... is stored in memory at an - address passed [in r0]. */ - cif->flags = (unsigned)FFI_TYPE_STRUCT; - break; - - default: - cif->flags = FFI_TYPE_INT; - break; - } - - return FFI_OK; -} - -extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, - unsigned, unsigned, unsigned *, void (*fn)(void)); - -void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) -{ - extended_cif ecif; - - int small_struct = (cif->flags == FFI_TYPE_INT - && cif->rtype->type == FFI_TYPE_STRUCT); - - ecif.cif = cif; - ecif.avalue = avalue; - - unsigned int temp; - - /* If the return value is a struct and we don't have a return */ - /* value address then we need to make one */ - - if ((rvalue == NULL) && - (cif->flags == FFI_TYPE_STRUCT)) - { - ecif.rvalue = alloca(cif->rtype->size); - } - else if (small_struct) - ecif.rvalue = &temp; - else - ecif.rvalue = rvalue; - - switch (cif->abi) - { - case FFI_SYSV: - ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, - fn); - - break; - default: - FFI_ASSERT(0); - break; - } - if (small_struct) - memcpy (rvalue, &temp, cif->rtype->size); -} - -/** private members **/ - -static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, - void** args, ffi_cif* cif); - -void ffi_closure_SYSV (ffi_closure *); - -/* This function is jumped to by the trampoline */ -unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *); - -unsigned int -ffi_closure_SYSV_inner (closure, respp, args) - ffi_closure *closure; - void **respp; - void *args; -{ - // our various things... - ffi_cif *cif; - void **arg_area; - - cif = closure->cif; - arg_area = (void**) alloca (cif->nargs * sizeof (void*)); - - /* this call will initialize ARG_AREA, such that each - * element in that array points to the corresponding - * value on the stack; and if the function returns - * a structure, it will re-set RESP to point to the - * structure return address. */ - - ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif); - - (closure->fun) (cif, *respp, arg_area, closure->user_data); - - return cif->flags; -} - -/*@-exportheader@*/ -static void -ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, - void **avalue, ffi_cif *cif) -/*@=exportheader@*/ -{ - register unsigned int i; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; - - argp = stack; - - if ( cif->flags == FFI_TYPE_STRUCT ) { - *rvalue = *(void **) argp; - argp += 4; - } - - p_argv = avalue; - - for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) - { - size_t z; - - size_t alignment = (*p_arg)->alignment; - if (alignment < 4) - alignment = 4; - /* Align if necessary */ - if ((alignment - 1) & (unsigned) argp) { - argp = (char *) ALIGN(argp, alignment); - } - - z = (*p_arg)->size; - - /* because we're little endian, this is what it turns into. */ - - *p_argv = (void*) argp; - - p_argv++; - argp += z; - } - - return; -} - -/* How to make a trampoline. */ - -#ifdef __arm__ - -// __clear_cache seems to be missing on iOS5, so we omit it. Danger, Will Robinson. - -#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ -({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ - unsigned int __fun = (unsigned int)(FUN); \ - unsigned int __ctx = (unsigned int)(CTX); \ - *(unsigned int*) &__tramp[0] = 0xe92d000f; /* stmfd sp!, {r0-r3} */ \ - *(unsigned int*) &__tramp[4] = 0xe59f0000; /* ldr r0, [pc] */ \ - *(unsigned int*) &__tramp[8] = 0xe59ff000; /* ldr pc, [pc] */ \ - *(unsigned int*) &__tramp[12] = __ctx; \ - *(unsigned int*) &__tramp[16] = __fun; \ - }) - -#else - -#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ -({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ - unsigned int __fun = (unsigned int)(FUN); \ - unsigned int __ctx = (unsigned int)(CTX); \ - *(unsigned int*) &__tramp[0] = 0xe92d000f; /* stmfd sp!, {r0-r3} */ \ - *(unsigned int*) &__tramp[4] = 0xe59f0000; /* ldr r0, [pc] */ \ - *(unsigned int*) &__tramp[8] = 0xe59ff000; /* ldr pc, [pc] */ \ - *(unsigned int*) &__tramp[12] = __ctx; \ - *(unsigned int*) &__tramp[16] = __fun; \ - __clear_cache((&__tramp[0]), (&__tramp[19])); \ -}) - -#endif - - -/* the cif must already be prep'ed */ - -ffi_status -ffi_prep_closure_loc (ffi_closure* closure, - ffi_cif* cif, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data, - void *codeloc) -{ - FFI_ASSERT (cif->abi == FFI_SYSV); - - FFI_INIT_TRAMPOLINE (&closure->tramp[0], \ - &ffi_closure_SYSV, \ - codeloc); - - closure->cif = cif; - closure->user_data = user_data; - closure->fun = fun; - - return FFI_OK; -} - -#endif - -#import "TargetConditionals.h" -#if TARGET_IPHONE_SIMULATOR - - -/* ----------------------------------------------------------------------- - ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc. - Copyright (c) 2002 Ranjit Mathew - Copyright (c) 2002 Bo Thorsen - Copyright (c) 2002 Roger Sayle - Copyright (C) 2008 Free Software Foundation, Inc. - - x86 Foreign Function Interface - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - ----------------------------------------------------------------------- */ - -#ifndef __x86_64__ - -/* ffi_prep_args is called by the assembly routine once stack space - has been allocated for the function's arguments */ - -void ffi_prep_args(char *stack, extended_cif *ecif) -{ - register unsigned int i; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; - - argp = stack; - - if (ecif->cif->flags == FFI_TYPE_STRUCT) - { - *(void **) argp = ecif->rvalue; - argp += 4; - } - - p_argv = ecif->avalue; - - for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; - i != 0; - i--, p_arg++) - { - size_t z; - - /* Align if necessary */ - if ((sizeof(int) - 1) & (unsigned) argp) - argp = (char *) ALIGN(argp, sizeof(int)); - - z = (*p_arg)->size; - if (z < sizeof(int)) - { - z = sizeof(int); - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); - break; - - case FFI_TYPE_UINT8: - *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); - break; - - case FFI_TYPE_SINT16: - *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); - break; - - case FFI_TYPE_UINT16: - *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); - break; - - case FFI_TYPE_SINT32: - *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv); - break; - - case FFI_TYPE_UINT32: - *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); - break; - - case FFI_TYPE_STRUCT: - *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); - break; - - default: - FFI_ASSERT(0); - } - } - else - { - memcpy(argp, *p_argv, z); - } - p_argv++; - argp += z; - } - - return; -} - -/* Perform machine dependent cif processing */ -ffi_status ffi_prep_cif_machdep(ffi_cif *cif) -{ - /* Set the return type flag */ - switch (cif->rtype->type) - { - case FFI_TYPE_VOID: -#ifdef X86 - case FFI_TYPE_STRUCT: -#endif -#if defined(X86) || defined(X86_DARWIN) - case FFI_TYPE_UINT8: - case FFI_TYPE_UINT16: - case FFI_TYPE_SINT8: - case FFI_TYPE_SINT16: -#endif - - case FFI_TYPE_SINT64: - case FFI_TYPE_FLOAT: - case FFI_TYPE_DOUBLE: -//## case FFI_TYPE_LONGDOUBLE: - cif->flags = (unsigned) cif->rtype->type; - break; - - case FFI_TYPE_UINT64: - cif->flags = FFI_TYPE_SINT64; - break; - -#ifndef X86 - case FFI_TYPE_STRUCT: - if (cif->rtype->size == 1) - { - cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */ - } - else if (cif->rtype->size == 2) - { - cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */ - } - else if (cif->rtype->size == 4) - { - cif->flags = FFI_TYPE_INT; /* same as int type */ - } - else if (cif->rtype->size == 8) - { - cif->flags = FFI_TYPE_SINT64; /* same as int64 type */ - } - else - { - cif->flags = FFI_TYPE_STRUCT; - } - break; -#endif - - default: - cif->flags = FFI_TYPE_INT; - break; - } - -#ifdef X86_DARWIN - cif->bytes = (cif->bytes + 15) & ~0xF; -#endif - - return FFI_OK; -} - -extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, - unsigned, unsigned, unsigned *, void (*fn)(void)); - - -void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) -{ - extended_cif ecif; - ecif.cif = cif; - ecif.avalue = avalue; - - /* If the return value is a struct and we don't have a return */ - /* value address then we need to make one */ - - if ((rvalue == NULL) && - (cif->flags == FFI_TYPE_STRUCT)) - { - ecif.rvalue = alloca(cif->rtype->size); - } - else - ecif.rvalue = rvalue; - - - switch (cif->abi) - { - case FFI_SYSV: - ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, - fn); - break; - default: - FFI_ASSERT(0); - break; - } -} - - -/** private members **/ - -static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, - void** args, ffi_cif* cif); -void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *) - __attribute__ ((regparm(1))); -unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *) - __attribute__ ((regparm(1))); -void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *) - __attribute__ ((regparm(1))); - -/* This function is jumped to by the trampoline */ - -unsigned int FFI_HIDDEN -ffi_closure_SYSV_inner (closure, respp, args) - ffi_closure *closure; - void **respp; - void *args; -{ - /* our various things... */ - ffi_cif *cif; - void **arg_area; - - cif = closure->cif; - arg_area = (void**) alloca (cif->nargs * sizeof (void*)); - - /* this call will initialize ARG_AREA, such that each - * element in that array points to the corresponding - * value on the stack; and if the function returns - * a structure, it will re-set RESP to point to the - * structure return address. */ - - ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif); - - (closure->fun) (cif, *respp, arg_area, closure->user_data); - - return cif->flags; -} - -static void -ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, - ffi_cif *cif) -{ - register unsigned int i; - register void **p_argv; - register char *argp; - register ffi_type **p_arg; - - argp = stack; - - if ( cif->flags == FFI_TYPE_STRUCT ) { - *rvalue = *(void **) argp; - argp += 4; - } - - p_argv = avalue; - - for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) - { - size_t z; - - /* Align if necessary */ - if ((sizeof(int) - 1) & (unsigned) argp) { - argp = (char *) ALIGN(argp, sizeof(int)); - } - - z = (*p_arg)->size; - - /* because we're little endian, this is what it turns into. */ - - *p_argv = (void*) argp; - - p_argv++; - argp += z; - } - - return; -} - -/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ - -#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ -({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ - unsigned int __fun = (unsigned int)(FUN); \ - unsigned int __ctx = (unsigned int)(CTX); \ - unsigned int __dis = __fun - (__ctx + 10); \ - *(unsigned char*) &__tramp[0] = 0xb8; \ - *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ - *(unsigned char *) &__tramp[5] = 0xe9; \ - *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \ - }) - -#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) \ -({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ - unsigned int __fun = (unsigned int)(FUN); \ - unsigned int __ctx = (unsigned int)(CTX); \ - unsigned int __dis = __fun - (__ctx + 10); \ - unsigned short __size = (unsigned short)(SIZE); \ - *(unsigned char*) &__tramp[0] = 0xb8; \ - *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ - *(unsigned char *) &__tramp[5] = 0xe8; \ - *(unsigned int*) &__tramp[6] = __dis; /* call __fun */ \ - *(unsigned char *) &__tramp[10] = 0xc2; \ - *(unsigned short*) &__tramp[11] = __size; /* ret __size */ \ - }) - -/* the cif must already be prep'ed */ - -ffi_status -ffi_prep_closure_loc (ffi_closure* closure, - ffi_cif* cif, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data, - void *codeloc) -{ - if (cif->abi == FFI_SYSV) - { - FFI_INIT_TRAMPOLINE (&closure->tramp[0], - &ffi_closure_SYSV, - (void*)codeloc); - } - else - { - return FFI_BAD_ABI; - } - - closure->cif = cif; - closure->user_data = user_data; - closure->fun = fun; - - return FFI_OK; -} - -/* ------- Native raw API support -------------------------------- */ - -ffi_status -ffi_prep_raw_closure_loc (ffi_raw_closure* closure, - ffi_cif* cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data, - void *codeloc) -{ - int i; - - if (cif->abi != FFI_SYSV) { - return FFI_BAD_ABI; - } - - // we currently don't support certain kinds of arguments for raw - // closures. This should be implemented by a separate assembly language - // routine, since it would require argument processing, something we - // don't do now for performance. - - for (i = cif->nargs-1; i >= 0; i--) - { - FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT); - FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE); - } - - - FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV, - codeloc); - - closure->cif = cif; - closure->user_data = user_data; - closure->fun = fun; - - return FFI_OK; -} - -static void -ffi_prep_args_raw(char *stack, extended_cif *ecif) -{ - memcpy (stack, ecif->avalue, ecif->cif->bytes); -} - -/* we borrow this routine from libffi (it must be changed, though, to - * actually call the function passed in the first argument. as of - * libffi-1.20, this is not the case.) - */ - -extern void -ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *, unsigned, - unsigned, unsigned *, void (*fn)(void)); - -void -ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue) -{ - extended_cif ecif; - void **avalue = (void **)fake_avalue; - - ecif.cif = cif; - ecif.avalue = avalue; - - /* If the return value is a struct and we don't have a return */ - /* value address then we need to make one */ - - if ((rvalue == NULL) && - (cif->rtype->type == FFI_TYPE_STRUCT)) - { - ecif.rvalue = alloca(cif->rtype->size); - } - else - ecif.rvalue = rvalue; - - - switch (cif->abi) - { - case FFI_SYSV: - ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags, - ecif.rvalue, fn); - break; - default: - FFI_ASSERT(0); - break; - } -} - -#endif /* __x86_64__ */ - -#endif \ No newline at end of file diff --git a/libffi/ffi.h b/libffi/ffi.h deleted file mode 100644 index c9c5042..0000000 --- a/libffi/ffi.h +++ /dev/null @@ -1,952 +0,0 @@ -#include "TargetConditionals.h" - -/* Define this if you want extra debugging. */ -#undef FFI_DEBUG - -#ifdef LIBFFI_ASM -#define FFI_HIDDEN(name) -#else -#define FFI_HIDDEN -#endif - -#if defined (X86_64) && defined (__i386__) -#undef X86_64 -#define X86 -#endif - -#if TARGET_IPHONE_SIMULATOR - -/* -----------------------------------------------------------------*-C-*- - ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. - Copyright (C) 2008 Free Software Foundation, Inc. - - Target configuration macros for x86 and x86-64. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - ----------------------------------------------------------------------- */ - -#ifndef LIBFFI_TARGET_H -#define LIBFFI_TARGET_H - -/* ---- System specific configurations ----------------------------------- */ - -#if defined (X86_64) && defined (__i386__) -#undef X86_64 -#define X86 -#endif - -/* ---- Generic type definitions ----------------------------------------- */ - -#ifndef LIBFFI_ASM -typedef unsigned long ffi_arg; -typedef signed long ffi_sarg; - -typedef enum ffi_abi { - FFI_FIRST_ABI = 0, - - /* ---- Intel x86 and AMD x86-64 - */ -#if (defined(__i386__) || defined(__x86_64__)) - FFI_SYSV, - FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */ -#ifdef __i386__ - FFI_DEFAULT_ABI = FFI_SYSV, -#else - FFI_DEFAULT_ABI = FFI_UNIX64, -#endif -#endif - - FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 -} ffi_abi; -#endif - -/* ---- Definitions for closures ----------------------------------------- */ - -#define FFI_CLOSURES 1 -#define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1) -#define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2) - -#if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN)) -#define FFI_TRAMPOLINE_SIZE 24 -#define FFI_NATIVE_RAW_API 0 -#else -#define FFI_TRAMPOLINE_SIZE 10 -#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ -#endif - -#endif - - - -#else - - -/* -----------------------------------------------------------------*-C-*- - ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. - Target configuration macros for ARM. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - ----------------------------------------------------------------------- */ - -#ifndef LIBFFI_TARGET_H -#define LIBFFI_TARGET_H - -#ifndef LIBFFI_ASM -typedef unsigned long ffi_arg; -typedef signed long ffi_sarg; - -typedef enum ffi_abi { - FFI_FIRST_ABI = 0, - FFI_SYSV, - FFI_DEFAULT_ABI = FFI_SYSV, - FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 -} ffi_abi; -#endif - -/* ---- Definitions for closures ----------------------------------------- */ - -#define FFI_CLOSURES 1 -#define FFI_TRAMPOLINE_SIZE 20 -#define FFI_NATIVE_RAW_API 0 - -#endif - - - -#endif - - - - - -#if TARGET_IPHONE_SIMULATOR - -/* -----------------------------------------------------------------*-C-*- - libffi @VERSION@ - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - ----------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------- - The basic API is described in the README file. - - The raw API is designed to bypass some of the argument packing - and unpacking on architectures for which it can be avoided. - - The closure API allows interpreted functions to be packaged up - inside a C function pointer, so that they can be called as C functions, - with no understanding on the client side that they are interpreted. - It can also be used in other cases in which it is necessary to package - up a user specified parameter and a function pointer as a single - function pointer. - - The closure API must be implemented in order to get its functionality, - e.g. for use by gij. Routines are provided to emulate the raw API - if the underlying platform doesn't allow faster implementation. - - More details on the raw and cloure API can be found in: - - http://gcc.gnu.org/ml/java/1999-q3/msg00138.html - - and - - http://gcc.gnu.org/ml/java/1999-q3/msg00174.html - -------------------------------------------------------------------- */ - -#ifndef LIBFFI_H -#define LIBFFI_H - -#ifdef __cplusplus -extern "C" { -#endif - - /* Specify which architecture libffi is configured for. */ -#ifndef X86_DARWIN -#define X86_DARWIN -#endif - - /* ---- System configuration information --------------------------------- */ - - -#ifndef LIBFFI_ASM - -#include -#include - - /* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). - But we can find it either under the correct ANSI name, or under GNU - C's internal name. */ -#ifdef LONG_LONG_MAX -# define FFI_LONG_LONG_MAX LONG_LONG_MAX -#else -# ifdef LLONG_MAX -# define FFI_LONG_LONG_MAX LLONG_MAX -# else -# ifdef __GNUC__ -# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ -# endif -# endif -#endif - - /* The closure code assumes that this works on pointers, i.e. a size_t */ - /* can hold a pointer. */ - - typedef struct _ffi_type - { - size_t size; - unsigned short alignment; - unsigned short type; - struct _ffi_type **elements; - } ffi_type; - -#ifndef LIBFFI_HIDE_BASIC_TYPES -#if SCHAR_MAX == 127 -# define ffi_type_uchar ffi_type_uint8 -# define ffi_type_schar ffi_type_sint8 -#else -#error "char size not supported" -#endif - -#if SHRT_MAX == 32767 -# define ffi_type_ushort ffi_type_uint16 -# define ffi_type_sshort ffi_type_sint16 -#elif SHRT_MAX == 2147483647 -# define ffi_type_ushort ffi_type_uint32 -# define ffi_type_sshort ffi_type_sint32 -#else -#error "short size not supported" -#endif - -#if INT_MAX == 32767 -# define ffi_type_uint ffi_type_uint16 -# define ffi_type_sint ffi_type_sint16 -#elif INT_MAX == 2147483647 -# define ffi_type_uint ffi_type_uint32 -# define ffi_type_sint ffi_type_sint32 -#elif INT_MAX == 9223372036854775807 -# define ffi_type_uint ffi_type_uint64 -# define ffi_type_sint ffi_type_sint64 -#else -#error "int size not supported" -#endif - -#if LONG_MAX == 2147483647 -# if FFI_LONG_LONG_MAX != 9223372036854775807 -#error "no 64-bit data type supported" -# endif -#elif LONG_MAX != 9223372036854775807 -#error "long size not supported" -#endif - -#if LONG_MAX == 2147483647 -# define ffi_type_ulong ffi_type_uint32 -# define ffi_type_slong ffi_type_sint32 -#elif LONG_MAX == 9223372036854775807 -# define ffi_type_ulong ffi_type_uint64 -# define ffi_type_slong ffi_type_sint64 -#else -#error "long size not supported" -#endif - - /* These are defined in types.c */ - extern ffi_type ffi_type_void; - extern ffi_type ffi_type_uint8; - extern ffi_type ffi_type_sint8; - extern ffi_type ffi_type_uint16; - extern ffi_type ffi_type_sint16; - extern ffi_type ffi_type_uint32; - extern ffi_type ffi_type_sint32; - extern ffi_type ffi_type_uint64; - extern ffi_type ffi_type_sint64; - extern ffi_type ffi_type_float; - extern ffi_type ffi_type_double; - extern ffi_type ffi_type_pointer; - -#if 1 /* @HAVE_LONG_DOUBLE@ */ - extern ffi_type ffi_type_longdouble; -#else -#define ffi_type_longdouble ffi_type_double -#endif -#endif /* LIBFFI_HIDE_BASIC_TYPES */ - - typedef enum { - FFI_OK = 0, - FFI_BAD_TYPEDEF, - FFI_BAD_ABI - } ffi_status; - - typedef unsigned FFI_TYPE; - - typedef struct { - ffi_abi abi; - unsigned nargs; - ffi_type **arg_types; - ffi_type *rtype; - unsigned bytes; - unsigned flags; -#ifdef FFI_EXTRA_CIF_FIELDS - FFI_EXTRA_CIF_FIELDS; -#endif - } ffi_cif; - - /* ---- Definitions for the raw API -------------------------------------- */ - -#ifndef FFI_SIZEOF_ARG -# if LONG_MAX == 2147483647 -# define FFI_SIZEOF_ARG 4 -# elif LONG_MAX == 9223372036854775807 -# define FFI_SIZEOF_ARG 8 -# endif -#endif - -#ifndef FFI_SIZEOF_JAVA_RAW -# define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG -#endif - - typedef union { - ffi_sarg sint; - ffi_arg uint; - float flt; - char data[FFI_SIZEOF_ARG]; - void* ptr; - } ffi_raw; - -#if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8 - /* This is a special case for mips64/n32 ABI (and perhaps others) where - sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */ - typedef union { - signed int sint; - unsigned int uint; - float flt; - char data[FFI_SIZEOF_JAVA_RAW]; - void* ptr; - } ffi_java_raw; -#else - typedef ffi_raw ffi_java_raw; -#endif - - - void ffi_raw_call (ffi_cif *cif, - void (*fn)(void), - void *rvalue, - ffi_raw *avalue); - - void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); - void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); - size_t ffi_raw_size (ffi_cif *cif); - - /* This is analogous to the raw API, except it uses Java parameter */ - /* packing, even on 64-bit machines. I.e. on 64-bit machines */ - /* longs and doubles are followed by an empty 64-bit word. */ - - void ffi_java_raw_call (ffi_cif *cif, - void (*fn)(void), - void *rvalue, - ffi_java_raw *avalue); - - void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw); - void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args); - size_t ffi_java_raw_size (ffi_cif *cif); - - /* ---- Definitions for closures ----------------------------------------- */ - -#if FFI_CLOSURES - - typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - ffi_cif *cif; - void (*fun)(ffi_cif*,void*,void**,void*); - void *user_data; - } ffi_closure __attribute__((aligned (8))); - - void *ffi_closure_alloc (size_t size, void **code); - void ffi_closure_free (void *); - - ffi_status - ffi_prep_closure (ffi_closure*, - ffi_cif *, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data); - - ffi_status - ffi_prep_closure_loc (ffi_closure*, - ffi_cif *, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data, - void*codeloc); - - typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - - ffi_cif *cif; - -#if !FFI_NATIVE_RAW_API - - /* if this is enabled, then a raw closure has the same layout - as a regular closure. We use this to install an intermediate - handler to do the transaltion, void** -> ffi_raw*. */ - - void (*translate_args)(ffi_cif*,void*,void**,void*); - void *this_closure; - -#endif - - void (*fun)(ffi_cif*,void*,ffi_raw*,void*); - void *user_data; - - } ffi_raw_closure; - - typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - - ffi_cif *cif; - -#if !FFI_NATIVE_RAW_API - - /* if this is enabled, then a raw closure has the same layout - as a regular closure. We use this to install an intermediate - handler to do the transaltion, void** -> ffi_raw*. */ - - void (*translate_args)(ffi_cif*,void*,void**,void*); - void *this_closure; - -#endif - - void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*); - void *user_data; - - } ffi_java_raw_closure; - - ffi_status - ffi_prep_raw_closure (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data); - - ffi_status - ffi_prep_raw_closure_loc (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data, - void *codeloc); - - ffi_status - ffi_prep_java_raw_closure (ffi_java_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), - void *user_data); - - ffi_status - ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), - void *user_data, - void *codeloc); - -#endif /* FFI_CLOSURES */ - - /* ---- Public interface definition -------------------------------------- */ - - ffi_status ffi_prep_cif(ffi_cif *cif, - ffi_abi abi, - unsigned int nargs, - ffi_type *rtype, - ffi_type **atypes); - - void ffi_call(ffi_cif *cif, - void (*fn)(void), - void *rvalue, - void **avalue); - - /* Useful for eliminating compiler warnings */ -#define FFI_FN(f) ((void (*)(void))f) - - /* ---- Definitions shared with assembly code ---------------------------- */ - -#endif - - /* If these change, update src/mips/ffitarget.h. */ -#define FFI_TYPE_VOID 0 -#define FFI_TYPE_INT 1 -#define FFI_TYPE_FLOAT 2 -#define FFI_TYPE_DOUBLE 3 -#if 0 /* @HAVE_LONG_DOUBLE@ */ -#define FFI_TYPE_LONGDOUBLE 4 -#else -#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE -#endif -#define FFI_TYPE_UINT8 5 -#define FFI_TYPE_SINT8 6 -#define FFI_TYPE_UINT16 7 -#define FFI_TYPE_SINT16 8 -#define FFI_TYPE_UINT32 9 -#define FFI_TYPE_SINT32 10 -#define FFI_TYPE_UINT64 11 -#define FFI_TYPE_SINT64 12 -#define FFI_TYPE_STRUCT 13 -#define FFI_TYPE_POINTER 14 - - /* This should always refer to the last type code (for sanity checks) */ -#define FFI_TYPE_LAST FFI_TYPE_POINTER - -#ifdef __cplusplus -} -#endif - -#endif - - - -#else - -/* -----------------------------------------------------------------*-C-*- - libffi @VERSION@ - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - ``Software''), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. - - ----------------------------------------------------------------------- */ - -/* ------------------------------------------------------------------- - The basic API is described in the README file. - - The raw API is designed to bypass some of the argument packing - and unpacking on architectures for which it can be avoided. - - The closure API allows interpreted functions to be packaged up - inside a C function pointer, so that they can be called as C functions, - with no understanding on the client side that they are interpreted. - It can also be used in other cases in which it is necessary to package - up a user specified parameter and a function pointer as a single - function pointer. - - The closure API must be implemented in order to get its functionality, - e.g. for use by gij. Routines are provided to emulate the raw API - if the underlying platform doesn't allow faster implementation. - - More details on the raw and cloure API can be found in: - - http://gcc.gnu.org/ml/java/1999-q3/msg00138.html - - and - - http://gcc.gnu.org/ml/java/1999-q3/msg00174.html - -------------------------------------------------------------------- */ - -#ifndef LIBFFI_H -#define LIBFFI_H - -#ifdef __cplusplus -extern "C" { -#endif - - /* Specify which architecture libffi is configured for. */ -#ifndef armv6 -#define armv6 -#endif - - /* ---- System configuration information --------------------------------- */ - - -#ifndef LIBFFI_ASM - -#include -#include - - /* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). - But we can find it either under the correct ANSI name, or under GNU - C's internal name. */ -#ifdef LONG_LONG_MAX -# define FFI_LONG_LONG_MAX LONG_LONG_MAX -#else -# ifdef LLONG_MAX -# define FFI_LONG_LONG_MAX LLONG_MAX -# else -# ifdef __GNUC__ -# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ -# endif -# endif -#endif - - /* The closure code assumes that this works on pointers, i.e. a size_t */ - /* can hold a pointer. */ - - typedef struct _ffi_type - { - size_t size; - unsigned short alignment; - unsigned short type; - struct _ffi_type **elements; - } ffi_type; - -#ifndef LIBFFI_HIDE_BASIC_TYPES -#if SCHAR_MAX == 127 -# define ffi_type_uchar ffi_type_uint8 -# define ffi_type_schar ffi_type_sint8 -#else -#error "char size not supported" -#endif - -#if SHRT_MAX == 32767 -# define ffi_type_ushort ffi_type_uint16 -# define ffi_type_sshort ffi_type_sint16 -#elif SHRT_MAX == 2147483647 -# define ffi_type_ushort ffi_type_uint32 -# define ffi_type_sshort ffi_type_sint32 -#else -#error "short size not supported" -#endif - -#if INT_MAX == 32767 -# define ffi_type_uint ffi_type_uint16 -# define ffi_type_sint ffi_type_sint16 -#elif INT_MAX == 2147483647 -# define ffi_type_uint ffi_type_uint32 -# define ffi_type_sint ffi_type_sint32 -#elif INT_MAX == 9223372036854775807 -# define ffi_type_uint ffi_type_uint64 -# define ffi_type_sint ffi_type_sint64 -#else -#error "int size not supported" -#endif - -#if LONG_MAX == 2147483647 -# if FFI_LONG_LONG_MAX != 9223372036854775807 -#error "no 64-bit data type supported" -# endif -#elif LONG_MAX != 9223372036854775807 -#error "long size not supported" -#endif - -#if LONG_MAX == 2147483647 -# define ffi_type_ulong ffi_type_uint32 -# define ffi_type_slong ffi_type_sint32 -#elif LONG_MAX == 9223372036854775807 -# define ffi_type_ulong ffi_type_uint64 -# define ffi_type_slong ffi_type_sint64 -#else -#error "long size not supported" -#endif - - /* These are defined in types.c */ - extern ffi_type ffi_type_void; - extern ffi_type ffi_type_uint8; - extern ffi_type ffi_type_sint8; - extern ffi_type ffi_type_uint16; - extern ffi_type ffi_type_sint16; - extern ffi_type ffi_type_uint32; - extern ffi_type ffi_type_sint32; - extern ffi_type ffi_type_uint64; - extern ffi_type ffi_type_sint64; - extern ffi_type ffi_type_float; - extern ffi_type ffi_type_double; - extern ffi_type ffi_type_pointer; - -#if 0 // @HAVE_LONG_DOUBLE@ - extern ffi_type ffi_type_longdouble; -#else -#define ffi_type_longdouble ffi_type_double -#endif -#endif /* LIBFFI_HIDE_BASIC_TYPES */ - - typedef enum { - FFI_OK = 0, - FFI_BAD_TYPEDEF, - FFI_BAD_ABI - } ffi_status; - - typedef unsigned FFI_TYPE; - - typedef struct { - ffi_abi abi; - unsigned nargs; - ffi_type **arg_types; - ffi_type *rtype; - unsigned bytes; - unsigned flags; -#ifdef FFI_EXTRA_CIF_FIELDS - FFI_EXTRA_CIF_FIELDS; -#endif - } ffi_cif; - - /* ---- Definitions for the raw API -------------------------------------- */ - -#ifndef FFI_SIZEOF_ARG -# if LONG_MAX == 2147483647 -# define FFI_SIZEOF_ARG 4 -# elif LONG_MAX == 9223372036854775807 -# define FFI_SIZEOF_ARG 8 -# endif -#endif - -#ifndef FFI_SIZEOF_JAVA_RAW -# define FFI_SIZEOF_JAVA_RAW FFI_SIZEOF_ARG -#endif - - typedef union { - ffi_sarg sint; - ffi_arg uint; - float flt; - char data[FFI_SIZEOF_ARG]; - void* ptr; - } ffi_raw; - -#if FFI_SIZEOF_JAVA_RAW == 4 && FFI_SIZEOF_ARG == 8 - /* This is a special case for mips64/n32 ABI (and perhaps others) where - sizeof(void *) is 4 and FFI_SIZEOF_ARG is 8. */ - typedef union { - signed int sint; - unsigned int uint; - float flt; - char data[FFI_SIZEOF_JAVA_RAW]; - void* ptr; - } ffi_java_raw; -#else - typedef ffi_raw ffi_java_raw; -#endif - - - void ffi_raw_call (ffi_cif *cif, - void (*fn)(void), - void *rvalue, - ffi_raw *avalue); - - void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); - void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); - size_t ffi_raw_size (ffi_cif *cif); - - /* This is analogous to the raw API, except it uses Java parameter */ - /* packing, even on 64-bit machines. I.e. on 64-bit machines */ - /* longs and doubles are followed by an empty 64-bit word. */ - - void ffi_java_raw_call (ffi_cif *cif, - void (*fn)(void), - void *rvalue, - ffi_java_raw *avalue); - - void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_java_raw *raw); - void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_java_raw *raw, void **args); - size_t ffi_java_raw_size (ffi_cif *cif); - - /* ---- Definitions for closures ----------------------------------------- */ - -#if FFI_CLOSURES - - typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - ffi_cif *cif; - void (*fun)(ffi_cif*,void*,void**,void*); - void *user_data; - } ffi_closure __attribute__((aligned (8))); - - void *ffi_closure_alloc (size_t size, void **code); - void ffi_closure_free (void *); - - ffi_status - ffi_prep_closure (ffi_closure*, - ffi_cif *, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data); - - ffi_status - ffi_prep_closure_loc (ffi_closure*, - ffi_cif *, - void (*fun)(ffi_cif*,void*,void**,void*), - void *user_data, - void*codeloc); - - typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - - ffi_cif *cif; - -#if !FFI_NATIVE_RAW_API - - /* if this is enabled, then a raw closure has the same layout - as a regular closure. We use this to install an intermediate - handler to do the transaltion, void** -> ffi_raw*. */ - - void (*translate_args)(ffi_cif*,void*,void**,void*); - void *this_closure; - -#endif - - void (*fun)(ffi_cif*,void*,ffi_raw*,void*); - void *user_data; - - } ffi_raw_closure; - - typedef struct { - char tramp[FFI_TRAMPOLINE_SIZE]; - - ffi_cif *cif; - -#if !FFI_NATIVE_RAW_API - - /* if this is enabled, then a raw closure has the same layout - as a regular closure. We use this to install an intermediate - handler to do the transaltion, void** -> ffi_raw*. */ - - void (*translate_args)(ffi_cif*,void*,void**,void*); - void *this_closure; - -#endif - - void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*); - void *user_data; - - } ffi_java_raw_closure; - - ffi_status - ffi_prep_raw_closure (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data); - - ffi_status - ffi_prep_raw_closure_loc (ffi_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_raw*,void*), - void *user_data, - void *codeloc); - - ffi_status - ffi_prep_java_raw_closure (ffi_java_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), - void *user_data); - - ffi_status - ffi_prep_java_raw_closure_loc (ffi_java_raw_closure*, - ffi_cif *cif, - void (*fun)(ffi_cif*,void*,ffi_java_raw*,void*), - void *user_data, - void *codeloc); - -#endif /* FFI_CLOSURES */ - - /* ---- Public interface definition -------------------------------------- */ - - ffi_status ffi_prep_cif(ffi_cif *cif, - ffi_abi abi, - unsigned int nargs, - ffi_type *rtype, - ffi_type **atypes); - - void ffi_call(ffi_cif *cif, - void (*fn)(void), - void *rvalue, - void **avalue); - - /* Useful for eliminating compiler warnings */ -#define FFI_FN(f) ((void (*)(void))f) - - /* ---- Definitions shared with assembly code ---------------------------- */ - -#endif - - /* If these change, update src/mips/ffitarget.h. */ -#define FFI_TYPE_VOID 0 -#define FFI_TYPE_INT 1 -#define FFI_TYPE_FLOAT 2 -#define FFI_TYPE_DOUBLE 3 -#if 0 // @HAVE_LONG_DOUBLE@ -#define FFI_TYPE_LONGDOUBLE 4 -#else -#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE -#endif -#define FFI_TYPE_UINT8 5 -#define FFI_TYPE_SINT8 6 -#define FFI_TYPE_UINT16 7 -#define FFI_TYPE_SINT16 8 -#define FFI_TYPE_UINT32 9 -#define FFI_TYPE_SINT32 10 -#define FFI_TYPE_UINT64 11 -#define FFI_TYPE_SINT64 12 -#define FFI_TYPE_STRUCT 13 -#define FFI_TYPE_POINTER 14 - - /* This should always refer to the last type code (for sanity checks) */ -#define FFI_TYPE_LAST FFI_TYPE_POINTER - -#ifdef __cplusplus -} -#endif - -#endif - - -#endif diff --git a/objc/NuInternals.h b/objc/NuInternals.h index d1e603e..40aa552 100644 --- a/objc/NuInternals.h +++ b/objc/NuInternals.h @@ -26,7 +26,7 @@ extern NSMutableDictionary *nu_block_table; -id Nu__null; +extern id Nu__null; // Execution contexts are NSMutableDictionaries that are keyed by // symbols. Here we define two string keys that allow us to store From 6423eb07bf5c8c7c6d845fd6e5ce306aa2ca93f6 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Thu, 14 Jul 2016 15:30:45 +0200 Subject: [PATCH 06/26] arm64 checks --- objc/NuBridge.m | 18 +++++++++--------- objc/NuBridgedBlock.m | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/objc/NuBridge.m b/objc/NuBridge.m index eed3cfb..2bb8cba 100644 --- a/objc/NuBridge.m +++ b/objc/NuBridge.m @@ -86,7 +86,7 @@ NSMutableDictionary *nu_block_table = nil; -#ifdef __x86_64__ +#if defined(__x86_64__) || defined(__arm64__) #define NSRECT_SIGNATURE0 "{_NSRect={_NSPoint=dd}{_NSSize=dd}}" #define NSRECT_SIGNATURE1 "{_NSRect=\"origin\"{_NSPoint=\"x\"d\"y\"d}\"size\"{_NSSize=\"width\"d\"height\"d}}" @@ -154,8 +154,8 @@ static void initialize_ffi_types(void) ffi_type_nspoint.alignment = 0; ffi_type_nspoint.type = FFI_TYPE_STRUCT; ffi_type_nspoint.elements = malloc(3 * sizeof(ffi_type*)); -#ifdef __x86_64__ - ffi_type_nspoint.elements[0] = &ffi_type_double; +#if defined(__x86_64__) || defined(__arm64__) + ffi_type_nspoint.elements[0] = &ffi_type_double; ffi_type_nspoint.elements[1] = &ffi_type_double; #else ffi_type_nspoint.elements[0] = &ffi_type_float; @@ -167,8 +167,8 @@ static void initialize_ffi_types(void) ffi_type_nssize.alignment = 0; ffi_type_nssize.type = FFI_TYPE_STRUCT; ffi_type_nssize.elements = malloc(3 * sizeof(ffi_type*)); -#ifdef __x86_64__ - ffi_type_nssize.elements[0] = &ffi_type_double; +#if defined(__x86_64__) || defined(__arm64__) + ffi_type_nssize.elements[0] = &ffi_type_double; ffi_type_nssize.elements[1] = &ffi_type_double; #else ffi_type_nssize.elements[0] = &ffi_type_float; @@ -188,8 +188,8 @@ static void initialize_ffi_types(void) ffi_type_nsrange.alignment = 0; ffi_type_nsrange.type = FFI_TYPE_STRUCT; ffi_type_nsrange.elements = malloc(3 * sizeof(ffi_type*)); -#ifdef __x86_64__ - ffi_type_nsrange.elements[0] = &ffi_type_uint64; +#if defined(__x86_64__) || defined(__arm64__) + ffi_type_nsrange.elements[0] = &ffi_type_uint64; ffi_type_nsrange.elements[1] = &ffi_type_uint64; #else ffi_type_nsrange.elements[0] = &ffi_type_uint; @@ -229,8 +229,8 @@ static char get_typeChar_from_typeString(const char *typeString) case 's': return &ffi_type_sshort; case 'I': return &ffi_type_uint; case 'i': return &ffi_type_sint; -#ifdef __x86_64__ - case 'L': return &ffi_type_ulong; +#if defined(__x86_64__) || defined(__arm64__) + case 'L': return &ffi_type_ulong; case 'l': return &ffi_type_slong; #else case 'L': return &ffi_type_uint; diff --git a/objc/NuBridgedBlock.m b/objc/NuBridgedBlock.m index d38d5dd..5201717 100644 --- a/objc/NuBridgedBlock.m +++ b/objc/NuBridgedBlock.m @@ -65,7 +65,7 @@ static id make_cblock (NuBlock *nuBlock, NSString *signature) int i = 0xFFFF; void(^cBlock)(void)=[^(void){printf("%i",i);} copy]; -#ifdef __x86_64__ +#if defined(__x86_64__) || defined(__arm64__) /* this is what happens when a block is called on x86 64 mov %rax,-0x18(%rbp) //the pointer to the block object is in rax mov -0x18(%rbp),%rax From a5f85920bf1d4046b4d476479039cae5b59bd5d2 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Thu, 14 Jul 2016 16:28:31 +0200 Subject: [PATCH 07/26] add B return type --- objc/NuBridge.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/objc/NuBridge.m b/objc/NuBridge.m index 2bb8cba..bcad9b5 100644 --- a/objc/NuBridge.m +++ b/objc/NuBridge.m @@ -556,6 +556,11 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type *((float *) objc_value) = (float) [nu_value doubleValue]; return NO; } + case 'B': + { + *((BOOL *) objc_value) = (BOOL) [nu_value boolValue]; + return NO; + } case 'v': { return NO; @@ -588,7 +593,7 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type !strcmp(typeString, CGRECT_SIGNATURE2) ) { NSRect *rect = (NSRect *) objc_value; - id cursor = nu_value; + id cursor = nu_value; rect->origin.x = (CGFloat) [[cursor car] doubleValue]; cursor = [cursor cdr]; rect->origin.y = (CGFloat) [[cursor car] doubleValue]; cursor = [cursor cdr]; rect->size.width = (CGFloat) [[cursor car] doubleValue]; cursor = [cursor cdr]; From 0d8c3b3607d61aa555ecb445afe87bf5f066d467 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Thu, 14 Jul 2016 18:22:23 +0200 Subject: [PATCH 08/26] fix types B l q --- objc/NuBridge.m | 8 ++++++-- objc/NuHandler.m | 21 ++++++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/objc/NuBridge.m b/objc/NuBridge.m index bcad9b5..9262bba 100644 --- a/objc/NuBridge.m +++ b/objc/NuBridge.m @@ -558,7 +558,11 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type } case 'B': { - *((BOOL *) objc_value) = (BOOL) [nu_value boolValue]; + // if (nu_value == Nu__null) { + // *((BOOL *) objc_value) = (BOOL) 0; + // } else { + *((BOOL *) objc_value) = (BOOL) [nu_value boolValue]; + //} return NO; } case 'v': @@ -870,7 +874,7 @@ id get_nu_value_from_objc_value(void *objc_value, const char *typeString) case 'B': { if (*((unsigned int *)objc_value) == 0) - return [NSNull null]; + return [NSNumber numberWithInt:0]; else return [NSNumber numberWithInt:1]; } diff --git a/objc/NuHandler.m b/objc/NuHandler.m index 1510b21..8745cbc 100644 --- a/objc/NuHandler.m +++ b/objc/NuHandler.m @@ -164,8 +164,8 @@ static IMP handler_returning_void(void *userdata) { }); } -#define MAKE_HANDLER_WITH_TYPE(type) \ -static IMP handler_returning_ ## type (void* userdata) \ +#define MAKE_HANDLER_WITH_TYPE_AND_SUFFIX(type, suffix) \ +static IMP handler_returning_ ## suffix (void* userdata) \ { \ return imp_implementationWithBlock(^(id receiver, ...) { \ struct nu_handler_description description; \ @@ -178,12 +178,21 @@ static IMP handler_returning_void(void *userdata) { return result; \ }); \ } +#define MAKE_HANDLER_WITH_TYPE(type) MAKE_HANDLER_WITH_TYPE_AND_SUFFIX(type, type) MAKE_HANDLER_WITH_TYPE(id) MAKE_HANDLER_WITH_TYPE(int) -MAKE_HANDLER_WITH_TYPE(bool) MAKE_HANDLER_WITH_TYPE(float) MAKE_HANDLER_WITH_TYPE(double) +MAKE_HANDLER_WITH_TYPE_AND_SUFFIX(bool,bool) //bool is not passed right to the inner macro? + +/** + * Newly added for 64bit + * Do we need Q and L as well? + */ +MAKE_HANDLER_WITH_TYPE(long) +MAKE_HANDLER_WITH_TYPE_AND_SUFFIX(long long,long_long) + #ifdef DARWIN MAKE_HANDLER_WITH_TYPE(CGRect) MAKE_HANDLER_WITH_TYPE(CGPoint) @@ -231,6 +240,12 @@ + (IMP) handlerWithSelector:(SEL)sel block:(NuBlock *)block signature:(const cha else if ([returnType isEqualToString:@"d"]) { return handler_returning_double(userdata); } + else if ([returnType isEqualToString:@"l"]) { + return handler_returning_long(userdata); + } + else if ([returnType isEqualToString:@"q"]) { + return handler_returning_long_long(userdata); + } #ifdef DARWIN else if ([returnType isEqualToString:@"{CGRect={CGPoint=ff}{CGSize=ff}}"]) { return handler_returning_CGRect(userdata); From d42b6057331087ceff81f46b9af61d85a2b82efb Mon Sep 17 00:00:00 2001 From: ksjogo Date: Fri, 15 Jul 2016 12:19:16 +0200 Subject: [PATCH 09/26] ignore system operator on iOS for the moment --- objc/NuOperators.m | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/objc/NuOperators.m b/objc/NuOperators.m index 8e380ea..8abfcc8 100644 --- a/objc/NuOperators.m +++ b/objc/NuOperators.m @@ -1961,7 +1961,12 @@ @interface Nu_system_operator : NuOperator {} @implementation Nu_system_operator - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context { - id cursor = cdr; +#if TARGET_OS_IPHONE + NSLog(@"System operator currently not supported on iOS"); + //FIXME: Use NSTask + return [NSNumber numberWithInt:1]; +#else + id cursor = cdr; NSMutableString *command = [NSMutableString string]; while (cursor && (cursor != [NSNull null])) { [command appendString:[[[cursor car] evalWithContext:context] stringValue]]; @@ -1970,6 +1975,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context const char *commandString = [command cStringUsingEncoding:NSUTF8StringEncoding]; int result = system(commandString) >> 8; // this needs an explanation return [NSNumber numberWithInt:result]; +#endif } @end From a85b01b039d712bcce79b8f3119896f7b1289bf0 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Fri, 15 Jul 2016 12:19:59 +0200 Subject: [PATCH 10/26] fix init warning --- objc/NuMarkupOperator.m | 2 +- objc/NuParser.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/objc/NuMarkupOperator.m b/objc/NuMarkupOperator.m index c1477cb..a8d39d3 100644 --- a/objc/NuMarkupOperator.m +++ b/objc/NuMarkupOperator.m @@ -174,7 +174,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context } else if ([evaluatedItem isKindOfClass:[NSArray class]]) { NSArray *evaluatedArray = (NSArray *) evaluatedItem; - int max = [evaluatedArray count]; + NSUInteger max = [evaluatedArray count]; for (int i = 0; i < max; i++) { id objectAtIndex = [evaluatedArray objectAtIndex:i]; [body appendString:[objectAtIndex stringValue]]; diff --git a/objc/NuParser.m b/objc/NuParser.m index 80469f9..f8417aa 100644 --- a/objc/NuParser.m +++ b/objc/NuParser.m @@ -651,7 +651,7 @@ -(id) parse:(NSString*)string // try to parse a character literal. // if that doesn't work, then interpret the quote as the quote operator. bool isACharacterLiteral = false; - int characterLiteralValue; + int characterLiteralValue = 0; if (i + 2 < imax) { if ([string characterAtIndex:i+1] != '\\') { if ([string characterAtIndex:i+2] == '\'') { From b054146a9d380d720df38142adac82640d6c8042 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Fri, 15 Jul 2016 12:20:27 +0200 Subject: [PATCH 11/26] xcode proj setup --- Nu.xcworkspace/contents.xcworkspacedata | 10 ----- Xcode/Nu.xcodeproj/project.pbxproj | 52 +++++++++++++++++++++++++ Xcode/NuApp/NuApp-Info.plist | 2 + 3 files changed, 54 insertions(+), 10 deletions(-) delete mode 100644 Nu.xcworkspace/contents.xcworkspacedata diff --git a/Nu.xcworkspace/contents.xcworkspacedata b/Nu.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index d5fec2d..0000000 --- a/Nu.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/Xcode/Nu.xcodeproj/project.pbxproj b/Xcode/Nu.xcodeproj/project.pbxproj index c1abc27..f2205c9 100644 --- a/Xcode/Nu.xcodeproj/project.pbxproj +++ b/Xcode/Nu.xcodeproj/project.pbxproj @@ -231,6 +231,20 @@ remoteGlobalIDString = 8DC2EF4F0486A6940098B216; remoteInfo = Nu; }; + 433CE5691D38EA4100EE7273 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 433CE5641D38EA4100EE7273 /* libffi.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = DB13B1661849DF1E0010F42D; + remoteInfo = "libffi-iOS"; + }; + 433CE56B1D38EA4100EE7273 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 433CE5641D38EA4100EE7273 /* libffi.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = DB13B1911849DF510010F42D; + remoteInfo = "libffi-Mac"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -406,6 +420,7 @@ 22EE2C0813A4731600895861 /* NuAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NuAppDelegate.h; sourceTree = ""; }; 22EE2C0913A4731600895861 /* NuAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NuAppDelegate.m; sourceTree = ""; }; 32DBCF5E0370ADEE00C91783 /* Nu_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Nu_Prefix.pch; sourceTree = ""; }; + 433CE5641D38EA4100EE7273 /* libffi.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libffi.xcodeproj; path = ../libffi/libffi.xcodeproj; sourceTree = ""; }; 43B5D4021D36686B00D1E1FD /* libNuTouch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libNuTouch.a; sourceTree = BUILT_PRODUCTS_DIR; }; 43DCFCB21D369D8200CB6E63 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libffi.a; path = "../libffi/build/Debug-iphoneos/libffi.a"; sourceTree = ""; }; 4F43427B1420476C00AC1BFD /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ../main/main.m; sourceTree = ""; }; @@ -466,6 +481,7 @@ 0867D691FE84028FC02AAC07 /* Nu */ = { isa = PBXGroup; children = ( + 433CE5641D38EA4100EE7273 /* libffi.xcodeproj */, 56E07743170B028400FF0A4B /* Default-568h@2x.png */, 22B3B41C13B0359300B3AB31 /* objc */, 22B3B3E413B033EE00B3AB31 /* nu */, @@ -724,6 +740,15 @@ name = "Supporting Files"; sourceTree = ""; }; + 433CE5651D38EA4100EE7273 /* Products */ = { + isa = PBXGroup; + children = ( + 433CE56A1D38EA4100EE7273 /* libffi.a */, + 433CE56C1D38EA4100EE7273 /* ffi.dylib */, + ); + name = Products; + sourceTree = ""; + }; 43DCFCB41D369D9400CB6E63 /* NuTouch */ = { isa = PBXGroup; children = ( @@ -882,6 +907,12 @@ mainGroup = 0867D691FE84028FC02AAC07 /* Nu */; productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 433CE5651D38EA4100EE7273 /* Products */; + ProjectRef = 433CE5641D38EA4100EE7273 /* libffi.xcodeproj */; + }, + ); projectRoot = ""; targets = ( 8DC2EF4F0486A6940098B216 /* Nu */, @@ -892,6 +923,23 @@ }; /* End PBXProject section */ +/* Begin PBXReferenceProxy section */ + 433CE56A1D38EA4100EE7273 /* libffi.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libffi.a; + remoteRef = 433CE5691D38EA4100EE7273 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 433CE56C1D38EA4100EE7273 /* ffi.dylib */ = { + isa = PBXReferenceProxy; + fileType = "compiled.mach-o.dylib"; + path = ffi.dylib; + remoteRef = 433CE56B1D38EA4100EE7273 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + /* Begin PBXResourcesBuildPhase section */ 22EE2BF213A4731600895861 /* Resources */ = { isa = PBXResourcesBuildPhase; @@ -1310,6 +1358,8 @@ HEADER_SEARCH_PATHS = ( /usr/local/include, "$(SRCROOT)/../objc", + ../libffi/darwin_common/include, + ../libffi/darwin_ios/include, ); INFOPLIST_FILE = "NuApp/NuApp-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.2; @@ -1346,6 +1396,8 @@ HEADER_SEARCH_PATHS = ( /usr/local/include, "$(SRCROOT)/../objc", + ../libffi/darwin_common/include, + ../libffi/darwin_ios/include, ); INFOPLIST_FILE = "NuApp/NuApp-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.2; diff --git a/Xcode/NuApp/NuApp-Info.plist b/Xcode/NuApp/NuApp-Info.plist index 955a746..da76972 100644 --- a/Xcode/NuApp/NuApp-Info.plist +++ b/Xcode/NuApp/NuApp-Info.plist @@ -26,6 +26,8 @@ 1.0 LSRequiresIPhoneOS + UIRequiresFullScreen + UISupportedInterfaceOrientations UIInterfaceOrientationPortrait From ddfca812060abdc0e299c4f165bf8e41f9d04670 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Fri, 15 Jul 2016 12:20:36 +0200 Subject: [PATCH 12/26] newer ffi --- objc/NuBridge.m | 35 ++++++++++++++++++++++++----------- objc/NuBridgedBlock.m | 17 +++++++++++++++-- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/objc/NuBridge.m b/objc/NuBridge.m index 9262bba..b9910a0 100644 --- a/objc/NuBridge.m +++ b/objc/NuBridge.m @@ -1220,8 +1220,13 @@ static IMP construct_method_handler(SEL sel, NuBlock *block, const char *signatu NSLog(@"unable to prepare closure for signature %s (ffi_prep_cif failed)", signature); return NULL; } - ffi_closure *closure = (ffi_closure *)mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (closure == (ffi_closure *) -1) { +#if TARGET_OS_IPHONE + void* funcPtr; + ffi_closure *closure = ffi_closure_alloc(sizeof(ffi_closure), &funcPtr); +#else + ffi_closure *closure = (ffi_closure *)mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); +#endif + if (closure == (ffi_closure *) -1) { NSLog(@"unable to prepare closure for signature %s (mmap failed with error %d)", signature, errno); return NULL; } @@ -1229,15 +1234,23 @@ static IMP construct_method_handler(SEL sel, NuBlock *block, const char *signatu NSLog(@"unable to prepare closure for signature %s (could not allocate memory for closure)", signature); return NULL; } - if (ffi_prep_closure(closure, cif, objc_calling_nu_method_handler, userdata) != FFI_OK) { - NSLog(@"unable to prepare closure for signature %s (ffi_prep_closure failed)", signature); - return NULL; - } - if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1) { - NSLog(@"unable to prepare closure for signature %s (mprotect failed with error %d)", signature, errno); - return NULL; - } - return (IMP) closure; +#if TARGET_OS_IPHONE + if (ffi_prep_closure_loc(closure, cif, objc_calling_nu_method_handler, userdata, funcPtr) != FFI_OK) { +#else + if (ffi_prep_closure(closure, cif, objc_calling_nu_method_handler, userdata) != FFI_OK) { +#endif + NSLog(@"unable to prepare closure for signature %s (ffi_prep_closure failed)", signature); + return NULL; + } +#if TARGET_OS_IPHONE + return funcPtr; +#else + if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1) { + NSLog(@"unable to prepare closure for signature %s (mprotect failed with error %d)", signature, errno); + return NULL; + } + return (void*)closure; +#endif } id add_method_to_class(Class c, NSString *methodName, NSString *signature, NuBlock *block) diff --git a/objc/NuBridgedBlock.m b/objc/NuBridgedBlock.m index 5201717..7de9b9d 100644 --- a/objc/NuBridgedBlock.m +++ b/objc/NuBridgedBlock.m @@ -192,8 +192,13 @@ static void objc_calling_nu_block_handler(ffi_cif* cif, void* returnvalue, void* NSLog(@"unable to prepare closure for signature %s (ffi_prep_cif failed)", signature); return NULL; } - ffi_closure *closure = (ffi_closure *)mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (closure == (ffi_closure *) -1) { +#if TARGET_OS_IPHONE + void* funcPtr; + ffi_closure *closure = ffi_closure_alloc(sizeof(ffi_closure), &funcPtr); +#else + ffi_closure *closure = (ffi_closure *)mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); +#endif + if (closure == (ffi_closure *) -1) { NSLog(@"unable to prepare closure for signature %s (mmap failed with error %d)", signature, errno); return NULL; } @@ -201,15 +206,23 @@ static void objc_calling_nu_block_handler(ffi_cif* cif, void* returnvalue, void* NSLog(@"unable to prepare closure for signature %s (could not allocate memory for closure)", signature); return NULL; } +#if TARGET_OS_IPHONE + if (ffi_prep_closure_loc(closure, cif, objc_calling_nu_block_handler, userdata, funcPtr) != FFI_OK) { +#else if (ffi_prep_closure(closure, cif, objc_calling_nu_block_handler, userdata) != FFI_OK) { +#endif NSLog(@"unable to prepare closure for signature %s (ffi_prep_closure failed)", signature); return NULL; } +#ifdef TARGET_OS_IPHONE + return funcPtr; +#else if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1) { NSLog(@"unable to prepare closure for signature %s (mprotect failed with error %d)", signature, errno); return NULL; } return (void*)closure; +#endif } #endif //__BLOCKS__ \ No newline at end of file From 68e1e3c2ecac932387a007d3307fd2cfa6924e46 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Fri, 15 Jul 2016 16:09:08 +0200 Subject: [PATCH 13/26] added shieds for quasiquote nesting --- objc/NuParser.m | 6 ++++++ test/test_quasiquote.nu | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/objc/NuParser.m b/objc/NuParser.m index f8417aa..bb911a4 100644 --- a/objc/NuParser.m +++ b/objc/NuParser.m @@ -700,6 +700,12 @@ -(id) parse:(NSString*)string } break; } + case '~': + { + [self quasiquoteEvalNextElement]; + [self quoteNextElement]; + break; + } case '`': { [self quasiquoteNextElement]; diff --git a/test/test_quasiquote.nu b/test/test_quasiquote.nu index ac331e5..4ef0114 100644 --- a/test/test_quasiquote.nu +++ b/test/test_quasiquote.nu @@ -36,7 +36,14 @@ (assert_throws "NuQuasiquoteEvalOutsideQuasiquote" (do () (,(+ 1 1))))) - + + (- (id) testShielding is + (macro shielded (name) + `(macro ,name (inner) + `(+ 2 ~,inner))) + (shielded shield) + (assert_equal (shield 5) 7)) + (- (id) testSplicing is ; Single element (assert_equal '(1) `(,@(list 1))) From 7b1bd28448151a507240c43526bec7fa0929e830 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Fri, 15 Jul 2016 16:14:38 +0200 Subject: [PATCH 14/26] fallback for synthesized _ivars --- objc/NSObject+Nu.m | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/objc/NSObject+Nu.m b/objc/NSObject+Nu.m index 54c9846..445cda1 100644 --- a/objc/NSObject+Nu.m +++ b/objc/NSObject+Nu.m @@ -380,7 +380,13 @@ - (id) handleUnknownMessage:(id) message withContext:(NSMutableDictionary *) con - (id) valueForIvar:(NSString *) name { Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); - if (!v) { + + if (!v) { + //check if a _variable was synthesized + v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] cStringUsingEncoding:NSUTF8StringEncoding]); + } + + if (!v) { // look for sparse ivar storage NSMutableDictionary *sparseIvars = [self associatedObjectForKey:@"__nuivars"]; if (sparseIvars) { @@ -402,7 +408,13 @@ - (id) valueForIvar:(NSString *) name - (BOOL) hasValueForIvar:(NSString *) name { Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); - if (!v) { + + if (!v) { + //check if a _variable was synthesized + v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] cStringUsingEncoding:NSUTF8StringEncoding]); + } + + if (!v) { // look for sparse ivar storage NSMutableDictionary *sparseIvars = [self associatedObjectForKey:@"__nuivars"]; if (sparseIvars) { @@ -425,7 +437,11 @@ - (BOOL) hasValueForIvar:(NSString *) name - (void) setValue:(id) value forIvar:(NSString *)name { Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); - if (!v) { + if (!v) { + //check if a _variable was synthesized + v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] cStringUsingEncoding:NSUTF8StringEncoding]); + } + if (!v) { NSMutableDictionary *sparseIvars = [self associatedObjectForKey:@"__nuivars"]; if (!sparseIvars) { sparseIvars = [[[NSMutableDictionary alloc] init] autorelease]; @@ -508,7 +524,11 @@ + (NSArray *) instanceVariableNames + (NSString *) signatureForIvar:(NSString *)name { Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); - return [NSString stringWithCString:ivar_getTypeEncoding(v) encoding:NSUTF8StringEncoding]; + if (!v) { + //check if a _variable was synthesized + v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] cStringUsingEncoding:NSUTF8StringEncoding]); + } + return [NSString stringWithCString:ivar_getTypeEncoding(v) encoding:NSUTF8StringEncoding]; } + (id) inheritedByClass:(NuClass *) newClass From 455cd819984231441c82b933ca0be96d14a8023d Mon Sep 17 00:00:00 2001 From: ksjogo Date: Mon, 18 Jul 2016 16:59:57 +0200 Subject: [PATCH 15/26] move inheriitedByClass to later stage --- objc/NuClass.m | 3 +++ objc/NuOperators.m | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/objc/NuClass.m b/objc/NuClass.m index 35432a5..169c49a 100644 --- a/objc/NuClass.m +++ b/objc/NuClass.m @@ -239,6 +239,9 @@ - (void) registerClass if (isRegistered == NO) { objc_registerClassPair(c); isRegistered = YES; + if ([class_getSuperclass(self->c) respondsToSelector:@selector(inheritedByClass:)]) { + [class_getSuperclass(self->c) inheritedByClass:self]; + } } } diff --git a/objc/NuOperators.m b/objc/NuOperators.m index 8abfcc8..ebd536a 100644 --- a/objc/NuOperators.m +++ b/objc/NuOperators.m @@ -1813,10 +1813,6 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context childClass = [NuClass classWithClass:newClass]; [childClass setRegistered:NO]; //NSLog(@"created class %@", [childClass name]); - // it seems dangerous to call this here. Maybe it's better to wait until the new class is registered. - if ([parentClass respondsToSelector:@selector(inheritedByClass:)]) { - [parentClass inheritedByClass:childClass]; - } if (!childClass) { // This class may have already been defined previously From 69fbcff0ce37bda8ead8f27d6b8a7e91d757c9de Mon Sep 17 00:00:00 2001 From: ksjogo Date: Mon, 18 Jul 2016 18:13:02 +0200 Subject: [PATCH 16/26] disabe nuhandlers and add simple cblock test in nuapp --- Xcode/NuApp/NuAppDelegate.m | 9 +++++++++ objc/NuBridge.m | 4 +++- objc/NuBridgedBlock.m | 4 ++-- objc/NuHandler.h | 6 +++++- objc/NuHandler.m | 3 ++- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Xcode/NuApp/NuAppDelegate.m b/Xcode/NuApp/NuAppDelegate.m index 968d94c..a14f3ca 100644 --- a/Xcode/NuApp/NuAppDelegate.m +++ b/Xcode/NuApp/NuAppDelegate.m @@ -9,6 +9,8 @@ #import "NuAppDelegate.h" #import "Nu.h" +#import "NuBlock.h" +#import "NuBridgedBlock.h" #import @@ -56,6 +58,13 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [regex release]; NSLog(@"running tests"); int failures = [[[Nu sharedParser] parseEval:@"(NuTestCase runAllTests)"] intValue]; + + NSString* script = @"(do () (puts \"cBlock Work!\"))"; + id parsed = [[Nu sharedParser] parse:script]; + NuBlock* block = [[Nu sharedParser] eval:parsed]; + void (^cblock)() = [NuBridgedBlock cBlockWithNuBlock:block signature:@"v"]; + cblock(); + if (failures == 0) { view.backgroundColor = [UIColor greenColor]; label.text = @"Everything Nu!"; diff --git a/objc/NuBridge.m b/objc/NuBridge.m index b9910a0..10d29bd 100644 --- a/objc/NuBridge.m +++ b/objc/NuBridge.m @@ -1193,10 +1193,12 @@ static void objc_calling_nu_method_handler(ffi_cif* cif, void* returnvalue, void static IMP construct_method_handler(SEL sel, NuBlock *block, const char *signature) { char **userdata = generate_userdata(sel, block, signature); - IMP imp = [NuHandlerWarehouse handlerWithSelector:sel block:block signature:signature userdata:userdata]; +#if !TARGET_OS_IPHONE + IMP imp = [NuHandlerWarehouse handlerWithSelector:sel block:block signature:signature userdata:userdata]; if (imp) { return imp; } +#endif int argument_count = 0; while (userdata[argument_count] != 0) argument_count++; #if 0 diff --git a/objc/NuBridgedBlock.m b/objc/NuBridgedBlock.m index 7de9b9d..a3fbac3 100644 --- a/objc/NuBridgedBlock.m +++ b/objc/NuBridgedBlock.m @@ -60,7 +60,7 @@ -(void)dealloc //the caller gets ownership of the block static id make_cblock (NuBlock *nuBlock, NSString *signature) { - void *funcptr = construct_block_handler(nuBlock, [signature UTF8String]); + void(*funcptr)(void) = construct_block_handler(nuBlock, [signature UTF8String]); int i = 0xFFFF; void(^cBlock)(void)=[^(void){printf("%i",i);} copy]; @@ -74,7 +74,7 @@ static id make_cblock (NuBlock *nuBlock, NSString *signature) callq *%rax */ //2*(sizeof(void*)) = 0x10 - *((void **)(id)cBlock + 2) = (void *)funcptr; + *((void **)(id)cBlock + 2) = (void *)funcptr; #else /* this is what happens when a block is called on x86 32 mov %eax,-0x14(%ebp) //the pointer to the block object is in eax diff --git a/objc/NuHandler.h b/objc/NuHandler.h index db3ca5e..06b40f5 100644 --- a/objc/NuHandler.h +++ b/objc/NuHandler.h @@ -6,6 +6,9 @@ // // +#if !TARGET_OS_IPHONE + + #import @class NuBlock; @@ -18,6 +21,7 @@ struct nu_handler_description char **description; }; + /*! @class NuHandlerWarehouse @abstract Internal class used to store and vend method implementations on platforms that don't allow them to be constructed at runtime. @@ -32,4 +36,4 @@ static void nu_handler(void *return_value, id receiver, va_list ap); - +#endif diff --git a/objc/NuHandler.m b/objc/NuHandler.m index 8745cbc..472e92c 100644 --- a/objc/NuHandler.m +++ b/objc/NuHandler.m @@ -4,7 +4,7 @@ // // Created by Tim Burks on 4/24/16. // - +#if !TARGET_OS_IPHONE #import "NuHandler.h" #import "NuCell.h" #import "NuInternals.h" @@ -297,3 +297,4 @@ + (IMP) handlerWithSelector:(SEL)sel block:(NuBlock *)block signature:(const cha } @end +#endif \ No newline at end of file From 52e5c711f32944c1f4c71e1f842afb3cb8198f36 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Thu, 21 Jul 2016 11:10:49 +0200 Subject: [PATCH 17/26] fix os x --- objc/NSData+Nu.m | 2 +- objc/NuBridgedBlock.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/objc/NSData+Nu.m b/objc/NSData+Nu.m index 2301334..ccf3992 100644 --- a/objc/NSData+Nu.m +++ b/objc/NSData+Nu.m @@ -48,7 +48,7 @@ + (NSData *) dataWithShellCommand:(NSString *) command standardInput:(id) input else { fullCommand = [NSString stringWithFormat:@"%@ > %@", command, outputFileName]; } - const char *commandString = [[fullCommand stringValue] cStringUsingEncoding:NSUTF8StringEncoding]; + const char *commandString = [fullCommand cStringUsingEncoding:NSUTF8StringEncoding]; int result = system(commandString) >> 8; // this needs an explanation if (!result) returnValue = [NSData dataWithContentsOfFile:outputFileName]; diff --git a/objc/NuBridgedBlock.m b/objc/NuBridgedBlock.m index a3fbac3..d8273c3 100644 --- a/objc/NuBridgedBlock.m +++ b/objc/NuBridgedBlock.m @@ -214,7 +214,7 @@ static void objc_calling_nu_block_handler(ffi_cif* cif, void* returnvalue, void* NSLog(@"unable to prepare closure for signature %s (ffi_prep_closure failed)", signature); return NULL; } -#ifdef TARGET_OS_IPHONE +#if TARGET_OS_IPHONE return funcPtr; #else if (mprotect(closure, sizeof(closure), PROT_READ | PROT_EXEC) == -1) { From 30946e58223273eca3cd2f28b36cb879f7c01343 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Mon, 25 Jul 2016 01:18:41 +0200 Subject: [PATCH 18/26] set ios deployment target to 7.0 --- Xcode/Nu.xcodeproj/project.pbxproj | 4 ++-- libffi | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Xcode/Nu.xcodeproj/project.pbxproj b/Xcode/Nu.xcodeproj/project.pbxproj index f2205c9..1b206cc 100644 --- a/Xcode/Nu.xcodeproj/project.pbxproj +++ b/Xcode/Nu.xcodeproj/project.pbxproj @@ -1447,7 +1447,7 @@ ../libffi/darwin_common/include, ../libffi/darwin_ios/include, ); - IPHONEOS_DEPLOYMENT_TARGET = 9.2; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; MTL_ENABLE_DEBUG_INFO = YES; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1485,7 +1485,7 @@ ../libffi/darwin_common/include, ../libffi/darwin_ios/include, ); - IPHONEOS_DEPLOYMENT_TARGET = 9.2; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/libffi b/libffi index 5a3bf17..284900b 160000 --- a/libffi +++ b/libffi @@ -1 +1 @@ -Subproject commit 5a3bf17e2b28cddfb48edb74c83f768c77f79912 +Subproject commit 284900b74030d725da528461e53dc2354c1dca6a From 2b56f23fe5da8cba68feadbd89f41146f84a68ea Mon Sep 17 00:00:00 2001 From: ksjogo Date: Thu, 30 Mar 2017 14:06:12 +0200 Subject: [PATCH 19/26] updated libffi --- libffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libffi b/libffi index 284900b..7d504f7 160000 --- a/libffi +++ b/libffi @@ -1 +1 @@ -Subproject commit 284900b74030d725da528461e53dc2354c1dca6a +Subproject commit 7d504f7a8e33f6da27941f5dc5d889fe60b8b9c8 From 9c149fbe4b189ed07c207e1c7ab05feb8f74b022 Mon Sep 17 00:00:00 2001 From: Dirk Theisen Date: Thu, 13 Apr 2017 11:57:37 +0200 Subject: [PATCH 20/26] Fixed all compile time warnigns as of Xcode 8.3.1 --- objc/NSObject+Nu.h | 2 ++ objc/NSObject+Nu.m | 1 + objc/NuBridge.m | 3 --- objc/NuBridgeSupport.m | 4 +++- objc/NuOperators.m | 2 ++ objc/NuParser.m | 1 + objc/NuTestHelper.m | 8 +------- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/objc/NSObject+Nu.h b/objc/NSObject+Nu.h index ab1af90..a8d676a 100644 --- a/objc/NSObject+Nu.h +++ b/objc/NSObject+Nu.h @@ -95,4 +95,6 @@ /*! Property list helper. Return the binary property list representation of the object. */ - (NSData *) binaryPropertyListRepresentation; +- (NSString *) stringValue; + @end diff --git a/objc/NSObject+Nu.m b/objc/NSObject+Nu.m index 445cda1..ba6a3b9 100644 --- a/objc/NSObject+Nu.m +++ b/objc/NSObject+Nu.m @@ -13,6 +13,7 @@ #import "NuMethod.h" #import "NuClass.h" #import "NuCell.h" +#import "NSString+Nu.h" @protocol NuCanSetAction - (void) setAction:(SEL) action; diff --git a/objc/NuBridge.m b/objc/NuBridge.m index 10d29bd..aaf10f5 100644 --- a/objc/NuBridge.m +++ b/objc/NuBridge.m @@ -1275,9 +1275,6 @@ id add_method_to_class(Class c, NSString *methodName, NSString *signature, NuBlo if (!nu_block_table) nu_block_table = [[NSMutableDictionary alloc] init]; // watch for problems caused by these ugly casts... [nu_block_table setObject:block forKey:[NSNumber numberWithUnsignedLong:(unsigned long) imp]]; -#if !TARGET_OS_IPHONE - [[NSGarbageCollector defaultCollector] disableCollectorForPointer: block]; -#endif // insert the method handler in the class method table nu_class_replaceMethod(c, selector, imp, signature_str); //NSLog(@"setting handler for %s(%s) in class %s", method_name_str, signature_str, class_getName(c)); diff --git a/objc/NuBridgeSupport.m b/objc/NuBridgeSupport.m index ef11781..cc96206 100644 --- a/objc/NuBridgeSupport.m +++ b/objc/NuBridgeSupport.m @@ -8,6 +8,8 @@ #import "NuBridgeSupport.h" #import "NuInternals.h" +#import "NSFileManager+Nu.h" + #pragma mark - NuBridgeSupport.m @@ -175,4 +177,4 @@ + (NSString *) stringValue } @end -#endif \ No newline at end of file +#endif diff --git a/objc/NuOperators.m b/objc/NuOperators.m index ebd536a..933b8bc 100644 --- a/objc/NuOperators.m +++ b/objc/NuOperators.m @@ -17,6 +17,8 @@ #import "NuBridge.h" #import "NuBridgedFunction.h" #import "NuClass.h" +#include +#import "NSString+Nu.h" #if TARGET_OS_IPHONE #import diff --git a/objc/NuParser.m b/objc/NuParser.m index bb911a4..ff9ae68 100644 --- a/objc/NuParser.m +++ b/objc/NuParser.m @@ -14,6 +14,7 @@ #import "NSDictionary+Nu.h" #import "NuException.h" #import "NuCell.h" +#include #define PARSE_NORMAL 0 #define PARSE_COMMENT 1 diff --git a/objc/NuTestHelper.m b/objc/NuTestHelper.m index b5adcba..ee6a6e0 100644 --- a/objc/NuTestHelper.m +++ b/objc/NuTestHelper.m @@ -115,17 +115,11 @@ - (void) finalize + (void) resetDeallocationCount { -#if !TARGET_OS_IPHONE - [[NSGarbageCollector defaultCollector] collectExhaustively]; -#endif deallocationCount = 0; } + (int) deallocationCount { -#if !TARGET_OS_IPHONE - [[NSGarbageCollector defaultCollector] collectExhaustively]; -#endif return deallocationCount; } @@ -147,4 +141,4 @@ + (NSRange) getNSRangeFromProxy:(id) proxy { return [proxy NSRangeValue]; } -@end \ No newline at end of file +@end From 8a487f61b6e52a7b10d03c41095aa0d992cad97b Mon Sep 17 00:00:00 2001 From: Dirk Theisen Date: Thu, 13 Apr 2017 14:02:18 +0200 Subject: [PATCH 21/26] Used more modern NSNumber literals to make code less verbose. --- objc/NSNumber+Nu.m | 6 +++--- objc/NSString+Nu.m | 4 ++-- objc/NuBridge.m | 10 +++++----- objc/NuBridgeSupport.m | 2 +- objc/NuCell.m | 2 +- objc/NuEnumerable.m | 4 ++-- objc/NuOperators.m | 10 +++++----- objc/NuParser.m | 4 ++-- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/objc/NSNumber+Nu.m b/objc/NSNumber+Nu.m index 3f94132..189291c 100644 --- a/objc/NSNumber+Nu.m +++ b/objc/NSNumber+Nu.m @@ -23,7 +23,7 @@ - (id) times:(id) block @try { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [args setCar:[NSNumber numberWithInt:i]]; + [args setCar:@(i)]; [block evalWithArguments:args context:Nu__null]; [pool release]; } @@ -56,7 +56,7 @@ - (id) downTo:(id) number do:(id) block for (i = startValue; i >= finalValue; i--) { @try { - [args setCar:[NSNumber numberWithInt:i]]; + [args setCar:@(i)]; [block evalWithArguments:args context:Nu__null]; } @catch (NuBreakException *exception) { @@ -85,7 +85,7 @@ - (id) upTo:(id) number do:(id) block for (i = startValue; i <= finalValue; i++) { @try { - [args setCar:[NSNumber numberWithInt:i]]; + [args setCar:@(i)]; [block evalWithArguments:args context:Nu__null]; } @catch (NuBreakException *exception) { diff --git a/objc/NSString+Nu.m b/objc/NSString+Nu.m index f2056b9..429fa43 100644 --- a/objc/NSString+Nu.m +++ b/objc/NSString+Nu.m @@ -36,7 +36,7 @@ - (id) initWithString:(NSString *) s - (id) nextObject { if (index < [string length]) { - return [NSNumber numberWithInt:[string characterAtIndex:index++]]; + return @([string characterAtIndex:index++]); } else { return nil; } @@ -249,4 +249,4 @@ - (void) appendCharacter:(unichar) c [self appendFormat:@"%C", c]; } -@end \ No newline at end of file +@end diff --git a/objc/NuBridge.m b/objc/NuBridge.m index aaf10f5..484b906 100644 --- a/objc/NuBridge.m +++ b/objc/NuBridge.m @@ -746,7 +746,7 @@ id get_nu_value_from_objc_value(void *objc_value, const char *typeString) #endif case 'i': { - return [NSNumber numberWithInt:*((int *)objc_value)]; + return @(*((int *)objc_value)); } #ifndef __ppc__ case 'C': @@ -827,10 +827,10 @@ id get_nu_value_from_objc_value(void *objc_value, const char *typeString) NSRange *range = (NSRange *)objc_value; NuCell *list = [[[NuCell alloc] init] autorelease]; id cursor = list; - [cursor setCar:[NSNumber numberWithInteger:range->location]]; + [cursor setCar:@(range->location)]; [cursor setCdr:[[[NuCell alloc] init] autorelease]]; cursor = [cursor cdr]; - [cursor setCar:[NSNumber numberWithInteger:range->length]]; + [cursor setCar:@(range->length)]; return list; } else if ( @@ -874,9 +874,9 @@ id get_nu_value_from_objc_value(void *objc_value, const char *typeString) case 'B': { if (*((unsigned int *)objc_value) == 0) - return [NSNumber numberWithInt:0]; + return @0; else - return [NSNumber numberWithInt:1]; + return @1; } case '^': { diff --git a/objc/NuBridgeSupport.m b/objc/NuBridgeSupport.m index cc96206..54d45be 100644 --- a/objc/NuBridgeSupport.m +++ b/objc/NuBridgeSupport.m @@ -76,7 +76,7 @@ + (void)importFramework:(NSString *) framework fromPath:(NSString *) path intoDi forKey:[[node attributeForName:@"name"] stringValue]]; } else if ([[node name] isEqual:@"enum"]) { - [enums setValue:[NSNumber numberWithInt:[[[node attributeForName:@"value"] stringValue] intValue]] + [enums setValue:@([[[node attributeForName:@"value"] stringValue] intValue]) forKey:[[node attributeForName:@"name"] stringValue]]; } else if ([[node name] isEqual:@"function"]) { diff --git a/objc/NuCell.m b/objc/NuCell.m index 1176c9a..7f7e929 100644 --- a/objc/NuCell.m +++ b/objc/NuCell.m @@ -345,7 +345,7 @@ - (id) eachWithIndex:(id) block int i = 0; while (cursor && (cursor != Nu__null)) { [args setCar:[cursor car]]; - [[args cdr] setCar:[NSNumber numberWithInt:i]]; + [[args cdr] setCar:@(i)]; [block evalWithArguments:args context:Nu__null]; cursor = [cursor cdr]; i++; diff --git a/objc/NuEnumerable.m b/objc/NuEnumerable.m index 84d7f19..1933a8e 100644 --- a/objc/NuEnumerable.m +++ b/objc/NuEnumerable.m @@ -59,7 +59,7 @@ - (id) eachWithIndex:(NuBlock *) block @try { [args setCar:object]; - [[args cdr] setCar:[NSNumber numberWithInt:i]]; + [[args cdr] setCar:@(i)]; [block evalWithArguments:args context:nil]; } @catch (NuBreakException *exception) { @@ -157,7 +157,7 @@ - (NSArray *) mapWithIndex:(id) callable int i = 0; while ((object = [enumerator nextObject])) { [args setCar:object]; - [[args cdr] setCar:[NSNumber numberWithInt:i]]; + [[args cdr] setCar:@(i)]; [results addObject:[callable evalWithArguments:args context:nil]]; i++; } diff --git a/objc/NuOperators.m b/objc/NuOperators.m index 933b8bc..55509f0 100644 --- a/objc/NuOperators.m +++ b/objc/NuOperators.m @@ -1268,7 +1268,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context product %= [[[cursor car] evalWithContext:context] intValue]; cursor = [cursor cdr]; } - return [NSNumber numberWithInt:product]; + return @(product); } @end @@ -1962,7 +1962,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context #if TARGET_OS_IPHONE NSLog(@"System operator currently not supported on iOS"); //FIXME: Use NSTask - return [NSNumber numberWithInt:1]; + return @1; #else id cursor = cdr; NSMutableString *command = [NSMutableString string]; @@ -1972,7 +1972,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context } const char *commandString = [command cStringUsingEncoding:NSUTF8StringEncoding]; int result = system(commandString) >> 8; // this needs an explanation - return [NSNumber numberWithInt:result]; + return @(result); #endif } @@ -2010,7 +2010,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context else { [NSException raise: @"NuArityError" format:@"sleep expects 1 argument, got 0"]; } - return [NSNumber numberWithInt:result]; + return @(result); } @end @@ -2394,7 +2394,7 @@ void load_builtins(NuSymbolTable *symbolTable) // set some commonly-used globals [(NuSymbol *) [symbolTable symbolWithString:@"NSUTF8StringEncoding"] - setValue:[NSNumber numberWithInt:NSUTF8StringEncoding]]; + setValue:@(NSUTF8StringEncoding)]; [(NuSymbol *) [symbolTable symbolWithString:@"NSLog"] // let's make this an operator someday setValue:[NuBridgedFunction functionWithName:@"NSLog" signature:@"v@"]]; diff --git a/objc/NuParser.m b/objc/NuParser.m index ff9ae68..f5cd483 100644 --- a/objc/NuParser.m +++ b/objc/NuParser.m @@ -575,7 +575,7 @@ -(id) parse:(NSString*)string switch(stri) { case '(': ParserDebug(@"Parser: ( %d on line %d", column, linenum); - [opens push:[NSNumber numberWithInt:column]]; + [opens push:@(column)]; parens++; if ([partial length] == 0) { [self openList]; @@ -694,7 +694,7 @@ -(id) parse:(NSString*)string } } if (isACharacterLiteral) { - [self addAtom:[NSNumber numberWithInt:characterLiteralValue]]; + [self addAtom:@(characterLiteralValue)]; } else { [self quoteNextElement]; From 7a2dc39c46dfe94f9a6cb5914d332a2836a081e9 Mon Sep 17 00:00:00 2001 From: Dirk Theisen Date: Thu, 13 Apr 2017 14:16:41 +0200 Subject: [PATCH 22/26] Used -UTF8String to make the code less verbose. --- objc/NSBundle+Nu.m | 2 +- objc/NSData+Nu.m | 4 ++-- objc/NSFileManager+Nu.m | 8 ++++---- objc/NSObject+Nu.m | 28 ++++++++++++++-------------- objc/Nu.m | 6 +++--- objc/NuBridge.m | 12 ++++++------ objc/NuBridgeSupport.m | 2 +- objc/NuBridgedConstant.m | 4 ++-- objc/NuBridgedFunction.m | 6 +++--- objc/NuClass.m | 14 +++++++------- objc/NuOperators.m | 16 ++++++++-------- objc/NuParser.m | 18 +++++++++--------- objc/NuPointer.m | 4 ++-- objc/NuSuper.m | 4 ++-- objc/NuSymbol.m | 2 +- 15 files changed, 65 insertions(+), 65 deletions(-) diff --git a/objc/NSBundle+Nu.m b/objc/NSBundle+Nu.m index 8660f1c..c952257 100644 --- a/objc/NSBundle+Nu.m +++ b/objc/NSBundle+Nu.m @@ -59,7 +59,7 @@ - (id) loadNuFile:(NSString *) nuFileName withContext:(NSMutableDictionary *) co if (string) { NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; id parser = [context lookupObjectForKey:[symbolTable symbolWithString:@"_parser"]]; - id body = [parser parse:string asIfFromFilename:[fileName cStringUsingEncoding:NSUTF8StringEncoding]]; + id body = [parser parse:string asIfFromFilename:[fileName UTF8String]]; [body evalWithContext:context]; return [symbolTable symbolWithString:@"t"]; } diff --git a/objc/NSData+Nu.m b/objc/NSData+Nu.m index ccf3992..bd2e464 100644 --- a/objc/NSData+Nu.m +++ b/objc/NSData+Nu.m @@ -48,11 +48,11 @@ + (NSData *) dataWithShellCommand:(NSString *) command standardInput:(id) input else { fullCommand = [NSString stringWithFormat:@"%@ > %@", command, outputFileName]; } - const char *commandString = [fullCommand cStringUsingEncoding:NSUTF8StringEncoding]; + const char *commandString = [fullCommand UTF8String]; int result = system(commandString) >> 8; // this needs an explanation if (!result) returnValue = [NSData dataWithContentsOfFile:outputFileName]; - system([[NSString stringWithFormat:@"rm -f %@ %@", inputFileName, outputFileName] cStringUsingEncoding:NSUTF8StringEncoding]); + system([[NSString stringWithFormat:@"rm -f %@ %@", inputFileName, outputFileName] UTF8String]); } free(input_template); free(output_template); diff --git a/objc/NSFileManager+Nu.m b/objc/NSFileManager+Nu.m index 040afd1..7757bf7 100644 --- a/objc/NSFileManager+Nu.m +++ b/objc/NSFileManager+Nu.m @@ -27,7 +27,7 @@ + (id) creationTimeForFileNamed:(NSString *) filename { if (!filename) return nil; - const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; + const char *path = [[filename stringByExpandingTildeInPath] UTF8String]; struct stat sb; int result = stat(path, &sb); if (result == -1) { @@ -41,7 +41,7 @@ + (id) modificationTimeForFileNamed:(NSString *) filename { if (!filename) return nil; - const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; + const char *path = [[filename stringByExpandingTildeInPath] UTF8String]; struct stat sb; int result = stat(path, &sb); if (result == -1) { @@ -54,7 +54,7 @@ + (int) directoryExistsNamed:(NSString *) filename { if (!filename) return NO; - const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; + const char *path = [[filename stringByExpandingTildeInPath] UTF8String]; struct stat sb; int result = stat(path, &sb); if (result == -1) { @@ -67,7 +67,7 @@ + (int) fileExistsNamed:(NSString *) filename { if (!filename) return NO; - const char *path = [[filename stringByExpandingTildeInPath] cStringUsingEncoding:NSUTF8StringEncoding]; + const char *path = [[filename stringByExpandingTildeInPath] UTF8String]; struct stat sb; int result = stat(path, &sb); if (result == -1) { diff --git a/objc/NSObject+Nu.m b/objc/NSObject+Nu.m index ba6a3b9..a03b5e2 100644 --- a/objc/NSObject+Nu.m +++ b/objc/NSObject+Nu.m @@ -99,7 +99,7 @@ - (NuSelectorCache *) lookupSymbol:(NuSymbol *)childSymbol if (!child) { child = [[[NuSelectorCache alloc] initWithSymbol:childSymbol parent:self] autorelease]; NSString *selectorString = [child selectorName]; - [child setSelector:sel_registerName([selectorString cStringUsingEncoding:NSUTF8StringEncoding])]; + [child setSelector:sel_registerName([selectorString UTF8String])]; [children setValue:child forKey:(id)childSymbol]; } return child; @@ -176,7 +176,7 @@ - (id) sendMessage:(id)cdr withContext:(NSMutableDictionary *)context cursor = [cursor cdr]; } } - // sel = sel_getUid([selectorString cStringUsingEncoding:NSUTF8StringEncoding]); + // sel = sel_getUid([selectorString UTF8String]); sel = [selectorCache selector]; } @@ -298,7 +298,7 @@ - (id) handleUnknownMessage:(id) message withContext:(NSMutableDictionary *) con cursor = [cursor cdr]; } } - // sel = sel_getUid([selectorString cStringUsingEncoding:NSUTF8StringEncoding]); + // sel = sel_getUid([selectorString UTF8String]); sel = [selectorCache selector]; } @@ -380,11 +380,11 @@ - (id) handleUnknownMessage:(id) message withContext:(NSMutableDictionary *) con - (id) valueForIvar:(NSString *) name { - Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); + Ivar v = class_getInstanceVariable([self class], [name UTF8String]); if (!v) { //check if a _variable was synthesized - v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] cStringUsingEncoding:NSUTF8StringEncoding]); + v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] UTF8String]); } if (!v) { @@ -408,11 +408,11 @@ - (id) valueForIvar:(NSString *) name - (BOOL) hasValueForIvar:(NSString *) name { - Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); + Ivar v = class_getInstanceVariable([self class], [name UTF8String]); if (!v) { //check if a _variable was synthesized - v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] cStringUsingEncoding:NSUTF8StringEncoding]); + v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] UTF8String]); } if (!v) { @@ -437,10 +437,10 @@ - (BOOL) hasValueForIvar:(NSString *) name - (void) setValue:(id) value forIvar:(NSString *)name { - Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); + Ivar v = class_getInstanceVariable([self class], [name UTF8String]); if (!v) { //check if a _variable was synthesized - v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] cStringUsingEncoding:NSUTF8StringEncoding]); + v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] UTF8String]); } if (!v) { NSMutableDictionary *sparseIvars = [self associatedObjectForKey:@"__nuivars"]; @@ -524,10 +524,10 @@ + (NSArray *) instanceVariableNames + (NSString *) signatureForIvar:(NSString *)name { - Ivar v = class_getInstanceVariable([self class], [name cStringUsingEncoding:NSUTF8StringEncoding]); + Ivar v = class_getInstanceVariable([self class], [name UTF8String]); if (!v) { //check if a _variable was synthesized - v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] cStringUsingEncoding:NSUTF8StringEncoding]); + v = class_getInstanceVariable([self class], [[@"_" stringByAppendingString:name] UTF8String]); } return [NSString stringWithCString:ivar_getTypeEncoding(v) encoding:NSUTF8StringEncoding]; } @@ -540,7 +540,7 @@ + (id) inheritedByClass:(NuClass *) newClass + (id) createSubclassNamed:(NSString *) subclassName { Class c = [self class]; - const char *name = [subclassName cStringUsingEncoding:NSUTF8StringEncoding]; + const char *name = [subclassName UTF8String]; // does the class already exist? Class s = objc_getClass(name); @@ -580,7 +580,7 @@ + (BOOL) copyInstanceMethod:(NSString *) methodName fromClass:(NuClass *)prototy { Class thisClass = [self class]; Class otherClass = [prototypeClass wrappedClass]; - const char *method_name_str = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; + const char *method_name_str = [methodName UTF8String]; SEL selector = sel_registerName(method_name_str); BOOL result = nu_copyInstanceMethod(thisClass, otherClass, selector); return result; @@ -665,7 +665,7 @@ - (id) set:(NuCell *) propertyList id value = [[cursor cdr] car]; id label = ([key isKindOfClass:[NuSymbol class]] && [key isLabel]) ? [key labelName] : key; if ([label isEqualToString:@"action"] && [self respondsToSelector:@selector(setAction:)]) { - SEL selector = sel_registerName([value cStringUsingEncoding:NSUTF8StringEncoding]); + SEL selector = sel_registerName([value UTF8String]); [(id) self setAction:selector]; } else { diff --git a/objc/Nu.m b/objc/Nu.m index 69eb5a6..1163770 100644 --- a/objc/Nu.m +++ b/objc/Nu.m @@ -138,7 +138,7 @@ int NuMain(int argc, const char *argv[]) NSString *main_nu = [NSString stringWithContentsOfFile:main_path encoding:NSUTF8StringEncoding error:NULL]; if (main_nu) { NuParser *parser = [Nu sharedParser]; - id script = [parser parse:main_nu asIfFromFilename:[main_nu cStringUsingEncoding:NSUTF8StringEncoding]]; + id script = [parser parse:main_nu asIfFromFilename:[main_nu UTF8String]]; [parser eval:script]; [parser release]; return 0; @@ -214,7 +214,7 @@ int NuMain(int argc, const char *argv[]) } @catch (NuException* nuException) { - printf("%s\n", [[nuException dump] cStringUsingEncoding:NSUTF8StringEncoding]); + printf("%s\n", [[nuException dump] UTF8String]); } @catch (id exception) { @@ -402,7 +402,7 @@ + (BOOL) loadNuFile:(NSString *) fileName fromBundleWithIdentifier:(NSString *) NSString *fileNu = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL]; if (fileNu) { NuParser *parser = [Nu sharedParser]; - id script = [parser parse:fileNu asIfFromFilename:[filePath cStringUsingEncoding:NSUTF8StringEncoding]]; + id script = [parser parse:fileNu asIfFromFilename:[filePath UTF8String]]; if (!context) context = [parser context]; [script evalWithContext:context]; success = YES; diff --git a/objc/NuBridge.m b/objc/NuBridge.m index 484b906..309b304 100644 --- a/objc/NuBridge.m +++ b/objc/NuBridge.m @@ -576,7 +576,7 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type *((SEL *) objc_value) = 0; return NO; } - const char *selectorName = [nu_value cStringUsingEncoding:NSUTF8StringEncoding]; + const char *selectorName = [nu_value UTF8String]; if (selectorName) { *((SEL *) objc_value) = sel_registerName(selectorName); return NO; @@ -659,7 +659,7 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type char **array = (char **) malloc (array_size * sizeof(char *)); int i; for (i = 0; i < array_size; i++) { - array[i] = strdup([[nu_value objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding]); + array[i] = strdup([[nu_value objectAtIndex:i] UTF8String]); } *((char ***) objc_value) = array; return NO; @@ -690,7 +690,7 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type case '*': { - *((char **) objc_value) = (char*)[[nu_value stringValue] cStringUsingEncoding:NSUTF8StringEncoding]; + *((char **) objc_value) = (char*)[[nu_value stringValue] UTF8String]; return NO; } @@ -1257,8 +1257,8 @@ static IMP construct_method_handler(SEL sel, NuBlock *block, const char *signatu id add_method_to_class(Class c, NSString *methodName, NSString *signature, NuBlock *block) { - const char *method_name_str = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; - const char *signature_str = [signature cStringUsingEncoding:NSUTF8StringEncoding]; + const char *method_name_str = [methodName UTF8String]; + const char *signature_str = [signature UTF8String]; SEL selector = sel_registerName(method_name_str); //NuSymbolTable *symbolTable = [[block context] objectForKey:SYMBOLS_KEY]; @@ -1568,7 +1568,7 @@ id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *co if ((returnType == Nu__null) || ([argumentTypes length] < [argumentNames length])) { // look up the signature - SEL selector = sel_registerName([methodName cStringUsingEncoding:NSUTF8StringEncoding]); + SEL selector = sel_registerName([methodName UTF8String]); NSMethodSignature *methodSignature = [classToExtend instanceMethodSignatureForSelector:selector]; if (!methodSignature) diff --git a/objc/NuBridgeSupport.m b/objc/NuBridgeSupport.m index 54d45be..0294191 100644 --- a/objc/NuBridgeSupport.m +++ b/objc/NuBridgeSupport.m @@ -31,7 +31,7 @@ @implementation NuBridgeSupport + (void)importLibrary:(NSString *) libraryPath { //NSLog(@"importing library %@", libraryPath); - dlopen([libraryPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_LAZY | RTLD_GLOBAL); + dlopen([libraryPath UTF8String], RTLD_LAZY | RTLD_GLOBAL); } + (void)importFramework:(NSString *) framework fromPath:(NSString *) path intoDictionary:(NSMutableDictionary *) BridgeSupport diff --git a/objc/NuBridgedConstant.m b/objc/NuBridgedConstant.m index bf1eea0..ba845b4 100644 --- a/objc/NuBridgedConstant.m +++ b/objc/NuBridgedConstant.m @@ -14,7 +14,7 @@ @implementation NuBridgedConstant + (id) constantWithName:(NSString *) name signature:(NSString *) signature { - const char *constant_name = [name cStringUsingEncoding:NSUTF8StringEncoding]; + const char *constant_name = [name UTF8String]; void *constant = dlsym(RTLD_DEFAULT, constant_name); if (!constant) { NSLog(@"%s", dlerror()); @@ -22,7 +22,7 @@ + (id) constantWithName:(NSString *) name signature:(NSString *) signature NSLog(@"In Xcode, check the 'Preserve Private External Symbols' checkbox."); return nil; } - return get_nu_value_from_objc_value(constant, [signature cStringUsingEncoding:NSUTF8StringEncoding]); + return get_nu_value_from_objc_value(constant, [signature UTF8String]); } @end diff --git a/objc/NuBridgedFunction.m b/objc/NuBridgedFunction.m index 8feb3d6..888108c 100644 --- a/objc/NuBridgedFunction.m +++ b/objc/NuBridgedFunction.m @@ -29,8 +29,8 @@ - (void) dealloc - (NuBridgedFunction *) initWithName:(NSString *)n signature:(NSString *)s { - name = strdup([n cStringUsingEncoding:NSUTF8StringEncoding]); - signature = strdup([s cStringUsingEncoding:NSUTF8StringEncoding]); + name = strdup([n UTF8String]); + signature = strdup([s UTF8String]); function = dlsym(RTLD_DEFAULT, name); if (!function) { [NSException raise:@"NuCantFindBridgedFunction" @@ -43,7 +43,7 @@ - (NuBridgedFunction *) initWithName:(NSString *)n signature:(NSString *)s + (NuBridgedFunction *) functionWithName:(NSString *)name signature:(NSString *)signature { - const char *function_name = [name cStringUsingEncoding:NSUTF8StringEncoding]; + const char *function_name = [name UTF8String]; void *function = dlsym(RTLD_DEFAULT, function_name); if (!function) { [NSException raise:@"NuCantFindBridgedFunction" diff --git a/objc/NuClass.m b/objc/NuClass.m index 169c49a..49f3276 100644 --- a/objc/NuClass.m +++ b/objc/NuClass.m @@ -29,7 +29,7 @@ @implementation NuClass + (NuClass *) classWithName:(NSString *)string { - const char *name = [string cStringUsingEncoding:NSUTF8StringEncoding]; + const char *name = [string UTF8String]; Class class = objc_getClass(name); if (class) { return [[[self alloc] initWithClass:class] autorelease]; @@ -51,7 +51,7 @@ + (NuClass *) classWithClass:(Class) class - (id) initWithClassNamed:(NSString *) string { - const char *name = [string cStringUsingEncoding:NSUTF8StringEncoding]; + const char *name = [string UTF8String]; Class class = objc_getClass(name); return [self initWithClass: class]; } @@ -159,7 +159,7 @@ - (NSComparisonResult) compare:(NuClass *) anotherClass - (NuMethod *) classMethodWithName:(NSString *) methodName { - const char *methodNameString = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; + const char *methodNameString = [methodName UTF8String]; NuMethod *method = Nu__null; unsigned int method_count; Method *method_list = class_copyMethodList(object_getClass([self wrappedClass]), &method_count); @@ -175,7 +175,7 @@ - (NuMethod *) classMethodWithName:(NSString *) methodName - (NuMethod *) instanceMethodWithName:(NSString *) methodName { - const char *methodNameString = [methodName cStringUsingEncoding:NSUTF8StringEncoding]; + const char *methodNameString = [methodName UTF8String]; NuMethod *method = Nu__null; unsigned int method_count; Method *method_list = class_copyMethodList([self wrappedClass], &method_count); @@ -204,7 +204,7 @@ - (id) addClassMethod:(NSString *)methodName signature:(NSString *)signature bod - (id) addInstanceVariable:(NSString *)variableName signature:(NSString *)signature { //NSLog(@"adding instance variable %@", variableName); - nu_class_addInstanceVariable_withSignature(c, [variableName cStringUsingEncoding:NSUTF8StringEncoding], [signature cStringUsingEncoding:NSUTF8StringEncoding]); + nu_class_addInstanceVariable_withSignature(c, [variableName UTF8String], [signature UTF8String]); return Nu__null; } @@ -263,13 +263,13 @@ - (NSArray *) instanceVariableNames { - (BOOL) addPropertyWithName:(NSString *) name { const objc_property_attribute_t attributes[10]; unsigned int attributeCount = 0; - return class_addProperty(c, [name cStringUsingEncoding:NSUTF8StringEncoding], + return class_addProperty(c, [name UTF8String], attributes, attributeCount); } - (NuProperty *) propertyWithName:(NSString *) name { - objc_property_t property = class_getProperty(c, [name cStringUsingEncoding:NSUTF8StringEncoding]); + objc_property_t property = class_getProperty(c, [name UTF8String]); return [NuProperty propertyWithProperty:(objc_property_t) property]; } diff --git a/objc/NuOperators.m b/objc/NuOperators.m index 55509f0..8b6857b 100644 --- a/objc/NuOperators.m +++ b/objc/NuOperators.m @@ -1511,7 +1511,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context } else { #endif - printf("%s\n", [string cStringUsingEncoding:NSUTF8StringEncoding]); + printf("%s\n", [string UTF8String]); #if !TARGET_OS_IPHONE } #endif @@ -1558,7 +1558,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context } else { #endif - printf("%s", [string cStringUsingEncoding:NSUTF8StringEncoding]); + printf("%s", [string UTF8String]); #if !TARGET_OS_IPHONE } #endif @@ -1634,7 +1634,7 @@ id loadNuLibraryFile(NSString *nuFileName, id parser, id context, id symbolTable NSString *string = [NSString stringWithContentsOfFile:fullPath]; id value = Nu__null; if (string) { - id body = [parser parse:string asIfFromFilename:[fullPath cStringUsingEncoding:NSUTF8StringEncoding]]; + id body = [parser parse:string asIfFromFilename:[fullPath UTF8String]]; value = [body evalWithContext:context]; return [symbolTable symbolWithString:@"t"]; } @@ -1697,7 +1697,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context if (fileName) { NSString *string = [NSString stringWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:NULL]; if (string) { - id body = [parser parse:string asIfFromFilename:[fileName cStringUsingEncoding:NSUTF8StringEncoding]]; + id body = [parser parse:string asIfFromFilename:[fileName UTF8String]]; [body evalWithContext:context]; return [symbolTable symbolWithString:@"t"]; } @@ -1811,7 +1811,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context #if defined(__x86_64__) || TARGET_OS_IPHONE - newClass = objc_allocateClassPair(parentClass, [[className stringValue] cStringUsingEncoding:NSUTF8StringEncoding], 0); + newClass = objc_allocateClassPair(parentClass, [[className stringValue] UTF8String], 0); childClass = [NuClass classWithClass:newClass]; [childClass setRegistered:NO]; //NSLog(@"created class %@", [childClass name]); @@ -1920,8 +1920,8 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context cursor = [cursor cdr]; NSString *signature = signature_for_identifier(variableType, symbolTable); nu_class_addInstanceVariable_withSignature(classToExtend, - [[variableName stringValue] cStringUsingEncoding:NSUTF8StringEncoding], - [signature cStringUsingEncoding:NSUTF8StringEncoding]); + [[variableName stringValue] UTF8String], + [signature UTF8String]); //NSLog(@"adding ivar %@ with signature %@", [variableName stringValue], signature); } return Nu__null; @@ -1970,7 +1970,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context [command appendString:[[[cursor car] evalWithContext:context] stringValue]]; cursor = [cursor cdr]; } - const char *commandString = [command cStringUsingEncoding:NSUTF8StringEncoding]; + const char *commandString = [command UTF8String]; int result = system(commandString) >> 8; // this needs an explanation return @(result); #endif diff --git a/objc/NuParser.m b/objc/NuParser.m index f5cd483..27e8d5f 100644 --- a/objc/NuParser.m +++ b/objc/NuParser.m @@ -61,7 +61,7 @@ - (int) interact; static id atomWithString(NSString *string, NuSymbolTable *symbolTable) { - const char *cstring = [string cStringUsingEncoding:NSUTF8StringEncoding]; + const char *cstring = [string UTF8String]; char *endptr; // If the string can be converted to a long, it's an NSNumber. long lvalue = strtol(cstring, &endptr, 0); @@ -1038,13 +1038,13 @@ - (int) interact progn = [[self parse:[NSString stringWithCString:line encoding:NSUTF8StringEncoding]] retain]; } @catch (NuException* nuException) { - printf("%s\n", [[nuException dump] cStringUsingEncoding:NSUTF8StringEncoding]); + printf("%s\n", [[nuException dump] UTF8String]); [self reset]; } @catch (id exception) { printf("%s: %s\n", - [[exception name] cStringUsingEncoding:NSUTF8StringEncoding], - [[exception reason] cStringUsingEncoding:NSUTF8StringEncoding]); + [[exception name] UTF8String], + [[exception reason] UTF8String]); [self reset]; } @@ -1053,7 +1053,7 @@ - (int) interact while (cursor && (cursor != [NSNull null])) { if ([cursor car] != [NSNull null]) { id expression = [cursor car]; - //printf("evaluating %s\n", [[expression stringValue] cStringUsingEncoding:NSUTF8StringEncoding]); + //printf("evaluating %s\n", [[expression stringValue] UTF8String]); @try { @@ -1066,16 +1066,16 @@ - (int) interact else { stringToDisplay = [result stringValue]; } - printf("%s\n", [stringToDisplay cStringUsingEncoding:NSUTF8StringEncoding]); + printf("%s\n", [stringToDisplay UTF8String]); } } @catch (NuException* nuException) { - printf("%s\n", [[nuException dump] cStringUsingEncoding:NSUTF8StringEncoding]); + printf("%s\n", [[nuException dump] UTF8String]); } @catch (id exception) { printf("%s: %s\n", - [[exception name] cStringUsingEncoding:NSUTF8StringEncoding], - [[exception reason] cStringUsingEncoding:NSUTF8StringEncoding]); + [[exception name] UTF8String], + [[exception reason] UTF8String]); } } cursor = [cursor cdr]; diff --git a/objc/NuPointer.m b/objc/NuPointer.m index 95d9e31..a558702 100644 --- a/objc/NuPointer.m +++ b/objc/NuPointer.m @@ -57,7 +57,7 @@ - (void) allocateSpaceForTypeString:(NSString *) s if (thePointerIsMine) free(pointer); [self setTypeString:s]; - const char *type = [s cStringUsingEncoding:NSUTF8StringEncoding]; + const char *type = [s UTF8String]; while (*type && (*type != '^')) type++; if (*type) @@ -77,7 +77,7 @@ - (void) dealloc - (id) value { - const char *type = [typeString cStringUsingEncoding:NSUTF8StringEncoding]; + const char *type = [typeString UTF8String]; while (*type && (*type != '^')) type++; if (*type) diff --git a/objc/NuSuper.m b/objc/NuSuper.m index 58af9f9..5ac5eff 100644 --- a/objc/NuSuper.m +++ b/objc/NuSuper.m @@ -58,7 +58,7 @@ - (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context cursor = [cursor cdr]; } } - SEL sel = sel_getUid([selectorString cStringUsingEncoding:NSUTF8StringEncoding]); + SEL sel = sel_getUid([selectorString UTF8String]); // we're going to send the message to the handler of its superclass instead of one defined for its class. Class c = class_getSuperclass(class); @@ -77,4 +77,4 @@ - (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context return result; } -@end \ No newline at end of file +@end diff --git a/objc/NuSymbol.m b/objc/NuSymbol.m index b4c1df1..1d2f163 100644 --- a/objc/NuSymbol.m +++ b/objc/NuSymbol.m @@ -101,7 +101,7 @@ @implementation NuSymbol - (void) _setStringValue:(NSString *) string { self->stringValue = [string copy]; - const char *cstring = [string cStringUsingEncoding:NSUTF8StringEncoding]; + const char *cstring = [string UTF8String]; NSUInteger len = strlen(cstring); self->isLabel = (cstring[len - 1] == ':'); self->isGensym = (len > 2) && (cstring[0] == '_') && (cstring[1] == '_'); From 56d2f7988e94e090dfedd53162b904eaf4e238d6 Mon Sep 17 00:00:00 2001 From: Dirk Theisen Date: Thu, 13 Apr 2017 14:37:47 +0200 Subject: [PATCH 23/26] Replaced all occurrences of (id)[NSNull null] with Nu__null for brevity and some efficiency. --- objc/NSArray+Nu.m | 8 ++--- objc/NSDictionary+Nu.m | 4 +-- objc/NSNull+Nu.m | 6 ++-- objc/NSObject+Nu.m | 4 +-- objc/NSSet+Nu.m | 2 +- objc/Nu.m | 4 +-- objc/NuBridge.m | 70 ++++++++++++++++++++-------------------- objc/NuBridgedFunction.m | 2 +- objc/NuMacro.m | 2 +- objc/NuMarkupOperator.m | 14 ++++---- objc/NuMethod.m | 2 +- objc/NuOperators.m | 4 +-- objc/NuParser.m | 24 +++++++------- objc/NuSuper.m | 6 ++-- objc/NuSwizzles.m | 10 +++--- objc/NuSymbol.m | 10 +++--- 16 files changed, 86 insertions(+), 86 deletions(-) diff --git a/objc/NSArray+Nu.m b/objc/NSArray+Nu.m index 6c72d60..a3a7e1b 100644 --- a/objc/NSArray+Nu.m +++ b/objc/NSArray+Nu.m @@ -142,17 +142,17 @@ - (void) addObjectsFromList:(id)list - (void) addPossiblyNullObject:(id)anObject { - [self addObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; + [self addObject:((anObject == nil) ? Nu__null : anObject)]; } - (void) insertPossiblyNullObject:(id)anObject atIndex:(int)index { - [self insertObject:((anObject == nil) ? (id)[NSNull null] : anObject) atIndex:index]; + [self insertObject:((anObject == nil) ? Nu__null : anObject) atIndex:index]; } - (void) replaceObjectAtIndex:(int)index withPossiblyNullObject:(id)anObject { - [self replaceObjectAtIndex:index withObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; + [self replaceObjectAtIndex:index withObject:((anObject == nil) ? Nu__null : anObject)]; } - (void) sortUsingBlock:(NuBlock *) block @@ -160,4 +160,4 @@ - (void) sortUsingBlock:(NuBlock *) block [self sortUsingFunction:sortedArrayUsingBlockHelper context:block]; } -@end \ No newline at end of file +@end diff --git a/objc/NSDictionary+Nu.m b/objc/NSDictionary+Nu.m index f134ea7..14d95b6 100644 --- a/objc/NSDictionary+Nu.m +++ b/objc/NSDictionary+Nu.m @@ -22,7 +22,7 @@ + (NSDictionary *) dictionaryWithList:(id) list key = [key labelName]; } id value = [[cursor cdr] car]; - if (!value || [value isEqual:[NSNull null]]) { + if (!value || [value isEqual:Nu__null]) { [d removeObjectForKey:key]; } else { [d setValue:value forKey:key]; @@ -133,7 +133,7 @@ - (id) lookupObjectForKey:(id)key - (void) setPossiblyNullObject:(id) anObject forKey:(id) aKey { - [self setObject:((anObject == nil) ? (id)[NSNull null] : anObject) forKey:aKey]; + [self setObject:((anObject == nil) ? Nu__null : anObject) forKey:aKey]; } @end diff --git a/objc/NSNull+Nu.m b/objc/NSNull+Nu.m index 89b6200..63f3e0e 100644 --- a/objc/NSNull+Nu.m +++ b/objc/NSNull+Nu.m @@ -28,7 +28,7 @@ - (NSUInteger) count - (NSMutableArray *) array { - return [NSMutableArray array]; + return @[]; } - (NSString *) stringValue @@ -41,9 +41,9 @@ - (BOOL) isEqual:(id) other return ((self == other) || (other == 0)) ? 1l : 0l; } -- (const char *) cStringUsingEncoding:(NSStringEncoding) encoding +- (const char *) UTF8String { - return [[self stringValue] cStringUsingEncoding:encoding]; + return [[self stringValue] UTF8String]; } @end diff --git a/objc/NSObject+Nu.m b/objc/NSObject+Nu.m index a03b5e2..e25b703 100644 --- a/objc/NSObject+Nu.m +++ b/objc/NSObject+Nu.m @@ -305,7 +305,7 @@ - (id) handleUnknownMessage:(id) message withContext:(NSMutableDictionary *) con // If the object responds to methodSignatureForSelector:, we should create and forward an invocation to it. NSMethodSignature *methodSignature = sel ? [self methodSignatureForSelector:sel] : 0; if (methodSignature) { - id result = [NSNull null]; + id result = Nu__null; // Create an invocation to forward. NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; [invocation setTarget:self]; @@ -331,7 +331,7 @@ - (id) handleUnknownMessage:(id) message withContext:(NSMutableDictionary *) con [invocation getReturnValue:buffer]; result = get_nu_value_from_objc_value(buffer, [methodSignature methodReturnType]); } @catch (id exception) { - result = [NSNull null]; + result = Nu__null; } free(buffer); } diff --git a/objc/NSSet+Nu.m b/objc/NSSet+Nu.m index 5cd6e91..87348db 100644 --- a/objc/NSSet+Nu.m +++ b/objc/NSSet+Nu.m @@ -50,7 +50,7 @@ @implementation NSMutableSet(Nu) - (void) addPossiblyNullObject:(id)anObject { - [self addObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; + [self addObject:((anObject == nil) ? Nu__null : anObject)]; } @end diff --git a/objc/Nu.m b/objc/Nu.m index 1163770..fcaeef0 100644 --- a/objc/Nu.m +++ b/objc/Nu.m @@ -249,7 +249,7 @@ void NuInit() initialized = YES; @autoreleasepool { // as a convenience, we set a file static variable to nil. - Nu__null = [NSNull null]; + Nu__null = Nu__null; // add enumeration to collection classes [NSArray include: [NuClass classWithClass:[NuEnumerable class]]]; @@ -298,7 +298,7 @@ void NuInit() id _nunull() { - return [NSNull null]; + return Nu__null; } id _nustring(const unsigned char *string) diff --git a/objc/NuBridge.m b/objc/NuBridge.m index 309b304..db5cc91 100644 --- a/objc/NuBridge.m +++ b/objc/NuBridge.m @@ -483,7 +483,7 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type case 'c': #endif { - if (nu_value == [NSNull null]) { + if (nu_value == Nu__null) { *((int *) objc_value) = 0; return NO; } @@ -512,7 +512,7 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type #endif case 'L': { - if (nu_value == [NSNull null]) { + if (nu_value == Nu__null) { *((unsigned long *) objc_value) = 0; return NO; } @@ -521,7 +521,7 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type } case 'l': { - if (nu_value == [NSNull null]) { + if (nu_value == Nu__null) { *((long *) objc_value) = 0; return NO; } @@ -530,7 +530,7 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type } case 'Q': { - if (nu_value == [NSNull null]) { + if (nu_value == Nu__null) { *((unsigned long long *) objc_value) = 0; return NO; } @@ -539,7 +539,7 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type } case 'q': { - if (nu_value == [NSNull null]) { + if (nu_value == Nu__null) { *((long long *) objc_value) = 0; return NO; } @@ -572,7 +572,7 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type case ':': { // selectors must be strings (symbols could be ok too...) - if (!nu_value || (nu_value == [NSNull null])) { + if (!nu_value || (nu_value == Nu__null)) { *((SEL *) objc_value) = 0; return NO; } @@ -647,7 +647,7 @@ int set_objc_value_from_nu_value(void *objc_value, id nu_value, const char *type case '^': { - if (!nu_value || (nu_value == [NSNull null])) { + if (!nu_value || (nu_value == Nu__null)) { *((char ***) objc_value) = NULL; return NO; } @@ -719,12 +719,12 @@ id get_nu_value_from_objc_value(void *objc_value, const char *typeString) switch(typeChar) { case 'v': { - return [NSNull null]; + return Nu__null; } case '@': { id result = *((id *)objc_value); - return result ? result : (id)[NSNull null]; + return result ? result : Nu__null; } case '#': { @@ -882,7 +882,7 @@ id get_nu_value_from_objc_value(void *objc_value, const char *typeString) { if (!strcmp(typeString, "^v")) { if (*((unsigned long *)objc_value) == 0) - return [NSNull null]; + return Nu__null; else { id nupointer = [[[NuPointer alloc] init] autorelease]; [nupointer setPointer:*((void **)objc_value)]; @@ -899,15 +899,15 @@ id get_nu_value_from_objc_value(void *objc_value, const char *typeString) // CGImageRef is one. As we find others, we can add them here. else if (!strcmp(typeString, "^{CGImage=}")) { id result = *((id *)objc_value); - return result ? result : (id)[NSNull null]; + return result ? result : Nu__null; } else if (!strcmp(typeString, "^{CGColor=}")) { id result = *((id *)objc_value); - return result ? result : (id)[NSNull null]; + return result ? result : Nu__null; } else { if (*((unsigned long *)objc_value) == 0) - return [NSNull null]; + return Nu__null; else { id nupointer = [[[NuPointer alloc] init] autorelease]; [nupointer setPointer:*((void **)objc_value)]; @@ -915,11 +915,11 @@ id get_nu_value_from_objc_value(void *objc_value, const char *typeString) return nupointer; } } - return [NSNull null]; + return Nu__null; } default: NSLog (@"UNIMPLEMENTED: unable to wrap object of type %s", typeString); - return [NSNull null]; + return Nu__null; } } @@ -968,7 +968,7 @@ id nu_calling_objc_method_handler(id target, Method m, NSMutableArray *args) // ensure that methods declared to return void always return void. char return_type_buffer[BUFSIZE]; method_getReturnType(m, return_type_buffer, BUFSIZE); - return (!strcmp(return_type_buffer, "v")) ? (id)[NSNull null] : result; + return (!strcmp(return_type_buffer, "v")) ? Nu__null : result; } id result; @@ -976,7 +976,7 @@ id nu_calling_objc_method_handler(id target, Method m, NSMutableArray *args) NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SEL s = method_getName(m); - result = [NSNull null]; + result = Nu__null; // dynamically construct the method call @@ -1267,7 +1267,7 @@ id add_method_to_class(Class c, NSString *methodName, NSString *signature, NuBlo IMP imp = construct_method_handler(selector, block, signature_str); if (imp == NULL) { NSLog(@"failed to construct handler for %s(%s)", method_name_str, signature_str); - return [NSNull null]; + return Nu__null; } // save the block in a hash table keyed by the imp. @@ -1278,7 +1278,7 @@ id add_method_to_class(Class c, NSString *methodName, NSString *signature, NuBlo // insert the method handler in the class method table nu_class_replaceMethod(c, selector, imp, signature_str); //NSLog(@"setting handler for %s(%s) in class %s", method_name_str, signature_str, class_getName(c)); - return [NSNull null]; + return Nu__null; } @@ -1368,7 +1368,7 @@ static void prepare_symbols(NuSymbolTable *symbolTable) [modifiers addObject:@"r"]; } else if (cursor_car == void_symbol) { - if (![cursor cdr] || ([cursor cdr] == [NSNull null])) { + if (![cursor cdr] || ([cursor cdr] == Nu__null)) { if (modifiers) [signature appendString:[[modifiers sortedArrayUsingSelector:@selector(compare:)] componentsJoinedByString:@""]]; [signature appendString:@"v"]; @@ -1381,7 +1381,7 @@ static void prepare_symbols(NuSymbolTable *symbolTable) } } else if (cursor_car == id_symbol) { - if (![cursor cdr] || ([cursor cdr] == [NSNull null])) { + if (![cursor cdr] || ([cursor cdr] == Nu__null)) { if (modifiers) [signature appendString:[[modifiers sortedArrayUsingSelector:@selector(compare:)] componentsJoinedByString:@""]]; [signature appendString:@"@"]; @@ -1478,17 +1478,17 @@ id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *co { NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - id returnType = [NSNull null]; + id returnType = Nu__null; id selector = [[[NuCell alloc] init] autorelease]; - id argumentTypes = [NSNull null]; - id argumentNames = [NSNull null]; + id argumentTypes = Nu__null; + id argumentNames = Nu__null; id isSymbol = [symbolTable symbolWithString:@"is"]; id cursor = cdr; id selector_cursor = nil; id argumentTypes_cursor = nil; id argumentNames_cursor = nil; - if (cursor && (cursor != [NSNull null]) && ([cursor car] != isSymbol)) { + if (cursor && (cursor != Nu__null) && ([cursor car] != isSymbol)) { // scan the return type if (![[cursor car] atom]) { returnType = [cursor car] ; @@ -1498,10 +1498,10 @@ id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *co // The return type specifier must be a list (in parens). If it is missing, leave it as null. returnType = Nu__null; } - if (cursor && (cursor != [NSNull null])) { + if (cursor && (cursor != Nu__null)) { [selector setCar:[cursor car]]; // scan a part of the selector cursor = [cursor cdr]; - if (cursor && (cursor != [NSNull null])) { + if (cursor && (cursor != Nu__null)) { if ([cursor car] != isSymbol) { argumentTypes = [[[NuCell alloc] init] autorelease]; argumentNames = [[[NuCell alloc] init] autorelease]; @@ -1510,10 +1510,10 @@ id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *co [argumentTypes setCar:[cursor car]]; cursor = [cursor cdr]; } - if (cursor && (cursor != [NSNull null])) { + if (cursor && (cursor != Nu__null)) { [argumentNames setCar:[cursor car]]; cursor = [cursor cdr]; - if (cursor && (cursor != [NSNull null])) { + if (cursor && (cursor != Nu__null)) { selector_cursor = selector; argumentTypes_cursor = argumentTypes; argumentNames_cursor = argumentNames; @@ -1524,7 +1524,7 @@ id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *co } } // scan each remaining part of the selector - while (cursor && (cursor != [NSNull null]) && ([cursor car] != isSymbol)) { + while (cursor && (cursor != Nu__null) && ([cursor car] != isSymbol)) { [selector_cursor setCdr:[[[NuCell alloc] init] autorelease]]; [argumentTypes_cursor setCdr:[[[NuCell alloc] init] autorelease]]; [argumentNames_cursor setCdr:[[[NuCell alloc] init] autorelease]]; @@ -1534,20 +1534,20 @@ id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *co [selector_cursor setCar:[cursor car]]; cursor = [cursor cdr]; - if (cursor && (cursor != [NSNull null])) { + if (cursor && (cursor != Nu__null)) { if (![[cursor car] atom]) { // the argument type specifier must be a list. If it is missing, we'll use a default. [argumentTypes_cursor setCar:[cursor car]]; cursor = [cursor cdr]; } - if (cursor && (cursor != [NSNull null])) { + if (cursor && (cursor != Nu__null)) { [argumentNames_cursor setCar:[cursor car]]; cursor = [cursor cdr]; } } } - if (cursor && (cursor != [NSNull null])) { + if (cursor && (cursor != Nu__null)) { //NSLog(@"selector: %@", [selector stringValue]); //NSLog(@"argument names: %@", [argumentNames stringValue]); //NSLog(@"argument types:%@", [argumentTypes stringValue]); @@ -1559,7 +1559,7 @@ id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *co // combine the selectors into the method name NSMutableString *methodName = [[[NSMutableString alloc] init] autorelease]; selector_cursor = selector; - while (selector_cursor && (selector_cursor != [NSNull null])) { + while (selector_cursor && (selector_cursor != Nu__null)) { [methodName appendString:[[selector_cursor car] stringValue]]; selector_cursor = [selector_cursor cdr]; } @@ -1595,7 +1595,7 @@ id help_add_method_to_class(Class classToExtend, id cdr, NSMutableDictionary *co // then describe the arguments argumentTypes_cursor = argumentTypes; - while (argumentTypes_cursor && (argumentTypes_cursor != [NSNull null])) { + while (argumentTypes_cursor && (argumentTypes_cursor != Nu__null)) { id typeIdentifier = [argumentTypes_cursor car]; [signature appendString:signature_for_identifier(typeIdentifier, symbolTable)]; argumentTypes_cursor = [argumentTypes_cursor cdr]; diff --git a/objc/NuBridgedFunction.m b/objc/NuBridgedFunction.m index 888108c..afce34f 100644 --- a/objc/NuBridgedFunction.m +++ b/objc/NuBridgedFunction.m @@ -90,7 +90,7 @@ - (id) evalWithArguments:(id) cdr context:(NSMutableDictionary *) context int status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, argument_count, result_type, argument_types); if (status != FFI_OK) { NSLog (@"failed to prepare cif structure"); - return [NSNull null]; + return Nu__null; } id arg_cursor = cdr; diff --git a/objc/NuMacro.m b/objc/NuMacro.m index f6b49c4..020eea6 100644 --- a/objc/NuMacro.m +++ b/objc/NuMacro.m @@ -138,7 +138,7 @@ - (id) body:(NuCell *) oldBody withGensymPrefix:(NSString *) prefix symbolTable: - (id) expandUnquotes:(id) oldBody withContext:(NSMutableDictionary *) context { NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; - if (oldBody == [NSNull null]) + if (oldBody == Nu__null) return oldBody; id unquote = [symbolTable symbolWithString:@"unquote"]; id car = [oldBody car]; diff --git a/objc/NuMarkupOperator.m b/objc/NuMarkupOperator.m index a8d39d3..b390055 100644 --- a/objc/NuMarkupOperator.m +++ b/objc/NuMarkupOperator.m @@ -101,7 +101,7 @@ - (id) initWithTag:(NSString *) _tag prefix:(NSString *) _prefix contents:(id) _ prefix = @""; } [prefix retain]; - contents = _contents ? _contents : [NSNull null]; + contents = _contents ? _contents : Nu__null; [contents retain]; empty = [voidHTMLElements containsObject:tag]; return self; @@ -146,27 +146,27 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context } for (int i = 0; i < 2; i++) { id cursor = (i == 0) ? contents : cdr; - while (cursor && (cursor != [NSNull null])) { + while (cursor && (cursor != Nu__null)) { id item = [cursor car]; if ([item isKindOfClass:[NuSymbol class]] && [item isLabel]) { cursor = [cursor cdr]; - if (cursor && (cursor != [NSNull null])) { + if (cursor && (cursor != Nu__null)) { id value = [[cursor car] evalWithContext:context]; id attributeName = [[item labelName] stringByReplacingOccurrencesOfString:@"=" withString:@":"]; - if ([value isEqual:[NSNull null]]) { + if ([value isEqual:Nu__null]) { // omit attributes that are "false" } else if ([value isEqual:t_symbol]) { // boolean attributes with "true" are written without values [attributes appendFormat:@" %@", attributeName]; } else { - id stringValue = [value isEqual:[NSNull null]] ? @"" : [value stringValue]; + id stringValue = [value isEqual:Nu__null] ? @"" : [value stringValue]; [attributes appendFormat:@" %@=\"%@\"", attributeName, stringValue]; } } } else { id evaluatedItem = [item evalWithContext:context]; - if (!evaluatedItem || (evaluatedItem == [NSNull null])) { + if (!evaluatedItem || (evaluatedItem == Nu__null)) { // do nothing } else if ([evaluatedItem isKindOfClass:[NSString class]]) { @@ -184,7 +184,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context [body appendString:[evaluatedItem stringValue]]; } } - if (cursor && (cursor != [NSNull null])) + if (cursor && (cursor != Nu__null)) cursor = [cursor cdr]; } } diff --git a/objc/NuMethod.m b/objc/NuMethod.m index b5eee66..65752b5 100644 --- a/objc/NuMethod.m +++ b/objc/NuMethod.m @@ -32,7 +32,7 @@ - (id) initWithMethod:(Method) method - (NSString *) name { - return m ? [NSString stringWithCString:(sel_getName(method_getName(m))) encoding:NSUTF8StringEncoding] : (NSString *) [NSNull null]; + return m ? [NSString stringWithCString:(sel_getName(method_getName(m))) encoding:NSUTF8StringEncoding] : (NSString *) Nu__null; } - (int) argumentCount diff --git a/objc/NuOperators.m b/objc/NuOperators.m index 8b6857b..b400942 100644 --- a/objc/NuOperators.m +++ b/objc/NuOperators.m @@ -1751,7 +1751,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context id arg_values = [[NuCell alloc] init]; id cursor = [cdr car]; - if ((cursor != [NSNull null]) && [[cursor car] atom]) { + if ((cursor != Nu__null) && [[cursor car] atom]) { [arg_names setCar:[cursor car]]; [arg_values setCar:[[cursor cdr] car]]; } @@ -1966,7 +1966,7 @@ - (id) callWithArguments:(id)cdr context:(NSMutableDictionary *)context #else id cursor = cdr; NSMutableString *command = [NSMutableString string]; - while (cursor && (cursor != [NSNull null])) { + while (cursor && (cursor != Nu__null)) { [command appendString:[[[cursor car] evalWithContext:context] stringValue]]; cursor = [cursor cdr]; } diff --git a/objc/NuParser.m b/objc/NuParser.m index 27e8d5f..db383dd 100644 --- a/objc/NuParser.m +++ b/objc/NuParser.m @@ -47,7 +47,7 @@ - (int) state; - (NuCell *) root; - (NuStack *) opens; - (NSString *) stringValue; -- (const char *) cStringUsingEncoding:(NSStringEncoding) encoding; +- (const char *) UTF8String; - (id) init; - (void) openList; - (void) closeList; @@ -222,9 +222,9 @@ - (NSString *) stringValue return [self description]; } -- (const char *) cStringUsingEncoding:(NSStringEncoding) encoding +- (const char *) UTF8String { - return [[self stringValue] cStringUsingEncoding:encoding]; + return [[self stringValue] UTF8String]; } - (void) reset @@ -252,7 +252,7 @@ - (void) reset - (id) init { - if (Nu__null == 0) Nu__null = [NSNull null]; + if (Nu__null == 0) Nu__null = Nu__null; if ((self = [super init])) { filenum = -1; @@ -279,7 +279,7 @@ - (id) init - (void) close { // break this retain cycle so the parser can be deleted. - [context setPossiblyNullObject:[NSNull null] forKey:[symbolTable symbolWithString:@"_parser"]]; + [context setPossiblyNullObject:Nu__null forKey:[symbolTable symbolWithString:@"_parser"]]; } - (void) dealloc @@ -405,10 +405,10 @@ - (void) closeListCell --depth; if (addToCar) { - [current setCar:[NSNull null]]; + [current setCar:Nu__null]; } else { - [current setCdr:[NSNull null]]; + [current setCdr:Nu__null]; current = [stack pop]; } addToCar = false; @@ -557,7 +557,7 @@ static NSUInteger nu_parse_escape_sequences(NSString *string, NSUInteger i, NSUI -(id) parse:(NSString*)string { - if (!string) return [NSNull null]; // don't crash, at least. + if (!string) return Nu__null; // don't crash, at least. column = 0; if (state != PARSE_REGEX) @@ -940,7 +940,7 @@ -(id) parse:(NSString*)string [partial retain]; } if ([self incomplete]) { - return [NSNull null]; + return Nu__null; } else { NuCell *expressions = root; @@ -1048,10 +1048,10 @@ - (int) interact [self reset]; } - if (progn && (progn != [NSNull null])) { + if (progn && (progn != Nu__null)) { id cursor = [progn cdr]; - while (cursor && (cursor != [NSNull null])) { - if ([cursor car] != [NSNull null]) { + while (cursor && (cursor != Nu__null)) { + if ([cursor car] != Nu__null) { id expression = [cursor car]; //printf("evaluating %s\n", [[expression stringValue] UTF8String]); diff --git a/objc/NuSuper.m b/objc/NuSuper.m index 5ac5eff..906ea8a 100644 --- a/objc/NuSuper.m +++ b/objc/NuSuper.m @@ -39,7 +39,7 @@ + (NuSuper *) superWithObject:(id) o ofClass:(Class) c - (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context { // By themselves, Objective-C objects evaluate to themselves. - if (!cdr || (cdr == [NSNull null])) + if (!cdr || (cdr == Nu__null)) return object; //NSLog(@"messaging super with %@", [cdr stringValue]); @@ -50,10 +50,10 @@ - (id) evalWithArguments:(id)cdr context:(NSMutableDictionary *)context id selector = [cursor car]; NSMutableString *selectorString = [NSMutableString stringWithString:[selector stringValue]]; cursor = [cursor cdr]; - while (cursor && (cursor != [NSNull null])) { + while (cursor && (cursor != Nu__null)) { [args addObject:[[cursor car] evalWithContext:context]]; cursor = [cursor cdr]; - if (cursor && (cursor != [NSNull null])) { + if (cursor && (cursor != Nu__null)) { [selectorString appendString:[[cursor car] stringValue]]; cursor = [cursor cdr]; } diff --git a/objc/NuSwizzles.m b/objc/NuSwizzles.m index 5791fb3..4e00083 100644 --- a/objc/NuSwizzles.m +++ b/objc/NuSwizzles.m @@ -20,7 +20,7 @@ @implementation NSCFDictionarySwizzles - (void)nuSetObject:(id)anObject forKey:(id)aKey { - [self nuSetObject:((anObject == nil) ? (id)[NSNull null] : anObject) forKey:aKey]; + [self nuSetObject:((anObject == nil) ? (id)Nu__null : anObject) forKey:aKey]; } @end @@ -32,17 +32,17 @@ @implementation NSCFArraySwizzles - (void)nuAddObject:(id)anObject { - [self nuAddObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; + [self nuAddObject:((anObject == nil) ? (id)Nu__null : anObject)]; } - (void)nuInsertObject:(id)anObject atIndex:(int)index { - [self nuInsertObject:((anObject == nil) ? (id)[NSNull null] : anObject) atIndex:index]; + [self nuInsertObject:((anObject == nil) ? (id)Nu__null : anObject) atIndex:index]; } - (void)nuReplaceObjectAtIndex:(int)index withObject:(id)anObject { - [self nuReplaceObjectAtIndex:index withObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; + [self nuReplaceObjectAtIndex:index withObject:((anObject == nil) ? Nu__null : anObject)]; } @end @@ -54,7 +54,7 @@ @implementation NSCFSetSwizzles - (void)nuAddObject:(id)anObject { - [self nuAddObject:((anObject == nil) ? (id)[NSNull null] : anObject)]; + [self nuAddObject:((anObject == nil) ? Nu__null : anObject)]; } @end diff --git a/objc/NuSymbol.m b/objc/NuSymbol.m index 1d2f163..cc64b88 100644 --- a/objc/NuSymbol.m +++ b/objc/NuSymbol.m @@ -142,7 +142,7 @@ - (NSString *) stringValue - (int) intValue { - return (value == [NSNull null]) ? 0 : 1; + return (value == Nu__null) ? 0 : 1; } - (bool) isGensym @@ -179,10 +179,10 @@ - (id) evalWithContext:(NSMutableDictionary *)context if (c == '@') { NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; id object = [context lookupObjectForKey:[symbolTable symbolWithString:@"self"]]; - if (!object) return [NSNull null]; + if (!object) return Nu__null; id ivarName = [[self stringValue] substringFromIndex:1]; id result = [object valueForIvar:ivarName]; - return result ? result : (id) [NSNull null]; + return result ? result : Nu__null; } // Next, try to find the symbol in the local evaluation context. @@ -217,7 +217,7 @@ - (id) evalWithContext:(NSMutableDictionary *)context // Undefined globals evaluate to null. if (c == '$') - return [NSNull null]; + return Nu__null; // Now we try looking in the bridge support dictionaries. NuSymbolTable *symbolTable = [context objectForKey:SYMBOLS_KEY]; @@ -262,7 +262,7 @@ - (id) evalWithContext:(NSMutableDictionary *)context } } [NSException raise:@"NuUndefinedSymbol" format:@"%@", errorDescription]; - return [NSNull null]; + return Nu__null; } - (NSComparisonResult) compare:(NuSymbol *) anotherSymbol From be0d3671a7fd06751c567cb4d73c782f474e84a9 Mon Sep 17 00:00:00 2001 From: Tim Burks Date: Thu, 13 Apr 2017 07:59:48 -0700 Subject: [PATCH 24/26] Set Nu__null = [NSNull null] --- objc/Nu.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/objc/Nu.m b/objc/Nu.m index fcaeef0..c8cbe67 100644 --- a/objc/Nu.m +++ b/objc/Nu.m @@ -249,7 +249,7 @@ void NuInit() initialized = YES; @autoreleasepool { // as a convenience, we set a file static variable to nil. - Nu__null = Nu__null; + Nu__null = [NSNull null]; // add enumeration to collection classes [NSArray include: [NuClass classWithClass:[NuEnumerable class]]]; From ce824cd252268246b71a9c1ec94846c5a8887668 Mon Sep 17 00:00:00 2001 From: Tim Burks Date: Thu, 13 Apr 2017 08:05:18 -0700 Subject: [PATCH 25/26] Fix compiler warnings about array type and a self-assigned variable. --- objc/NSNull+Nu.m | 2 +- objc/NuParser.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/objc/NSNull+Nu.m b/objc/NSNull+Nu.m index 63f3e0e..3fb7843 100644 --- a/objc/NSNull+Nu.m +++ b/objc/NSNull+Nu.m @@ -28,7 +28,7 @@ - (NSUInteger) count - (NSMutableArray *) array { - return @[]; + return [@[] mutableCopy]; } - (NSString *) stringValue diff --git a/objc/NuParser.m b/objc/NuParser.m index db383dd..1501154 100644 --- a/objc/NuParser.m +++ b/objc/NuParser.m @@ -252,7 +252,7 @@ - (void) reset - (id) init { - if (Nu__null == 0) Nu__null = Nu__null; + if (Nu__null == 0) Nu__null = [NSNull null]; if ((self = [super init])) { filenum = -1; From caa19df53d72ac86849f4bf096c2eaad24a78984 Mon Sep 17 00:00:00 2001 From: ksjogo Date: Fri, 14 Apr 2017 17:33:56 +0200 Subject: [PATCH 26/26] remove ios readline include --- objc/NuOperators.m | 2 ++ objc/NuParser.m | 2 ++ 2 files changed, 4 insertions(+) diff --git a/objc/NuOperators.m b/objc/NuOperators.m index b400942..cc1bf7a 100644 --- a/objc/NuOperators.m +++ b/objc/NuOperators.m @@ -17,7 +17,9 @@ #import "NuBridge.h" #import "NuBridgedFunction.h" #import "NuClass.h" +#if !TARGET_OS_IPHONE #include +#endif #import "NSString+Nu.h" #if TARGET_OS_IPHONE diff --git a/objc/NuParser.m b/objc/NuParser.m index 1501154..fdae275 100644 --- a/objc/NuParser.m +++ b/objc/NuParser.m @@ -14,7 +14,9 @@ #import "NSDictionary+Nu.h" #import "NuException.h" #import "NuCell.h" +#if !TARGET_OS_IPHONE #include +#endif #define PARSE_NORMAL 0 #define PARSE_COMMENT 1