{-# OPTIONS_GHC -fglasgow-exts -fallow-undecidable-instances -fallow-overlapping-instances #-} {-# LANGUAGE MagicHash, UndecidableInstances, OverlappingInstances #-} module Idris.RunIO where -- import SimplDSL import Ivor.TT import Ivor.Shell import Ivor.Construction import Idris.AbsSyntax import Data.Typeable import Data.IORef import System.IO.Unsafe import System.IO import Control.Monad.Error import Control.Concurrent import Debug.Trace newtype Lock = Lock QSem instance Typeable Lock where typeOf a = mkTyConApp (mkTyCon "Lock") [] instance Show Lock where show x = "<>" instance Eq Lock where (==) x y = False -- Hmm instance ViewConst Handle where typeof x = (name "Handle") instance ViewConst Lock where typeof x = (name "Lock") exec :: Context -> Term -> IO () exec ctxt wurzel = do res <- runIO ctxt (view (whnf ctxt wurzel)) putStrLn $ show res runIO :: Context -> ViewTerm -> IO ViewTerm runIO ctxt (App (App (App (Name _ d) _) act) k) | d == name "IO.IODo" = runAction ctxt (parseAction act) k runIO ctxt (App (App (Name _ l) _) res) | l == name "IO.IOReturn" = return res runIO _ x = fail $ "Not an IO action: " ++ show x data Action = ReadStr | WriteStr String | Fork ViewTerm | NewLock Int | DoLock Lock | DoUnlock Lock | NewRef | ReadRef Int | WriteRef Int ViewTerm | CantReduce ViewTerm parseAction x = parseAction' x [] where parseAction' (App f a) args = parseAction' f (a:args) parseAction' (Name _ n) args = (getAction n args) getAction n [] | n == name "IO.GetStr" = ReadStr getAction n [Constant str] | n == name "IO.PutStr" = case cast str of Just str' -> WriteStr str' getAction n [_,t] | n == name "IO.Fork" = Fork t getAction n [Constant i] | n == name "IO.NewLock" = case cast i of Just i' -> NewLock i' getAction n [lock] | n == name "IO.DoLock" = DoLock (getLock lock) | n == name "IO.DoUnlock" = DoUnlock (getLock lock) getAction n [] | n == name "IO.NewRef" = NewRef getAction n [_,Constant i] | n == name "IO.ReadRef" = case cast i of Just i' -> ReadRef i' getAction n [_,Constant i,val] | n == name "IO.WriteRef" = case cast i of Just i' -> WriteRef i' val getAction n args = CantReduce (apply (Name Unknown n) args) getHandle (App _ (Constant h)) = case cast h of Just h' -> h' getLock (Constant h) = case cast h of Just h' -> h' Nothing -> error ("Lock error in constant " ++ show h) getLock x = error ("Lock error " ++ show x) continue ctxt k arg = case fastCheck ctxt (App k arg) of t -> let next = whnf ctxt t in runIO ctxt (view next) {- Right t -> let next = whnf ctxt t in runIO ctxt (view next) Left err -> fail $ "Can't happen - continue " ++ err ++ "\n" ++ show k ++ "\n" ++ show arg -} unit = Name Unknown (name "II") runAction ctxt (WriteStr str) k -- Print the string, then run the continuation with the argument 'II' = do putStr str hFlush stdout continue ctxt k unit runAction ctxt ReadStr k -- Read a string then run the continuation with the constant str = do str <- getLine continue ctxt k (Constant str) runAction ctxt (Fork t) k = do forkIO (do x <- runIO ctxt t return ()) continue ctxt k unit runAction ctxt (NewLock n) k = do mv <- newQSem n continue ctxt k (Constant (Lock mv)) runAction ctxt (DoLock l) k = do primLock l continue ctxt k unit runAction ctxt (DoUnlock l) k = do primUnlock l continue ctxt k unit runAction ctxt NewRef k = do i <- newRef continue ctxt k (Constant i) runAction ctxt (ReadRef i) k = do v <- getMem i continue ctxt k v runAction ctxt (WriteRef i val) k = do putMem i val continue ctxt k unit runAction ctxt (CantReduce t) k = do fail $ "Stuck at: " ++ show t -- hFlush stdout primLock :: Lock -> IO () primLock (Lock lock) = do waitQSem lock primUnlock :: Lock -> IO () primUnlock (Lock lock) = signalQSem lock -- Some mutable memory, for implementing IORefs idris side. type Value = ViewTerm defaultVal = (Constant (0xDEADBEEF::Int)) data MemState = MemState (IORef (Int, [Value])) memory :: MemState memory = unsafePerformIO (do mem <- newIORef (0, (take 100 (repeat defaultVal))) return (MemState mem)) newRef :: IO Int newRef = do let (MemState mem) = memory (p,ref) <- readIORef mem writeIORef mem (p+1, ref) return p putMem :: Int -> Value -> IO () putMem loc val = do let (MemState mem) = memory (p,content) <- readIORef mem writeIORef mem (p, update content loc val) getMem :: Int -> IO Value getMem loc = do let (MemState mem) = memory (p, content) <- readIORef mem return (content!!!(loc, "getMem fail")) update :: [a] -> Int -> a -> [a] update [] _ _ = [] update (x:xs) 0 v = (v:xs) update (x:xs) n v = x:(update xs (n-1) v)