diff options
| author | Joel Martin <github@martintribe.org> | 2014-12-23 20:35:48 -0700 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2015-01-09 16:16:52 -0600 |
| commit | b76aa73bc76a28d7c6bb3c5a43acc9afd9ec42c8 (patch) | |
| tree | 4b57f91dcf1df0e079a4251a1cab78fe0188dfb4 /haskell/step2_eval.hs | |
| parent | a816262a057ecc4bd1fd07750d21cab81490f336 (diff) | |
| download | mal-b76aa73bc76a28d7c6bb3c5a43acc9afd9ec42c8.tar.gz mal-b76aa73bc76a28d7c6bb3c5a43acc9afd9ec42c8.zip | |
Haskell: steps 0-3
Diffstat (limited to 'haskell/step2_eval.hs')
| -rw-r--r-- | haskell/step2_eval.hs | 93 |
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..0a95fcc --- /dev/null +++ b/haskell/step2_eval.hs @@ -0,0 +1,93 @@ +import System.IO (hGetLine, hFlush, hIsEOF, stdin, stdout) +import Control.Monad (when, mapM) +import Control.Monad.Error (throwError) +import qualified Data.Map as Map +import qualified Data.Traversable as DT + +import Types +import Reader (read_str) +import Printer (_pr_str) + +-- read +mal_read :: String -> IO MalVal +mal_read str = read_str str + +-- eval +eval_ast :: MalVal -> (Map.Map String MalVal) -> IO MalVal +eval_ast (MalSymbol sym) env = do + case Map.lookup sym env of + Nothing -> error $ "'" ++ sym ++ "' not found" + Just v -> return v +eval_ast ast@(MalList lst) env = do + new_lst <- mapM (\x -> (eval x env)) lst + return $ MalList new_lst +eval_ast ast@(MalVector lst) env = do + new_lst <- mapM (\x -> (eval x env)) lst + return $ MalVector new_lst +eval_ast ast@(MalHashMap lst) env = do + new_hm <- DT.mapM (\x -> (eval x env)) lst + return $ MalHashMap new_hm +eval_ast ast env = return ast + +apply_ast :: MalVal -> (Map.Map String MalVal) -> IO MalVal +apply_ast ast@(MalList _) env = do + el <- eval_ast ast env + case el of + (MalList (MalFunc (FuncT f) : rest)) -> + return $ f $ MalList rest + el -> + error $ "invalid apply: " ++ (show el) + +eval :: MalVal -> (Map.Map String MalVal) -> IO MalVal +eval ast env = do + case ast of + (MalList lst) -> apply_ast ast env + _ -> eval_ast ast env + + +-- print +mal_print :: MalVal -> String +mal_print exp = show exp + +-- repl +add args = case args of + (MalList [MalNumber a, MalNumber b]) -> MalNumber $ a + b + _ -> error $ "illegal arguments to +" +sub args = case args of + (MalList [MalNumber a, MalNumber b]) -> MalNumber $ a - b + _ -> error $ "illegal arguments to -" +mult args = case args of + (MalList [MalNumber a, MalNumber b]) -> MalNumber $ a * b + _ -> error $ "illegal arguments to *" +divd args = case args of + (MalList [MalNumber a, MalNumber b]) -> MalNumber $ a `div` b + _ -> error $ "illegal arguments to /" + +repl_env :: Map.Map String MalVal +repl_env = Map.fromList [("+", _malfunc add), + ("-", _malfunc sub), + ("*", _malfunc mult), + ("/", _malfunc divd)] + +rep :: String -> IO String +rep line = do + ast <- mal_read line + exp <- eval ast repl_env + return $ mal_print exp + +repl_loop :: IO () +repl_loop = do + putStr "user> " + hFlush stdout + ineof <- hIsEOF stdin + when (not ineof) $ do + line <- hGetLine stdin + if null line + then repl_loop + else do + out <- catchAny (rep line) $ \e -> do + return $ "Error: " ++ (show e) + putStrLn out + repl_loop + +main = repl_loop |
