summaryrefslogtreecommitdiff
path: root/app/Frontend.hs
blob: 990e79d486b2706ac16b4462d0f9a4dd6c459100 (plain)
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
module Frontend where

import Builtins
import Code (Interp(..))
import Control.Monad (when)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Except (except, runExceptT)
import Control.Monad.Trans.State.Lazy (evalStateT, gets, modify)
import qualified Data.Map as M
import Env (PrlgEnv)
import qualified IR
import qualified Interpreter as I
import Load
  ( compile
  , intern
  , loadExpansion
  , processInput
  , queryExpansion
  , shunt
  )
import System.Console.Haskeline
import qualified Text.Pretty.Simple as Ppr

ppr :: Show a => a -> PrlgEnv ()
ppr x =
  liftIO $
  Ppr.pPrintOpt
    Ppr.CheckColorTty
    Ppr.defaultOutputOptionsDarkBg
      { Ppr.outputOptionsCompactParens = True
      , Ppr.outputOptionsIndentAmount = 2
      , Ppr.outputOptionsPageWidth = 80
      }
    x

-- the signature of this is too ugly to include here
handleError m = do
  res <- runExceptT m
  case res of
    Left err -> do
      lift $ outputStrLn err
      modify $ \s -> s {cmdq = []}
    _ -> pure ()

processCmd precompileHook ast' = do
  ast <- shunt ast'
  code <- lift $ intern ast >>= precompileHook >>= compile
  lift (I.prove code) >>= except

interpreterStart :: PrlgEnv ()
interpreterStart = do
  addPrelude
  interpreterLoop True

interpreterLoop :: Bool -> PrlgEnv ()
interpreterLoop queryMode = do
  q <- gets cmdq
  case q of
    [] -> do
      minput <-
        lift $
        getInputLine
          (if queryMode
             then "prlg? "
             else "prlg |- ")
      case minput of
        Nothing -> return ()
        Just "." -> interpreterLoop (not queryMode)
        Just input -> do
          handleError $ processInput "<user input>" queryMode input
          interpreterLoop queryMode
    ((mode, ast):asts) -> do
      modify $ \s -> s {cmdq = asts}
      handleError $ do
        resOK <-
          processCmd
            (if mode
               then queryExpansion
               else loadExpansion)
            ast
        finished <- lift $ gets (null . cmdq)
        when finished . lift . lift . outputStrLn $
          case (resOK, queryMode) of
            (True, True) -> "yes."
            (False, True) -> "no proof."
            (True, False) -> "ok."
            (False, False) -> "rejected."
      interpreterLoop queryMode

interpreter :: InputT IO ()
interpreter =
  evalStateT
    interpreterStart
    (Interp
       { defs = M.empty
       , cur = error "no cur"
       , cho = []
       , ops = []
       , opstash = []
       , macrostash = []
       , strtable = IR.emptystrtable
       , cmdq = []
       })