summaryrefslogtreecommitdiff
path: root/app/Frontend.hs
blob: e049365c87425beef630bce60cbbadf27ad97959 (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
module Frontend where

import Builtins
import Code (Interp(..))
import CodeLens
import Control.Monad (when)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Except (except, runExceptT)
import Control.Monad.Trans.State.Lazy (evalStateT)
import qualified Data.Map as M
import Env (PrlgEnv)
import qualified IR
import qualified Interpreter as I
import Lens.Micro.Mtl
import Load
  ( compile
  , intern
  , loadExpansion
  , processInput
  , queryExpansion
  , shunt
  )
import System.Console.Haskeline

-- 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
      cmdq .= []
    _ -> (pure () :: PrlgEnv ()) --prevents ambiguity

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 <- use 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
      cmdq .= asts
      handleError $ do
        resOK <-
          processCmd
            (if mode
               then queryExpansion
               else loadExpansion)
            ast
        finished <- lift $ null <$> use 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 = []
       })