module Language.Haskell.TH.Desugar (
DExp(..), DLetDec(..), DPat(..), DType(..), DKind, DCxt, DPred(..),
DTyVarBndr(..), DMatch(..), DClause(..), DDec(..),
DDerivClause(..), DerivStrategy(..), DPatSynDir(..), DPatSynType,
Overlap(..), PatSynArgs(..), NewOrData(..),
DTypeFamilyHead(..), DFamilyResultSig(..), InjectivityAnn(..),
DCon(..), DConFields(..), DBangType, DVarBangType,
Bang(..), SourceUnpackedness(..), SourceStrictness(..),
DForeign(..),
DPragma(..), DRuleBndr(..), DTySynEqn(..), DInfo(..), DInstanceDec,
Role(..), AnnTarget(..),
Desugar(..),
dsExp, dsDecs, dsType, dsInfo,
dsPatOverExp, dsPatsOverExp, dsPatX,
dsLetDecs, dsTvb, dsCxt,
dsCon, dsForeign, dsPragma, dsRuleBndr,
PatM, dsPred, dsPat, dsDec, dsDerivClause, dsLetDec,
dsMatches, dsBody, dsGuards, dsDoStmts, dsComp, dsClauses,
dsBangType, dsVarBangType,
#if __GLASGOW_HASKELL__ > 710
dsTypeFamilyHead, dsFamilyResultSig,
#endif
#if __GLASGOW_HASKELL__ >= 801
dsPatSynDir,
#endif
module Language.Haskell.TH.Desugar.Sweeten,
expand, expandType,
reifyWithWarning,
withLocalDeclarations, dsReify, reifyWithLocals_maybe, reifyWithLocals,
DsMonad(..), DsM,
scExp, scLetDec,
applyDExp, applyDType,
dPatToDExp, removeWilds,
getDataD, dataConNameToDataName, dataConNameToCon,
nameOccursIn, allNamesIn, flattenDValD, getRecordSelectors,
mkTypeName, mkDataName, newUniqueName,
mkTupleDExp, mkTupleDPat, maybeDLetE, maybeDCaseE,
substTy,
tupleDegree_maybe, tupleNameDegree_maybe,
unboxedSumDegree_maybe, unboxedSumNameDegree_maybe,
unboxedTupleDegree_maybe, unboxedTupleNameDegree_maybe,
strictToBang,
extractBoundNamesStmt, extractBoundNamesDec, extractBoundNamesPat
) where
import Language.Haskell.TH.Desugar.Core
import Language.Haskell.TH.Desugar.Util
import Language.Haskell.TH.Desugar.Sweeten
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Desugar.Reify
import Language.Haskell.TH.Desugar.Expand
import Language.Haskell.TH.Desugar.Match
import qualified Data.Map as M
import qualified Data.Set as S
#if __GLASGOW_HASKELL__ < 709
import Data.Foldable ( foldMap )
#endif
import Prelude hiding ( exp )
class Desugar th ds | ds -> th where
desugar :: DsMonad q => th -> q ds
sweeten :: ds -> th
instance Desugar Exp DExp where
desugar = dsExp
sweeten = expToTH
instance Desugar Type DType where
desugar = dsType
sweeten = typeToTH
instance Desugar Cxt DCxt where
desugar = dsCxt
sweeten = cxtToTH
instance Desugar TyVarBndr DTyVarBndr where
desugar = dsTvb
sweeten = tvbToTH
instance Desugar [Dec] [DDec] where
desugar = dsDecs
sweeten = decsToTH
instance Desugar [Con] [DCon] where
desugar = concatMapM dsCon
sweeten = map conToTH
flattenDValD :: Quasi q => DLetDec -> q [DLetDec]
flattenDValD dec@(DValD (DVarPa _) _) = return [dec]
flattenDValD (DValD pat exp) = do
x <- newUniqueName "x"
let top_val_d = DValD (DVarPa x) exp
bound_names = S.elems $ extractBoundNamesDPat pat
other_val_ds <- mapM (mk_val_d x) bound_names
return $ top_val_d : other_val_ds
where
mk_val_d x name = do
y <- newUniqueName "y"
let pat' = wildify name y pat
match = DMatch pat' (DVarE y)
cas = DCaseE (DVarE x) [match]
return $ DValD (DVarPa name) cas
wildify name y p =
case p of
DLitPa lit -> DLitPa lit
DVarPa n
| n == name -> DVarPa y
| otherwise -> DWildPa
DConPa con ps -> DConPa con (map (wildify name y) ps)
DTildePa pa -> DTildePa (wildify name y pa)
DBangPa pa -> DBangPa (wildify name y pa)
DSigPa pa ty -> DSigPa (wildify name y pa) ty
DWildPa -> DWildPa
flattenDValD other_dec = return [other_dec]
fvDType :: DType -> S.Set Name
fvDType = go
where
go (DForallT tvbs _cxt ty) = go ty `S.difference` (foldMap dtvbName tvbs)
go (DAppT ty1 ty2) = go ty1 `S.union` go ty2
go (DSigT ty ki) = go ty `S.union` fvDType ki
go (DVarT n) = S.singleton n
go (DConT _) = S.empty
go DArrowT = S.empty
go (DLitT {}) = S.empty
go DWildCardT = S.empty
go DStarT = S.empty
dtvbName :: DTyVarBndr -> S.Set Name
dtvbName (DPlainTV n) = S.singleton n
dtvbName (DKindedTV n _) = S.singleton n
getRecordSelectors :: Quasi q
=> DType
-> [DCon]
-> q [DLetDec]
getRecordSelectors arg_ty cons = merge_let_decs `fmap` concatMapM get_record_sels cons
where
get_record_sels (DCon _ _ con_name con _) = case con of
DRecC fields -> go fields
_ -> return []
where
go fields = do
varName <- qNewName "field"
let tvbs = fvDType arg_ty
forall' = DForallT (map DPlainTV $ S.toList tvbs) []
num_pats = length fields
return $ concat
[ [ DSigD name (forall' $ DArrowT `DAppT` arg_ty `DAppT` res_ty)
, DFunD name [DClause [DConPa con_name (mk_field_pats n num_pats varName)]
(DVarE varName)] ]
| ((name, _strict, res_ty), n) <- zip fields [0..]
, fvDType res_ty `S.isSubsetOf` tvbs
]
mk_field_pats :: Int -> Int -> Name -> [DPat]
mk_field_pats 0 total name = DVarPa name : (replicate (total1) DWildPa)
mk_field_pats n total name = DWildPa : mk_field_pats (n1) (total1) name
merge_let_decs :: [DLetDec] -> [DLetDec]
merge_let_decs decs =
let (name_clause_map, decs') = gather_decs M.empty S.empty decs
in augment_clauses name_clause_map decs'
where
gather_decs :: M.Map Name [DClause] -> S.Set Name -> [DLetDec]
-> (M.Map Name [DClause], [DLetDec])
gather_decs name_clause_map _ [] = (name_clause_map, [])
gather_decs name_clause_map type_sig_names (x:xs)
| DFunD n clauses <- x
= let name_clause_map' = M.insertWith (\new old -> old ++ new)
n clauses name_clause_map
in if n `M.member` name_clause_map
then gather_decs name_clause_map' type_sig_names xs
else let (map', decs') = gather_decs name_clause_map'
type_sig_names xs
in (map', x:decs')
| DSigD n _ <- x
= if n `S.member` type_sig_names
then gather_decs name_clause_map type_sig_names xs
else let (map', decs') = gather_decs name_clause_map
(n `S.insert` type_sig_names) xs
in (map', x:decs')
| otherwise =
let (map', decs') = gather_decs name_clause_map type_sig_names xs
in (map', x:decs')
augment_clauses :: M.Map Name [DClause] -> [DLetDec] -> [DLetDec]
augment_clauses _ [] = []
augment_clauses name_clause_map (x:xs)
| DFunD n _ <- x, Just merged_clauses <- n `M.lookup` name_clause_map
= DFunD n merged_clauses:augment_clauses name_clause_map xs
| otherwise = x:augment_clauses name_clause_map xs