packages feed

Elm-0.13: compiler/Compiler.hs

{-# OPTIONS_GHC -W #-}
module Main where

import Control.Monad (foldM, when)
import qualified Data.Maybe as Maybe
import Text.Blaze.Html.Renderer.String (renderHtml)
import qualified Data.ByteString.Lazy.Char8 as BS
import qualified System.Console.CmdArgs as CmdArgs
import System.Directory
import System.Exit (exitSuccess)
import System.FilePath
import GHC.Conc

import Build.Dependencies (getBuildRecipe, Recipe(..))
import qualified Generate.Html as Html
import qualified Metadata.Prelude as Prelude
import qualified Build.Utils as Utils
import qualified Build.Flags as Flag
import qualified Build.File as File
import qualified Elm.Internal.Paths as Path

main :: IO ()
main = do setNumCapabilities =<< getNumProcessors
          compileArgs =<< CmdArgs.cmdArgs Flag.flags

compileArgs :: Flag.Flags -> IO ()
compileArgs flags =
  do when (Flag.get_runtime flags) $ do
       putStrLn Path.runtime
       exitSuccess
     case Flag.files flags of
       [] -> putStrLn "Usage: elm [OPTIONS] [FILES]\nFor more help: elm --help"
       fs -> mapM_ (build flags) fs

build :: Flag.Flags -> FilePath -> IO ()
build flags rootFile =
    do let noPrelude = Flag.no_prelude flags
       builtIns <- Prelude.interfaces noPrelude

       (Recipe elmFiles jsFiles) <-
           if Flag.make flags
             then Utils.run (getBuildRecipe (Flag.src_dir flags) builtIns rootFile)
             else return (Recipe [rootFile] [])

       moduleName <- File.build flags builtIns elmFiles

       let elmos = map (Utils.elmo flags) elmFiles
       js <- foldM appendToOutput BS.empty (elmos ++ jsFiles)

       (extension, code) <-
           if Flag.only_js flags
           then do putStr "Generating JavaScript ... "
                   makeJs js
           else do putStr "Generating HTML ... "
                   makeHtml js moduleName

       let targetFile = Utils.buildPath flags rootFile extension
       createDirectoryIfMissing True (takeDirectory targetFile)
       BS.writeFile targetFile code
       putStrLn "Done"

    where
      appendToOutput :: BS.ByteString -> FilePath -> IO BS.ByteString
      appendToOutput js filePath = do
        src <- BS.readFile filePath
        return (BS.append src js)

      getRuntime :: IO Html.JSSource
      getRuntime =
          let runtimePath = Maybe.fromMaybe Path.runtime (Flag.set_runtime flags) in
          case Flag.bundle_runtime flags of
            False -> return (Html.Link runtimePath)
            True  -> Html.Source `fmap` BS.readFile runtimePath

      makeJs :: BS.ByteString -> IO (String, BS.ByteString)
      makeJs js =
        do runtime <- getRuntime
           case runtime of
             Html.Link _ -> return ("js", js)
             Html.Source rts -> return ("js", BS.append rts js)

      makeHtml :: BS.ByteString -> String -> IO (String, BS.ByteString)
      makeHtml js moduleName =
        do runtime <- getRuntime
           return ("html", BS.pack $ renderHtml (html runtime))
        where
          sources js = map Html.Link (Flag.scripts flags) ++ [ Html.Source js ]
          html runtime =
              Html.generate runtime (takeBaseName rootFile) (sources js) moduleName ""