File: Pretty.hs

package info (click to toggle)
hugs98 98.200311-4
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 12,964 kB
  • ctags: 8,084
  • sloc: ansic: 67,521; haskell: 61,497; xml: 4,566; sh: 3,264; cpp: 1,936; yacc: 1,094; makefile: 915; cs: 883; sed: 10
file content (747 lines) | stat: -rw-r--r-- 23,697 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
{-# OPTIONS -w #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Language.Haskell.Pretty
-- Copyright   :  (c) The GHC Team, Noel Winstanley 1997-2000
-- License     :  BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer  :  libraries@haskell.org
-- Stability   :  experimental
-- Portability :  portable
--
-- Pretty printer for Haskell.
--
-----------------------------------------------------------------------------

module Language.Haskell.Pretty (
		-- * Pretty printing
		Pretty,
		prettyPrintStyleMode, prettyPrintWithMode, prettyPrint,
		-- * Pretty-printing styles (from @Text.PrettyPrint.HughesPJ@)
		P.Style(..), P.style, P.Mode(..),
		-- * Haskell formatting modes
		PPHsMode(..), Indent, PPLayout(..), defaultMode) where

import Language.Haskell.Syntax

import qualified Text.PrettyPrint as P

infixl 5 $$$

-----------------------------------------------------------------------------

-- | Varieties of layout we can use.
data PPLayout = PPOffsideRule	-- ^ classical layout
	      | PPSemiColon	-- ^ classical layout made explicit
	      | PPInLine	-- ^ inline decls, with newlines between them
	      | PPNoLayout	-- ^ everything on a single line
	      deriving Eq

type Indent = Int

-- | Pretty-printing parameters.
data PPHsMode = PPHsMode {
				-- | indentation of a class or instance
		classIndent :: Indent,
				-- | indentation of a @do@-expression
		doIndent :: Indent,
				-- | indentation of the body of a
				-- @case@ expression
		caseIndent :: Indent,
				-- | indentation of the declarations in a
				-- @let@ expression
		letIndent :: Indent,
				-- | indentation of the declarations in a
				-- @where@ clause
		whereIndent :: Indent,
				-- | indentation added for continuation
				-- lines that would otherwise be offside
		onsideIndent :: Indent,
				-- | blank lines between statements?
		spacing :: Bool,
				-- | Pretty-printing style to use
		layout :: PPLayout,
				-- | add GHC-style @LINE@ pragmas to output?
		linePragmas :: Bool,
				-- | not implemented yet
		comments :: Bool
		}

-- | The default mode: pretty-print using the offside rule and sensible
-- defaults.
defaultMode :: PPHsMode
defaultMode = PPHsMode{
		      classIndent = 8,
		      doIndent = 3,
		      caseIndent = 4,
		      letIndent = 4,
		      whereIndent = 6,
		      onsideIndent = 2,
		      spacing = True,
		      layout = PPOffsideRule,
		      linePragmas = False,
		      comments = True
		      }

-- | Pretty printing monad
newtype DocM s a = DocM (s -> a)

instance Functor (DocM s) where
	 fmap f xs = do x <- xs; return (f x)

instance Monad (DocM s) where
	(>>=) = thenDocM
	(>>) = then_DocM
	return = retDocM

{-# INLINE thenDocM #-}
{-# INLINE then_DocM #-}
{-# INLINE retDocM #-}
{-# INLINE unDocM #-}
{-# INLINE getPPEnv #-}

thenDocM :: DocM s a -> (a -> DocM s b) -> DocM s b
thenDocM m k = DocM $ (\s -> case unDocM m $ s of a -> unDocM (k a) $ s)

then_DocM :: DocM s a -> DocM s b -> DocM s b
then_DocM m k = DocM $ (\s -> case unDocM m $ s of _ -> unDocM k $ s)

retDocM :: a -> DocM s a
retDocM a = DocM (\_s -> a)

unDocM :: DocM s a -> (s -> a)
unDocM (DocM f) = f

-- all this extra stuff, just for this one function.
getPPEnv :: DocM s s
getPPEnv = DocM id

-- So that pp code still looks the same
-- this means we lose some generality though

-- | The document type produced by these pretty printers uses a 'PPHsMode'
-- environment.
type Doc = DocM PPHsMode P.Doc

-- | Things that can be pretty-printed, including all the syntactic objects
-- in "Language.Haskell.Syntax".
class Pretty a where
	-- | Pretty-print something in isolation.
	pretty :: a -> Doc
	-- | Pretty-print something in a precedence context.
	prettyPrec :: Int -> a -> Doc
	pretty = prettyPrec 0
	prettyPrec _ = pretty

-- The pretty printing combinators

empty :: Doc
empty = return P.empty

nest :: Int -> Doc -> Doc
nest i m = m >>= return . P.nest i


-- Literals

text, ptext :: String -> Doc
text = return . P.text
ptext = return . P.text

char :: Char -> Doc
char = return . P.char

int :: Int -> Doc
int = return . P.int

integer :: Integer -> Doc
integer = return . P.integer

float :: Float -> Doc
float = return . P.float

double :: Double -> Doc
double = return . P.double

rational :: Rational -> Doc
rational = return . P.rational

-- Simple Combining Forms

parens, brackets, braces,quotes,doubleQuotes :: Doc -> Doc
parens d = d >>= return . P.parens
brackets d = d >>= return . P.brackets
braces d = d >>= return . P.braces
quotes d = d >>= return . P.quotes
doubleQuotes d = d >>= return . P.doubleQuotes

parensIf :: Bool -> Doc -> Doc
parensIf True = parens
parensIf False = id

-- Constants

semi,comma,colon,space,equals :: Doc
semi = return P.semi
comma = return P.comma
colon = return P.colon
space = return P.space
equals = return P.equals

lparen,rparen,lbrack,rbrack,lbrace,rbrace :: Doc
lparen = return  P.lparen
rparen = return  P.rparen
lbrack = return  P.lbrack
rbrack = return  P.rbrack
lbrace = return  P.lbrace
rbrace = return  P.rbrace

-- Combinators

(<>),(<+>),($$),($+$) :: Doc -> Doc -> Doc
aM <> bM = do{a<-aM;b<-bM;return (a P.<> b)}
aM <+> bM = do{a<-aM;b<-bM;return (a P.<+> b)}
aM $$ bM = do{a<-aM;b<-bM;return (a P.$$ b)}
aM $+$ bM = do{a<-aM;b<-bM;return (a P.$+$ b)}

hcat,hsep,vcat,sep,cat,fsep,fcat :: [Doc] -> Doc
hcat dl = sequence dl >>= return . P.hcat
hsep dl = sequence dl >>= return . P.hsep
vcat dl = sequence dl >>= return . P.vcat
sep dl = sequence dl >>= return . P.sep
cat dl = sequence dl >>= return . P.cat
fsep dl = sequence dl >>= return . P.fsep
fcat dl = sequence dl >>= return . P.fcat

-- Some More

hang :: Doc -> Int -> Doc -> Doc
hang dM i rM = do{d<-dM;r<-rM;return $ P.hang d i r}

-- Yuk, had to cut-n-paste this one from Pretty.hs
punctuate :: Doc -> [Doc] -> [Doc]
punctuate _ []     = []
punctuate p (d1:ds) = go d1 ds
                   where
                     go d [] = [d]
                     go d (e:es) = (d <> p) : go e es

-- | render the document with a given style and mode.
renderStyleMode :: P.Style -> PPHsMode -> Doc -> String
renderStyleMode ppStyle ppMode d = P.renderStyle ppStyle . unDocM d $ ppMode

-- | render the document with a given mode.
renderWithMode :: PPHsMode -> Doc -> String
renderWithMode = renderStyleMode P.style

-- | render the document with 'defaultMode'.
render :: Doc -> String
render = renderWithMode defaultMode

-- | pretty-print with a given style and mode.
prettyPrintStyleMode :: Pretty a => P.Style -> PPHsMode -> a -> String
prettyPrintStyleMode ppStyle ppMode = renderStyleMode ppStyle ppMode . pretty

-- | pretty-print with the default style and a given mode.
prettyPrintWithMode :: Pretty a => PPHsMode -> a -> String
prettyPrintWithMode = prettyPrintStyleMode P.style

-- | pretty-print with the default style and 'defaultMode'.
prettyPrint :: Pretty a => a -> String
prettyPrint = prettyPrintWithMode defaultMode

fullRenderWithMode :: PPHsMode -> P.Mode -> Int -> Float ->
		      (P.TextDetails -> a -> a) -> a -> Doc -> a
fullRenderWithMode ppMode m i f fn e mD =
		   P.fullRender m i f fn e $ (unDocM mD) ppMode


fullRender :: P.Mode -> Int -> Float -> (P.TextDetails -> a -> a)
	      -> a -> Doc -> a
fullRender = fullRenderWithMode defaultMode

-------------------------  Pretty-Print a Module --------------------
instance Pretty HsModule where
	pretty (HsModule pos m mbExports imp decls) =
		markLine pos $
		topLevel (ppHsModuleHeader m mbExports)
			 (map pretty imp ++ map pretty decls)

--------------------------  Module Header ------------------------------
ppHsModuleHeader :: Module -> Maybe [HsExportSpec] ->  Doc
ppHsModuleHeader m mbExportList = mySep [
	text "module",
	pretty m,
	maybePP (parenList . map pretty) mbExportList,
	text "where"]

instance Pretty Module where
	pretty (Module modName) = text modName

instance Pretty HsExportSpec where
	pretty (HsEVar name)		    = pretty name
	pretty (HsEAbs name)		    = pretty name
	pretty (HsEThingAll name)	    = pretty name <> text "(..)"
	pretty (HsEThingWith name nameList) =
		pretty name <> (parenList . map pretty $ nameList)
	pretty (HsEModuleContents m)       = text "module" <+> pretty m

instance Pretty HsImportDecl where
	pretty (HsImportDecl pos m qual mbName mbSpecs) =
		markLine pos $
		mySep [text "import",
		       if qual then text "qualified" else empty,
		       pretty m,
		       maybePP (\m' -> text "as" <+> pretty m') mbName,
		       maybePP exports mbSpecs]
	    where
		exports (b,specList) =
			if b then text "hiding" <+> specs else specs
		    where specs = parenList . map pretty $ specList

instance Pretty HsImportSpec where
	pretty (HsIVar name)                = pretty name
	pretty (HsIAbs name)                = pretty name
	pretty (HsIThingAll name)           = pretty name <> text "(..)"
	pretty (HsIThingWith name nameList) =
		pretty name <> (parenList . map pretty $ nameList)

-------------------------  Declarations ------------------------------
instance Pretty HsDecl where
	pretty (HsTypeDecl loc name nameList htype) =
		blankline $
		markLine loc $
		mySep ( [text "type", pretty name]
			++ map pretty nameList
			++ [equals, pretty htype])

	pretty (HsDataDecl loc context name nameList constrList derives) =
		blankline $
		markLine loc $
		mySep ( [text "data", ppHsContext context, pretty name]
			++ map pretty nameList)
			<+> (myVcat (zipWith (<+>) (equals : repeat (char '|'))
						   (map pretty constrList))
			$$$ ppHsDeriving derives)

	pretty (HsNewTypeDecl pos context name nameList constr derives) =
		blankline $
		markLine pos $
		mySep ( [text "newtype", ppHsContext context, pretty name]
			++ map pretty nameList)
			<+> equals <+> (pretty constr $$$ ppHsDeriving derives)

	--m{spacing=False}
	-- special case for empty class declaration
	pretty (HsClassDecl pos context name nameList []) =
		blankline $
		markLine pos $
		mySep ( [text "class", ppHsContext context, pretty name]
			++ map pretty nameList)
	pretty (HsClassDecl pos context name nameList declList) =
		blankline $
		markLine pos $
		mySep ( [text "class", ppHsContext context, pretty name]
			++ map pretty nameList ++ [text "where"])
		$$$ ppBody classIndent (map pretty declList)

	-- m{spacing=False}
	-- special case for empty instance declaration
	pretty (HsInstDecl pos context name args []) =
		blankline $
		markLine pos $
		mySep ( [text "instance", ppHsContext context, pretty name]
			++ map ppHsTypeArg args)
	pretty (HsInstDecl pos context name args declList) =
		blankline $
		markLine pos $
		mySep ( [text "instance", ppHsContext context, pretty name]
			++ map ppHsTypeArg args ++ [text "where"])
		$$$ ppBody classIndent (map pretty declList)

	pretty (HsDefaultDecl pos htypes) =
		blankline $
		markLine pos $
		text "default" <+> parenList (map pretty htypes)

	pretty (HsTypeSig pos nameList qualType) =
		blankline $
		markLine pos $
		mySep ((punctuate comma . map pretty $ nameList)
		      ++ [text "::", pretty qualType])

	pretty (HsFunBind matches) =
		foldr ($$$) empty (map pretty matches)

	pretty (HsPatBind pos pat rhs whereDecls) =
		markLine pos $
		myFsep [pretty pat, pretty rhs] $$$ ppWhere whereDecls

	pretty (HsInfixDecl pos assoc prec opList) =
		blankline $
		markLine pos $
		mySep ([pretty assoc, int prec]
		       ++ (punctuate comma . map pretty $ opList))

instance Pretty HsAssoc where
	pretty HsAssocNone  = text "infix"
	pretty HsAssocLeft  = text "infixl"
	pretty HsAssocRight = text "infixr"

instance Pretty HsMatch where
	pretty (HsMatch pos f ps rhs whereDecls) =
		markLine pos $
		myFsep (lhs ++ [pretty rhs])
		$$$ ppWhere whereDecls
	    where
		lhs = case ps of
			l:r:ps' | isSymbolName f ->
				let hd = [pretty l, ppHsName f, pretty r] in
				if null ps' then hd
				else parens (myFsep hd) : map (prettyPrec 2) ps'
			_ -> pretty f : map (prettyPrec 2) ps

ppWhere :: [HsDecl] -> Doc
ppWhere [] = empty
ppWhere l = nest 2 (text "where" $$$ ppBody whereIndent (map pretty l))

------------------------- Data & Newtype Bodies -------------------------
instance Pretty HsConDecl where
	pretty (HsRecDecl _pos name fieldList) =
		pretty name <> (braceList . map ppField $ fieldList)

	pretty (HsConDecl _pos name@(HsSymbol _) [l, r]) =
		myFsep [pretty l, ppHsName name, pretty r]
	pretty (HsConDecl _pos name typeList) =
		mySep $ ppHsName name : map pretty typeList

ppField :: ([HsName],HsBangType) -> Doc
ppField (names, ty) =
	myFsepSimple $ (punctuate comma . map pretty $ names) ++
		       [text "::", pretty ty]

instance Pretty HsBangType where
	pretty (HsBangedTy ty) = char '!' <> ppHsTypeArg ty
	pretty (HsUnBangedTy ty) = ppHsTypeArg ty

ppHsDeriving :: [HsQName] -> Doc
ppHsDeriving []  = empty
ppHsDeriving [d] = text "deriving" <+> ppHsQName d
ppHsDeriving ds  = text "deriving" <+> parenList (map ppHsQName ds)

------------------------- Types -------------------------
instance Pretty HsQualType where
	pretty (HsQualType context htype) =
		myFsep [ppHsContext context, pretty htype]

ppHsTypeArg :: HsType -> Doc
ppHsTypeArg = prettyPrec 2

-- precedences:
-- 0: top level
-- 1: left argument of ->
-- 2: argument of constructor

instance Pretty HsType where
	prettyPrec p (HsTyFun a b) = parensIf (p > 0) $
		myFsep [prettyPrec 1 a, text "->", pretty b]
	prettyPrec _ (HsTyTuple l) = parenList . map pretty $ l
	prettyPrec p (HsTyApp a b)
		| a == list_tycon = brackets $ pretty b		-- special case
		| otherwise = parensIf (p > 1) $
			myFsep [pretty a, prettyPrec 2 b]
	prettyPrec _ (HsTyVar name) = pretty name
	prettyPrec _ (HsTyCon name) = pretty name

------------------------- Expressions -------------------------
instance Pretty HsRhs where
	pretty (HsUnGuardedRhs e) = equals <+> pretty e
	pretty (HsGuardedRhss guardList) = myVcat . map pretty $ guardList

instance Pretty HsGuardedRhs where
	pretty (HsGuardedRhs _pos guard body) =
		myFsep [char '|', pretty guard, equals, pretty body]

instance Pretty HsLiteral where
	pretty (HsInt i)        = integer i
	pretty (HsChar c)       = text (show c)
	pretty (HsString s)     = text (show s)
	pretty (HsFrac r)       = double (fromRational r)
	-- GHC unboxed literals:
	pretty (HsCharPrim c)   = text (show c)           <> char '#'
	pretty (HsStringPrim s) = text (show s)           <> char '#'
	pretty (HsIntPrim i)    = integer i               <> char '#'
	pretty (HsFloatPrim r)  = float  (fromRational r) <> char '#'
	pretty (HsDoublePrim r) = double (fromRational r) <> text "##"

instance Pretty HsExp where
	pretty (HsLit l) = pretty l
	-- lambda stuff
	pretty (HsInfixApp a op b) = myFsep [pretty a, pretty op, pretty b]
	pretty (HsNegApp e) = myFsep [char '-', pretty e]
	pretty (HsApp a b) = myFsep [pretty a, pretty b]
	pretty (HsLambda _loc expList body) = myFsep $
		char '\\' : map pretty expList ++ [text "->", pretty body]
	-- keywords
	pretty (HsLet expList letBody) =
		myFsep [text "let" <+> ppBody letIndent (map pretty expList),
			text "in", pretty letBody]
	pretty (HsIf cond thenexp elsexp) =
		myFsep [text "if", pretty cond,
			text "then", pretty thenexp,
			text "else", pretty elsexp]
	pretty (HsCase cond altList) =
		myFsep [text "case", pretty cond, text "of"]
		$$$ ppBody caseIndent (map pretty altList)
	pretty (HsDo stmtList) =
		text "do" $$$ ppBody doIndent (map pretty stmtList)
	-- Constructors & Vars
	pretty (HsVar name) = pretty name
	pretty (HsCon name) = pretty name
	pretty (HsTuple expList) = parenList . map pretty $ expList
	-- weird stuff
	pretty (HsParen e) = parens . pretty $ e
	pretty (HsLeftSection e op) = parens (pretty e <+> pretty op)
	pretty (HsRightSection op e) = parens (pretty op <+> pretty e)
	pretty (HsRecConstr c fieldList) =
		pretty c <> (braceList . map pretty $ fieldList)
	pretty (HsRecUpdate e fieldList) =
		pretty e <> (braceList . map pretty $ fieldList)
	-- patterns
	-- special case that would otherwise be buggy
	pretty (HsAsPat name (HsIrrPat e)) =
		myFsep [pretty name <> char '@', char '~' <> pretty e]
	pretty (HsAsPat name e) = hcat [pretty name, char '@', pretty e]
	pretty HsWildCard = char '_'
	pretty (HsIrrPat e) = char '~' <> pretty e
	-- Lists
	pretty (HsList list) =
		bracketList . punctuate comma . map pretty $ list
	pretty (HsEnumFrom e) =
		bracketList [pretty e, text ".."]
	pretty (HsEnumFromTo from to) =
		bracketList [pretty from, text "..", pretty to]
	pretty (HsEnumFromThen from thenE) =
		bracketList [pretty from <> comma, pretty thenE, text ".."]
	pretty (HsEnumFromThenTo from thenE to) =
		bracketList [pretty from <> comma, pretty thenE,
			     text "..", pretty to]
	pretty (HsListComp e stmtList) =
		bracketList ([pretty e, char '|']
			     ++ (punctuate comma . map pretty $ stmtList))
	pretty (HsExpTypeSig _pos e ty) =
		myFsep [pretty e, text "::", pretty ty]

------------------------- Patterns -----------------------------

instance Pretty HsPat where
	prettyPrec _ (HsPVar name) = pretty name
	prettyPrec _ (HsPLit lit) = pretty lit
	prettyPrec _ (HsPNeg p) = myFsep [char '-', pretty p]
	prettyPrec p (HsPInfixApp a op b) = parensIf (p > 0) $
		myFsep [pretty a, pretty (HsQConOp op), pretty b]
	prettyPrec p (HsPApp n ps) = parensIf (p > 1) $
		myFsep (pretty n : map pretty ps)
	prettyPrec _ (HsPTuple ps) = parenList . map pretty $ ps
	prettyPrec _ (HsPList ps) =
		bracketList . punctuate comma . map pretty $ ps
	prettyPrec _ (HsPParen p) = parens . pretty $ p
	prettyPrec _ (HsPRec c fields) =
		pretty c <> (braceList . map pretty $ fields)
	-- special case that would otherwise be buggy
	prettyPrec _ (HsPAsPat name (HsPIrrPat pat)) =
		myFsep [pretty name <> char '@', char '~' <> pretty pat]
	prettyPrec _ (HsPAsPat name pat) =
		hcat [pretty name, char '@', pretty pat]
	prettyPrec _ HsPWildCard = char '_'
	prettyPrec _ (HsPIrrPat pat) = char '~' <> pretty pat

instance Pretty HsPatField where
	pretty (HsPFieldPat name pat) =
		myFsep [pretty name, equals, pretty pat]

------------------------- Case bodies  -------------------------
instance Pretty HsAlt where
	pretty (HsAlt _pos e gAlts decls) =
		pretty e <+> pretty gAlts $$$ ppWhere decls

instance Pretty HsGuardedAlts where
	pretty (HsUnGuardedAlt e) = text "->" <+> pretty e
	pretty (HsGuardedAlts altList) = myVcat . map pretty $ altList

instance Pretty HsGuardedAlt where
	pretty (HsGuardedAlt _pos e body) =
		myFsep [char '|', pretty e, text "->", pretty body]

------------------------- Statements in monads & list comprehensions -----
instance Pretty HsStmt where
	pretty (HsGenerator _loc e from) =
		pretty e <+> text "<-" <+> pretty from
	pretty (HsQualifier e) = pretty e
	pretty (HsLetStmt declList) =
		text "let" $$$ ppBody letIndent (map pretty declList)

------------------------- Record updates
instance Pretty HsFieldUpdate where
	pretty (HsFieldUpdate name e) =
		myFsep [pretty name, equals, pretty e]

------------------------- Names -------------------------
instance Pretty HsQOp where
	pretty (HsQVarOp n) = ppHsQNameInfix n
	pretty (HsQConOp n) = ppHsQNameInfix n

ppHsQNameInfix :: HsQName -> Doc
ppHsQNameInfix name
	| isSymbolName (getName name) = ppHsQName name
	| otherwise = char '`' <> ppHsQName name <> char '`'

instance Pretty HsQName where
	pretty name = parensIf (isSymbolName (getName name)) (ppHsQName name)

ppHsQName :: HsQName -> Doc
ppHsQName (UnQual name) = ppHsName name
ppHsQName (Qual m name) = pretty m <> char '.' <> ppHsName name
ppHsQName (Special sym) = text (specialName sym)

instance Pretty HsOp where
	pretty (HsVarOp n) = ppHsNameInfix n
	pretty (HsConOp n) = ppHsNameInfix n

ppHsNameInfix :: HsName -> Doc
ppHsNameInfix name
	| isSymbolName name = ppHsName name
	| otherwise = char '`' <> ppHsName name <> char '`'

instance Pretty HsName where
	pretty name = parensIf (isSymbolName name) (ppHsName name)

ppHsName :: HsName -> Doc
ppHsName (HsIdent s)  = text s
ppHsName (HsSymbol s) = text s

instance Pretty HsCName where
	pretty (HsVarName n) = pretty n
	pretty (HsConName n) = pretty n

isSymbolName :: HsName -> Bool
isSymbolName (HsSymbol _) = True
isSymbolName _ = False

getName :: HsQName -> HsName
getName (UnQual s) = s
getName (Qual _ s) = s
getName (Special HsCons) = HsSymbol ":"
getName (Special HsFunCon) = HsSymbol "->"
getName (Special s) = HsIdent (specialName s)

specialName :: HsSpecialCon -> String
specialName HsUnitCon = "()"
specialName HsListCon = "[]"
specialName HsFunCon = "->"
specialName (HsTupleCon n) = "(" ++ replicate (n-1) ',' ++ ")"
specialName HsCons = ":"

ppHsContext :: HsContext -> Doc
ppHsContext []      = empty
ppHsContext context = mySep [parenList (map ppHsAsst context), text "=>"]

-- hacked for multi-parameter type classes

ppHsAsst :: HsAsst -> Doc
ppHsAsst (a,ts) = myFsep (ppHsQName a : map ppHsTypeArg ts)

------------------------- pp utils -------------------------
maybePP :: (a -> Doc) -> Maybe a -> Doc
maybePP _ Nothing = empty
maybePP pp (Just a) = pp a

parenList :: [Doc] -> Doc
parenList = parens . myFsepSimple . punctuate comma

braceList :: [Doc] -> Doc
braceList = braces . myFsepSimple . punctuate comma

bracketList :: [Doc] -> Doc
bracketList = brackets . myFsepSimple

-- Wrap in braces and semicolons, with an extra space at the start in
-- case the first doc begins with "-", which would be scanned as {-
flatBlock :: [Doc] -> Doc
flatBlock = braces . (space <>) . hsep . punctuate semi

-- Same, but put each thing on a separate line
prettyBlock :: [Doc] -> Doc
prettyBlock = braces . (space <>) . vcat . punctuate semi

-- Monadic PP Combinators -- these examine the env

blankline :: Doc -> Doc
blankline dl = do{e<-getPPEnv;if spacing e && layout e /= PPNoLayout
			      then space $$ dl else dl}
topLevel :: Doc -> [Doc] -> Doc
topLevel header dl = do
	 e <- fmap layout getPPEnv
	 case e of
	     PPOffsideRule -> header $$ vcat dl
	     PPSemiColon -> header $$ prettyBlock dl
	     PPInLine -> header $$ prettyBlock dl
	     PPNoLayout -> header <+> flatBlock dl

ppBody :: (PPHsMode -> Int) -> [Doc] -> Doc
ppBody f dl = do
	 e <- fmap layout getPPEnv
	 case e of PPOffsideRule -> indent
		   PPSemiColon   -> indentExplicit
		   _ -> flatBlock dl
		   where
		   indent  = do{i <-fmap f getPPEnv;nest i . vcat $ dl}
		   indentExplicit = do {i <- fmap f getPPEnv;
			   nest i . prettyBlock $ dl}

($$$) :: Doc -> Doc -> Doc
a $$$ b = layoutChoice (a $$) (a <+>) b

mySep :: [Doc] -> Doc
mySep = layoutChoice mySep' hsep
	where
	-- ensure paragraph fills with indentation.
	mySep' [x]    = x
	mySep' (x:xs) = x <+> fsep xs
	mySep' []     = error "Internal error: mySep"

myVcat :: [Doc] -> Doc
myVcat = layoutChoice vcat hsep

myFsepSimple :: [Doc] -> Doc
myFsepSimple = layoutChoice fsep hsep

-- same, except that continuation lines are indented,
-- which is necessary to avoid triggering the offside rule.
myFsep :: [Doc] -> Doc
myFsep = layoutChoice fsep' hsep
	where	fsep' [] = empty
		fsep' (d:ds) = do
			e <- getPPEnv
			let n = onsideIndent e
			nest n (fsep (nest (-n) d:ds))

layoutChoice :: (a -> Doc) -> (a -> Doc) -> a -> Doc
layoutChoice a b dl = do e <- getPPEnv
                         if layout e == PPOffsideRule ||
                            layout e == PPSemiColon
                          then a dl else b dl

-- Prefix something with a LINE pragma, if requested.
-- GHC's LINE pragma actually sets the current line number to n-1, so
-- that the following line is line n.  But if there's no newline before
-- the line we're talking about, we need to compensate by adding 1.

markLine :: SrcLoc -> Doc -> Doc
markLine loc doc = do
	e <- getPPEnv
	let y = srcLine loc
	let line l =
	      text ("{-# LINE " ++ show l ++ " \"" ++ srcFilename loc ++ "\" #-}")
	if linePragmas e then layoutChoice (line y $$) (line (y+1) <+>) doc
	      else doc