split most of Control.Exception into new Control.Exception.Base
authorRoss Paterson <ross@soi.city.ac.uk>
Tue, 12 Aug 2008 12:49:12 +0000 (12:49 +0000)
committerRoss Paterson <ross@soi.city.ac.uk>
Tue, 12 Aug 2008 12:49:12 +0000 (12:49 +0000)
Move everything but catches/Handler into a new internal module.
This was needed to get the new exceptions working with Hugs, because Hugs
has the constraint that all Haskell 98 library modules, and everything
they include, must be Haskell 98.  This also involves a different
representation of SomeException for Hugs, so that type is exported
opaquely for Hugs.  Then Control.Exception.Base is Haskell 98 as far as
Hugs is concerned, but Control.Exception needs the extensions turned on.

Control.Exception re-exports everything from Control.Exception.Base
except the functions used by the GHC runtime.

Control/Exception.hs
Control/Exception/Base.hs [new file with mode: 0644]
Control/OldException.hs
Foreign/Marshal/Alloc.hs
Foreign/Marshal/Pool.hs
System/Environment.hs
System/IO.hs
System/IO/Error.hs
System/Timeout.hs
base.cabal

index 48f4f15..0591348 100644 (file)
@@ -1,7 +1,5 @@
 {-# OPTIONS_GHC -XNoImplicitPrelude #-}
 
-#include "Typeable.h"
-
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Exception
 module Control.Exception (
 
         -- * The Exception type
+#ifdef __HUGS__
+        SomeException,
+#else
         SomeException(..),
+#endif
         Exception(..),          -- instance Eq, Ord, Show, Typeable
         IOException,            -- instance Eq, Ord, Show, Typeable
         ArithException(..),     -- instance Eq, Ord, Show, Typeable
@@ -40,9 +42,9 @@ module Control.Exception (
         AssertionFailed(..),
         AsyncException(..),     -- instance Eq, Ord, Show, Typeable
 
-#ifdef __GLASGOW_HASKELL__
-        NonTermination(..), nonTermination,
-        NestedAtomically(..), nestedAtomically,
+#if __GLASGOW_HASKELL__ || __HUGS__
+        NonTermination(..),
+        NestedAtomically(..),
 #endif
 
         BlockedOnDeadMVar(..),
@@ -71,10 +73,10 @@ module Control.Exception (
 
         -- ** The @catch@ functions
         catch,     -- :: IO a -> (Exception -> IO a) -> IO a
-#ifdef __GLASGOW_HASKELL__
+#if __GLASGOW_HASKELL__ || __HUGS__
         catches, Handler(..),
-        catchJust, -- :: (Exception -> Maybe b) -> IO a -> (b -> IO a) -> IO a
 #endif
+        catchJust, -- :: (Exception -> Maybe b) -> IO a -> (b -> IO a) -> IO a
 
         -- ** The @handle@ functions
         handle,    -- :: (Exception -> IO a) -> IO a -> IO a
@@ -123,187 +125,18 @@ module Control.Exception (
         bracketOnError,
 
         finally,        -- :: IO a -> IO b -> IO a
-
-#ifdef __GLASGOW_HASKELL__
-        recSelError, recConError, irrefutPatError, runtimeError,
-        nonExhaustiveGuardsError, patError, noMethodBindingError,
-#endif
   ) where
 
+import Control.Exception.Base
+
 #ifdef __GLASGOW_HASKELL__
 import GHC.Base
 import GHC.IOBase
-import GHC.List
-import GHC.Show
-import GHC.IOBase as ExceptionBase
-import GHC.Exception hiding ( Exception )
-import GHC.Conc
-#endif
-
-#ifdef __HUGS__
-import Hugs.Exception   as ExceptionBase
-#endif
-
-import Data.Dynamic
-import Data.Either
 import Data.Maybe
-
-#ifdef __NHC__
-import qualified System.IO.Error as H'98 (catch)
-import System.IO.Error (ioError)
-import IO              (bracket)
-import DIOError         -- defn of IOError type
-import System          (ExitCode())
-import System.IO.Unsafe (unsafePerformIO)
-import Unsafe.Coerce    (unsafeCoerce)
-
--- minimum needed for nhc98 to pretend it has Exceptions
-
-{-
-data Exception   = IOException    IOException
-                 | ArithException ArithException
-                 | ArrayException ArrayException
-                 | AsyncException AsyncException
-                 | ExitException  ExitCode
-                 deriving Show
--}
-class ({-Typeable e,-} Show e) => Exception e where
-    toException   :: e -> SomeException
-    fromException :: SomeException -> Maybe e
-
-data SomeException = forall e . Exception e => SomeException e
-
-INSTANCE_TYPEABLE0(SomeException,someExceptionTc,"SomeException")
-
-instance Show SomeException where
-    showsPrec p (SomeException e) = showsPrec p e
-instance Exception SomeException where
-    toException se = se
-    fromException = Just
-
-type IOException = IOError
-instance Exception IOError where
-    toException                     = SomeException
-    fromException (SomeException e) = Just (unsafeCoerce e)
-
-instance Exception ExitCode where
-    toException                     = SomeException
-    fromException (SomeException e) = Just (unsafeCoerce e)
-
-data ArithException
-data ArrayException
-data AsyncException
-data AssertionFailed
-data PatternMatchFail
-data NoMethodError
-data Deadlock
-data BlockedOnDeadMVar
-data BlockedIndefinitely
-data ErrorCall
-data RecConError
-data RecSelError
-data RecUpdError
-instance Show ArithException
-instance Show ArrayException
-instance Show AsyncException
-instance Show AssertionFailed
-instance Show PatternMatchFail
-instance Show NoMethodError
-instance Show Deadlock
-instance Show BlockedOnDeadMVar
-instance Show BlockedIndefinitely
-instance Show ErrorCall
-instance Show RecConError
-instance Show RecSelError
-instance Show RecUpdError
-
-catch   :: Exception e
-        => IO a         -- ^ The computation to run
-        -> (e -> IO a)  -- ^ Handler to invoke if an exception is raised
-        -> IO a
-catch io h = H'98.catch  io  (h . fromJust . fromException . toException)
-
-throwIO  :: Exception e => e -> IO a
-throwIO   = ioError . fromJust . fromException . toException
-
-throw    :: Exception e => e -> a
-throw     = unsafePerformIO . throwIO
-
-evaluate :: a -> IO a
-evaluate x = x `seq` return x
-
-assert :: Bool -> a -> a
-assert True  x = x
-assert False _ = throw (toException (UserError "" "Assertion failed"))
-
 #endif
 
-#ifndef __GLASGOW_HASKELL__
--- Dummy definitions for implementations lacking asynchonous exceptions
-
-block   :: IO a -> IO a
-block    = id
-unblock :: IO a -> IO a
-unblock  = id
-blocked :: IO Bool
-blocked  = return False
-#endif
-
------------------------------------------------------------------------------
--- Catching exceptions
-
--- |This is the simplest of the exception-catching functions.  It
--- takes a single argument, runs it, and if an exception is raised
--- the \"handler\" is executed, with the value of the exception passed as an
--- argument.  Otherwise, the result is returned as normal.  For example:
---
--- >   catch (openFile f ReadMode) 
--- >       (\e -> hPutStr stderr ("Couldn't open "++f++": " ++ show e))
---
--- For catching exceptions in pure (non-'IO') expressions, see the
--- function 'evaluate'.
---
--- Note that due to Haskell\'s unspecified evaluation order, an
--- expression may return one of several possible exceptions: consider
--- the expression @error \"urk\" + 1 \`div\` 0@.  Does
--- 'catch' execute the handler passing
--- @ErrorCall \"urk\"@, or @ArithError DivideByZero@?
---
--- The answer is \"either\": 'catch' makes a
--- non-deterministic choice about which exception to catch.  If you
--- call it again, you might get a different exception back.  This is
--- ok, because 'catch' is an 'IO' computation.
---
--- Note that 'catch' catches all types of exceptions, and is generally
--- used for \"cleaning up\" before passing on the exception using
--- 'throwIO'.  It is not good practice to discard the exception and
--- continue, without first checking the type of the exception (it
--- might be a 'ThreadKilled', for example).  In this case it is usually better
--- to use 'catchJust' and select the kinds of exceptions to catch.
---
--- Also note that the "Prelude" also exports a function called
--- 'Prelude.catch' with a similar type to 'Control.Exception.catch',
--- except that the "Prelude" version only catches the IO and user
--- families of exceptions (as required by Haskell 98).  
---
--- We recommend either hiding the "Prelude" version of 'Prelude.catch'
--- when importing "Control.Exception": 
---
--- > import Prelude hiding (catch)
---
--- or importing "Control.Exception" qualified, to avoid name-clashes:
---
--- > import qualified Control.Exception as C
---
--- and then using @C.catch@
---
-#ifndef __NHC__
-catch   :: Exception e
-        => IO a         -- ^ The computation to run
-        -> (e -> IO a)  -- ^ Handler to invoke if an exception is raised
-        -> IO a
-catch = ExceptionBase.catchException
-#endif
+#if __GLASGOW_HASKELL__ || __HUGS__
+data Handler a = forall e . Exception e => Handler (e -> IO a)
 
 catches :: IO a -> [Handler a] -> IO a
 catches io handlers = io `catch` catchesHandler handlers
@@ -314,159 +147,8 @@ catchesHandler handlers e = foldr tryHandler (throw e) handlers
               = case fromException e of
                 Just e' -> handler e'
                 Nothing -> res
-
-data Handler a = forall e . Exception e => Handler (e -> IO a)
--- | The function 'catchJust' is like 'catch', but it takes an extra
--- argument which is an /exception predicate/, a function which
--- selects which type of exceptions we\'re interested in.
---
--- >   result <- catchJust errorCalls thing_to_try handler
---
--- Any other exceptions which are not matched by the predicate
--- are re-raised, and may be caught by an enclosing
--- 'catch' or 'catchJust'.
-catchJust
-        :: Exception e
-        => (e -> Maybe b)         -- ^ Predicate to select exceptions
-        -> IO a                   -- ^ Computation to run
-        -> (b -> IO a)            -- ^ Handler
-        -> IO a
-catchJust p a handler = catch a handler'
-  where handler' e = case p e of 
-                        Nothing -> throw e
-                        Just b  -> handler b
-
--- | A version of 'catch' with the arguments swapped around; useful in
--- situations where the code for the handler is shorter.  For example:
---
--- >   do handle (\e -> exitWith (ExitFailure 1)) $
--- >      ...
-handle     :: Exception e => (e -> IO a) -> IO a -> IO a
-handle     =  flip catch
-
--- | A version of 'catchJust' with the arguments swapped around (see
--- 'handle').
-handleJust :: Exception e => (e -> Maybe b) -> (b -> IO a) -> IO a -> IO a
-handleJust p =  flip (catchJust p)
-
------------------------------------------------------------------------------
--- 'mapException'
-
--- | This function maps one exception into another as proposed in the
--- paper \"A semantics for imprecise exceptions\".
-
--- Notice that the usage of 'unsafePerformIO' is safe here.
-
-mapException :: (Exception e1, Exception e2) => (e1 -> e2) -> a -> a
-mapException f v = unsafePerformIO (catch (evaluate v)
-                                          (\x -> throw (f x)))
-
------------------------------------------------------------------------------
--- 'try' and variations.
-
--- | Similar to 'catch', but returns an 'Either' result which is
--- @('Right' a)@ if no exception was raised, or @('Left' e)@ if an
--- exception was raised and its value is @e@.
---
--- >  try a = catch (Right `liftM` a) (return . Left)
---
--- Note: as with 'catch', it is only polite to use this variant if you intend
--- to re-throw the exception after performing whatever cleanup is needed.
--- Otherwise, 'tryJust' is generally considered to be better.
---
--- Also note that "System.IO.Error" also exports a function called
--- 'System.IO.Error.try' with a similar type to 'Control.Exception.try',
--- except that it catches only the IO and user families of exceptions
--- (as required by the Haskell 98 @IO@ module).
-
-try :: Exception e => IO a -> IO (Either e a)
-try a = catch (a >>= \ v -> return (Right v)) (\e -> return (Left e))
-
--- | A variant of 'try' that takes an exception predicate to select
--- which exceptions are caught (c.f. 'catchJust').  If the exception
--- does not match the predicate, it is re-thrown.
-tryJust :: Exception e => (e -> Maybe b) -> IO a -> IO (Either b a)
-tryJust p a = do
-  r <- try a
-  case r of
-        Right v -> return (Right v)
-        Left  e -> case p e of
-                        Nothing -> throw e
-                        Just b  -> return (Left b)
-
-onException :: IO a -> IO b -> IO a
-onException io what = io `catch` \e -> do what
-                                          throw (e :: SomeException)
-
------------------------------------------------------------------------------
--- Some Useful Functions
-
--- | When you want to acquire a resource, do some work with it, and
--- then release the resource, it is a good idea to use 'bracket',
--- because 'bracket' will install the necessary exception handler to
--- release the resource in the event that an exception is raised
--- during the computation.  If an exception is raised, then 'bracket' will 
--- re-raise the exception (after performing the release).
---
--- A common example is opening a file:
---
--- > bracket
--- >   (openFile "filename" ReadMode)
--- >   (hClose)
--- >   (\handle -> do { ... })
---
--- The arguments to 'bracket' are in this order so that we can partially apply 
--- it, e.g.:
---
--- > withFile name mode = bracket (openFile name mode) hClose
---
-#ifndef __NHC__
-bracket 
-        :: IO a         -- ^ computation to run first (\"acquire resource\")
-        -> (a -> IO b)  -- ^ computation to run last (\"release resource\")
-        -> (a -> IO c)  -- ^ computation to run in-between
-        -> IO c         -- returns the value from the in-between computation
-bracket before after thing =
-  block (do
-    a <- before 
-    r <- unblock (thing a) `onException` after a
-    after a
-    return r
- )
 #endif
 
--- | A specialised variant of 'bracket' with just a computation to run
--- afterward.
--- 
-finally :: IO a         -- ^ computation to run first
-        -> IO b         -- ^ computation to run afterward (even if an exception 
-                        -- was raised)
-        -> IO a         -- returns the value from the first computation
-a `finally` sequel =
-  block (do
-    r <- unblock a `onException` sequel
-    sequel
-    return r
-  )
-
--- | A variant of 'bracket' where the return value from the first computation
--- is not required.
-bracket_ :: IO a -> IO b -> IO c -> IO c
-bracket_ before after thing = bracket before (const after) (const thing)
-
--- | Like bracket, but only performs the final action if there was an 
--- exception raised by the in-between computation.
-bracketOnError
-        :: IO a         -- ^ computation to run first (\"acquire resource\")
-        -> (a -> IO b)  -- ^ computation to run last (\"release resource\")
-        -> (a -> IO c)  -- ^ computation to run in-between
-        -> IO c         -- returns the value from the in-between computation
-bracketOnError before after thing =
-  block (do
-    a <- before 
-    unblock (thing a) `onException` after a
-  )
-
 -- -----------------------------------------------------------------------------
 -- Asynchronous exceptions
 
@@ -543,108 +225,3 @@ until the point when the 'Control.Concurrent.MVar.takeMVar' succeeds.
 Similar arguments apply for other interruptible operations like
 'System.IO.openFile'.
 -}
-
-#if !(__GLASGOW_HASKELL__ || __NHC__)
-assert :: Bool -> a -> a
-assert True x = x
-assert False _ = throw (AssertionFailed "")
-#endif
-
-#ifndef __NHC__
-recSelError, recConError, irrefutPatError, runtimeError,
-             nonExhaustiveGuardsError, patError, noMethodBindingError
-        :: Addr# -> a   -- All take a UTF8-encoded C string
-
-recSelError              s = throw (RecSelError (unpackCStringUtf8# s)) -- No location info unfortunately
-runtimeError             s = error (unpackCStringUtf8# s)               -- No location info unfortunately
-
-nonExhaustiveGuardsError s = throw (PatternMatchFail (untangle s "Non-exhaustive guards in"))
-irrefutPatError          s = throw (PatternMatchFail (untangle s "Irrefutable pattern failed for pattern"))
-recConError              s = throw (RecConError      (untangle s "Missing field in record construction"))
-noMethodBindingError     s = throw (NoMethodError    (untangle s "No instance nor default method for class operation"))
-patError                 s = throw (PatternMatchFail (untangle s "Non-exhaustive patterns in"))
-
------
-
-data PatternMatchFail = PatternMatchFail String
-INSTANCE_TYPEABLE0(PatternMatchFail,patternMatchFailTc,"PatternMatchFail")
-
-instance Exception PatternMatchFail
-
-instance Show PatternMatchFail where
-    showsPrec _ (PatternMatchFail err) = showString err
-
------
-
-data RecSelError = RecSelError String
-INSTANCE_TYPEABLE0(RecSelError,recSelErrorTc,"RecSelError")
-
-instance Exception RecSelError
-
-instance Show RecSelError where
-    showsPrec _ (RecSelError err) = showString err
-
------
-
-data RecConError = RecConError String
-INSTANCE_TYPEABLE0(RecConError,recConErrorTc,"RecConError")
-
-instance Exception RecConError
-
-instance Show RecConError where
-    showsPrec _ (RecConError err) = showString err
-
------
-
-data RecUpdError = RecUpdError String
-INSTANCE_TYPEABLE0(RecUpdError,recUpdErrorTc,"RecUpdError")
-
-instance Exception RecUpdError
-
-instance Show RecUpdError where
-    showsPrec _ (RecUpdError err) = showString err
-
------
-
-data NoMethodError = NoMethodError String
-INSTANCE_TYPEABLE0(NoMethodError,noMethodErrorTc,"NoMethodError")
-
-instance Exception NoMethodError
-
-instance Show NoMethodError where
-    showsPrec _ (NoMethodError err) = showString err
-
------
-
-data NonTermination = NonTermination
-INSTANCE_TYPEABLE0(NonTermination,nonTerminationTc,"NonTermination")
-
-instance Exception NonTermination
-
-instance Show NonTermination where
-    showsPrec _ NonTermination = showString "<<loop>>"
-
--- GHC's RTS calls this
-nonTermination :: SomeException
-nonTermination = toException NonTermination
-
------
-
-data NestedAtomically = NestedAtomically
-INSTANCE_TYPEABLE0(NestedAtomically,nestedAtomicallyTc,"NestedAtomically")
-
-instance Exception NestedAtomically
-
-instance Show NestedAtomically where
-    showsPrec _ NestedAtomically = showString "Control.Concurrent.STM.atomically was nested"
-
--- GHC's RTS calls this
-nestedAtomically :: SomeException
-nestedAtomically = toException NestedAtomically
-
------
-
-instance Exception Dynamic
-
-#endif
-
diff --git a/Control/Exception/Base.hs b/Control/Exception/Base.hs
new file mode 100644 (file)
index 0000000..c8f4d09
--- /dev/null
@@ -0,0 +1,688 @@
+{-# OPTIONS_GHC -XNoImplicitPrelude #-}
+
+#include "Typeable.h"
+
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Exception.Base
+-- Copyright   :  (c) The University of Glasgow 2001
+-- License     :  BSD-style (see the file libraries/base/LICENSE)
+-- 
+-- Maintainer  :  libraries@haskell.org
+-- Stability   :  experimental
+-- Portability :  non-portable (extended exceptions)
+--
+-- Extensible exceptions, except for multiple handlers.
+--
+-----------------------------------------------------------------------------
+
+module Control.Exception.Base (
+
+        -- * The Exception type
+#ifdef __HUGS__
+        SomeException,
+#else
+        SomeException(..),
+#endif
+        Exception(..),
+        IOException,
+        ArithException(..),
+        ArrayException(..),
+        AssertionFailed(..),
+        AsyncException(..),
+
+#if __GLASGOW_HASKELL__ || __HUGS__
+        NonTermination(..),
+        NestedAtomically(..),
+#endif
+
+        BlockedOnDeadMVar(..),
+        BlockedIndefinitely(..),
+        Deadlock(..),
+        NoMethodError(..),
+        PatternMatchFail(..),
+        RecConError(..),
+        RecSelError(..),
+        RecUpdError(..),
+        ErrorCall(..),
+
+        -- * Throwing exceptions
+        throwIO,
+        throw,
+        ioError,
+#ifdef __GLASGOW_HASKELL__
+        throwTo,
+#endif
+
+        -- * Catching Exceptions
+
+        -- ** The @catch@ functions
+        catch,
+        catchJust,
+
+        -- ** The @handle@ functions
+        handle,
+        handleJust,
+
+        -- ** The @try@ functions
+        try,
+        tryJust,
+        onException,
+
+        -- ** The @evaluate@ function
+        evaluate,
+
+        -- ** The @mapException@ function
+        mapException,
+
+        -- * Asynchronous Exceptions
+
+        -- ** Asynchronous exception control
+
+        block,
+        unblock,
+        blocked,
+
+        -- * Assertions
+
+        assert,
+
+        -- * Utilities
+
+        bracket,
+        bracket_,
+        bracketOnError,
+
+        finally,
+
+#ifdef __GLASGOW_HASKELL__
+        -- * Calls for GHC runtime
+        recSelError, recConError, irrefutPatError, runtimeError,
+        nonExhaustiveGuardsError, patError, noMethodBindingError,
+        nonTermination, nestedAtomically,
+#endif
+  ) where
+
+#ifdef __GLASGOW_HASKELL__
+import GHC.Base
+import GHC.IOBase
+import GHC.List
+import GHC.Show
+import GHC.IOBase
+import GHC.Exception hiding ( Exception )
+import GHC.Conc
+#endif
+
+#ifdef __HUGS__
+import Prelude hiding (catch)
+import Hugs.Prelude (ExitCode(..))
+import Hugs.IOExts (unsafePerformIO)
+import Hugs.Exception (SomeException(DynamicException, IOException,
+                                     ArithException, ArrayException, ExitException),
+                       evaluate, IOException, ArithException, ArrayException)
+import qualified Hugs.Exception
+#endif
+
+import Data.Dynamic
+import Data.Either
+import Data.Maybe
+
+#ifdef __NHC__
+import qualified System.IO.Error as H'98 (catch)
+import System.IO.Error (ioError)
+import IO              (bracket)
+import DIOError         -- defn of IOError type
+import System          (ExitCode())
+import System.IO.Unsafe (unsafePerformIO)
+import Unsafe.Coerce    (unsafeCoerce)
+
+-- minimum needed for nhc98 to pretend it has Exceptions
+
+{-
+data Exception   = IOException    IOException
+                 | ArithException ArithException
+                 | ArrayException ArrayException
+                 | AsyncException AsyncException
+                 | ExitException  ExitCode
+                 deriving Show
+-}
+class ({-Typeable e,-} Show e) => Exception e where
+    toException   :: e -> SomeException
+    fromException :: SomeException -> Maybe e
+
+data SomeException = forall e . Exception e => SomeException e
+
+INSTANCE_TYPEABLE0(SomeException,someExceptionTc,"SomeException")
+
+instance Show SomeException where
+    showsPrec p (SomeException e) = showsPrec p e
+instance Exception SomeException where
+    toException se = se
+    fromException = Just
+
+type IOException = IOError
+instance Exception IOError where
+    toException                     = SomeException
+    fromException (SomeException e) = Just (unsafeCoerce e)
+
+instance Exception ExitCode where
+    toException                     = SomeException
+    fromException (SomeException e) = Just (unsafeCoerce e)
+
+data ArithException
+data ArrayException
+data AsyncException
+data AssertionFailed
+data PatternMatchFail
+data NoMethodError
+data Deadlock
+data BlockedOnDeadMVar
+data BlockedIndefinitely
+data ErrorCall
+data RecConError
+data RecSelError
+data RecUpdError
+instance Show ArithException
+instance Show ArrayException
+instance Show AsyncException
+instance Show AssertionFailed
+instance Show PatternMatchFail
+instance Show NoMethodError
+instance Show Deadlock
+instance Show BlockedOnDeadMVar
+instance Show BlockedIndefinitely
+instance Show ErrorCall
+instance Show RecConError
+instance Show RecSelError
+instance Show RecUpdError
+
+catch   :: Exception e
+        => IO a         -- ^ The computation to run
+        -> (e -> IO a)  -- ^ Handler to invoke if an exception is raised
+        -> IO a
+catch io h = H'98.catch  io  (h . fromJust . fromException . toException)
+
+throwIO  :: Exception e => e -> IO a
+throwIO   = ioError . fromJust . fromException . toException
+
+throw    :: Exception e => e -> a
+throw     = unsafePerformIO . throwIO
+
+evaluate :: a -> IO a
+evaluate x = x `seq` return x
+
+assert :: Bool -> a -> a
+assert True  x = x
+assert False _ = throw (toException (UserError "" "Assertion failed"))
+
+#endif
+
+#ifdef __HUGS__
+class (Typeable e, Show e) => Exception e where
+    toException   :: e -> SomeException
+    fromException :: SomeException -> Maybe e
+
+    toException e = DynamicException (toDyn e) (flip showsPrec e)
+    fromException (DynamicException dyn _) = fromDynamic dyn
+    fromException _ = Nothing
+
+INSTANCE_TYPEABLE0(SomeException,someExceptionTc,"SomeException")
+INSTANCE_TYPEABLE0(IOException,iOExceptionTc,"IOException")
+INSTANCE_TYPEABLE0(ArithException,arithExceptionTc,"ArithException")
+INSTANCE_TYPEABLE0(ArrayException,arrayExceptionTc,"ArrayException")
+INSTANCE_TYPEABLE0(ExitCode,exitCodeTc,"ExitCode")
+INSTANCE_TYPEABLE0(ErrorCall,errorCallTc,"ErrorCall")
+INSTANCE_TYPEABLE0(AssertionFailed,assertionFailedTc,"AssertionFailed")
+INSTANCE_TYPEABLE0(AsyncException,asyncExceptionTc,"AsyncException")
+INSTANCE_TYPEABLE0(BlockedOnDeadMVar,blockedOnDeadMVarTc,"BlockedOnDeadMVar")
+INSTANCE_TYPEABLE0(BlockedIndefinitely,blockedIndefinitelyTc,"BlockedIndefinitely")
+INSTANCE_TYPEABLE0(Deadlock,deadlockTc,"Deadlock")
+
+instance Exception SomeException where
+    toException se = se
+    fromException = Just
+
+instance Exception IOException where
+    toException = IOException
+    fromException (IOException e) = Just e
+    fromException _ = Nothing
+
+instance Exception ArrayException where
+    toException = ArrayException
+    fromException (ArrayException e) = Just e
+    fromException _ = Nothing
+
+instance Exception ArithException where
+    toException = ArithException
+    fromException (ArithException e) = Just e
+    fromException _ = Nothing
+
+instance Exception ExitCode where
+    toException = ExitException
+    fromException (ExitException e) = Just e
+    fromException _ = Nothing
+
+data ErrorCall = ErrorCall String
+
+instance Show ErrorCall where
+    showsPrec _ (ErrorCall err) = showString err
+
+instance Exception ErrorCall where
+    toException (ErrorCall s) = Hugs.Exception.ErrorCall s
+    fromException (Hugs.Exception.ErrorCall s) = Just (ErrorCall s)
+    fromException _ = Nothing
+
+data BlockedOnDeadMVar = BlockedOnDeadMVar
+data BlockedIndefinitely = BlockedIndefinitely
+data Deadlock = Deadlock
+data AssertionFailed = AssertionFailed String
+data AsyncException
+  = StackOverflow
+  | HeapOverflow
+  | ThreadKilled
+  | UserInterrupt
+  deriving (Eq, Ord)
+
+instance Show BlockedOnDeadMVar where
+    showsPrec _ BlockedOnDeadMVar = showString "thread blocked indefinitely"
+
+instance Show BlockedIndefinitely where
+    showsPrec _ BlockedIndefinitely = showString "thread blocked indefinitely"
+
+instance Show Deadlock where
+    showsPrec _ Deadlock = showString "<<deadlock>>"
+
+instance Show AssertionFailed where
+    showsPrec _ (AssertionFailed err) = showString err
+
+instance Show AsyncException where
+    showsPrec _ StackOverflow   = showString "stack overflow"
+    showsPrec _ HeapOverflow    = showString "heap overflow"
+    showsPrec _ ThreadKilled    = showString "thread killed"
+    showsPrec _ UserInterrupt   = showString "user interrupt"
+
+instance Exception BlockedOnDeadMVar
+instance Exception BlockedIndefinitely
+instance Exception Deadlock
+instance Exception AssertionFailed
+instance Exception AsyncException
+
+throw :: Exception e => e -> a
+throw e = Hugs.Exception.throw (toException e)
+
+throwIO :: Exception e => e -> IO a
+throwIO e = Hugs.Exception.throwIO (toException e)
+#endif
+
+#ifndef __GLASGOW_HASKELL__
+-- Dummy definitions for implementations lacking asynchonous exceptions
+
+block   :: IO a -> IO a
+block    = id
+unblock :: IO a -> IO a
+unblock  = id
+blocked :: IO Bool
+blocked  = return False
+#endif
+
+-----------------------------------------------------------------------------
+-- Catching exceptions
+
+-- |This is the simplest of the exception-catching functions.  It
+-- takes a single argument, runs it, and if an exception is raised
+-- the \"handler\" is executed, with the value of the exception passed as an
+-- argument.  Otherwise, the result is returned as normal.  For example:
+--
+-- >   catch (openFile f ReadMode)
+-- >       (\e -> hPutStr stderr ("Couldn't open "++f++": " ++ show e))
+--
+-- For catching exceptions in pure (non-'IO') expressions, see the
+-- function 'evaluate'.
+--
+-- Note that due to Haskell\'s unspecified evaluation order, an
+-- expression may return one of several possible exceptions: consider
+-- the expression @error \"urk\" + 1 \`div\` 0@.  Does
+-- 'catch' execute the handler passing
+-- @ErrorCall \"urk\"@, or @ArithError DivideByZero@?
+--
+-- The answer is \"either\": 'catch' makes a
+-- non-deterministic choice about which exception to catch.  If you
+-- call it again, you might get a different exception back.  This is
+-- ok, because 'catch' is an 'IO' computation.
+--
+-- Note that 'catch' catches all types of exceptions, and is generally
+-- used for \"cleaning up\" before passing on the exception using
+-- 'throwIO'.  It is not good practice to discard the exception and
+-- continue, without first checking the type of the exception (it
+-- might be a 'ThreadKilled', for example).  In this case it is usually better
+-- to use 'catchJust' and select the kinds of exceptions to catch.
+--
+-- Also note that the "Prelude" also exports a function called
+-- 'Prelude.catch' with a similar type to 'Control.Exception.catch',
+-- except that the "Prelude" version only catches the IO and user
+-- families of exceptions (as required by Haskell 98).
+--
+-- We recommend either hiding the "Prelude" version of 'Prelude.catch'
+-- when importing "Control.Exception":
+--
+-- > import Prelude hiding (catch)
+--
+-- or importing "Control.Exception" qualified, to avoid name-clashes:
+--
+-- > import qualified Control.Exception as C
+--
+-- and then using @C.catch@
+--
+#ifndef __NHC__
+catch   :: Exception e
+        => IO a         -- ^ The computation to run
+        -> (e -> IO a)  -- ^ Handler to invoke if an exception is raised
+        -> IO a
+#if __GLASGOW_HASKELL__
+catch = GHC.IOBase.catchException
+#elif __HUGS__
+catch m h = Hugs.Exception.catchException m h'
+  where h' e = case fromException e of
+            Just e' -> h e'
+            Nothing -> throwIO e
+#endif
+#endif
+
+-- | The function 'catchJust' is like 'catch', but it takes an extra
+-- argument which is an /exception predicate/, a function which
+-- selects which type of exceptions we\'re interested in.
+--
+-- >   result <- catchJust errorCalls thing_to_try handler
+--
+-- Any other exceptions which are not matched by the predicate
+-- are re-raised, and may be caught by an enclosing
+-- 'catch' or 'catchJust'.
+catchJust
+        :: Exception e
+        => (e -> Maybe b)         -- ^ Predicate to select exceptions
+        -> IO a                   -- ^ Computation to run
+        -> (b -> IO a)            -- ^ Handler
+        -> IO a
+catchJust p a handler = catch a handler'
+  where handler' e = case p e of
+                        Nothing -> throw e
+                        Just b  -> handler b
+
+-- | A version of 'catch' with the arguments swapped around; useful in
+-- situations where the code for the handler is shorter.  For example:
+--
+-- >   do handle (\e -> exitWith (ExitFailure 1)) $
+-- >      ...
+handle     :: Exception e => (e -> IO a) -> IO a -> IO a
+handle     =  flip catch
+
+-- | A version of 'catchJust' with the arguments swapped around (see
+-- 'handle').
+handleJust :: Exception e => (e -> Maybe b) -> (b -> IO a) -> IO a -> IO a
+handleJust p =  flip (catchJust p)
+
+-----------------------------------------------------------------------------
+-- 'mapException'
+
+-- | This function maps one exception into another as proposed in the
+-- paper \"A semantics for imprecise exceptions\".
+
+-- Notice that the usage of 'unsafePerformIO' is safe here.
+
+mapException :: (Exception e1, Exception e2) => (e1 -> e2) -> a -> a
+mapException f v = unsafePerformIO (catch (evaluate v)
+                                          (\x -> throw (f x)))
+
+-----------------------------------------------------------------------------
+-- 'try' and variations.
+
+-- | Similar to 'catch', but returns an 'Either' result which is
+-- @('Right' a)@ if no exception was raised, or @('Left' e)@ if an
+-- exception was raised and its value is @e@.
+--
+-- >  try a = catch (Right `liftM` a) (return . Left)
+--
+-- Note: as with 'catch', it is only polite to use this variant if you intend
+-- to re-throw the exception after performing whatever cleanup is needed.
+-- Otherwise, 'tryJust' is generally considered to be better.
+--
+-- Also note that "System.IO.Error" also exports a function called
+-- 'System.IO.Error.try' with a similar type to 'Control.Exception.try',
+-- except that it catches only the IO and user families of exceptions
+-- (as required by the Haskell 98 @IO@ module).
+
+try :: Exception e => IO a -> IO (Either e a)
+try a = catch (a >>= \ v -> return (Right v)) (\e -> return (Left e))
+
+-- | A variant of 'try' that takes an exception predicate to select
+-- which exceptions are caught (c.f. 'catchJust').  If the exception
+-- does not match the predicate, it is re-thrown.
+tryJust :: Exception e => (e -> Maybe b) -> IO a -> IO (Either b a)
+tryJust p a = do
+  r <- try a
+  case r of
+        Right v -> return (Right v)
+        Left  e -> case p e of
+                        Nothing -> throw e
+                        Just b  -> return (Left b)
+
+onException :: IO a -> IO b -> IO a
+onException io what = io `catch` \e -> do what
+                                          throw (e :: SomeException)
+
+-----------------------------------------------------------------------------
+-- Some Useful Functions
+
+-- | When you want to acquire a resource, do some work with it, and
+-- then release the resource, it is a good idea to use 'bracket',
+-- because 'bracket' will install the necessary exception handler to
+-- release the resource in the event that an exception is raised
+-- during the computation.  If an exception is raised, then 'bracket' will
+-- re-raise the exception (after performing the release).
+--
+-- A common example is opening a file:
+--
+-- > bracket
+-- >   (openFile "filename" ReadMode)
+-- >   (hClose)
+-- >   (\handle -> do { ... })
+--
+-- The arguments to 'bracket' are in this order so that we can partially apply
+-- it, e.g.:
+--
+-- > withFile name mode = bracket (openFile name mode) hClose
+--
+#ifndef __NHC__
+bracket
+        :: IO a         -- ^ computation to run first (\"acquire resource\")
+        -> (a -> IO b)  -- ^ computation to run last (\"release resource\")
+        -> (a -> IO c)  -- ^ computation to run in-between
+        -> IO c         -- returns the value from the in-between computation
+bracket before after thing =
+  block (do
+    a <- before
+    r <- unblock (thing a) `onException` after a
+    after a
+    return r
+ )
+#endif
+
+-- | A specialised variant of 'bracket' with just a computation to run
+-- afterward.
+--
+finally :: IO a         -- ^ computation to run first
+        -> IO b         -- ^ computation to run afterward (even if an exception
+                        -- was raised)
+        -> IO a         -- returns the value from the first computation
+a `finally` sequel =
+  block (do
+    r <- unblock a `onException` sequel
+    sequel
+    return r
+  )
+
+-- | A variant of 'bracket' where the return value from the first computation
+-- is not required.
+bracket_ :: IO a -> IO b -> IO c -> IO c
+bracket_ before after thing = bracket before (const after) (const thing)
+
+-- | Like bracket, but only performs the final action if there was an
+-- exception raised by the in-between computation.
+bracketOnError
+        :: IO a         -- ^ computation to run first (\"acquire resource\")
+        -> (a -> IO b)  -- ^ computation to run last (\"release resource\")
+        -> (a -> IO c)  -- ^ computation to run in-between
+        -> IO c         -- returns the value from the in-between computation
+bracketOnError before after thing =
+  block (do
+    a <- before
+    unblock (thing a) `onException` after a
+  )
+
+#if !(__GLASGOW_HASKELL__ || __NHC__)
+assert :: Bool -> a -> a
+assert True x = x
+assert False _ = throw (AssertionFailed "")
+#endif
+
+-----
+
+#if __GLASGOW_HASKELL__ || __HUGS__
+data PatternMatchFail = PatternMatchFail String
+INSTANCE_TYPEABLE0(PatternMatchFail,patternMatchFailTc,"PatternMatchFail")
+
+instance Show PatternMatchFail where
+    showsPrec _ (PatternMatchFail err) = showString err
+
+#ifdef __HUGS__
+instance Exception PatternMatchFail where
+    toException (PatternMatchFail err) = Hugs.Exception.PatternMatchFail err
+    fromException (Hugs.Exception.PatternMatchFail err) = Just (PatternMatchFail err)
+    fromException _ = Nothing
+#else
+instance Exception PatternMatchFail
+#endif
+
+-----
+
+data RecSelError = RecSelError String
+INSTANCE_TYPEABLE0(RecSelError,recSelErrorTc,"RecSelError")
+
+instance Show RecSelError where
+    showsPrec _ (RecSelError err) = showString err
+
+#ifdef __HUGS__
+instance Exception RecSelError where
+    toException (RecSelError err) = Hugs.Exception.RecSelError err
+    fromException (Hugs.Exception.RecSelError err) = Just (RecSelError err)
+    fromException _ = Nothing
+#else
+instance Exception RecSelError
+#endif
+
+-----
+
+data RecConError = RecConError String
+INSTANCE_TYPEABLE0(RecConError,recConErrorTc,"RecConError")
+
+instance Show RecConError where
+    showsPrec _ (RecConError err) = showString err
+
+#ifdef __HUGS__
+instance Exception RecConError where
+    toException (RecConError err) = Hugs.Exception.RecConError err
+    fromException (Hugs.Exception.RecConError err) = Just (RecConError err)
+    fromException _ = Nothing
+#else
+instance Exception RecConError
+#endif
+
+-----
+
+data RecUpdError = RecUpdError String
+INSTANCE_TYPEABLE0(RecUpdError,recUpdErrorTc,"RecUpdError")
+
+instance Show RecUpdError where
+    showsPrec _ (RecUpdError err) = showString err
+
+#ifdef __HUGS__
+instance Exception RecUpdError where
+    toException (RecUpdError err) = Hugs.Exception.RecUpdError err
+    fromException (Hugs.Exception.RecUpdError err) = Just (RecUpdError err)
+    fromException _ = Nothing
+#else
+instance Exception RecUpdError
+#endif
+
+-----
+
+data NoMethodError = NoMethodError String
+INSTANCE_TYPEABLE0(NoMethodError,noMethodErrorTc,"NoMethodError")
+
+instance Show NoMethodError where
+    showsPrec _ (NoMethodError err) = showString err
+
+#ifdef __HUGS__
+instance Exception NoMethodError where
+    toException (NoMethodError err) = Hugs.Exception.NoMethodError err
+    fromException (Hugs.Exception.NoMethodError err) = Just (NoMethodError err)
+    fromException _ = Nothing
+#else
+instance Exception NoMethodError
+#endif
+
+-----
+
+data NonTermination = NonTermination
+INSTANCE_TYPEABLE0(NonTermination,nonTerminationTc,"NonTermination")
+
+instance Show NonTermination where
+    showsPrec _ NonTermination = showString "<<loop>>"
+
+#ifdef __HUGS__
+instance Exception NonTermination where
+    toException NonTermination = Hugs.Exception.NonTermination
+    fromException Hugs.Exception.NonTermination = Just NonTermination
+    fromException _ = Nothing
+#else
+instance Exception NonTermination
+#endif
+
+-----
+
+data NestedAtomically = NestedAtomically
+INSTANCE_TYPEABLE0(NestedAtomically,nestedAtomicallyTc,"NestedAtomically")
+
+instance Show NestedAtomically where
+    showsPrec _ NestedAtomically = showString "Control.Concurrent.STM.atomically was nested"
+
+instance Exception NestedAtomically
+
+-----
+
+instance Exception Dynamic
+
+#endif /* __GLASGOW_HASKELL__ || __HUGS__ */
+
+#ifdef __GLASGOW_HASKELL__
+recSelError, recConError, irrefutPatError, runtimeError,
+             nonExhaustiveGuardsError, patError, noMethodBindingError
+        :: Addr# -> a   -- All take a UTF8-encoded C string
+
+recSelError              s = throw (RecSelError (unpackCStringUtf8# s)) -- No location info unfortunately
+runtimeError             s = error (unpackCStringUtf8# s)               -- No location info unfortunately
+
+nonExhaustiveGuardsError s = throw (PatternMatchFail (untangle s "Non-exhaustive guards in"))
+irrefutPatError          s = throw (PatternMatchFail (untangle s "Irrefutable pattern failed for pattern"))
+recConError              s = throw (RecConError      (untangle s "Missing field in record construction"))
+noMethodBindingError     s = throw (NoMethodError    (untangle s "No instance nor default method for class operation"))
+patError                 s = throw (PatternMatchFail (untangle s "Non-exhaustive patterns in"))
+
+-- GHC's RTS calls this
+nonTermination :: SomeException
+nonTermination = toException NonTermination
+
+-- GHC's RTS calls this
+nestedAtomically :: SomeException
+nestedAtomically = toException NestedAtomically
+#endif
index 1b392d8..00b1cf4 100644 (file)
@@ -135,7 +135,7 @@ import GHC.Base
 import GHC.Num
 import GHC.Show
 import GHC.IOBase ( IO )
-import GHC.IOBase (block, unblock, evaluate, catchException, throwIO)
+import GHC.IOBase (catchException)
 import qualified GHC.IOBase as ExceptionBase
 import qualified GHC.IOBase as New
 import GHC.Conc hiding (setUncaughtExceptionHandler,
@@ -146,11 +146,12 @@ import GHC.Handle       ( stdout, hFlush )
 #endif
 
 #ifdef __HUGS__
-import Hugs.Exception   as ExceptionBase
+import Prelude          hiding (catch)
+import Hugs.Prelude     as New (ExitCode(..))
 #endif
 
 import qualified Control.Exception as New
-import           Control.Exception ( throw, SomeException )
+import           Control.Exception ( throw, SomeException, block, unblock, evaluate, throwIO )
 import System.IO.Error  hiding ( catch, try )
 import System.IO.Unsafe (unsafePerformIO)
 import Data.Dynamic
@@ -725,7 +726,7 @@ nonTermination = New.toException NonTermination
 
 -- For now at least, make the monolithic Exception type an instance of
 -- the Exception class
-instance ExceptionBase.Exception Exception
+instance New.Exception Exception
 
 instance Show Exception where
   showsPrec _ (IOException err)          = shows err
index 220d02b..9911718 100644 (file)
@@ -50,7 +50,7 @@ import GHC.Num
 import NHC.FFI                  ( FinalizerPtr, CInt(..) )
 import IO                       ( bracket )
 #else
-import Control.Exception        ( bracket )
+import Control.Exception.Base   ( bracket )
 #endif
 
 #ifdef __HUGS__
index e7d2d8e..540c164 100644 (file)
@@ -57,7 +57,7 @@ import Data.IORef            ( IORef, newIORef, readIORef, writeIORef )
 #if defined(__NHC__)
 import IO                    ( bracket )
 #else
-import Control.Exception     ( bracket )
+import Control.Exception.Base ( bracket )
 #endif
 #endif
 
index 12ed580..4b32987 100644 (file)
@@ -32,7 +32,7 @@ import Prelude
 import Data.List
 import Foreign
 import Foreign.C
-import Control.Exception        ( bracket )
+import Control.Exception.Base   ( bracket )
 import Control.Monad
 import GHC.IOBase
 #endif
index b414fba..3d3893d 100644 (file)
@@ -161,7 +161,7 @@ module System.IO (
     openBinaryTempFile,
   ) where
 
-import Control.Exception
+import Control.Exception.Base
 
 #ifndef __NHC__
 import Data.Bits
index a4c5b59..0313d7b 100644 (file)
@@ -90,23 +90,24 @@ module System.IO.Error (
 #endif
   ) where
 
-import {-# SOURCE #-} Prelude (catch)
-
+#ifndef __HUGS__
 import Data.Either
+#endif
 import Data.Maybe
 
 #ifdef __GLASGOW_HASKELL__
+import {-# SOURCE #-} Prelude (catch)
+
 import GHC.Base
 import GHC.IOBase
 import Text.Show
 #endif
 
 #ifdef __HUGS__
-import Hugs.Prelude(Handle, IOException(..), IOErrorType(..))
+import Hugs.Prelude(Handle, IOException(..), IOErrorType(..), IO)
 #endif
 
 #ifdef __NHC__
-import Prelude
 import IO
   ( IOError ()
   , try
index 0e82704..959e1a2 100644 (file)
@@ -26,7 +26,7 @@ import Prelude             (Show(show), IO, Ord((<)), Eq((==)), Int,
 import Data.Maybe          (Maybe(..))
 import Control.Monad       (Monad(..), guard)
 import Control.Concurrent  (forkIO, threadDelay, myThreadId, killThread)
-import Control.Exception   (Exception, handleJust, throwTo, bracket)
+import Control.Exception.Base (Exception, handleJust, throwTo, bracket)
 import Data.Dynamic        (Typeable, fromDynamic)
 import Data.Typeable
 import Data.Unique         (Unique, newUnique)
index 42a232d..01bfdd1 100644 (file)
@@ -154,6 +154,8 @@ Library {
         Text.Show,
         Text.Show.Functions
         Unsafe.Coerce
+    other-modules:
+        Control.Exception.Base
     c-sources:
         cbits/PrelIOUtils.c
         cbits/WCsubst.c