HaRe-0.6: tools/base/pretty/PrettyPrint2.hs
module PrettyPrint2 where
import qualified PrettyDoc as P(Doc)
import PrettyDoc hiding (Doc)
import PrettyEnv
import TokenTags
import MUtils
type Doc = DocM P.Doc
class Show a => Printable a where
ppi :: a -> Doc -- Prettyprint Intelligently
ppiList :: [a] -> Doc -- Specialized for Char/String
ppis :: a -> [Doc] -- To allow for cases in which we can generate
-- a list of Docs from a given type
wrap :: a -> Doc -- for bracketing
ppi = plain
ppiList = brackets . ppiFSeq
ppis a = [ ppi a ]
wrap = parens . ppi
-- Essential instances:
instance Show Doc where show (DocM d) = show (d defaultMode) -- useless?
instance Printable Doc where ppi = id
instance Printable Char where
ppi c = char c
ppiList = text -- this defines how strings are printed, since String=[Char]
wrap = ppi
instance Printable a => Printable [a] where
ppi = ppiList
ppis = map ppi
wrap = ppi
-- A class to make it easier to print Haskell infix operators correctly:
class Printable a => PrintableOp a where
isOp :: a -> Bool
ppiOp :: a -> Doc
{- How to print operators "mod" and "+":
ppi should produce "mod" and "+".
wrap should produce "mod" and "(+)".
ppiOp should produce "`mod`" and "+". -}
-- A class to make it easier to print type applications like (,) a b and
-- [] Int in the normal way, (a,b) and [Int].
class Printable fun => PrintableApp fun arg where
wrapApp,ppiApp :: fun -> [arg] -> Doc
cdoc = DocM . const
-- Hughes/SimonPJ style pretty printing operators:
char = cdoc . Char
text = cdoc . Text
empty = cdoc Empty
group l ds = DocM $ \e->Group l [de|DocM d<-map ppi ds,let de=d e,nonEmpty de]
nest n = fmap (nest' n) . ppi
where
nest' n (Nest n' d) = nest' (n+n') d
nest' n d = Nest n d
-- Eta expansions because of the annying monomorphism restriction!
attr a = fmap (Attr a) . ppi
kw d = attr Reserved d
var d = attr Var d
con d = attr Con d
varop d = attr VarOp d
conop d = attr ConOp d
tcon d = attr TCon d
lit d = attr Lit d
cmnt d = attr Comment d
modn d = attr ModName d
a<>b = hcat [ppi a,ppi b]
a<+>b = hsep [ppi a,ppi b]
a$$b = vcat [ppi a,ppi b]
hcat ds = group (Horiz Cat) ds
hsep ds = group (Horiz Sep) ds
vcat ds = group Vert ds
cat ds = group (HorizOrVert Cat) ds
sep ds = group (HorizOrVert Sep) ds
fcat ds = group (Fill Cat) ds
fsep ds = group (Fill Sep) ds
plain x = text (show x)
punctuate p [] = []
punctuate p (d:ds) = go d ds
where go d [] = [ppi d]
go d (e:es) = (d <> p) : go e es
-- Additional pretty printing functions:
{-
ppiSeq :: Printable a => [a] -> Doc
ppiSet :: Printable a => Doc -> [a] -> Doc
ppiSep0 :: Printable a => ([Doc] -> Doc) -> Doc -> [a] -> Doc
ppiFSeq :: Printable a => [a] -> Doc
ppiFSet :: Printable a => Doc -> [a] -> Doc
ppiTuple :: Printable a => [a] -> Doc
ppiFTuple :: Printable a => [a] -> Doc
wrapTuple :: Printable a => [a] -> Doc
wrapSeq :: Printable a => [a] -> Doc
wrapSet :: Printable a => Doc -> [a] -> Doc
wrapFTuple :: Printable a => [a] -> Doc
wrapFSeq :: Printable a => [a] -> Doc
wrapFSet :: Printable a => Doc -> [a] -> Doc
wrapSep0 :: Printable a => ([Doc] -> Doc) -> Doc -> [a] -> Doc
-}
ppiSeq ds = ppiSet ',' ds
ppiSet s ds = ppiSep0 sep s ds
ppiSep0 sepOp separator [] = empty
ppiSep0 sepOp separator [d] = ppi d
ppiSep0 sepOp separator ds = sepOp $ punctuate separator $ map ppi ds
ppiFSeq ds = ppiFSet ',' ds
ppiFSet s ds = ppiSep0 fsep s ds
ppiTuple ds = parens (ppiSeq ds)
ppiFTuple ds = parens (ppiFSeq ds)
wrapTuple ds = parens (wrapSeq ds)
wrapSeq ds = wrapSet ',' ds
wrapSet s ds = wrapSep0 sep s ds
wrapFTuple ds = parens (wrapFSeq ds)
wrapFSeq ds = wrapFSet ',' ds
wrapFSet s ds = wrapSep0 fsep s ds
wrapSep0 sepOp separator [] = empty
wrapSep0 sepOp separator [d] = wrap d
wrapSep0 sepOp separator ds = sepOp $ punctuate separator $ map wrap ds
--maybepp :: (a -> Doc) -> Maybe a -> Doc
maybepp pf (Just a) = pf a
maybepp _ Nothing = empty
optpp b x = if b then ppi x else empty
ppiBinOp lhs op rhs = sep [lhs<+>op,letNest rhs]
parenBinOp x op y = parens (ppiBinOp x op y) -- should consult infixParens!!
-- These are rather pointless, but kept around for backwards compatibility:
lparen = kw '('
rparen = kw ')'
lbrack = kw '['
rbrack = kw ']'
lbrace = kw '{'
rbrace = kw '}'
quote = kw '\''
dquote = kw '"'
bquote = kw '`'
equals = kw '='
comma = kw ','
float = plain :: Float->Doc
double = plain :: Double->Doc
space = ppi ' '
parens d = lparen<>d<>rparen
brackets d = lbrack<>d<>rbrack
braces d = lbrace<>d<>rbrace
doubleQuotes d = dquote<>d<>dquote
backQuotes d = bquote<>d<>bquote
{-
quotes, charQuotes, backQuotes, doubleQuotes,
quote, backQuote, doubleQuote, semi, comma, colon, space, equals,
hang, punctuate,
-}
-- Environment manipulating functions:
withPPEnv :: PPHsMode -> Doc -> Doc
withPPEnv mode d = return $ (unDocM d) mode
updPPEnv f d = do e <- getPPEnv; withPPEnv (f e) d
doNotation :: Doc -> Doc
doNotation = updPPEnv (\e->e { insideDo = True })
doElseNest d = do e <- getPPEnv
if insideDo e then nest (doElseIndent e) (ppi d) else ppi d
ppIfDebug debug = ifM (debugInfo # getPPEnv) (ppi debug) empty
ppIfTypeInfo tinfo = ifM (typeInfo # getPPEnv) (ppi tinfo) empty
ppIfUnicode unicode ascii =
ifM (useUnicode # getPPEnv)
(ppi unicode)
(ppi ascii)
withUnicode d = updPPEnv (\e->e{useUnicode=True}) d
withDebug d = updPPEnv (\e->e{debugInfo=True}) d
classNest, doNest, caseNest, letNest, funNest, dataNest
:: Printable a => a -> Doc
classNest = nest' classIndent
doNest = nest' doIndent
caseNest = nest' caseIndent
letNest = nest' letIndent
funNest = nest' funIndent
dataNest = nest' dataIndent
nest' p d = do { e <- getPPEnv ; nest (p e) (ppi d) }
blankline :: Doc -> Doc
blankline d = do e <- getPPEnv
if spacing e && layoutType e /= PPNoLayout
then d
$$ space
else d
layout ds = do e <- getPPEnv
case layoutType e of
--PPSemiColon ->
--PPUtrecht ->
PPNoLayout -> braces . hsep . punctuate ';' $ ds
_ -> vcat ds
-- Obsolete:
appParensOn = id
appParensOff = id