{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -Wno-missing-methods #-}
module Agda where
import Agda.Convert (fromResponse)
import Agda.Interaction.Base (Command, Command' (Command, Done, Error), CommandM, CommandState (optionsOnReload), IOTCM, initCommandState)
import qualified Agda.Interaction.Imports as Imp
import Agda.Interaction.InteractionTop (initialiseCommandQueue, maybeAbort, runInteraction)
import Agda.Interaction.Options (CommandLineOptions (optAbsoluteIncludePaths))
import Agda.TypeChecking.Errors (prettyError, prettyTCWarnings')
import Agda.TypeChecking.Monad
( TCErr,
commandLineOptions,
runTCMTop',
)
import Agda.TypeChecking.Monad.Base (TCM)
import qualified Agda.TypeChecking.Monad.Benchmark as Bench
import Agda.TypeChecking.Monad.State (setInteractionOutputCallback)
import Agda.Utils.Impossible (CatchImpossible (catchImpossible), Impossible)
import Agda.VersionCommit (versionWithCommitInfo)
import Monad
import Control.Exception
import Control.Monad.Except (catchError)
import Control.Monad.Reader
import Control.Monad.State
import Data.Maybe (listToMaybe)
import Data.Text (pack)
getAgdaVersion :: String
getAgdaVersion = versionWithCommitInfo
interact :: ServerM IO ()
interact = do
env <- ask
writeLog "[Agda] interaction start"
result <- mapReaderT runTCMPrettyErrors $ do
-- decides how to output Response
lift $
setInteractionOutputCallback $ \response -> do
reaction <- fromResponse response
sendResponse env reaction
-- keep reading command
commands <- liftIO $ initialiseCommandQueue (readCommand env)
-- start the loop
opts <- commandLineOptions
let commandState = (initCommandState commands) {optionsOnReload = opts {optAbsoluteIncludePaths = []}}
_ <- mapReaderT (`runStateT` commandState) (loop env)
return ()
-- TODO: we should examine the result
case result of
Left _err -> return ()
Right _val -> return ()
where
loop :: Env -> ServerM CommandM ()
loop env = do
Bench.reset
done <- Bench.billTo [] $ do
r <- lift $ maybeAbort runInteraction
case r of
Done -> return True -- Done.
Error s -> do
writeLog ("Error " <> pack s)
return False
Command _ -> do
writeLog "[Response] Finished sending, waiting for them to complete"
waitUntilResponsesSent
signalCommandFinish
return False
lift Bench.print
unless done (loop env)
-- Reads the next command from the Channel
readCommand :: Env -> IO Command
readCommand env = Command <$> consumeCommand env
parseIOTCM :: String -> Either String IOTCM
parseIOTCM raw = case listToMaybe $ reads raw of
Just (x, "") -> Right x
Just (_, remnent) -> Left $ "not consumed: " ++ remnent
_ -> Left $ "cannot read: " ++ raw
-- TODO: handle the caught errors
-- | Run a TCM action in IO and throw away all of the errors
runTCMPrettyErrors :: TCM a -> IO (Either String a)
runTCMPrettyErrors p =
runTCMTop' ((Right <$> p) `catchError` handleTCErr `catchImpossible` handleImpossible) `catch` catchException
where
handleTCErr :: TCErr -> TCM (Either String a)
handleTCErr err = do
s2s <- prettyTCWarnings' =<< Imp.getAllWarningsOfTCErr err
s1 <- prettyError err
let ss = filter (not . null) $ s2s ++ [s1]
let errorMsg = unlines ss
return (Left errorMsg)
handleImpossible :: Impossible -> TCM (Either String a)
handleImpossible = return . Left . show
catchException :: SomeException -> IO (Either String a)
catchException e = return $ Left $ show e