liquidhaskell-0.2.0.0: src/Language/Haskell/Liquid/PrettyPrint.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
-- | Module with all the printing and serialization routines
module Language.Haskell.Liquid.PrettyPrint (
-- * Tidy level
Tidy (..)
-- * Printing RType
, rtypeDoc
, ppr_rtype
-- * Printing an Orderable List
, pprManyOrdered
-- * Printing a List with many large items
, pprintLongList
, ppSpine
) where
import Type (tidyType)
import ErrUtils (ErrMsg)
import HscTypes (SourceError)
import SrcLoc -- (RealSrcSpan, SrcSpan (..))
import GHC (Name, Class)
import VarEnv (emptyTidyEnv)
import Language.Haskell.Liquid.Misc
import Language.Haskell.Liquid.GhcMisc
import Text.PrettyPrint.HughesPJ
import Language.Fixpoint.Types hiding (Predicate)
import Language.Fixpoint.Misc
import Language.Haskell.Liquid.Types hiding (sort)
import Language.Fixpoint.Names (dropModuleNames, propConName, hpropConName)
import TypeRep hiding (maybeParen, pprArrowChain)
import Text.Parsec.Pos (SourcePos, newPos, sourceName, sourceLine, sourceColumn)
import Text.Parsec.Error (ParseError)
import Var (Var)
import Control.Applicative ((<*>), (<$>))
import Data.Maybe (fromMaybe)
import Data.List (sort, sortBy)
import Data.Function (on)
import Data.Monoid (mempty)
import Data.Aeson
import qualified Data.Text as T
import Data.Interned
import qualified Data.HashMap.Strict as M
instance PPrint SrcSpan where
pprint = pprDoc
instance PPrint Doc where
pprint x = x
instance PPrint ErrMsg where
pprint = text . show
instance PPrint SourceError where
pprint = text . show
-- instance PPrint ParseError where
-- pprint = text . show
instance PPrint LParseError where
pprint (LPE _ msgs) = text "Parse Error: " <> vcat (map pprint msgs)
instance PPrint Var where
pprint = pprDoc
instance PPrint Name where
pprint = pprDoc
instance PPrint Type where
pprint = pprDoc . tidyType emptyTidyEnv
instance PPrint Class where
pprint = pprDoc
instance Show Predicate where
show = showpp
-- | Printing an Ordered List
---------------------------------------------------------------
pprManyOrdered :: (PPrint a, Ord a) => Tidy -> String -> [a] -> [Doc]
---------------------------------------------------------------
pprManyOrdered k msg = map ((text msg <+>) . pprintTidy k) . sort
---------------------------------------------------------------
-- | Pretty Printing RefType ----------------------------------
---------------------------------------------------------------
-- Should just make this a @Pretty@ instance but its too damn tedious
-- to figure out all the constraints.
rtypeDoc k = ppr_rtype (ppE k) TopPrec
where
ppE Lossy = ppEnvShort ppEnv
ppE Full = ppEnv
ppr_rtype bb p t@(RAllT _ _)
= ppr_forall bb p t
ppr_rtype bb p t@(RAllP _ _)
= ppr_forall bb p t
ppr_rtype bb p t@(RAllS _ _)
= ppr_forall bb p t
ppr_rtype _ _ (RVar a r)
= ppTy r $ pprint a
ppr_rtype bb p (RFun x t t' _)
= pprArrowChain p $ ppr_dbind bb FunPrec x t : ppr_fun_tail bb t'
ppr_rtype bb p (RApp c [t] rs r)
| isList c
= ppTy r $ brackets (ppr_rtype bb p t) <> ppReftPs bb rs
ppr_rtype bb p (RApp c ts rs r)
| isTuple c
= ppTy r $ parens (intersperse comma (ppr_rtype bb p <$> ts)) <> ppReftPs bb rs
ppr_rtype bb p (RApp c ts rs r)
| isEmpty rsDoc && isEmpty tsDoc
= ppTy r $ ppT c
| otherwise
= ppTy r $ parens $ ppT c <+> rsDoc <+> tsDoc
where
rsDoc = ppReftPs bb rs
tsDoc = hsep (ppr_rtype bb p <$> ts)
ppT | ppShort bb = text . symbolString . dropModuleNames . symbol . render . ppTycon
| otherwise = ppTycon
ppr_rtype bb p (RCls c ts)
= ppr_cls bb p c ts
ppr_rtype bb p t@(REx _ _ _)
= ppExists bb p t
ppr_rtype bb p t@(RAllE _ _ _)
= ppAllExpr bb p t
ppr_rtype _ _ (RExprArg e)
= braces $ pprint e
ppr_rtype bb p (RAppTy t t' r)
= ppTy r $ ppr_rtype bb p t <+> ppr_rtype bb p t'
ppr_rtype _ _ (ROth s)
= text $ "???-" ++ symbolString s
ppr_rtype bb p (RRTy e r o t)
= sep [ppp (pprint o <+> ppe <+> pprint r), ppr_rtype bb p t]
where ppe = (hsep $ punctuate comma (pprint <$> e)) <+> colon <> colon
ppp = \doc -> text "<<" <+> doc <+> text ">>"
ppr_rtype _ _ (RHole r)
= ppTy r $ text "_"
ppSpine (RAllT _ t) = text "RAllT" <+> parens (ppSpine t)
ppSpine (RAllP _ t) = text "RAllP" <+> parens (ppSpine t)
ppSpine (RAllE _ _ t) = text "RAllE" <+> parens (ppSpine t)
ppSpine (REx _ _ t) = text "REx" <+> parens (ppSpine t)
ppSpine (RFun _ i o _) = ppSpine i <+> text "->" <+> ppSpine o
ppSpine (RAppTy t t' _) = text "RAppTy" <+> parens (ppSpine t) <+> parens (ppSpine t')
ppSpine (RHole r) = text "RHole"
ppSpine (RCls c ts) = text "RCls" <+> parens (ppCls c ts)
ppSpine (RApp c ts rs _) = text "RApp" <+> parens (pprint c)
ppSpine (RVar v _) = text "RVar"
ppSpine (RExprArg _) = text "RExprArg"
ppSpine (ROth s) = text "ROth" <+> text (symbolString s)
ppSpine (RRTy _ _ _ _) = text "RRTy"
-- | From GHC: TypeRep
-- pprArrowChain p [a,b,c] generates a -> b -> c
pprArrowChain :: Prec -> [Doc] -> Doc
pprArrowChain _ [] = empty
pprArrowChain p (arg:args) = maybeParen p FunPrec $
sep [arg, sep (map (arrow <+>) args)]
-- | From GHC: TypeRep
maybeParen :: Prec -> Prec -> Doc -> Doc
maybeParen ctxt_prec inner_prec pretty
| ctxt_prec < inner_prec = pretty
| otherwise = parens pretty
-- ppExists :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> RType p c tv r -> Doc
ppExists bb p t
= text "exists" <+> brackets (intersperse comma [ppr_dbind bb TopPrec x t | (x, t) <- zs]) <> dot <> ppr_rtype bb p t'
where (zs, t') = split [] t
split zs (REx x t t') = split ((x,t):zs) t'
split zs t = (reverse zs, t)
-- ppAllExpr :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> RType p c tv r -> Doc
ppAllExpr bb p t
= text "forall" <+> brackets (intersperse comma [ppr_dbind bb TopPrec x t | (x, t) <- zs]) <> dot <> ppr_rtype bb p t'
where (zs, t') = split [] t
split zs (RAllE x t t') = split ((x,t):zs) t'
split zs t = (reverse zs, t)
ppReftPs bb rs
| all isTauto rs = empty
| not (ppPs ppEnv) = empty
| otherwise = angleBrackets $ hsep $ punctuate comma $ pprint <$> rs
-- ppr_dbind :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> Symbol -> RType p c tv r -> Doc
ppr_dbind bb p x t
| isNonSymbol x || (x == dummySymbol)
= ppr_rtype bb p t
| otherwise
= pprint x <> colon <> ppr_rtype bb p t
-- ppr_fun_tail :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> RType p c tv r -> [Doc]
ppr_fun_tail bb (RFun b t t' _)
= (ppr_dbind bb FunPrec b t) : (ppr_fun_tail bb t')
ppr_fun_tail bb t
= [ppr_rtype bb TopPrec t]
-- ppr_forall :: (RefTypable p c tv (), RefTypable p c tv r) => Bool -> Prec -> RType p c tv r -> Doc
ppr_forall bb p t
= maybeParen p FunPrec $ sep [ ppr_foralls (ppPs bb) (ty_vars trep) (ty_preds trep) (ty_labels trep) , ppr_clss cls, ppr_rtype bb TopPrec t' ]
where
trep = toRTypeRep t
(cls, t') = bkClass $ fromRTypeRep $ trep {ty_vars = [], ty_preds = [], ty_labels = []}
ppr_foralls False _ _ _= empty
ppr_foralls _ [] [] [] = empty
ppr_foralls True αs πs ss = text "forall" <+> dαs αs <+> dπs (ppPs bb) πs <+> dss (ppSs bb) ss <> dot
ppr_clss [] = empty
ppr_clss cs = (parens $ hsep $ punctuate comma (uncurry (ppr_cls bb p) <$> cs)) <+> text "=>"
dαs αs = sep $ pprint <$> αs
dπs _ [] = empty
dπs False _ = empty
dπs True πs = angleBrackets $ intersperse comma $ ppr_pvar_def pprint <$> πs
dss _ [] = empty
dss _ ss = angleBrackets $ intersperse comma $ pprint <$> ss
ppr_cls bb p c ts
= pp c <+> hsep (map (ppr_rtype bb p) ts)
where
pp | ppShort bb = text . symbolString . dropModuleNames . symbol . render . pprint
| otherwise = pprint
ppr_pvar_def pprv (PV s t _ xts)
= pprint s <+> dcolon <+> intersperse arrow dargs <+> ppr_pvar_kind pprv t
where
dargs = [pprv t | (t,_,_) <- xts]
ppr_pvar_kind pprv (PVProp t) = pprv t <+> arrow <+> ppr_name propConName
ppr_pvar_kind pprv (PVHProp) = ppr_name hpropConName
ppr_name = text . symbolString
instance PPrint RTyVar where
pprint (RTV α)
| ppTyVar ppEnv = ppr_tyvar α
| otherwise = ppr_tyvar_short α
ppr_tyvar = text . tvId
ppr_tyvar_short = text . showPpr
instance (Reftable s, PPrint s, PPrint p, Reftable p, PPrint t, PPrint (RType a b c p)) => PPrint (Ref t s (RType a b c p)) where
pprint (RPropP ss s) = ppRefArgs (fst <$> ss) <+> pprint s
pprint (RProp ss s) = ppRefArgs (fst <$> ss) <+> pprint (fromMaybe mempty (stripRTypeBase s))
ppRefArgs [] = empty
ppRefArgs ss = text "\\" <> hsep (ppRefSym <$> ss ++ [vv Nothing]) <+> text "->"
ppRefSym "" = text "_"
ppRefSym s = pprint s
instance (PPrint r, Reftable r) => PPrint (UReft r) where
pprint (U r p s)
| isTauto r = pprint p
| isTauto p = pprint r
| otherwise = pprint p <> text " & " <> pprint r
pprintLongList :: PPrint a => [a] -> Doc
pprintLongList = brackets . vcat . map pprint
instance (PPrint t) => PPrint (Annot t) where
pprint (AnnUse t) = text "AnnUse" <+> pprint t
pprint (AnnDef t) = text "AnnDef" <+> pprint t
pprint (AnnRDf t) = text "AnnRDf" <+> pprint t
pprint (AnnLoc l) = text "AnnLoc" <+> pprDoc l
pprAnnInfoBinds (l, xvs)
= vcat $ map (pprAnnInfoBind . (l,)) xvs
pprAnnInfoBind (RealSrcSpan k, xv)
= xd $$ pprDoc l $$ pprDoc c $$ pprint n $$ vd $$ text "\n\n\n"
where
l = srcSpanStartLine k
c = srcSpanStartCol k
(xd, vd) = pprXOT xv
n = length $ lines $ render vd
pprAnnInfoBind (_, _)
= empty
pprXOT (x, v) = (xd, pprint v)
where
xd = maybe (text "unknown") pprint x
instance PPrint a => PPrint (AnnInfo a) where
pprint (AI m) = vcat $ map pprAnnInfoBinds $ M.toList m
instance (Ord k, PPrint k, PPrint v) => PPrint (M.HashMap k v) where
pprint = ppTable
ppTable m = vcat $ pprxt <$> xts
where
pprxt (x,t) = pprint x $$ nest n (colon <+> pprint t)
n = 1 + maximum [ i | (x, _) <- xts, let i = keySize x, i <= thresh ]
keySize = length . render . pprint
xts = sortBy (compare `on` fst) $ M.toList m
thresh = 6