{-# language Trustworthy, TemplateHaskell #-}

module D10.Char.Splices
    (
    -- * Expressions
      d10Exp, d10ListExp
    -- * Patterns
    , d10Pat, d10ListPat
    ) where

import D10.Char.Conversions
import D10.Char.Unsafe

import Control.Monad ((>=>))
import Language.Haskell.TH.Lib (appE, charL, conE, litE, litP)
import Language.Haskell.TH.Syntax (Exp (..), Pat (..), Q)

-- | Produces an expression of type 'D10' that can be used
-- in a Template Haskell splice.
--
-- >>> d10Nat $(d10Exp 5)
-- 5
--
-- >>> d10Nat $(d10Exp 12)
-- ...
-- ... d10 must be between 0 and 9
-- ...
--
-- You may also be interested in 'd10', a quasi-quoter which
-- does something similar.

d10Exp :: Integer -> Q Exp
d10Exp :: Integer -> Q Exp
d10Exp = Integer -> Q D10
forall (m :: * -> *). MonadFail m => Integer -> m D10
integerD10Fail (Integer -> Q D10) -> (D10 -> Q Exp) -> Integer -> Q Exp
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> D10 -> Q Exp
d10Exp'

d10Exp' :: D10 -> Q Exp
d10Exp' :: D10 -> Q Exp
d10Exp' D10
x = Name -> Q Exp
conE 'D10_Unsafe Q Exp -> Q Exp -> Q Exp
`appE` Lit -> Q Exp
litE (Char -> Lit
charL (D10 -> Char
d10Char D10
x))

-- | Produces an expression of type @['D10']@ that can be used
-- in a Template Haskell splice.
--
-- >>> d10Nat <$> $(d10ListExp "")
-- []
--
-- >>> d10Nat <$> $(d10ListExp "5")
-- [5]
--
-- >>> d10Nat <$> $(d10ListExp "58")
-- [5,8]
--
-- >>> d10Nat <$> $(d10ListExp "a")
-- ...
-- ... d10 must be between 0 and 9
-- ...
--
-- You may also be interested in 'd10list', a quasi-quoter which
-- does something similar.

d10ListExp :: String -> Q Exp
d10ListExp :: String -> Q Exp
d10ListExp = String -> Q [D10]
forall (m :: * -> *). MonadFail m => String -> m [D10]
strD10ListFail (String -> Q [D10]) -> ([D10] -> Q Exp) -> String -> Q Exp
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> [D10] -> Q Exp
d10ListExp'

d10ListExp' :: [D10] -> Q Exp
d10ListExp' :: [D10] -> Q Exp
d10ListExp' =
  (D10 -> Q Exp -> Q Exp) -> Q Exp -> [D10] -> Q Exp
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr
    (\D10
x Q Exp
e -> Name -> Q Exp
conE '(:) Q Exp -> Q Exp -> Q Exp
`appE` D10 -> Q Exp
d10Exp' D10
x Q Exp -> Q Exp -> Q Exp
`appE` Q Exp
e)
    (Name -> Q Exp
conE '[])

---------------------------------------------------

-- | Produces a pattern that can be used in a splice
-- to match a particular 'D10' value.
--
-- >>> :{
--       case (charD10Maybe '5') of
--         Just $(d10Pat 4) -> "A"
--         Just $(d10Pat 5) -> "B"
--         _                -> "C"
-- >>> :}
-- "B"
--
-- You may wish to use the 'd10' quasi-quoter instead.

d10Pat :: Integer -> Q Pat
d10Pat :: Integer -> Q Pat
d10Pat = Integer -> Q D10
forall (m :: * -> *). MonadFail m => Integer -> m D10
integerD10Fail (Integer -> Q D10) -> (D10 -> Q Pat) -> Integer -> Q Pat
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> D10 -> Q Pat
d10Pat'

d10Pat' :: D10 -> Q Pat
d10Pat' :: D10 -> Q Pat
d10Pat' (D10_Unsafe Char
x) = [p| D10_Unsafe $(litP $ charL x) |]

-- | Produces a pattern that can be used in a splice
-- to match a particular list of 'D10' values.
--
-- >>> :{
--       case (strD10ListMaybe "56") of
--         Just $(d10ListPat "42") -> "A"
--         Just $(d10ListPat "56") -> "B"
--         _                       -> "C"
-- >>> :}
-- "B"
--
-- You may wish to use the 'd10list' quasi-quoter instead.

d10ListPat :: String -> Q Pat
d10ListPat :: String -> Q Pat
d10ListPat = String -> Q [D10]
forall (m :: * -> *). MonadFail m => String -> m [D10]
strD10ListFail (String -> Q [D10]) -> ([D10] -> Q Pat) -> String -> Q Pat
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> (D10 -> Q Pat -> Q Pat) -> Q Pat -> [D10] -> Q Pat
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\D10
x Q Pat
p -> [p| $(d10Pat' x) : $(p) |]) [p| [] |]