{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
#if __GLASGOW_HASKELL__ >= 708
{-# LANGUAGE EmptyCase #-}
#endif
module Language.Haskell.TH.Lift.Generics (
genericLiftWithPkg
#if MIN_VERSION_template_haskell(2,9,0)
, genericLiftTypedWithPkg
, genericLiftTypedTExpWithPkg
, genericLiftTypedCompatWithPkg
#endif
#if __GLASGOW_HASKELL__ >= 711
, genericLift
, genericLiftTyped
, genericLiftTypedTExp
, genericLiftTypedCompat
#endif
, GLift(..)
, GLiftDatatype(..)
, GLiftArgs(..)
, Lift(..)
) where
import Data.Foldable (foldl')
import Generics.Deriving
import GHC.Base (unpackCString#)
import GHC.Exts (Double(..), Float(..), Int(..), Word(..))
import Language.Haskell.TH.Lib
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Syntax.Compat
#if MIN_VERSION_template_haskell(2,8,0)
import Data.Char (ord)
import Data.Word (Word8)
#endif
#if MIN_VERSION_template_haskell(2,11,0)
import GHC.Exts (Char(..))
#endif
#undef CURRENT_PACKAGE_KEY
genericLiftWithPkg :: (Quote m, Generic a, GLift (Rep a)) => String -> a -> m Exp
genericLiftWithPkg pkg = glift pkg . from
#if MIN_VERSION_template_haskell(2,9,0)
genericLiftTypedWithPkg :: (Quote m, Generic a, GLift (Rep a)) => String -> a -> Code m a
genericLiftTypedWithPkg pkg = unsafeCodeCoerce . genericLiftWithPkg pkg
genericLiftTypedTExpWithPkg :: (Quote m, Generic a, GLift (Rep a)) => String -> a -> m (TExp a)
genericLiftTypedTExpWithPkg pkg = unsafeTExpCoerceQuote . genericLiftWithPkg pkg
genericLiftTypedCompatWithPkg :: (Quote m, Generic a, GLift (Rep a)) => String -> a -> Splice m a
# if MIN_VERSION_template_haskell(2,17,0)
genericLiftTypedCompatWithPkg = genericLiftTypedWithPkg
# else
genericLiftTypedCompatWithPkg = genericLiftTypedTExpWithPkg
# endif
#endif
#if __GLASGOW_HASKELL__ >= 711
genericLift :: (Quote m, Generic a, GLift (Rep a)) => a -> m Exp
genericLift = glift "" . from
genericLiftTyped :: (Quote m, Generic a, GLift (Rep a)) => a -> Code m a
genericLiftTyped = unsafeCodeCoerce . genericLift
genericLiftTypedTExp :: (Quote m, Generic a, GLift (Rep a)) => a -> m (TExp a)
genericLiftTypedTExp = unsafeTExpCoerceQuote . genericLift
genericLiftTypedCompat :: (Quote m, Generic a, GLift (Rep a)) => a -> Splice m a
# if MIN_VERSION_template_haskell(2,17,0)
genericLiftTypedCompat = genericLiftTyped
# else
genericLiftTypedCompat = genericLiftTypedTExp
# endif
#endif
class GLift f where
glift :: Quote m
=> String
-> f a
-> m Exp
instance (Datatype d, GLiftDatatype f) => GLift (D1 d f) where
glift _pkg d@(M1 x) = gliftWith pName mName x
where
pName, mName :: String
#if __GLASGOW_HASKELL__ >= 711
pName = packageName d
#else
pName = _pkg
#endif
mName = moduleName d
class GLiftDatatype f where
gliftWith :: Quote m
=> String
-> String
-> f a
-> m Exp
instance GLiftDatatype V1 where
gliftWith _ _ x =
return $ case x of
#if __GLASGOW_HASKELL__ >= 708
{}
#else
!_ -> undefined
#endif
instance (Constructor c, GLiftArgs f) => GLiftDatatype (C1 c f) where
gliftWith pName mName c@(M1 x) = do
args <- sequence (gliftArgs x)
return $ foldl' AppE (ConE (mkNameG_d pName mName cName)) args
where
cName :: String
cName = conName c
instance (GLiftDatatype f, GLiftDatatype g) => GLiftDatatype (f :+: g) where
gliftWith pName mName (L1 l) = gliftWith pName mName l
gliftWith pName mName (R1 r) = gliftWith pName mName r
class GLiftArgs f where
gliftArgs :: Quote m => f a -> [m Exp]
instance GLiftArgs U1 where
gliftArgs U1 = []
instance Lift c => GLiftArgs (K1 i c) where
gliftArgs (K1 x) = [liftQuote x]
instance GLiftArgs f => GLiftArgs (S1 s f) where
gliftArgs (M1 x) = gliftArgs x
instance (GLiftArgs f, GLiftArgs g) => GLiftArgs (f :*: g) where
gliftArgs (f :*: g) = gliftArgs f ++ gliftArgs g
instance GLiftArgs UAddr where
gliftArgs (UAddr a) = [return (LitE (StringPrimL (word8ify (unpackCString# a))))]
where
#if MIN_VERSION_template_haskell(2,8,0)
word8ify :: String -> [Word8]
word8ify = map (fromIntegral . ord)
#else
word8ify :: String -> String
word8ify = id
#endif
#if MIN_VERSION_template_haskell(2,11,0)
instance GLiftArgs UChar where
gliftArgs (UChar c) = [return (LitE (CharPrimL (C# c)))]
#endif
instance GLiftArgs UDouble where
gliftArgs (UDouble d) = [return (LitE (DoublePrimL (toRational (D# d))))]
instance GLiftArgs UFloat where
gliftArgs (UFloat f) = [return (LitE (floatPrimL (toRational (F# f))))]
instance GLiftArgs UInt where
gliftArgs (UInt i) = [return (LitE (IntPrimL (toInteger (I# i))))]
instance GLiftArgs UWord where
gliftArgs (UWord w) = [return (LitE (WordPrimL (toInteger (W# w))))]