{-# LANGUAGE CPP #-}
module Data.Time.TZTime.QQ
( tz
) where
import Data.List.NonEmpty (NonEmpty(..))
import Data.Time.TZTime.Internal as I
import Language.Haskell.TH (Exp, Q)
import Language.Haskell.TH.Quote
import Text.ParserCombinators.ReadP qualified as P
#if MIN_VERSION_template_haskell(2,17,0)
import Language.Haskell.TH.Syntax (unTypeCode)
#else
import Language.Haskell.TH.Syntax (unType)
#endif
tz :: QuasiQuoter
tz :: QuasiQuoter
tz = QuasiQuoter
{ quoteExp :: String -> Q Exp
quoteExp = String -> Q Exp
qexp
, quotePat :: String -> Q Pat
quotePat = \String
_ -> String -> Q Pat
forall a. String -> Q a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Cannot use 'tz' as a pattern."
, quoteType :: String -> Q Type
quoteType = \String
_ -> String -> Q Type
forall a. String -> Q a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Cannot use 'tz' as a type."
, quoteDec :: String -> Q [Dec]
quoteDec = \String
_ ->String -> Q [Dec]
forall a. String -> Q a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Cannot use 'tz' as a declaration."
}
where
qexp :: String -> Q Exp
qexp :: String -> Q Exp
qexp String
input = do
(LocalTime
lt, Maybe TimeZone
offsetMaybe, TZIdentifier
ident) <- String
-> ReadP (LocalTime, Maybe TimeZone, TZIdentifier)
-> Q (LocalTime, Maybe TimeZone, TZIdentifier)
forall a. String -> ReadP a -> Q a
I.readP_to_Q String
input (ReadP (LocalTime, Maybe TimeZone, TZIdentifier)
I.readComponentsP ReadP (LocalTime, Maybe TimeZone, TZIdentifier)
-> ReadP () -> ReadP (LocalTime, Maybe TimeZone, TZIdentifier)
forall a b. ReadP a -> ReadP b -> ReadP a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ReadP ()
P.skipSpaces)
LocalTime -> TZIdentifier -> Q (NonEmpty TZTime)
forall (m :: * -> *).
MonadFail m =>
LocalTime -> TZIdentifier -> m (NonEmpty TZTime)
I.getValidTZTimes LocalTime
lt TZIdentifier
ident Q (NonEmpty TZTime)
-> (NonEmpty TZTime -> Q (NonEmpty TZTime)) -> Q (NonEmpty TZTime)
forall a b. Q a -> (a -> Q b) -> Q b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe TimeZone -> NonEmpty TZTime -> Q (NonEmpty TZTime)
forall (m :: * -> *).
MonadFail m =>
Maybe TimeZone -> NonEmpty TZTime -> m (NonEmpty TZTime)
I.checkOffset Maybe TimeZone
offsetMaybe Q (NonEmpty TZTime) -> (NonEmpty TZTime -> Q Exp) -> Q Exp
forall a b. Q a -> (a -> Q b) -> Q b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
TZTime
tzt :| [] -> TZTime -> Q Exp
toExp TZTime
tzt
NonEmpty TZTime
tzts -> String -> Q Exp
forall a. String -> Q a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Q Exp) -> String -> Q Exp
forall a b. (a -> b) -> a -> b
$ String
"Ambiguous time: please specify an offset.\n" String -> String -> String
forall a. Semigroup a => a -> a -> a
<> NonEmpty TZTime -> String
I.mkSuggestions NonEmpty TZTime
tzts
toExp :: TZTime -> Q Exp
toExp :: TZTime -> Q Exp
toExp TZTime
tzt =
#if MIN_VERSION_template_haskell(2,17,0)
Code Q TZTime -> Q Exp
forall a (m :: * -> *). Quote m => Code m a -> m Exp
unTypeCode (Code Q TZTime -> Q Exp) -> Code Q TZTime -> Q Exp
forall a b. (a -> b) -> a -> b
$ TZTime -> Code Q TZTime
forall (m :: * -> *). Quote m => TZTime -> Code m TZTime
I.liftTZTime TZTime
tzt
#else
unType <$> I.liftTZTime tzt
#endif