{-# LANGUAGE GADTs #-} module DDC.Build.Pipeline.Salt ( PipeSalt (..) , pipeSalt) where import DDC.Build.Pipeline.Error import DDC.Build.Pipeline.Sink import DDC.Build.Pipeline.Llvm import DDC.Build.Builder import DDC.Data.Pretty import DDC.Llvm.Pretty () import DDC.Core.Check (AnTEC) import qualified DDC.Core.Transform.Reannotate as C import qualified DDC.Core.Module as C import qualified DDC.Core.Llvm.Convert as Llvm import qualified DDC.Core.Salt.Transfer as Salt import qualified DDC.Core.Salt.Platform as Salt import qualified DDC.Core.Salt as Salt import Control.Monad import Control.DeepSeq import System.Directory -- | Process a Core Salt module. data PipeSalt a where -- Plumb the module on without doing anything to it. PipeSaltId :: ![PipeSalt a] -> PipeSalt a -- Output the module in core language syntax. PipeSaltOutput :: !Sink -> PipeSalt a -- Insert control-transfer primops. -- This needs to be done before we convert the module to C or LLVM. PipeSaltTransfer :: ![PipeSalt (AnTEC a Salt.Name)] -> PipeSalt (AnTEC a Salt.Name) -- Print the module as a C source code. PipeSaltPrint :: !Bool -- With C prelude. -> !Salt.Platform -- Target platform specification -> !Sink -> PipeSalt a -- Convert the module to LLVM. PipeSaltToLlvm :: !Salt.Platform -> ![PipeLlvm] -> PipeSalt a -- Compile the module via C source code. PipeSaltCompile :: !Salt.Platform -- Target platform specification -> !Builder -- Builder to use. -> !FilePath -- Intermediate C file. -> !FilePath -- Object file. -> !(Maybe FilePath) -- Link into this exe file -> !Bool -- Keep intermediate .c files -> PipeSalt a deriving instance Show a => Show (PipeSalt a) -- | Process a Core Salt module. -- -- Returns empty list on success. pipeSalt :: (Show a, Pretty a, NFData a) => C.Module a Salt.Name -> PipeSalt a -> IO [Error] pipeSalt !mm !pp = case pp of PipeSaltId !pipes -> {-# SCC "PipeSaltId" #-} liftM concat $ mapM (pipeSalt mm) pipes PipeSaltOutput !sink -> {-# SCC "PipeSaltOutput" #-} pipeSink (renderIndent $ ppr mm) sink PipeSaltTransfer !pipes -> {-# SCC "PipeSaltTransfer" #-} case Salt.transferModule mm of Left err -> return [ErrorSaltConvert err] Right mm' -> liftM concat $ mapM (pipeSalt mm') pipes PipeSaltPrint !withPrelude !platform !sink -> {-# SCC "PipeSaltPrint" #-} case Salt.seaOfSaltModule withPrelude platform mm of Left err -> return $ [ErrorSaltConvert err] Right doc -> pipeSink (renderIndent doc) sink PipeSaltToLlvm !platform !more -> {-# SCC "PipeSaltToLlvm" #-} do let !mm_cut = C.reannotate (const ()) mm case Llvm.convertModule platform mm_cut of Left err -> return [ErrorSaltConvert err] Right mm' -> do results <- mapM (pipeLlvm mm') more return $ concat results PipeSaltCompile !platform !builder !cPath !oPath !mExePath !keepSeaFiles -> {-# SCC "PipeSaltCompile" #-} case Salt.seaOfSaltModule True platform mm of Left errs -> error $ show errs Right cDoc -> do let cSrc = renderIndent cDoc writeFile cPath cSrc -- Compile C source file into .o file. buildCC builder cPath oPath -- Link .o file into an executable if we were asked for one. (case mExePath of Nothing -> return () Just exePath -> do buildLdExe builder [oPath] exePath return ()) -- Remove intermediate .c files if we weren't asked for them. when (not keepSeaFiles) $ removeFile cPath return []