ajhc-0.8.0.1: lib/jhc/Jhc/IO.hs
{-# OPTIONS_JHC -fno-prelude -funboxed-tuples -fffi #-}
module Jhc.IO(
IO(..),
thenIO,
thenIO_,
returnIO,
fromUIO,
fromUIO_,
UIO(),
UIO_(),
World__(),
catch,
unIO,
etaIO,
dependingOn,
fixIO,
ioError,
runMain,
exitFailure,
strictReturn,
unsafeInterleaveIO,
error,
IOError(),
userError,
unsafePerformIO,
unsafePerformIO'
) where
import Jhc.Basics
import Jhc.Prim
import Jhc.Type.Handle
import qualified Jhc.Options
unIO :: IO a -> UIO a
unIO (IO (ST x)) = x
fromUIO :: UIO a -> IO a
fromUIO x = IO (ST x)
fromUIO_ :: UIO_ -> IO ()
fromUIO_ f = IO $ ST (\w -> (# f w, () #))
-- | this ensures the world parameter is eta expanded out
{-# INLINE etaIO #-}
etaIO :: IO a -> IO a
etaIO x = fromUIO (\w -> unIO x w)
-- unsafe operations
unsafePerformIO :: IO a -> a
unsafePerformIO x = case newWorld__ x of
world -> case unIO (errorContinuation x) world of
(# _, a #) -> a
-- | same as unsafePerformIO, but doesn't set up error handler
unsafePerformIO' :: IO a -> a
unsafePerformIO' x = case newWorld__ x of
world -> case (unIO x) world of
(# _, a #) -> a
-- we have to replace the error handler because the context might have quit by the time the value is evaluated.
unsafeInterleaveIO :: IO a -> IO a
unsafeInterleaveIO action = fromUIO $ \w -> (# w , case action' w of (# _, a #) -> a #)
where action' = unIO $ errorContinuation action
showError :: IOError -> IO b
--showError (IOError z) = putErrLn z `thenIO_` exitFailure
showError ioe = putErrLn (ioeGetErrorString ioe) `thenIO_` exitFailure
userError x = IOError User x Nothing Nothing
errorContinuation :: IO a -> IO a
errorContinuation x = catch x showError
ioError :: IOError -> IO a
ioError e = case Jhc.Options.target of
Jhc.Options.GhcHs -> fromUIO $
\w -> (case raiseIO__ e w of w' -> (# w', raiseError #))
_ -> showError e
catch :: IO a -> (IOError -> IO a) -> IO a
catch a k = case Jhc.Options.target of
Jhc.Options.GhcHs -> fromUIO $ \s -> catch__ (unIO a) (\ex -> unIO (k ex)) s
_ -> a -- no catching on other targets just yet
-- IO fixpoint operation
data FixIO a = FixIO World__ a
fixIO :: (a -> IO a) -> IO a
fixIO k = fromUIO $ \w -> let r = case k ans of
IO (ST z) -> case z w of
(# w', r' #) -> FixIO w' r'
ans = case r of
FixIO _ z -> z
in case r of
FixIO w' z -> (# w', z #)
-- some primitives
-- | this creates a new world object that artificially depends on its argument to avoid CSE.
foreign import primitive newWorld__ :: a -> World__
foreign import primitive "dependingOn" worldDep__ :: forall b. b -> World__ -> b
-- | this will return a value making it artificially depend on the state of the world. any uses of this value are guarenteed not to float before this point in the IO monad.
strictReturn :: a -> IO a
strictReturn a = IO $ ST $ \w -> (# w, worldDep__ a w #)
{-# INLINE runMain #-}
-- | this is wrapped around 'main' when compiling programs. it catches any exceptions and prints them to the screen and dies appropriatly.
runMain :: IO a -> World__ -> World__
runMain main w = case run w of
(# w, _ #) -> w
where
IO (ST run) = catch main $ \e ->
putErrLn "\nUncaught Exception:" `thenIO_`
putErrLn (ioeGetErrorString e) `thenIO_`
exitFailure
exitFailure :: IO a
exitFailure = IO $ ST $ \w -> exitFailure__ w
foreign import primitive exitFailure__ :: World__ -> (# World__, a #)
thenIO_ :: IO a -> IO b -> IO b
IO (ST a) `thenIO_` IO (ST b) = IO $ ST $ \w -> case a w of
(# w', _ #) -> b w'
IO (ST a) `thenIO` b = IO $ ST $ \w -> case a w of
(# w', v #) -> unIO (b v) w'
returnIO :: a -> IO a
returnIO x = IO $ ST (\w -> (# w, x #))
{-# NOINLINE error #-}
error s = unsafePerformIO' $
putErrLn "error:" `thenIO_`
putErrLn s `thenIO_`
exitFailure
putErrLn :: [Char] -> IO ()
putErrLn [] = putChar '\n'
putErrLn (c:cs) = putChar c `thenIO_` putErrLn cs
putChar :: Char -> IO ()
putChar c = c_putwchar (charToInt c)
foreign import primitive "U2U" charToInt :: Char -> Int
foreign import ccall "stdio.h jhc_utf8_putchar" c_putwchar :: Int -> IO ()
foreign import primitive "error.raiseIO__" raiseError :: a