Permalink
Browse files

Super work-in-progress on an exception handling system similar to Com…

…mon Lisp conditions and restarts
  • Loading branch information...
1 parent 9d13782 commit bb3c24e0fe25d818568b0f9f330b59e19afddc66 @jspahrsummers committed Jan 9, 2012
@@ -0,0 +1,10 @@
+//
+// EXTCondition.h
+// extobjc
+//
+// Created by Justin Spahr-Summers on 08.01.12.
+// Released into the public domain.
+//
+
+#import <Foundation/Foundation.h>
+
@@ -0,0 +1,10 @@
+//
+// EXTCondition.m
+// extobjc
+//
+// Created by Justin Spahr-Summers on 08.01.12.
+// Released into the public domain.
+//
+
+#import "EXTCondition.h"
+
@@ -0,0 +1,16 @@
+
+//
+// EXTConditionTest.h
+// extobjc
+//
+// Created by Justin Spahr-Summers on 08.01.12.
+// Released into the public domain.
+//
+
+// Logic unit tests contain unit test code that is designed to be linked into an independent test executable.
+
+#import <SenTestingKit/SenTestingKit.h>
+
+@interface EXTConditionTest : SenTestCase
+
+@end
@@ -0,0 +1,117 @@
+//
+// EXTConditionTest.m
+// extobjc
+//
+// Created by Justin Spahr-Summers on 08.01.12.
+// Released into the public domain.
+//
+
+#import "EXTConditionTest.h"
+#import "EXTCondition.h"
+#import "EXTSafeCategory.h"
+
+NSMutableArray *handlers;
+NSMutableDictionary *restarts;
+jmp_buf context;
+
+typedef enum {
+ EXTHandlerStatusInstallingHandlers = 0,
+ EXTHandlerStatusRunning,
+ EXTHandlerStatusDone
+} EXTHandlerStatus;
+
+typedef enum {
+ EXTConditionStatusNoException = 0,
+ EXTConditionStatusExceptionThrown
+} EXTConditionStatus;
+
+#define handle \
+ for (EXTHandlerStatus handlerStatus_ = EXTHandlerStatusInstallingHandlers; handlerStatus_ != EXTHandlerStatusDone; ++handlerStatus_) \
+ switch (handlerStatus_) \
+ for (BOOL loop2Done_ = NO; !loop2Done_; loop2Done_ = YES) \
+ default: \
+ if (handlerStatus_ == EXTHandlerStatusRunning)
+ /* @handle block begins with user code */
+
+#define rescue(TYPE, VAR) \
+ else if (handlerStatus_ == EXTHandlerStatusInstallingHandlers) \
+ for (id handler_ = nil; !handler_; (handler_ && ([handlers addObject:handler_], YES))) \
+ handler_ = ^(TYPE *VAR)
+
+#define restart(...) \
+ if (!setjmp(context) && ((restarts = [NSDictionary dictionaryWithKeysAndCopiedObjects:__VA_ARGS__, nil]) || YES))
+
+#define invoke(RESTART, ...) \
+ NSLog(@"%@", RESTART) \
+
+@interface NSDictionary (ConditionExtensions)
++ (id)dictionaryWithKeysAndCopiedObjects:(id)firstKey, ... NS_REQUIRES_NIL_TERMINATION;
+@end
+
+@interface TestCondition : NSObject
++ (void)raise;
+@end
+
+@implementation TestCondition
++ (void)raise; {
+ NSLog(@"jumping");
+ longjmp(context, 1);
+}
+
+@end
+
+@implementation EXTConditionTest
+
+- (void)testRestart {
+ handlers = [[NSMutableArray alloc] init];
+
+ handle {
+ __block NSString *str = @"foobar";
+
+ restart(
+ @"invalid-string", ^(NSString *newString){ str = newString; }
+ ) {
+ if ([str isEqualToString:@"foobar"])
+ [TestCondition raise];
+ }
+
+ NSLog(@"restarts: %@", restarts);
+
+ STAssertEqualObjects(str, @"fizzbuzz", @"");
+ } rescue (TestCondition, condition) {
+ invoke(@"invalid-string", @"fizzbuzz");
+ };
+
+ void (^testHandler)(TestCondition *) = [handlers objectAtIndex:0];
+ testHandler(nil);
+}
+
+@end
+
+@safecategory (NSDictionary, ConditionExtensions)
++ (id)dictionaryWithKeysAndCopiedObjects:(id)firstKey, ... {
+ if (!firstKey)
+ return [NSDictionary dictionary];
+
+ va_list args;
+ va_start(args, firstKey);
+
+ id firstObject = va_arg(args, id);
+
+ NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
+ [dictionary setObject:[firstObject copy] forKey:firstKey];
+
+ for (;;) {
+ id nextKey = va_arg(args, id);
+ if (!nextKey)
+ break;
+
+ id nextObject = va_arg(args, id);
+ [dictionary setObject:[nextObject copy] forKey:nextKey];
+ }
+
+ va_end(args);
+
+ return [dictionary copy];
+}
+@end
@@ -56,6 +56,12 @@
D0A8B313128A4BDE004AACE0 /* extobjc.h in Headers */ = {isa = PBXBuildFile; fileRef = D0A8B311128A4BDE004AACE0 /* extobjc.h */; };
D0A8B338128A5185004AACE0 /* EXTConcreteProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D0A8B336128A5185004AACE0 /* EXTConcreteProtocol.h */; };
D0A8B33A128A5185004AACE0 /* EXTConcreteProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D0A8B336128A5185004AACE0 /* EXTConcreteProtocol.h */; };
+ D0A93EAE14BACFE400CAAF36 /* EXTCondition.h in Headers */ = {isa = PBXBuildFile; fileRef = D0A93EAC14BACFE400CAAF36 /* EXTCondition.h */; };
+ D0A93EAF14BACFE400CAAF36 /* EXTCondition.h in Headers */ = {isa = PBXBuildFile; fileRef = D0A93EAC14BACFE400CAAF36 /* EXTCondition.h */; };
+ D0A93EB014BACFE400CAAF36 /* EXTCondition.m in Sources */ = {isa = PBXBuildFile; fileRef = D0A93EAD14BACFE400CAAF36 /* EXTCondition.m */; };
+ D0A93EB114BACFE400CAAF36 /* EXTCondition.m in Sources */ = {isa = PBXBuildFile; fileRef = D0A93EAD14BACFE400CAAF36 /* EXTCondition.m */; };
+ D0A93EB414BAD01600CAAF36 /* EXTConditionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D0A93EB314BAD01600CAAF36 /* EXTConditionTest.m */; };
+ D0A93EB514BAD01600CAAF36 /* EXTConditionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D0A93EB314BAD01600CAAF36 /* EXTConditionTest.m */; };
D0ACF896132B417100900962 /* EXTDispatchObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D0ACF894132B417100900962 /* EXTDispatchObject.h */; };
D0ACF897132B417100900962 /* EXTDispatchObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D0ACF894132B417100900962 /* EXTDispatchObject.h */; };
D0ACF898132B417100900962 /* EXTDispatchObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D0ACF895132B417100900962 /* EXTDispatchObject.m */; };
@@ -197,6 +203,10 @@
D0A8B30D128A4B56004AACE0 /* EXTSwizzleTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EXTSwizzleTest.m; sourceTree = "<group>"; };
D0A8B311128A4BDE004AACE0 /* extobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extobjc.h; sourceTree = "<group>"; };
D0A8B336128A5185004AACE0 /* EXTConcreteProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXTConcreteProtocol.h; sourceTree = "<group>"; };
+ D0A93EAC14BACFE400CAAF36 /* EXTCondition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXTCondition.h; sourceTree = "<group>"; };
+ D0A93EAD14BACFE400CAAF36 /* EXTCondition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EXTCondition.m; sourceTree = "<group>"; };
+ D0A93EB214BAD01600CAAF36 /* EXTConditionTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXTConditionTest.h; sourceTree = "<group>"; };
+ D0A93EB314BAD01600CAAF36 /* EXTConditionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EXTConditionTest.m; sourceTree = "<group>"; };
D0ACF894132B417100900962 /* EXTDispatchObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXTDispatchObject.h; sourceTree = "<group>"; };
D0ACF895132B417100900962 /* EXTDispatchObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EXTDispatchObject.m; sourceTree = "<group>"; };
D0ACF8AE132B506300900962 /* EXTBlockMethod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EXTBlockMethod.m; sourceTree = "<group>"; };
@@ -426,6 +436,8 @@
D07F83B1135D50E9008B9D6D /* EXTBlockTargetTest.m */,
D0C1D916128A57B600E96C0F /* EXTConcreteProtocolTest.h */,
D0C1D917128A57B600E96C0F /* EXTConcreteProtocolTest.m */,
+ D0A93EB214BAD01600CAAF36 /* EXTConditionTest.h */,
+ D0A93EB314BAD01600CAAF36 /* EXTConditionTest.m */,
D03EC9A1138A25F100559080 /* EXTCoroutineTest.h */,
D03EC9A2138A25F100559080 /* EXTCoroutineTest.m */,
D0337665131E54960039ACFD /* EXTFinalMethodTest.h */,
@@ -444,8 +456,8 @@
D0B9B0B413727EF800EC1224 /* EXTScopeTest.m */,
D0A8B30C128A4B56004AACE0 /* EXTSwizzleTest.h */,
D0A8B30D128A4B56004AACE0 /* EXTSwizzleTest.m */,
- D0A8B2DD128A495D004AACE0 /* OSX-Info.plist */,
D0CFB610128A8EEE006DC377 /* iOS-Info.plist */,
+ D0A8B2DD128A495D004AACE0 /* OSX-Info.plist */,
);
path = Tests;
sourceTree = "<group>";
@@ -459,6 +471,8 @@
D0ACF8AE132B506300900962 /* EXTBlockMethod.m */,
D0A8B336128A5185004AACE0 /* EXTConcreteProtocol.h */,
D0B6C99C128B121B00137E97 /* EXTConcreteProtocol.m */,
+ D0A93EAC14BACFE400CAAF36 /* EXTCondition.h */,
+ D0A93EAD14BACFE400CAAF36 /* EXTCondition.m */,
D0D0CE2B1389F57D003ECD3D /* EXTCoroutine.h */,
D0337660131E547C0039ACFD /* EXTFinalMethod.h */,
D033765F131E547C0039ACFD /* EXTFinalMethod.m */,
@@ -524,6 +538,7 @@
D0B9B0B213727A6600EC1224 /* EXTScope.h in Headers */,
D0D0CE2F1389F57D003ECD3D /* EXTCoroutine.h in Headers */,
D0E4D57C147F477C002C3C9F /* EXTAspect.h in Headers */,
+ D0A93EAF14BACFE400CAAF36 /* EXTCondition.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -551,6 +566,7 @@
D0B9B0B113727A6600EC1224 /* EXTScope.h in Headers */,
D0D0CE2E1389F57D003ECD3D /* EXTCoroutine.h in Headers */,
D0E4D57B147F477C002C3C9F /* EXTAspect.h in Headers */,
+ D0A93EAE14BACFE400CAAF36 /* EXTCondition.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -745,6 +761,7 @@
D002DAF41365694C005348A5 /* EXTNil.m in Sources */,
D0B9B0B013727A6600EC1224 /* EXTScope.m in Sources */,
D0E4D57E147F477C002C3C9F /* EXTAspect.m in Sources */,
+ D0A93EB114BACFE400CAAF36 /* EXTCondition.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -765,6 +782,7 @@
D0B9B0B513727EF800EC1224 /* EXTScopeTest.m in Sources */,
D03EC9A3138A25F100559080 /* EXTCoroutineTest.m in Sources */,
D035A5BB148022B9006C1001 /* EXTAspectTest.m in Sources */,
+ D0A93EB414BAD01600CAAF36 /* EXTConditionTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -785,6 +803,7 @@
D0B9B0B613727EF800EC1224 /* EXTScopeTest.m in Sources */,
D03EC9A4138A25F100559080 /* EXTCoroutineTest.m in Sources */,
D035A5BC148022B9006C1001 /* EXTAspectTest.m in Sources */,
+ D0A93EB514BAD01600CAAF36 /* EXTConditionTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -807,6 +826,7 @@
D002DAF31365694C005348A5 /* EXTNil.m in Sources */,
D0B9B0AF13727A6600EC1224 /* EXTScope.m in Sources */,
D0E4D57D147F477C002C3C9F /* EXTAspect.m in Sources */,
+ D0A93EB014BACFE400CAAF36 /* EXTCondition.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

0 comments on commit bb3c24e

Please sign in to comment.