{-# LANGUAGE TemplateHaskellQuotes #-}
module Clash.XException.TH
( mkShowXTupleInstances
, mkNFDataXTupleInstances
) where
import Data.Either (isLeft)
import Data.List (intersperse)
import Language.Haskell.TH.Compat
import Language.Haskell.TH.Syntax
isXName, hasUndefinedName, deepErrorXName, rnfXName, ensureSpineName :: Name
isXName = mkName "isX"
hasUndefinedName = mkName "hasUndefined"
deepErrorXName = mkName "deepErrorX"
rnfXName = mkName "rnfX"
ensureSpineName = mkName "ensureSpine"
showxName :: Name
showxName = mkName "ShowX"
showXFnName :: Name
showXFnName = mkName "showX"
showsPrecXName :: Name
showsPrecXName = mkName "showsPrecX"
nfdataxName :: Name
nfdataxName = mkName "NFDataX"
mkTup :: [Type] -> Type
mkTup names@(length -> n) =
foldl AppT (TupleT n) names
mkShowXTupleInstance :: Int -> Dec
mkShowXTupleInstance n =
InstanceD Nothing constraints instanceTyp [showsPrecXDecl, showXDecl]
where
constraints = fmap (AppT (ConT showxName)) vars
instanceTyp = ConT showxName `AppT` mkTup vars
names = fmap (mkName . ('a':) . show) [0..n-1]
vars = fmap VarT names
x = mkName "x"
s = mkName "s"
showsPrecXDecl = FunD showsPrecXName
[ Clause
[WildP, VarP x, VarP s]
(NormalB
(VarE 'mappend `AppE` (VarE showXFnName `AppE` VarE x) `AppE` VarE s))
[]
]
showXDecl = FunD showXFnName
[ Clause
[TupP (fmap VarP names)]
(NormalB
(VarE 'mconcat `AppE` (ListE
([LitE (StringL "(")]
<> intersperse (LitE (StringL ",")) (fmap toShowX names)
<> [LitE (StringL ")")]))))
[]
]
where
toShowX a = VarE showXFnName `AppE` VarE a
mkShowXTupleInstances :: [Int] -> Q [Dec]
mkShowXTupleInstances tupSizes =
return (fmap mkShowXTupleInstance tupSizes)
mkNFDataXTupleInstance :: Int -> Dec
mkNFDataXTupleInstance n =
InstanceD
Nothing
constraints
instanceTyp
[ ensureSpineDecl
, hasUndefinedDecl
, deepErrorXDecl
, rnfXDecl
]
where
constraints = map (AppT (ConT nfdataxName)) vars
instanceTyp = ConT nfdataxName `AppT` mkTup vars
names = map (mkName . ('a':) . show) [0..n-1]
vars = map VarT names
t = mkName "t"
s = mkName "s"
rnfXDecl = FunD rnfXName [
Clause
[AsP t (TildeP (TupP (map VarP names)))]
(NormalB (
CondE
(VarE 'isLeft `AppE` (VarE isXName `AppE` VarE t))
(TupE [])
(foldl
(\e1 e2 -> UInfixE e1 (VarE 'seq) (VarE rnfXName `AppE` e2))
(VarE rnfXName `AppE` VarE (head names))
(map VarE (tail names)))
))
[]
]
hasUndefinedDecl = FunD hasUndefinedName [
Clause
[AsP t (TildeP (TupP (map VarP names)))]
(NormalB (
CondE
(VarE 'isLeft `AppE` (VarE isXName `AppE` VarE t))
(ConE 'True)
(VarE 'or `AppE` ListE
(map ((VarE hasUndefinedName `AppE`) . VarE) names))
))
[]
]
ensureSpineDecl = FunD ensureSpineName [
Clause
[TildeP (TupP (map VarP names))]
(NormalB (mkTupE (map (AppE (VarE ensureSpineName) . VarE) names)))
[]
]
deepErrorXDecl = FunD deepErrorXName [
Clause
[VarP s]
(NormalB (mkTupE (replicate n (VarE deepErrorXName `AppE` VarE s))))
[]
]
mkNFDataXTupleInstances :: [Int] -> Q [Dec]
mkNFDataXTupleInstances tupSizes =
pure (map mkNFDataXTupleInstance tupSizes)