-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRepl.hs
58 lines (45 loc) · 1.67 KB
/
Repl.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
{-# LANGUAGE NoMonomorphismRestriction, UnicodeSyntax, MultiWayIf #-}
module HLisp.Repl ( repl ) where
import HLisp.Parser
import HLisp.Types
import HLisp.Eval
import Control.Applicative
import Control.Monad.Trans
import Control.Monad.Error
import Prelude hiding ( read, readFile )
import Prelude.Unicode
import Data.List ( delete )
import System.Exit
import System.IO.UTF8 ( readFile )
import System.IO.Error
-- Utilities
stripStart = dropWhile (≡ ' ')
printPrt = putStrLn ∘ pretty
infixr 0 #
(#) = flip ($)
-- :Command executor
execCommand [qc] | qc ∈ [":quit", ":q"] = liftIO exitSuccess
execCommand [lc, path] | lc ∈ [":load", ":l"] = liftIO $
either (error ∘ show) id
<$> parse
<$> readFile (filter (≢ '"') path)
`catchIOError` \e → [] <$ print e
execCommand _ = [] <$ liftIO (putStrLn "Invalid command!")
-- REPL
read = liftIO (putStr "> ") >> readAdaptive ""
where
readAdaptive prefix = do
codeChunk ← liftIO getLine
let code = stripStart (prefix ++ codeChunk)
if | null code → read
| ':' ≡ head code → execCommand (words code)
| otherwise → case (parse code) of
Left _ → case codeChunk of
"" → liftIO (putStrLn "...broken input") >> read
_ → readAdaptive code
Right r → return r
repl = runEvalT (read >>= eval >>= print # loop)
where
loop = forever
print = liftIO ∘ mapM_ printPrt
eval ts = mapM evalT ts `catchError` \e → [] <$ liftIO (printPrt e)