packages feed

lhc-0.6.20090126: lib/base/src/Lhc/IO.hs

{-# OPTIONS_LHC -N -funboxed-tuples -fffi #-}

module Lhc.IO(
    IO(..),
    thenIO,
    thenIO_,
    returnIO,

    UIO(),
    UIO_(),

    World__(),
    catch,
    unIO,
    etaIO,
    dependingOn,
    fixIO,
    ioError,
    runExpr,
    runMain,
    runNoWrapper,
    exitFailure,
    strictReturn,
    unsafeInterleaveIO,
    error,
    IOError(),
    showIOError,
    userError,
    unsafePerformIO,
    unsafePerformIO'
    ) where

import Lhc.Prim
import Lhc.Basics
import Lhc.Order
import qualified Lhc.Options


-- basic types


unIO :: IO a -> World__ -> (# World__, a #)
unIO (IO x) = x

type UIO a = World__ -> (# World__, a #)
type UIO_ = World__ -> World__

-- | this ensures the world parameter is eta expanded out
{-# INLINE etaIO #-}
etaIO :: IO a -> IO a
etaIO x = IO $ \w -> unIO x w

-- unsafe operations

unsafePerformIO :: IO a -> a
unsafePerformIO x = case newWorld__ x of
    world -> case errorContinuation x of
        IO y -> case y 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 = IO $ \w -> (# w , case action' w of (# _,  a #) -> a #)
    where IO action' = errorContinuation action


-- IO Exception handling

newtype IOError = IOError String
    deriving(Eq)

showIOError :: IOError -> String
showIOError (IOError x) = x

userError       :: String  -> IOError
userError str	=  IOError  str

showError :: IOError -> IO b
showError (IOError z) = putErrLn z `thenIO_` exitFailure

errorContinuation :: IO a -> IO a
errorContinuation x = catch x showError

ioError    ::  IOError -> IO a
ioError e  = case Lhc.Options.target of
    Lhc.Options.GhcHs -> IO $ \w -> raiseIO__ e w
    _ -> showError e


catch :: IO a -> (IOError -> IO a) -> IO a
catch (IO m) k =  case Lhc.Options.target of
    Lhc.Options.GhcHs -> IO $ \s -> catch__ m (\ex -> unIO (k ex)) s
    _ -> IO m  -- no catching on other targets just yet


-- IO fixpoint operation

data FixIO a = FixIO World__ a

fixIO :: (a -> IO a) -> IO a
fixIO k = IO $ \w -> let
            r = case k ans of
                    IO 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 $ \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 run = catch main $ \e ->
            putErrLn "\nUncaught Exception:" `thenIO_`
            putErrLn (showIOError e)         `thenIO_`
            exitFailure




exitFailure :: IO a
exitFailure = IO $ \w -> exitFailure__ w

foreign import primitive exitFailure__ :: World__ -> (# World__, a #)


thenIO_ :: IO a -> IO b -> IO b
IO a `thenIO_` IO b = IO $ \w -> case a w of
    (# w', _ #) -> b w'

IO a `thenIO` b = IO $ \w -> case a w of
    (# w', v #) -> unIO (b v) w'

returnIO :: a -> IO a
returnIO x = IO $ \w -> (# w, x #)

{-# NOINLINE error #-}
error s = unsafePerformIO' $
    putErrLn "error:"  `thenIO_`
    putErrLn s         `thenIO_`
    exitFailure

-- | no the implicit unsafeCoerce__ here!
foreign import primitive catch__ :: (World__ -> (# World__,a #)) -> (b -> World__ -> (# World__,a #)) -> World__ -> (# World__,a #)
foreign import primitive raiseIO__ :: a -> World__ -> (# World__,b #)


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 lhc_utf8_putchar" c_putwchar :: Int -> IO ()