{-# LANGUAGE QuasiQuotes     #-}
{-# LANGUAGE TemplateHaskell #-}
module Language.Dockerfile.EDSL.Quasi
  where

import           Language.Haskell.TH
import           Language.Haskell.TH.Quote
import           Language.Haskell.TH.Syntax

import           Language.Dockerfile.EDSL
import qualified Language.Dockerfile.Parser      as Parser
import           Language.Dockerfile.Syntax
import           Language.Dockerfile.Syntax.Lift

-- | Quasiquoter for embedding dockerfiles on the EDSL
--
-- @
-- putStr $ 'toDockerfile' $ do
--     from "node"
--     run "apt-get update"
--     [edockerfile|
--     RUN apt-get update
--     CMD node something.js
--     |]
-- @
edockerfile :: QuasiQuoter
edockerfile = dockerfile { quoteExp = edockerfileE
                         }

edockerfileE :: String -> ExpQ
edockerfileE e = case Parser.parseString e of
    Left err -> fail (show err)
    Right d ->
        let d' = filterEOL d
        in [| embed d' |]

dockerfile :: QuasiQuoter
dockerfile = QuasiQuoter { quoteExp = dockerfileE
                         , quoteDec = error "Can't use Dockerfile as a declaration"
                         , quotePat = error "Can't use Dockerfile as a pattern"
                         , quoteType = error "Can't use Dockerfile as a type"
                         }

dockerfileE :: String -> ExpQ
dockerfileE e = case Parser.parseString e of
    Left err -> fail (show err)
    Right d ->
        let d' = filterEOL d
        in lift d'

filterEOL = filter (\(InstructionPos i _ _) -> i /= EOL)