2024-11-17 18:33:14 -08:00
|
|
|
module Repl (repl, showEnvEntry) where
|
2024-11-15 18:39:44 -08:00
|
|
|
|
2024-11-17 18:33:14 -08:00
|
|
|
import Data.Functor (void)
|
|
|
|
|
import Data.List (isPrefixOf)
|
2024-11-17 01:57:53 -08:00
|
|
|
import qualified Data.Map as M
|
2024-11-17 18:33:14 -08:00
|
|
|
import qualified Data.Text as T
|
|
|
|
|
import Eval
|
2024-11-15 18:39:44 -08:00
|
|
|
import Expr
|
|
|
|
|
import Parser
|
|
|
|
|
import System.Console.Haskeline
|
|
|
|
|
import System.Directory (createDirectoryIfMissing, getHomeDirectory)
|
|
|
|
|
import System.FilePath ((</>))
|
|
|
|
|
|
2024-11-17 18:33:14 -08:00
|
|
|
data ReplCommand = Quit | DumpEnv | TypeQuery String | Input String deriving (Show)
|
2024-11-15 18:39:44 -08:00
|
|
|
|
|
|
|
|
parseCommand :: Maybe String -> Maybe ReplCommand
|
|
|
|
|
parseCommand Nothing = Nothing
|
|
|
|
|
parseCommand (Just ":q") = Just Quit
|
2024-11-17 18:33:14 -08:00
|
|
|
parseCommand (Just ":e") = Just DumpEnv
|
|
|
|
|
parseCommand (Just input)
|
|
|
|
|
| ":t" `isPrefixOf` input = case words input of
|
|
|
|
|
[":t", rest] -> Just $ TypeQuery rest
|
|
|
|
|
_ -> Nothing
|
|
|
|
|
| otherwise = Just $ Input input
|
|
|
|
|
|
|
|
|
|
showEnvEntry :: T.Text -> Expr -> String
|
|
|
|
|
showEnvEntry k v = T.unpack k ++ " : " ++ prettyS v
|
2024-11-15 18:39:44 -08:00
|
|
|
|
2024-11-17 18:33:14 -08:00
|
|
|
dumpEnv :: Env -> InputT IO ()
|
|
|
|
|
dumpEnv = void . M.traverseWithKey ((outputStrLn .) . showEnvEntry)
|
2024-11-15 18:39:44 -08:00
|
|
|
|
2024-11-17 18:33:14 -08:00
|
|
|
handleInput :: GlobalState -> String -> InputT IO GlobalState
|
|
|
|
|
handleInput env input =
|
|
|
|
|
let (res, env') = parseDefEmpty env (T.pack input)
|
|
|
|
|
in case res of
|
|
|
|
|
Left err -> outputStrLn err >> pure env'
|
|
|
|
|
Right () -> pure env'
|
2024-11-15 18:39:44 -08:00
|
|
|
|
2024-11-17 18:33:14 -08:00
|
|
|
repl :: IO GlobalState
|
2024-11-15 18:39:44 -08:00
|
|
|
repl = do
|
|
|
|
|
home <- getHomeDirectory
|
|
|
|
|
let basepath = home </> ".cache" </> "perga"
|
|
|
|
|
let filepath = basepath </> "history"
|
|
|
|
|
createDirectoryIfMissing True basepath
|
2024-11-17 18:33:14 -08:00
|
|
|
runInputT (defaultSettings{historyFile = Just filepath}) (loop GS{_defs = M.empty, _types = M.empty})
|
2024-11-15 18:39:44 -08:00
|
|
|
where
|
2024-11-17 18:33:14 -08:00
|
|
|
loop :: GlobalState -> InputT IO GlobalState
|
|
|
|
|
loop env = do
|
2024-11-15 18:39:44 -08:00
|
|
|
minput <- getInputLine "> "
|
|
|
|
|
case parseCommand minput of
|
2024-11-17 18:33:14 -08:00
|
|
|
Nothing -> pure env
|
|
|
|
|
Just Quit -> pure env
|
|
|
|
|
Just DumpEnv -> dumpEnv (_types env) >> loop env
|
|
|
|
|
Just (TypeQuery input) ->
|
|
|
|
|
( case M.lookup (T.pack input) (_types env) of
|
|
|
|
|
Nothing -> outputStrLn (input ++ " unbound")
|
|
|
|
|
Just expr -> outputStrLn $ prettyS expr
|
|
|
|
|
)
|
|
|
|
|
>> loop env
|
2024-11-15 18:39:44 -08:00
|
|
|
Just (Input input) -> do
|
2024-11-17 18:33:14 -08:00
|
|
|
env' <- handleInput env input
|
|
|
|
|
loop env'
|