{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
module Futhark.Compiler
(
runPipelineOnProgram
, runCompilerOnProgram
, FutharkConfig (..)
, newFutharkConfig
, dumpError
, module Futhark.Compiler.Program
, readProgram
, readLibrary
)
where
import Control.Monad
import Control.Monad.Reader
import Control.Monad.Except
import System.Exit (exitWith, ExitCode(..))
import System.IO
import qualified Data.Text.IO as T
import Futhark.Internalise
import Futhark.Pipeline
import Futhark.MonadFreshNames
import Futhark.Representation.AST
import qualified Futhark.Representation.SOACS as I
import qualified Futhark.TypeCheck as I
import Futhark.Compiler.Program
import qualified Language.Futhark as E
import Futhark.Util.Log
data FutharkConfig = FutharkConfig
{ futharkVerbose :: (Verbosity, Maybe FilePath)
, futharkWarn :: Bool
, futharkWerror :: Bool
, futharkSafe :: Bool
}
newFutharkConfig :: FutharkConfig
newFutharkConfig = FutharkConfig { futharkVerbose = (NotVerbose, Nothing)
, futharkWarn = True
, futharkWerror = False
, futharkSafe = False
}
dumpError :: FutharkConfig -> CompilerError -> IO ()
dumpError config err =
case err of
ExternalError s -> do
T.hPutStrLn stderr s
T.hPutStrLn stderr "If you find this error message confusing, uninformative, or wrong, please open an issue at https://github.com/diku-dk/futhark/issues."
InternalError s info CompilerBug -> do
T.hPutStrLn stderr "Internal compiler error."
T.hPutStrLn stderr "Please report this at https://github.com/diku-dk/futhark/issues."
report s info
InternalError s info CompilerLimitation -> do
T.hPutStrLn stderr "Known compiler limitation encountered. Sorry."
T.hPutStrLn stderr "Revise your program or try a different Futhark compiler."
report s info
where report s info = do
T.hPutStrLn stderr s
when (fst (futharkVerbose config) > NotVerbose) $
maybe (T.hPutStr stderr) T.writeFile
(snd (futharkVerbose config)) $ info <> "\n"
runCompilerOnProgram :: FutharkConfig
-> Pipeline I.SOACS lore
-> Action lore
-> FilePath
-> IO ()
runCompilerOnProgram config pipeline action file = do
res <- runFutharkM compile $ fst $ futharkVerbose config
case res of
Left err -> liftIO $ do
dumpError config err
exitWith $ ExitFailure 2
Right () ->
return ()
where compile = do
prog <- runPipelineOnProgram config pipeline file
when ((>NotVerbose) . fst $ futharkVerbose config) $
logMsg $ "Running action " ++ actionName action
actionProcedure action prog
when ((>NotVerbose) . fst $ futharkVerbose config) $
logMsg ("Done." :: String)
runPipelineOnProgram :: FutharkConfig
-> Pipeline I.SOACS tolore
-> FilePath
-> FutharkM (Prog tolore)
runPipelineOnProgram config pipeline file = do
when (pipelineVerbose pipeline_config) $
logMsg ("Reading and type-checking source program" :: String)
(ws, prog_imports, namesrc) <- readProgram file
when (futharkWarn config) $ do
liftIO $ hPutStr stderr $ show ws
when (futharkWerror config && ws /= mempty) $
externalErrorS "Treating above warnings as errors due to --Werror."
putNameSource namesrc
when (pipelineVerbose pipeline_config) $
logMsg ("Internalising program" :: String)
res <- internaliseProg (futharkSafe config) prog_imports
case res of
Left err ->
internalErrorS ("During internalisation: " <> pretty err) $ E.Prog Nothing $
concatMap (E.progDecs . fileProg . snd) prog_imports
Right int_prog -> do
when (pipelineVerbose pipeline_config) $
logMsg ("Type-checking internalised program" :: String)
typeCheckInternalProgram int_prog
runPasses pipeline pipeline_config int_prog
where pipeline_config =
PipelineConfig { pipelineVerbose = fst (futharkVerbose config) > NotVerbose
, pipelineValidate = True
}
typeCheckInternalProgram :: I.Prog -> FutharkM ()
typeCheckInternalProgram prog =
case I.checkProg prog of
Left err -> internalErrorS ("After internalisation:\n" ++ show err) (Just prog)
Right () -> return ()
readProgram :: (MonadError CompilerError m, MonadIO m) =>
FilePath -> m (Warnings, Imports, VNameSource)
readProgram = readLibrary . pure
readLibrary :: (MonadError CompilerError m, MonadIO m) =>
[FilePath] -> m (Warnings, Imports, VNameSource)
readLibrary = readLibraryWithBasis emptyBasis