module Repl(repl) where import System.IO.Unsafe (unsafePerformIO) import System.Console.Haskeline import Data.Char(isSpace) data Command = Quit | Load String | Code String | TypeCheck String bold = "\x1b[1m"; normal = "\x1b[0m"; repl :: (String -> (String, String)) -> Maybe (String -> String) -> IO () repl eval tc = runInputT defaultSettings (loop "") where loop prelude = do str <- read_input "" case str of Quit -> return () Load f -> loop (prelude ++ unsafePerformIO (readFile f)) Code str -> do let typ = case tc of Just tc -> Just (tc (prelude ++ str)) Nothing -> Nothing let (out, res) = eval (prelude ++ str) outputStr (bold ++ "==> " ++ normal) outputStr (case out of "" -> "" str -> str ++ "\n") outputStr res case typ of Nothing -> do { outputStrLn ""; loop prelude } Just t -> do outputStr " : " outputStrLn t loop prelude TypeCheck str -> case tc of Nothing -> loop prelude Just tc -> do let res = tc (prelude ++ str) outputStr (bold ++ "==> " ++ normal) outputStrLn res loop prelude read_input lines = do str <- if lines == "" then getInputLine (bold ++ ">>> " ++ normal) else getInputLine (bold ++ "..> " ++ normal) case str of Nothing -> return Quit Just "" -> return (Code lines) Just ":quit" -> return Quit Just ":q" -> return Quit Just (':':'l':'o':'a':'d':' ':file) -> return (Load (strip file)) Just (':':'l':' ':file) -> return (Load (strip file)) Just (':':'t':'y':'p':'e':' ':expr) -> return (TypeCheck expr) Just (':':'t':' ':expr) -> return (TypeCheck expr) Just ln -> read_input (lines ++ ln) strip str = takeWhile (not . isSpace) (dropWhile isSpace str)