diff options
| author | Joel Martin <github@martintribe.org> | 2014-12-24 23:17:38 -0700 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-01-09 16:16:54 -0600 |
| commit | 5400d4bf5e7fe7f968a4553f55101de962a39ef7 (patch) | |
| tree | 99db6dc9e3adc27678ce2bb36bef8a7b83ada171 /haskell/step3_env.hs | |
| parent | c150ec41f4f0b8f384f4b1b493a5ca61db42573c (diff) | |
| download | mal-5400d4bf5e7fe7f968a4553f55101de962a39ef7.tar.gz mal-5400d4bf5e7fe7f968a4553f55101de962a39ef7.zip | |
Haskell: add error handling and try*/catch*.
Achieve self-hosting!
Diffstat (limited to 'haskell/step3_env.hs')
| -rw-r--r-- | haskell/step3_env.hs | 46 |
1 files changed, 26 insertions, 20 deletions
diff --git a/haskell/step3_env.hs b/haskell/step3_env.hs index 6f65afd..3bd3b19 100644 --- a/haskell/step3_env.hs +++ b/haskell/step3_env.hs @@ -1,5 +1,7 @@ -import Control.Monad (when, mapM) -import Control.Monad.Error (throwError) +import System.IO (hFlush, stdout) +import Control.Monad (mapM) +import Control.Monad.Error (runErrorT) +import Control.Monad.Trans (liftIO) import qualified Data.Map as Map import qualified Data.Traversable as DT @@ -10,11 +12,11 @@ import Printer (_pr_str) import Env (Env, env_new, env_get, env_set) -- read -mal_read :: String -> IO MalVal +mal_read :: String -> IOThrows MalVal mal_read str = read_str str -- eval -eval_ast :: MalVal -> Env -> IO MalVal +eval_ast :: MalVal -> Env -> IOThrows MalVal eval_ast sym@(MalSymbol _) env = env_get env sym eval_ast ast@(MalList lst m) env = do new_lst <- mapM (\x -> (eval x env)) lst @@ -27,37 +29,37 @@ eval_ast ast@(MalHashMap lst m) env = do return $ MalHashMap new_hm m eval_ast ast env = return ast -let_bind :: Env -> [MalVal] -> IO Env +let_bind :: Env -> [MalVal] -> IOThrows Env let_bind env [] = return env let_bind env (b:e:xs) = do evaled <- eval e env - x <- env_set env b evaled + x <- liftIO $ env_set env b evaled let_bind env xs -apply_ast :: MalVal -> Env -> IO MalVal +apply_ast :: MalVal -> Env -> IOThrows MalVal apply_ast ast@(MalList (MalSymbol "def!" : args) _) env = do case args of (a1@(MalSymbol _): a2 : []) -> do evaled <- eval a2 env - env_set env a1 evaled - _ -> error $ "invalid def!" + liftIO $ env_set env a1 evaled + _ -> throwStr "invalid def!" apply_ast ast@(MalList (MalSymbol "let*" : args) _) env = do case args of (a1 : a2 : []) -> do params <- (_to_list a1) - let_env <- env_new $ Just env + let_env <- liftIO $ env_new $ Just env let_bind let_env params eval a2 let_env - _ -> error $ "invalid let*" + _ -> throwStr "invalid let*" apply_ast ast@(MalList _ _) env = do el <- eval_ast ast env case el of (MalList ((Func (Fn f) _) : rest) _) -> f $ rest el -> - error $ "invalid apply: " ++ (show el) + throwStr $ "invalid apply: " ++ (show el) -eval :: MalVal -> Env -> IO MalVal +eval :: MalVal -> Env -> IOThrows MalVal eval ast env = do case ast of (MalList _ _) -> apply_ast ast env @@ -70,15 +72,15 @@ mal_print exp = show exp -- repl add [MalNumber a, MalNumber b] = return $ MalNumber $ a + b -add _ = error $ "illegal arguments to +" +add _ = throwStr $ "illegal arguments to +" sub [MalNumber a, MalNumber b] = return $ MalNumber $ a - b -sub _ = error $ "illegal arguments to -" +sub _ = throwStr $ "illegal arguments to -" mult [MalNumber a, MalNumber b] = return $ MalNumber $ a * b -mult _ = error $ "illegal arguments to *" +mult _ = throwStr $ "illegal arguments to *" divd [MalNumber a, MalNumber b] = return $ MalNumber $ a `div` b -divd _ = error $ "illegal arguments to /" +divd _ = throwStr $ "illegal arguments to /" -rep :: Env -> String -> IO String +rep :: Env -> String -> IOThrows String rep env line = do ast <- mal_read line exp <- eval ast env @@ -91,9 +93,13 @@ repl_loop env = do Nothing -> return () Just "" -> repl_loop env Just str -> do - out <- catchAny (rep env str) $ \e -> do - return $ "Error: " ++ (show e) + res <- runErrorT $ rep env str + out <- case res of + Left (StringError str) -> return $ "Error: " ++ str + Left (MalValError mv) -> return $ "Error: " ++ (show mv) + Right val -> return val putStrLn out + hFlush stdout repl_loop env main = do |
