aboutsummaryrefslogtreecommitdiff
path: root/haskell/step2_eval.hs
diff options
context:
space:
mode:
Diffstat (limited to 'haskell/step2_eval.hs')
-rw-r--r--haskell/step2_eval.hs93
1 files changed, 93 insertions, 0 deletions
diff --git a/haskell/step2_eval.hs b/haskell/step2_eval.hs
new file mode 100644
index 0000000..9105737
--- /dev/null
+++ b/haskell/step2_eval.hs
@@ -0,0 +1,93 @@
+import System.IO (hFlush, stdout)
+import Control.Monad (mapM)
+import Control.Monad.Error (runErrorT)
+import qualified Data.Map as Map
+import qualified Data.Traversable as DT
+
+import Readline (readline, load_history)
+import Types
+import Reader (read_str)
+import Printer (_pr_str)
+
+-- read
+mal_read :: String -> IOThrows MalVal
+mal_read str = read_str str
+
+-- eval
+eval_ast :: MalVal -> (Map.Map String MalVal) -> IOThrows MalVal
+eval_ast (MalSymbol sym) env = do
+ case Map.lookup sym env of
+ Nothing -> throwStr $ "'" ++ sym ++ "' not found"
+ Just v -> return v
+eval_ast ast@(MalList lst m) env = do
+ new_lst <- mapM (\x -> (eval x env)) lst
+ return $ MalList new_lst m
+eval_ast ast@(MalVector lst m) env = do
+ new_lst <- mapM (\x -> (eval x env)) lst
+ return $ MalVector new_lst m
+eval_ast ast@(MalHashMap lst m) env = do
+ new_hm <- DT.mapM (\x -> (eval x env)) lst
+ return $ MalHashMap new_hm m
+eval_ast ast env = return ast
+
+apply_ast :: MalVal -> (Map.Map String MalVal) -> IOThrows MalVal
+apply_ast ast@(MalList _ _) env = do
+ el <- eval_ast ast env
+ case el of
+ (MalList ((Func (Fn f) _) : rest) _) ->
+ f $ rest
+ el ->
+ throwStr $ "invalid apply: " ++ (show el)
+
+eval :: MalVal -> (Map.Map String MalVal) -> IOThrows MalVal
+eval ast env = do
+ case ast of
+ (MalList _ _) -> apply_ast ast env
+ _ -> eval_ast ast env
+
+
+-- print
+mal_print :: MalVal -> String
+mal_print exp = show exp
+
+-- repl
+add [MalNumber a, MalNumber b] = return $ MalNumber $ a + b
+add _ = throwStr $ "illegal arguments to +"
+sub [MalNumber a, MalNumber b] = return $ MalNumber $ a - b
+sub _ = throwStr $ "illegal arguments to -"
+mult [MalNumber a, MalNumber b] = return $ MalNumber $ a * b
+mult _ = throwStr $ "illegal arguments to *"
+divd [MalNumber a, MalNumber b] = return $ MalNumber $ a `div` b
+divd _ = throwStr $ "illegal arguments to /"
+
+repl_env :: Map.Map String MalVal
+repl_env = Map.fromList [("+", _func add),
+ ("-", _func sub),
+ ("*", _func mult),
+ ("/", _func divd)]
+
+rep :: String -> IOThrows String
+rep line = do
+ ast <- mal_read line
+ exp <- eval ast repl_env
+ return $ mal_print exp
+
+repl_loop :: IO ()
+repl_loop = do
+ line <- readline "user> "
+ case line of
+ Nothing -> return ()
+ Just "" -> repl_loop
+ Just str -> do
+ res <- runErrorT $ rep 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
+
+main = do
+ load_history
+ repl_loop