{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Proof.Assistant.Idris where
import Control.Concurrent.Async (race)
import Data.ByteString (ByteString)
import Data.Coerce (coerce)
import Idris.Interaction.Command
import Proof.Assistant.Helpers
import Proof.Assistant.Request
import Proof.Assistant.ResourceLimit
import Proof.Assistant.Settings
import Proof.Assistant.State
import qualified Data.ByteString.Char8 as BS8
-- | Call Idris 2 as CLI application.
-- It prepares the CLI command, executes it and waits for response.
callIdris2 :: InterpreterState IdrisSettings -> InterpreterRequest -> IO ByteString
callIdris2 InterpreterState{..} ir@InterpreterRequest{..}
= case parseRequest interpreterRequestMessage of
Left err -> pure err
Right (ecmd, request) -> do
let s@ExternalInterpreterSettings{..} = coerce settings
action <- chooseCommand s ir ecmd request
let asyncExecutable = do
setPriority priority
(_exitCode, stdout, stderr) <- action
let response = unlines [if stdout == "\n" then "Done." else stdout, stderr]
pure $ toBS response
asyncTimer = asyncWait time
eresult <- race asyncTimer (handleErrorMaybe asyncExecutable)
case eresult of
Left () -> pure "Time limit exceeded"
Right bs -> pure bs
-- | Parse command. It could be unknown command or 'IdrisCommand' sub-command with its arguments
-- or even expression to evaluate.
parseRequest :: ByteString -> Either ByteString (Either () IdrisCommand, ByteString)
parseRequest rawCmd = case BS8.words rawSubCommand of
[] -> Left "empty command"
cmd : _ -> if BS8.isPrefixOf "/" cmd
then case matchSupported cmd of
Nothing -> Left $ "Unknown command: " <> cmd
Just aCmd -> Right (Right aCmd, dropCommand rawSubCommand)
else Right (Left (), rawSubCommand)
where
rawSubCommand = dropCommand rawCmd