strong-path-1.0.0.0: src/StrongPath/TH.hs
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_HADDOCK hide #-}
module StrongPath.TH
( -- ** QuasiQuoters
-- $quasiQuoters
absdir,
absdirP,
absdirW,
absfile,
absfileP,
absfileW,
reldir,
reldirP,
reldirW,
relfile,
relfileP,
relfileW,
)
where
import Control.Monad ((>=>))
import qualified Language.Haskell.TH.Lib as TH
import Language.Haskell.TH.Quote (QuasiQuoter (..))
import Language.Haskell.TH.Syntax (Lift (..))
import qualified Language.Haskell.TH.Syntax as TH
import StrongPath.FilePath
import StrongPath.Internal
-- $quasiQuoters
-- StrongPath provides quasi quoters that enable you to construct 'Path' in compile time.
-- You will need to enable 'QuasiQuotes' language extension in order to use them.
-- With quasi quoters, you can define paths like this:
--
-- > dirFooAbsPath :: Path System Abs (Dir FooDir)
-- > dirFooAbsPath = [absdir|/foo/bar|]
--
-- > someFile :: Path Posix (Rel FooDir) File ()
-- > someFile = [relfileP|some/file.txt|]
--
-- These will run at compile-time and underneath use the appropriate parser, ensuring that paths are valid and throwing compile-time error if not.
-- TODO: Split these into a separate module, StrongPath.QuasiQuoters, that will be reexported from this module.
-- This will also need extraction of some other parts of this module, in order to avoid cyclic imports.
qq ::
(Lift p, Show err) =>
(String -> Either err p) ->
(p -> TH.ExpQ) ->
QuasiQuoter
qq parse liftP =
QuasiQuoter
{ quoteExp = either (fail . show) liftP . parse,
quotePat = err "pattern",
quoteType = err "type",
quoteDec = err "declaration"
}
where
err what x = fail ("unexpected " ++ what ++ ", must be expression: " ++ x)
liftPath :: TH.TypeQ -> TH.TypeQ -> TH.TypeQ -> Path s b t -> TH.ExpQ
liftPath s b t p = [|$(lift p) :: Path $s $b $t|]
typeVar :: String -> TH.TypeQ
typeVar = TH.newName >=> TH.varT
absdir, absdirP, absdirW :: QuasiQuoter
absdir = qq parseAbsDir (liftPath [t|System|] [t|Abs|] [t|Dir $(typeVar "d")|])
absdirP = qq parseAbsDirP (liftPath [t|Posix|] [t|Abs|] [t|Dir $(typeVar "d")|])
absdirW = qq parseAbsDirW (liftPath [t|Windows|] [t|Abs|] [t|Dir $(typeVar "d")|])
absfile, absfileP, absfileW :: QuasiQuoter
absfile = qq parseAbsFile (liftPath [t|System|] [t|Abs|] [t|File $(typeVar "f")|])
absfileP = qq parseAbsFileP (liftPath [t|Posix|] [t|Abs|] [t|File $(typeVar "f")|])
absfileW = qq parseAbsFileW (liftPath [t|Windows|] [t|Abs|] [t|File $(typeVar "f")|])
reldir, reldirP, reldirW :: QuasiQuoter
reldir = qq parseRelDir (liftPath [t|System|] [t|Rel $(typeVar "d1")|] [t|Dir $(typeVar "d2")|])
reldirP = qq parseRelDirP (liftPath [t|Posix|] [t|Rel $(typeVar "d1")|] [t|Dir $(typeVar "d2")|])
reldirW = qq parseRelDirW (liftPath [t|Windows|] [t|Rel $(typeVar "d1")|] [t|Dir $(typeVar "d2")|])
relfile, relfileP, relfileW :: QuasiQuoter
relfile = qq parseRelFile (liftPath [t|System|] [t|Rel $(typeVar "d")|] [t|File $(typeVar "f")|])
relfileP = qq parseRelFileP (liftPath [t|Posix|] [t|Rel $(typeVar "d")|] [t|File $(typeVar "f")|])
relfileW = qq parseRelFileW (liftPath [t|Windows|] [t|Rel $(typeVar "d")|] [t|File $(typeVar "f")|])