{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskell #-}
module Language.Syntactic.TH where
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative
#endif
import Language.Haskell.TH
import Data.Hash (hashInt, combine)
import qualified Data.Hash as Hash
import Language.Syntactic
conName :: Con -> (Name, Int)
conName :: Con -> (Name, Int)
conName (NormalC Name
name [BangType]
args) = (Name
name, [BangType] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [BangType]
args)
conName (RecC Name
name [VarBangType]
args)    = (Name
name, [VarBangType] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [VarBangType]
args)
conName (InfixC BangType
_ Name
name BangType
_)   = (Name
name, Int
2)
conName (ForallC [TyVarBndr]
_ Cxt
_ Con
c)     = Con -> (Name, Int)
conName Con
c
#if __GLASGOW_HASKELL__ >= 800
conName (GadtC [Name
n] [BangType]
as Type
_)    = (Name
n, [BangType] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [BangType]
as)
conName (RecGadtC [Name
n] [VarBangType]
as Type
_) = (Name
n, [VarBangType] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [VarBangType]
as)
  
  
#endif
data Method
    = DefaultMethod Name Name
        
    | MatchingMethod Name (Con -> Int -> Name -> Int -> Clause) [Clause]
        
        
        
        
        
deriveClass
    :: Cxt       
    -> Name      
    -> Type      
    -> [Method]  
    -> DecsQ
deriveClass :: Cxt -> Name -> Type -> [Method] -> DecsQ
deriveClass Cxt
cxt Name
ty Type
clHead [Method]
methods = do
    Just [Con]
cs <- Info -> Maybe [Con]
viewDataDef (Info -> Maybe [Con]) -> Q Info -> Q (Maybe [Con])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Name -> Q Info
reify Name
ty
    [Dec] -> DecsQ
forall (m :: * -> *) a. Monad m => a -> m a
return
      [ Cxt -> Type -> [Dec] -> Dec
instD Cxt
cxt Type
clHead ([Dec] -> Dec) -> [Dec] -> Dec
forall a b. (a -> b) -> a -> b
$
          [ Name -> [Clause] -> Dec
FunD Name
method ([Clause]
clauses [Clause] -> [Clause] -> [Clause]
forall a. [a] -> [a] -> [a]
++ [Clause]
extra)
            | MatchingMethod Name
method Con -> Int -> Name -> Int -> Clause
mkClause [Clause]
extra <- [Method]
methods
            , let clauses :: [Clause]
clauses = [ Con -> Int -> Name -> Int -> Clause
mkClause Con
c Int
i Name
nm Int
ar | (Int
i,Con
c) <- [Int] -> [Con] -> [(Int, Con)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] [Con]
cs
                            , let (Name
nm,Int
ar) = Con -> (Name, Int)
conName Con
c
                            ]
          ] [Dec] -> [Dec] -> [Dec]
forall a. [a] -> [a] -> [a]
++
          [ Name -> [Clause] -> Dec
FunD Name
rhs [[Pat] -> Body -> [Dec] -> Clause
Clause [] (Exp -> Body
NormalB (Name -> Exp
VarE Name
lhs)) []]
            | DefaultMethod Name
rhs Name
lhs <- [Method]
methods
          ]
      ]
deriveClassSimple
    :: Name      
    -> Name      
    -> [Method]  
    -> DecsQ
deriveClassSimple :: Name -> Name -> [Method] -> DecsQ
deriveClassSimple Name
cl Name
ty = Cxt -> Name -> Type -> [Method] -> DecsQ
deriveClass [] Name
ty (Type -> Type -> Type
AppT (Name -> Type
ConT Name
cl) (Name -> Type
ConT Name
ty))
varSupply :: [Name]
varSupply :: [Name]
varSupply = (String -> Name) -> [String] -> [Name]
forall a b. (a -> b) -> [a] -> [b]
map String -> Name
mkName ([String] -> [Name]) -> [String] -> [Name]
forall a b. (a -> b) -> a -> b
$ [String] -> [String]
forall a. [a] -> [a]
tail ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[String]] -> [String]) -> [[String]] -> [String]
forall a b. (a -> b) -> a -> b
$ ([String] -> [String]) -> [String] -> [[String]]
forall a. (a -> a) -> a -> [a]
iterate [String] -> [String]
step [[]]
  where
    step :: [String] -> [String]
    step :: [String] -> [String]
