{-# LANGUAGE TypeSynonymInstances, TemplateHaskell, QuasiQuotes, MultiParamTypeClasses
, FlexibleInstances, DeriveDataTypeable, NamedFieldPuns, ScopedTypeVariables #-}
{-# OPTIONS_HADDOCK prune #-}
module Language.Pads.GenPretty where
import Language.Pads.Padsc
import Language.Pads.Errors
import Language.Pads.MetaData
import Language.Pads.TH
import Language.Haskell.TH as TH hiding (ppr)
import Text.PrettyPrint.Mainland
import Text.PrettyPrint.Mainland.Class
import qualified Data.List as L
import qualified Data.Set as S
import Control.Monad
import System.Posix.Types
import Data.Word
import Data.Int
import Data.Time
import Debug.Trace as D
pprE argE = AppE (VarE 'ppr) argE
pprListEs argEs = ListE (map pprE argEs)
pprCon1E argE = AppE (VarE 'pprCon1) argE
pprCon2E argE = AppE (VarE 'pprCon2) argE
pprCon1 arg = ppr (toList1 arg)
pprCon2 arg = ppr (toList2 arg)
getTyNames :: TH.Type -> S.Set TH.Name
getTyNames ty = case ty of
ForallT tvb cxt ty' -> getTyNames ty'
VarT name -> S.empty
ConT name -> S.singleton name
TupleT i -> S.empty
ArrowT -> S.empty
ListT -> S.empty
AppT t1 t2 -> getTyNames t1 `S.union` getTyNames t2
SigT ty kind -> getTyNames ty
getTyNamesFromCon :: TH.Con -> S.Set TH.Name
getTyNamesFromCon con = case con of
(NormalC name stys) -> S.unions (map (\(_,ty) -> getTyNames ty) stys)
(RecC name vstys) -> S.unions (map (\(_,_,ty) -> getTyNames ty) vstys)
(InfixC st1 name st2) -> getTyNames (snd st1) `S.union` getTyNames (snd st2)
(ForallC tvb cxt con) -> getTyNamesFromCon con
getNamedTys :: TH.Name -> Q [TH.Name]
getNamedTys ty_name = S.toList <$> getNamedTys' S.empty (S.singleton ty_name)
getNamedTys' :: S.Set TH.Name -> S.Set TH.Name -> Q (S.Set TH.Name)
getNamedTys' answers worklist =
if S.null worklist then return answers
else do
{ let (ty_name, worklist') = S.deleteFindMin worklist
; let answers' = S.insert ty_name answers
; info <- reify ty_name
; case info of
TyConI (NewtypeD [] ty_name' [] _ con derives) -> do
{ let all_nested = getTyNamesFromCon con
; let new_nested = all_nested `S.difference` answers'
; let new_worklist = worklist' `S.union` new_nested
; getNamedTys' answers' new_worklist
}
TyConI (DataD [] ty_name' [] _ cons derives) -> do
{ let all_nested = S.unions (map getTyNamesFromCon cons)
; let new_nested = all_nested `S.difference` answers'
; let new_worklist = worklist' `S.union` new_nested
; getNamedTys' answers' new_worklist
}
TyConI (TySynD _ _ _ ) -> do {reportError ("getTyNames: unimplemented TySynD case " ++ (nameBase ty_name)); return answers'}
TyConI (ForeignD _) -> do {reportError ("getTyNames: unimplemented ForeignD case " ++ (nameBase ty_name)); return answers'}
PrimTyConI _ _ _ -> return answers
otherwise -> do {reportError ("getTyNames: pattern didn't match for " ++ (nameBase ty_name)); return answers'}
}
baseTypeNames = S.fromList [ ''Int, ''Char, ''Digit, ''Text, ''String, ''StringFW, ''StringME
, ''StringSE, ''COff, ''EpochTime, ''FileMode, ''Int, ''Word, ''Int64
, ''Language.Pads.Errors.ErrInfo, ''Bool, ''Binary, ''Base_md, ''UTCTime, ''TimeZone
]
mkPrettyInstance :: TH.Name -> Q [TH.Dec]
mkPrettyInstance ty_name = mkPrettyInstance' (S.singleton ty_name) baseTypeNames []
mkMe :: TH.Name -> Q [TH.Dec]
mkMe n = do
D.traceM "HELLOOOOOOOOOO"
return []
mkPrettyInstance' :: S.Set TH.Name -> S.Set TH.Name -> [TH.Dec] -> Q [TH.Dec]
mkPrettyInstance' worklist done decls =
if S.null worklist then return decls
else do
let (ty_name, worklist') = S.deleteFindMin worklist
if ty_name `S.member` done then mkPrettyInstance' worklist' done decls
else do
let tyBaseName = nameBase ty_name
let baseStr = strToLower tyBaseName
let specificPprName = mkName (baseStr ++ "_ppr")
let funName = mkName (strToLower (tyBaseName ++ "_ppr"))
let inst = AppT (ConT ''Pretty) (ConT ty_name)
let genericPprName = mkName "ppr"
let ppr_method = ValD (VarP genericPprName) (NormalB (VarE specificPprName)) []
let instD = InstanceD Nothing [] inst [ppr_method]
let newDone = S.insert ty_name done
info <- reify ty_name
(nestedTyNames, decls') <- case info of
TyConI (NewtypeD [] ty_name' [] _ (NormalC ty_name'' [(Bang NoSourceUnpackedness NoSourceStrictness, AppT ListT ty)]) derives) -> do
{ let nestedTyNames = getTyNames ty
; (itemsE,itemsP) <- doGenPE "list"
; let mapE = AppE (AppE (VarE 'map) (VarE 'ppr)) itemsE
; let bodyE = AppE (AppE (VarE 'namedlist_ppr) (nameToStrLit ty_name)) mapE
; let argP = ConP (mkName tyBaseName) [itemsP]
; let clause = Clause [argP] (NormalB bodyE) []
; return (nestedTyNames, [instD, FunD specificPprName [clause]])
}
TyConI (NewtypeD [] ty_name' [] _ (NormalC ty_name'' [(Bang NoSourceUnpackedness NoSourceStrictness, AppT (AppT (ConT ty_con_name) ty_arg1) ty_arg2) ]) derives) -> do
{ let nestedTyNames = getTyNames ty_arg2
; (argP, body) <- mkPatBody tyBaseName pprCon2E
; let clause = Clause [argP] body []
; return (nestedTyNames, [instD, FunD specificPprName [clause]])
}
TyConI (NewtypeD [] ty_name' [] _ (NormalC ty_name'' [(Bang NoSourceUnpackedness NoSourceStrictness, AppT (ConT ty_con_name) ty_arg) ]) derives) -> do
{ let nestedTyNames = getTyNames ty_arg
; (argP, body) <- mkPatBody tyBaseName pprCon1E
; let clause = Clause [argP] body []
; return (nestedTyNames, [instD, FunD specificPprName [clause]])
}
TyConI (NewtypeD [] ty_name' [] _ (NormalC ty_name'' [(Bang NoSourceUnpackedness NoSourceStrictness, ConT core_name)]) derives) -> do
{ (argP, body) <- mkPatBody tyBaseName pprE
; let clause = Clause [argP] body []
; return (S.singleton core_name, [instD, FunD specificPprName [clause]])
}
TyConI (NewtypeD [] ty_name' [] _ (NormalC ty_name'' [(Bang NoSourceUnpackedness NoSourceStrictness, ty)]) derives) | isTuple ty -> do
{ let nestedTyNames = getTyNames ty
; let (len, tys) = tupleTyToListofTys ty
; (exps, pats) <- doGenPEs len "tuple"
; let bodyE = AppE (AppE (VarE 'namedtuple_ppr) (LitE (StringL tyBaseName))) (pprListEs exps)
; let argP = ConP (mkName tyBaseName) [TupP pats]
; let clause = Clause [argP] (NormalB bodyE) []
; return (nestedTyNames, [instD, FunD specificPprName [clause]])
}
TyConI (DataD [] ty_name' [] _ cons derives) | isDataType cons -> do
{ let nestedTyNames = S.unions (map getTyNamesFromCon cons)
; (exp, pat) <- doGenPE "case_arg"
; matches <- mapM mkClause cons
; let caseE = CaseE exp matches
; let clause = Clause [pat] (NormalB caseE) []
; return (nestedTyNames, [instD, FunD specificPprName [clause]] )
}
TyConI (DataD [] ty_name' [] _ cons derives) | isRecordType cons -> do
{ let nestedTyNames = S.unions (map getTyNamesFromCon cons)
; clause <- mkRecord (L.head cons)
; return (nestedTyNames, [instD, FunD specificPprName [clause]])
}
TyConI (DataD _ ty_name' _ _ cons derives) -> do
{
; return (S.empty, [])}
TyConI (TySynD ty_name' [] ty) -> do
{ let nestedTyNames = getTyNames ty
; return (nestedTyNames, [])}
TyConI (TySynD ty_name' tyVarBndrs ty) -> do
{ let nestedTyNames = getTyNames ty
; return (nestedTyNames, [])}
TyConI dec -> do {reportError ("otherwise; tyconI case "++(nameBase ty_name)) ; return (S.empty, [])}
otherwise -> do {reportError ("pattern didn't match for "++(nameBase ty_name)) ; return (S.empty, [])}
let newWorklist = worklist `S.union` nestedTyNames
let newDecls = decls'++decls
mkPrettyInstance' newWorklist newDone newDecls
isTuple (TupleT n) = True
isTuple (AppT ty _) = isTuple ty
isDataType [] = False
isDataType (NormalC _ _ : rest) = True
isDataType _ = False
isRecordType [] = False
isRecordType (RecC _ _ : rest) = True
isRecordType _ = False
mkPatBody core_name_str pprE = do
(exp,pat) <- doGenPE "arg"
bodyE <- [| namedty_ppr $(litE $ stringL core_name_str) $(return $ pprE exp) |]
argP <- conP (mkName core_name_str) [return pat]
return (argP, NormalB bodyE)
mkPatBodyNoArg core_name_str = do
bodyE <- [| text $(litE $ stringL core_name_str) |]
argP <- conP (mkName core_name_str) []
return (argP, NormalB bodyE)
mkClause con = case con of
NormalC name [] -> do
{ (argP, body) <- mkPatBodyNoArg (nameBase name)
; return (Match argP body [])
}
NormalC name ty_args -> do
{ (argP, body) <- mkPatBody (nameBase name) pprE
; return (Match argP body [])
}
otherwise -> error "mkClause not implemented for this kind of constructor."
mkRecord (RecC rec_name fields) = do
fieldInfo <- mapM mkField fields
let (recPs, recEs) = unzip fieldInfo
let recP = RecP rec_name recPs
let bodyE = AppE (AppE (VarE 'record_ppr) (nameToStrLit rec_name)) (ListE recEs)
return (Clause [recP] (NormalB bodyE) [])
mkField (field_name, _, ty) = do
(expE, pat) <- doGenPE (nameBase field_name)
fieldE <- [| field_ppr $(return $ nameToStrLit field_name) $(return $ pprE expE) |]
return ((field_name, pat), fieldE)
nameToStrLit name = LitE (StringL (nameBase name))