module Main where
	{
	import qualified Control.OldException as Exception;
	import Data.IORef;
	import Prelude;

	safeCatch :: IO () -> IO ();
	safeCatch f = Exception.catch f (\_ -> return ());

	type Thrower = IO Bool;

	type Catcher = IO Bool -> IO () -> IO ();

	checkCatch :: Catcher -> Thrower -> IO Bool;
	checkCatch catcher thrower = do
		{
		ref <- newIORef False;
		safeCatch (catcher thrower (writeIORef ref True));
		readIORef ref;
		};

	data Named a = MkNamed String a;

	checkNamedCatch :: Named Catcher -> Named Thrower -> IO ();
	checkNamedCatch (MkNamed cname catcher) (MkNamed tname thrower) = do
		{
		didCatch <- checkCatch catcher thrower;
		putStrLn (cname ++ (if didCatch then " CAUGHT " else " MISSED ") ++ tname);
		};

	checkNamedCatches :: [Named Catcher] -> [Named Thrower] -> IO ();
	checkNamedCatches [] _ = return ();
	checkNamedCatches _ [] = return ();
	checkNamedCatches [c] (t:tr) = do
		{
		checkNamedCatch c t;
		checkNamedCatches [c] tr;
		};
	checkNamedCatches (c:cr) ts = do
		{
		checkNamedCatches [c] ts;
		checkNamedCatches cr ts
		};


	-- throwers

	returnThrower :: Named Thrower;
	returnThrower = MkNamed "return" (return True);

	returnUndefinedThrower :: Named Thrower;
	returnUndefinedThrower = MkNamed "return undefined" (return undefined);

	returnErrorThrower :: Named Thrower;
	returnErrorThrower = MkNamed "return error" (return (error "some error"));

	undefinedThrower :: Named Thrower;
	undefinedThrower = MkNamed "undefined" undefined;

	failThrower :: Named Thrower;
	failThrower = MkNamed "fail" (fail "some failure");

	errorThrower :: Named Thrower;
	errorThrower = MkNamed "error" (error "some error");

	throwThrower :: Named Thrower;
	throwThrower = MkNamed "Exception.throw"
	 (Exception.throw (Exception.ErrorCall "throw error"));

	ioErrorErrorCallThrower :: Named Thrower;
	ioErrorErrorCallThrower = MkNamed "ioError ErrorCall"
	 (Exception.throwIO (Exception.ErrorCall "throw error"));

	ioErrorIOExceptionThrower :: Named Thrower;
	ioErrorIOExceptionThrower = MkNamed "ioError IOException"
	 (Exception.throwIO (Exception.IOException undefined));

	returnThrowThrower :: Named Thrower;
	returnThrowThrower = MkNamed "return Exception.throw"
	 (return (Exception.throw (Exception.ErrorCall "throw error")));


	-- catchers

	bindCatcher :: Named Catcher;
	bindCatcher = MkNamed ">>" (>>);

	preludeCatchCatcher :: Named Catcher;
	preludeCatchCatcher = MkNamed "Prelude.catch"
	 (\f cc -> Prelude.catch (f >> (return ())) (const cc));

	ceCatchCatcher :: Named Catcher;
	ceCatchCatcher = MkNamed "Exception.catch"
	 (\f cc -> Exception.catch (f >> (return ())) (const cc));

	finallyCatcher :: Named Catcher;
	finallyCatcher = MkNamed "Exception.finally"
	 (\f cc -> Exception.finally (f >> (return ())) cc);

	main = checkNamedCatches
		[bindCatcher,preludeCatchCatcher,ceCatchCatcher,finallyCatcher]
		[returnThrower,returnUndefinedThrower,returnThrowThrower,returnErrorThrower,failThrower,
		errorThrower,throwThrower,ioErrorErrorCallThrower,ioErrorIOExceptionThrower,undefinedThrower];

	}
