{-# language Trustworthy, TemplateHaskell #-}

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

import D10.Num.Conversions
import D10.Num.Unsafe (D10(..))

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

-- | Produces an expression of type @'D10' a@ 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 Integer)
forall a (m :: * -> *).
(Num a, MonadFail m) =>
Integer -> m (D10 a)
integerD10Fail (Integer -> Q (D10 Integer))
-> (D10 Integer -> Q Exp) -> Integer -> Q Exp
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> D10 Integer -> Q Exp
d10Exp'

d10Exp' :: D10 Integer -> Q Exp
d10Exp' :: D10 Integer -> Q Exp
d10Exp' (D10_Unsafe Integer
x) = Name -> Q Exp
conE 'D10_Unsafe Q Exp -> Q Exp -> Q Exp
`appE` (Name -> Q Exp
varE 'fromInteger Q Exp -> Q Exp -> Q Exp
`appE` Lit -> Q Exp
litE (Integer -> Lit
integerL Integer
x))

-- | Produces an expression of type @['D10' a]@ 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 Integer]
forall a (m :: * -> *). (Num a, MonadFail m) => String -> m [D10 a]
strD10ListFail (String -> Q [D10 Integer])
-> ([D10 Integer] -> Q Exp) -> String -> Q Exp
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> [D10 Integer] -> Q Exp
d10ListExp'

d10ListExp' :: [D10 Integer] -> Q Exp
d10ListExp' :: [D10 Integer] -> Q Exp
d10ListExp' =
  (D10 Integer -> Q Exp -> Q Exp) -> Q Exp -> [D10 Integer] -> Q Exp
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr
    (\D10 Integer
x Q Exp
e -> Name -> Q Exp
conE '(:) Q Exp -> Q Exp -> Q Exp
`appE` D10 Integer -> Q Exp
d10Exp' D10 Integer
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' a@ 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 Integer)
forall a (m :: * -> *).
(Num a, MonadFail m) =>
Integer -> m (D10 a)
integerD10Fail (Integer -> Q (D10 Integer))
-> (D10 Integer -> Q Pat) -> Integer -> Q Pat
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> D10 Integer -> Q Pat
d10Pat'

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

d10Pat'' :: Integral a => D10 a -> Q Pat
d10Pat'' :: D10 a -> Q Pat
d10Pat'' (D10_Unsafe a
x) = [p| D10_Unsafe $(litP $ integerL $ toInteger x) |]

-- | Produces a pattern that can be used in a splice
-- to match a particular list of @'D10' a@ 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 Integer]
forall a (m :: * -> *). (Num a, MonadFail m) => String -> m [D10 a]
strD10ListFail (String -> Q [D10 Integer])
-> ([D10 Integer] -> Q Pat) -> String -> Q Pat
forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> [D10 Integer] -> Q Pat
d10ListPat'

d10ListPat' :: [D10 Integer] -> Q Pat
d10ListPat' :: [D10 Integer] -> Q Pat
d10ListPat' = (D10 Integer -> Q Pat -> Q Pat) -> Q Pat -> [D10 Integer] -> Q Pat
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\D10 Integer
x Q Pat
p -> [p| $(d10Pat'' x) : $(p) |]) [p| [] |]