step [String]
vars = (Char -> [String]) -> String -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\Char
c -> (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Char
cChar -> String -> String
forall a. a -> [a] -> [a]
:) [String]
vars) [Char
'a' .. Char
'z']
deriveSymbol
    :: Name  
    -> DecsQ
deriveSymbol :: Name -> DecsQ
deriveSymbol Name
ty =
    Name -> Name -> [Method] -> DecsQ
deriveClassSimple ''Symbol Name
ty [Name -> (Con -> Int -> Name -> Int -> Clause) -> [Clause] -> Method
MatchingMethod 'symSig  Con -> Int -> Name -> Int -> Clause
forall p p. p -> p -> Name -> Int -> Clause
symSigClause []]
  where
    symSigClause :: p -> p -> Name -> Int -> Clause
symSigClause p
_ p
_ Name
con Int
arity =
      [Pat] -> Body -> [Dec] -> Clause
Clause [Name -> [Pat] -> Pat
ConP Name
con (Int -> Pat -> [Pat]
forall a. Int -> a -> [a]
replicate Int
arity Pat
WildP)] (Exp -> Body
NormalB (Name -> Exp
VarE 'signature)) []
deriveEquality
    :: Name  
    -> DecsQ
deriveEquality :: Name -> DecsQ
deriveEquality Name
ty = do
    Just [Con]
cs <- Info -> Maybe [Con]
viewDataDef (Info -> Maybe [Con]) -> Q Info -> Q (Maybe [Con])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Name -> Q Info
reify Name
ty
    let equalFallThrough :: [Clause]
equalFallThrough = if [Con] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Con]
cs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
1
          then [[Pat] -> Body -> [Dec] -> Clause
Clause [Pat
WildP, Pat
WildP] (Exp -> Body
NormalB (Exp -> Body) -> Exp -> Body
forall a b. (a -> b) -> a -> b
$ Name -> Exp
ConE 'False) []]
          else []
    Name -> Name -> [Method] -> DecsQ
deriveClassSimple ''Equality Name
ty
      [ Name -> (Con -> Int -> Name -> Int -> Clause) -> [Clause] -> Method
MatchingMethod 'equal Con -> Int -> Name -> Int -> Clause
forall p p. p -> p -> Name -> Int -> Clause
equalClause [Clause]
equalFallThrough
      , Name -> (Con -> Int -> Name -> Int -> Clause) -> [Clause] -> Method
MatchingMethod 'hash Con -> Int -> Name -> Int -> Clause
forall a p. Integral a => p -> a -> Name -> Int -> Clause
hashClause []
      ]
  where
    equalClause :: p -> p -> Name -> Int -> Clause
equalClause p
_ p
_ Name
con Int
arity = [Pat] -> Body -> [Dec] -> Clause
Clause
        [ Name -> [Pat] -> Pat
ConP Name
con [Name -> Pat
VarP Name
v | Name
v <- [Name]
vs1]
        , Name -> [Pat] -> Pat
ConP Name
con [Name -> Pat
VarP Name
v | Name
v <- [Name]
vs2]
        ]
        (Exp -> Body
NormalB Exp
body)
        []
      where
        vs1 :: [Name]
vs1 = Int -> [Name] -> [Name]
forall a. Int -> [a] -> [a]
take Int
arity [Name]
varSupply
        vs2 :: [Name]
vs2 = Int -> [Name] -> [Name]
forall a. Int -> [a] -> [a]
take Int
arity ([Name] -> [Name]) -> [Name] -> [Name]
forall a b. (a -> b) -> a -> b
$ Int -> [Name] -> [Name]
forall a. Int -> [a] -> [a]
drop Int
arity [Name]
varSupply
        body :: Exp
body = case Int
arity of
          Int
0 -> Name -> Exp
ConE 'True
          Int
_ -> Exp -> Exp -> Exp
AppE (Name -> Exp
VarE 'and)
                 ( [Exp] -> Exp
ListE
                     [ Maybe Exp -> Exp -> Maybe Exp -> Exp
InfixE (Exp -> Maybe Exp
forall a. a -> Maybe a
Just (Name -> Exp
VarE Name
v1)) (Name -> Exp
VarE '(==)) (Exp -> Maybe Exp
forall a. a -> Maybe a
Just (Name -> Exp
VarE Name
v2))
                       | (Name
v1,Name
v2) <- [Name] -> [Name] -> [(Name, Name)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Name]
vs1 [Name]
vs2
                     ]
                 )
    hashClause :: p -> a -> Name -> Int -> Clause
hashClause p
_ a
i Name
con Int
arity = [Pat] -> Body -> [Dec] -> Clause
Clause
        [Name -> [Pat] -> Pat
ConP Name
con [Name -> Pat
VarP Name
v | Name
v <- [Name]
vs]]
        (Exp -> Body
NormalB Exp
body)
        []
      where
        vs :: [Name]
vs = Int -> [Name] -> [Name]
forall a. Int -> [a] -> [a]
take Int
arity [Name]
varSupply
        body :: Exp
body = case Int
arity of
          Int
0 -> Exp -> Exp -> Exp
AppE (Name -> Exp
VarE 'hashInt) (Lit -> Exp
LitE (Integer -> Lit
IntegerL (a -> Integer
forall a. Integral a => a -> Integer
toInteger a
i)))
          Int
_ -> (Exp -> Exp -> Exp) -> [Exp] -> Exp
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldl1 Exp -> Exp -> Exp
AppE
                [ Name -> Exp
VarE 'foldr1
                , Name -> Exp
VarE 'combine
                , [Exp] -> Exp
ListE
                    ([Exp] -> Exp) -> [Exp] -> Exp
forall a b. (a -> b) -> a -> b
$ Exp -> Exp -> Exp
AppE (Name -> Exp
VarE 'hashInt) (Lit -> Exp
LitE (Integer -> Lit
IntegerL (a -> Integer
forall a. Integral a => a -> Integer
toInteger a
i)))
                    Exp -> [Exp] -> [Exp]
forall a. a -> [a] -> [a]
: [ Exp -> Exp -> Exp
AppE (Name -> Exp
VarE 'Hash.hash) (Name -> Exp
VarE Name
v)
                        | Name
v <- [Name]
vs
                      ]
                ]
deriveRender
    :: (String -> String)  
    -> Name                
    -> DecsQ
deriveRender :: (String -> String) -> Name -> DecsQ
deriveRender String -> String
modify Name
ty =
    Name -> Name -> [Method] -> DecsQ
deriveClassSimple ''Render Name
ty [Name -> (Con -> Int -> Name -> Int -> Clause) -> [Clause] -> Method
MatchingMethod 'renderSym Con -> Int -> Name -> Int -> Clause
renderClause []]
  where
    conName :: Name -> String
conName = String -> String
modify (String -> String) -> (Name -> String) -> Name -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Name -> String
nameBase
    renderClause :: Con -> Int -> Name -> Int -> Clause
renderClause Con
_ Int
_ Name
con Int
arity = [Pat] -> Body -> [Dec] -> Clause
Clause
        [Name -> [Pat] -> Pat
ConP Name
con [Name -> Pat
VarP Name
v | Name
v <- Int -> [Name] -> [Name]
forall a. Int -> [a] -> [a]
take Int
arity [Name]
varSupply]]
        (Exp -> Body
NormalB Exp
body)
        []
      where
        body :: Exp
body = case Int
arity of
            Int
0 -> Lit -> Exp
LitE (Lit -> Exp) -> Lit -> Exp
forall a b. (a -> b) -> a -> b
$ String -> Lit
StringL (String -> Lit) -> String -> Lit
forall a b. (a -> b) -> a -> b
$ Name -> String
conName Name
con
            Int
_ -> Name -> [Name] -> Exp
renderRHS Name
con ([Name] -> Exp) -> [Name] -> Exp
forall a b. (a -> b) -> a -> b
$ Int -> [Name] -> [Name]
forall a. Int -> [a] -> [a]
take Int
arity [Name]
varSupply
    renderRHS :: Name -> [Name] -> Exp
    renderRHS :: Name -> [Name] -> Exp
renderRHS Name
con [Name]
args =
      Exp -> Exp -> Exp
AppE (Name -> Exp
VarE 'concat)
        ( [Exp] -> Exp
ListE
            [ Lit -> Exp
LitE (String -> Lit
StringL String
"(")
            , Exp -> Exp -> Exp
AppE (Name -> Exp
VarE 'unwords)
                ([Exp] -> Exp
ListE (Lit -> Exp
LitE (String -> Lit
StringL (Name -> String
conName Name
con)) Exp -> [Exp] -> [Exp]
forall a. a -> [a] -> [a]
: (Name -> Exp) -> [Name] -> [Exp]
forall a b. (a -> b) -> [a] -> [b]
map Name -> Exp
showArg [Name]
args))
            , Lit -> Exp
LitE (String -> Lit
StringL String
")")
            ]
        )
    showArg :: Name -> Exp
    showArg :: Name -> Exp
showArg Name
arg = Exp -> Exp -> Exp
AppE (Name -> Exp
VarE 'show) (Name -> Exp
VarE Name
arg)
instD
    :: Cxt    
    -> Type   
    -> [Dec]  
    -> Dec
#if __GLASGOW_HASKELL__ >= 800
instD :: Cxt -> Type -> [Dec] -> Dec
instD = Maybe Overlap -> Cxt -> Type -> [Dec] -> Dec
InstanceD Maybe Overlap
forall a. Maybe a
Nothing
#else
instD = InstanceD
#endif
viewDataDef :: Info -> Maybe [Con]
#if __GLASGOW_HASKELL__ >= 800
viewDataDef :: Info -> Maybe [Con]
viewDataDef (TyConI (DataD Cxt
_ Name
_ [TyVarBndr]
_ Maybe Type
_ [Con]
cs [DerivClause]
_)) = [Con] -> Maybe [Con]
forall a. a -> Maybe a
Just [Con]
cs
#else
viewDataDef (TyConI (DataD _ _ _ cs _)) = Just cs
#endif
viewDataDef Info
_ = Maybe [Con]
forall a. Maybe a
Nothing
eqPred :: Type -> Type -> Pred
#if __GLASGOW_HASKELL__ >= 710
eqPred :: Type -> Type -> Type
eqPred Type
t1 Type
t2 = (Type -> Type -> Type) -> Cxt -> Type
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldl1 Type -> Type -> Type
AppT [Type
EqualityT,Type
t1,Type
t2]
#else
eqPred = EqualP
#endif
classPred
    :: Name            
    -> (Name -> Type)  
    -> [Type]          
    -> Pred
#if __GLASGOW_HASKELL__ >= 710
classPred :: Name -> (Name -> Type) -> Cxt -> Type
classPred Name
cl Name -> Type
con = (Type -> Type -> Type) -> Type -> Cxt -> Type
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Type -> Type -> Type
AppT (Name -> Type
con Name
cl)
#else
classPred cl con = ClassP cl
#endif
tySynInst :: Name -> [Type] -> Type -> Dec
#if __GLASGOW_HASKELL__ >= 808
tySynInst :: Name -> Cxt -> Type -> Dec
tySynInst Name
t Cxt
as Type
rhs = TySynEqn -> Dec
TySynInstD (TySynEqn -> Dec) -> TySynEqn -> Dec
forall a b. (a -> b) -> a -> b
$
  Maybe [TyVarBndr] -> Type -> Type -> TySynEqn
TySynEqn Maybe [TyVarBndr]
forall a. Maybe a
Nothing ((Type -> Type -> Type) -> Type -> Cxt -> Type
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl Type -> Type -> Type
AppT (Name -> Type
ConT Name
t) Cxt
as) Type
rhs
#elif __GLASGOW_HASKELL__ >= 708
tySynInst t as rhs = TySynInstD t (TySynEqn as rhs)
#else
tySynInst = TySynInstD
#endif