-- | Contains the high-level functionality to create 'Code' and then produce the actual generated code files.
module Language.Drasil.Code.CodeGeneration (
  -- * Preparing the code files
  makeCode,
  -- * Creating the code files
  createCodeFiles
) where

import Language.Drasil.Code.Code (Code(..))
import Language.Drasil.Code.Imperative.GOOL.Data (AuxData(..))

import Drasil.GOOL (FileData(..), ModData(modDoc))

import Text.PrettyPrint.HughesPJ (Doc,render)
import System.Directory (createDirectoryIfMissing)
import System.FilePath.Posix (takeDirectory)
import System.IO (hPutStrLn, hClose, openFile, IOMode(WriteMode))

-- | Makes code from 'FileData' ('FilePath's with module data) and 'AuxData' ('FilePath's with auxiliary document information).
makeCode :: [FileData] -> [AuxData] -> Code
makeCode :: [FileData] -> [AuxData] -> Code
makeCode [FileData]
files [AuxData]
aux = [(FilePath, Doc)] -> Code
Code ([(FilePath, Doc)] -> Code) -> [(FilePath, Doc)] -> Code
forall a b. (a -> b) -> a -> b
$ [FilePath] -> [Doc] -> [(FilePath, Doc)]
forall a b. [a] -> [b] -> [(a, b)]
zip ((FileData -> FilePath) -> [FileData] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map FileData -> FilePath
filePath [FileData]
files [FilePath] -> [FilePath] -> [FilePath]
forall a. [a] -> [a] -> [a]
++ (AuxData -> FilePath) -> [AuxData] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map AuxData -> FilePath
auxFilePath [AuxData]
aux)
  ((FileData -> Doc) -> [FileData] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map (ModData -> Doc
modDoc (ModData -> Doc) -> (FileData -> ModData) -> FileData -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileData -> ModData
fileMod) [FileData]
files [Doc] -> [Doc] -> [Doc]
forall a. [a] -> [a] -> [a]
++ (AuxData -> Doc) -> [AuxData] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map AuxData -> Doc
auxDoc [AuxData]
aux)

------------------
-- IO Functions --
------------------

-- | Creates the requested 'Code' by producing files.
createCodeFiles :: Code -> IO () -- [(FilePath, Doc)] -> IO ()
createCodeFiles :: Code -> IO ()
createCodeFiles (Code [(FilePath, Doc)]
cs) = ((FilePath, Doc) -> IO ()) -> [(FilePath, Doc)] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (FilePath, Doc) -> IO ()
createCodeFile [(FilePath, Doc)]
cs

-- | Helper that uses pairs of 'Code' to create a file written with the given document at the given 'FilePath'.
createCodeFile :: (FilePath, Doc) -> IO ()
createCodeFile :: (FilePath, Doc) -> IO ()
createCodeFile (FilePath
path, Doc
code) = do
  Bool -> FilePath -> IO ()
createDirectoryIfMissing Bool
True (FilePath -> FilePath
takeDirectory FilePath
path)
  Handle
h <- FilePath -> IOMode -> IO Handle
openFile FilePath
path IOMode
WriteMode
  Handle -> FilePath -> IO ()
hPutStrLn Handle
h (Doc -> FilePath
render Doc
code)
  Handle -> IO ()
hClose Handle
h