{-# LANGUAGE Safe #-}
{- |
Module : Language.Haskell.TH.Quote
Description : Quasi-quoting support for Template Haskell

Template Haskell supports quasiquoting, which permits users to construct
program fragments by directly writing concrete syntax.  A quasiquoter is
essentially a function with takes a string to a Template Haskell AST.
This module defines the 'QuasiQuoter' datatype, which specifies a
quasiquoter @q@ which can be invoked using the syntax
@[q| ... string to parse ... |]@ when the @QuasiQuotes@ language
extension is enabled, and some utility functions for manipulating
quasiquoters.  Nota bene: this package does not define any parsers,
that is up to you.
-}
module Language.Haskell.TH.Quote
  ( QuasiQuoter(..)
  , quoteFile
  , namedDefaultQuasiQuoter
  , defaultQuasiQuoter
  -- * For backwards compatibility
  , dataToQa, dataToExpQ, dataToPatQ
  ) where

import GHC.Boot.TH.Syntax
import GHC.Boot.TH.Quote
import Language.Haskell.TH.Syntax (dataToQa, dataToExpQ, dataToPatQ)


-- | 'quoteFile' takes a 'QuasiQuoter' and lifts it into one that read
-- the data out of a file.  For example, suppose @asmq@ is an
-- assembly-language quoter, so that you can write [asmq| ld r1, r2 |]
-- as an expression. Then if you define @asmq_f = quoteFile asmq@, then
-- the quote [asmq_f|foo.s|] will take input from file @"foo.s"@ instead
-- of the inline text
quoteFile :: QuasiQuoter -> QuasiQuoter
quoteFile :: QuasiQuoter -> QuasiQuoter
quoteFile (QuasiQuoter { quoteExp :: QuasiQuoter -> String -> Q Exp
quoteExp = String -> Q Exp
qe, quotePat :: QuasiQuoter -> String -> Q Pat
quotePat = String -> Q Pat
qp, quoteType :: QuasiQuoter -> String -> Q Type
quoteType = String -> Q Type
qt, quoteDec :: QuasiQuoter -> String -> Q [Dec]
quoteDec = String -> Q [Dec]
qd })
  = QuasiQuoter { quoteExp :: String -> Q Exp
quoteExp = (String -> Q Exp) -> String -> Q Exp
forall a. (String -> Q a) -> String -> Q a
get String -> Q Exp
qe, quotePat :: String -> Q Pat
quotePat = (String -> Q Pat) -> String -> Q Pat
forall a. (String -> Q a) -> String -> Q a
get String -> Q Pat
qp, quoteType :: String -> Q Type
quoteType = (String -> Q Type) -> String -> Q Type
forall a. (String -> Q a) -> String -> Q a
get String -> Q Type
qt, quoteDec :: String -> Q [Dec]
quoteDec = (String -> Q [Dec]) -> String -> Q [Dec]
forall a. (String -> Q a) -> String -> Q a
get String -> Q [Dec]
qd }
  where
   get :: (String -> Q a) -> String -> Q a
   get :: forall a. (String -> Q a) -> String -> Q a
get String -> Q a
old_quoter String
file_name = do { file_cts <- IO String -> Q String
forall a. IO a -> Q a
runIO (String -> IO String
readFile String
file_name)
                                 ; addDependentFile file_name
                                 ; old_quoter file_cts }

-- | A 'QuasiQuoter' that fails with a helpful error message in every
-- context. It is intended to be modified to create a 'QuasiQuoter' that
-- fails in all inappropriate contexts.
--
-- For example, you could write
--
-- @
-- myPatQQ = (namedDefaultQuasiQuoter "myPatQQ")
--   { quotePat = ... }
-- @
--
-- If 'myPatQQ' is used in an expression context, the compiler will report
-- that, naming 'myPatQQ'.
--
-- See also 'defaultQuasiQuoter', which does not name the 'QuasiQuoter' in
-- the error message, and might therefore be more appropriate when
-- the users of a particular 'QuasiQuoter' tend to define local \"synonyms\"
-- for it.
namedDefaultQuasiQuoter :: String -> QuasiQuoter
namedDefaultQuasiQuoter :: String -> QuasiQuoter
namedDefaultQuasiQuoter String
name = QuasiQuoter
  { quoteExp :: String -> Q Exp
quoteExp = String -> String -> Q Exp
forall {m :: * -> *} {p} {a}. MonadFail m => String -> p -> m a
f String
"use in expression contexts."
  , quotePat :: String -> Q Pat
quotePat = String -> String -> Q Pat
forall {m :: * -> *} {p} {a}. MonadFail m => String -> p -> m a
f String
"use in pattern contexts."
  , quoteType :: String -> Q Type
quoteType = String -> String -> Q Type
forall {m :: * -> *} {p} {a}. MonadFail m => String -> p -> m a
f String
"use in types."
  , quoteDec :: String -> Q [Dec]
quoteDec = String -> String -> Q [Dec]
forall {m :: * -> *} {p} {a}. MonadFail m => String -> p -> m a
f String
"creating declarations."
  }
  where
    f :: String -> p -> m a
f String
m p
_ = String -> m a
forall a. HasCallStack => String -> m a
forall (m :: * -> *) a.
(MonadFail m, HasCallStack) =>
String -> m a
fail (String -> m a) -> String -> m a
forall a b. (a -> b) -> a -> b
$ String
"The " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" quasiquoter is not for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
m

-- | A 'QuasiQuoter' that fails with a helpful error message in every
-- context. It is intended to be modified to create a 'QuasiQuoter' that
-- fails in all inappropriate contexts.
--
-- For example, you could write
--
-- @
-- myExpressionQQ = defaultQuasiQuoter
--   { quoteExp = ... }
-- @
--
-- See also 'namedDefaultQuasiQuoter', which names the 'QuasiQuoter' in the
-- error messages.
defaultQuasiQuoter :: QuasiQuoter
defaultQuasiQuoter :: QuasiQuoter
defaultQuasiQuoter = QuasiQuoter
  { quoteExp :: String -> Q Exp
quoteExp = String -> String -> Q Exp
forall {m :: * -> *} {p} {a}. MonadFail m => String -> p -> m a
f String
"use in expression contexts."
  , quotePat :: String -> Q Pat
quotePat = String -> String -> Q Pat
forall {m :: * -> *} {p} {a}. MonadFail m => String -> p -> m a
f String
"use in pattern contexts."
  , quoteType :: String -> Q Type
quoteType = String -> String -> Q Type
forall {m :: * -> *} {p} {a}. MonadFail m => String -> p -> m a
f String
"use in types."
  , quoteDec :: String -> Q [Dec]
quoteDec = String -> String -> Q [Dec]
forall {m :: * -> *} {p} {a}. MonadFail m => String -> p -> m a
f String
"creating declarations."
  }
  where
    f :: String -> p -> m a
f String
m p
_ = String -> m a
forall a. HasCallStack => String -> m a
forall (m :: * -> *) a.
(MonadFail m, HasCallStack) =>
String -> m a
fail (String -> m a) -> String -> m a
forall a b. (a -> b) -> a -> b
$ String
"This quasiquoter is not for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
m