/* Error-test.c * * Test Objective-C error facilities */ #include #include #include #include @protocol IntMath + new: (int) n; - init: (int) n; - (int) value; - plus: (id ) number; - times: (id ) number; - divide: (id ) number; @end /* IntMath */ @interface MathError : Error @end /* MathError */ @interface DivideByZeroError : MathError @end /* DivideByZeroError */ @interface Integer : Object { int value; } @end /* Integer */ @interface TestCatch : Catch @end /* TestCatch */ @implementation MathError - (const char *) message { return "mathematical error"; } @end /* MathError */ @implementation DivideByZeroError - (const char *) message { return "divide by zero attempted"; } @end /* DivideByZeroError */ @implementation Integer + new: (int) n { return [[super new] init: n]; } - init: (int) n { value = n; return self; } - init { value = 43; return self; } - (int) value { return value; } - plus: (id ) number { value += [number value]; return self; } - times: (id ) number { value *= [number value]; return self; } - divide: (id ) number { if ([number value] == 0) [[DivideByZeroError new] raise]; value /= [number value]; return self; } @end /* Integer */ @implementation TestCatch @end /* TestCatch */ void foo(id object, int number); int main(int argc, char **argv) { id tag = [CatchError new]; id n; int result; int i; n = [Integer new: 17]; for (i=-7; i<3; i++) { if ((result = set_catch([tag catch: [Error class]])) == 0) { printf("foo(%d, %d)...\n", [n value], i); foo(n, i); } else { id error = [tag error]; printf("An error was catched. Class: %s, message: %s.\n", [error name], [error message]); } } [tag free]; [[MathError new] raise]; return 0; } void foo(id object, int number) { id protect = [UnwindProtect new]; id test = [TestCatch new]; id tmp = [Integer new]; [protect cleanupBySending: @selector(init) to: object]; /* Dangerous to invoke [test cleanup] from a cleanup * action. But the freeing of the UnwindProtect frame will free * the catch frame too, so rawFree is enough. */ [protect cleanupBySending: @selector(rawFree) to: test]; [protect cleanupBySending: @selector(free) to: tmp]; switch(number) { case 0: [object divide: (tmp = [Integer new: number])]; break; case -1: [object plus: (tmp = [Integer new: 5])]; break; case 1: [test throw: object]; break; default: [object times: (tmp = [Integer new: number])]; } [protect cleanup]; printf("Computed: %d\n", [object value]); }