ddc-build-0.4.2.1: DDC/Build/Pipeline/Salt.hs
{-# 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.Base.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 []