-
Notifications
You must be signed in to change notification settings - Fork 0
/
MIT6005.hs
828 lines (695 loc) · 26.2 KB
/
MIT6005.hs
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
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
{-# OPTIONS_GHC -w #-}
-----------------------------------------------------------------------------
-- |
-- Module : MIT6005
-- Copyright : (c) Edward Z. Yang
-- (c) The GHC Team, Noel Winstanley 1997-2010
-- License : BSD-style (see the file libraries/base/LICENSE)
--
-- Maintainer : ezyang@mit.edu
-- Stability : experimental
-- Portability : portable
--
-- Pretty printer for the functional programming pseudocode used by
-- MIT's course 6.005. Source code modified from
-- Language.Haskell.Pretty.
--
-----------------------------------------------------------------------------
module MIT6005 (
-- * 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
import Data.List (intercalate, intersperse)
import Data.Char (toUpper)
infixl 5 $$$
-- Extra stuff
myCons = UnQual (HsIdent "Cons")
commify [] = empty
commify (a:[]) = a
commify (a:as) = a <> comma <+> commify as
-----------------------------------------------------------------------------
-- | 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.
--
-- /Note:/ the 'onsideIndent' must be positive and less than all other indents.
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 = empty
{-
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) = empty
{-
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]
++ [text "<" <> commify (map pretty nameList) <> text ">"]
++ [equals, pretty htype])
pretty (HsDataDecl loc context name nameList constrList derives) =
blankline $
markLine loc $
-- ezyang: New format for data declaration
ppHsContext context <+> pretty name <>
(
if null nameList
then empty
else text "<" <> commify (map pretty nameList) <> text ">"
)
<+> (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 ppHsAType args)
pretty (HsInstDecl pos context name args declList) =
blankline $
markLine pos $
mySep ( [text "instance", ppHsContext context, pretty name]
++ map ppHsAType 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 (HsForeignImport pos conv safety entity name ty) =
blankline $
markLine pos $
mySep $ [text "foreign", text "import", text conv, pretty safety] ++
(if null entity then [] else [text (show entity)]) ++
[pretty name, text "::", pretty ty]
pretty (HsForeignExport pos conv entity name ty) =
blankline $
markLine pos $
mySep $ [text "foreign", text "export", text conv] ++
(if null entity then [] else [text (show entity)]) ++
[pretty name, text "::", pretty ty]
pretty (HsFunBind matches) =
ppBindings (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 HsSafety where
pretty HsSafe = text "safe"
pretty HsUnsafe = text "unsafe"
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'
-- ezyang: add parentheses and commas in bindings
_ -> [pretty f <> lparen <> commify (map (prettyPrec 2) ps) <> rparen]
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 [prettyPrec prec_btype l, ppHsName name,
prettyPrec prec_btype r]
pretty (HsConDecl _pos name typeList) =
ppHsName name <> lparen <> commify (map (prettyPrec prec_atype) typeList) <> rparen
ppField :: ([HsName],HsBangType) -> Doc
ppField (names, ty) =
myFsepSimple $ (punctuate comma . map pretty $ names) ++
[text "::", pretty ty]
instance Pretty HsBangType where
prettyPrec _ (HsBangedTy ty) = char '!' <> ppHsAType ty
prettyPrec p (HsUnBangedTy ty) = prettyPrec p ty
ppHsDeriving :: [HsQName] -> Doc
-- no deriving info please
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]
ppHsBType :: HsType -> Doc
ppHsBType = prettyPrec prec_btype
ppHsAType :: HsType -> Doc
ppHsAType = prettyPrec prec_atype
-- precedences for types
prec_btype, prec_atype :: Int
prec_btype = 1 -- left argument of ->,
-- or either argument of an infix data constructor
prec_atype = 2 -- argument of type or data constructor, or of a class
instance Pretty HsType where
prettyPrec p (HsTyFun a b@(HsTyFun _ _)) = parensIf (p > 0) $
ppHsBType a <> comma <+> prettyPrec p b
prettyPrec p (HsTyFun a b) = parensIf (p > 0) $
myFsep [ppHsBType a, text "->", pretty b]
prettyPrec _ (HsTyTuple l) = parenList . map pretty $ l
prettyPrec p (HsTyApp a b)
| a == list_tycon = text "List<" <> pretty b <> text ">" -- special case
| otherwise = parensIf (p > prec_btype) $
pretty a <> text "<" <> ppHsAType b <> text ">"
prettyPrec _ (HsTyVar (HsIdent s)) = pretty (HsIdent (map toUpper s))
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
-- ezyang: more consing
pretty (HsInfixApp a (HsQConOp (Special HsCons)) b) = pretty (HsApp (HsApp (HsCon myCons) a) b)
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]
-- Make function do more familiar f(a, b, c) notation
pretty (HsApp a (HsParen b)) = pretty (HsApp a b)
pretty (HsApp a@(HsApp _ _) b) = prettyInside a <> comma <+> pretty b <> rparen
where prettyInside (HsApp a (HsParen b)) = prettyInside (HsApp a b)
prettyInside (HsApp a@(HsApp _ _) b) = prettyInside a <> comma <+> pretty b
prettyInside (HsApp a b) = pretty a <> lparen <> pretty b
pretty (HsApp a b) = pretty a <> lparen <> pretty b <> rparen
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 []) = text "Nil"
pretty (HsList (a:as)) =
pretty (HsApp (HsApp (HsCon myCons) a) (HsList as))
--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]
-- ezyang: Make list operations into explicit Cons's
prettyPrec p (HsPInfixApp a (Special HsCons) b) =
prettyPrec p (HsPApp myCons [a, b])
prettyPrec p (HsPInfixApp a op b) = parensIf (p > 0) $
myFsep [pretty a, pretty (HsQConOp op), pretty b]
-- convert pattern notation to prefix notation
prettyPrec p (HsPApp n ps) = --parensIf (p > 1) $
if null ps
then pretty n
else pretty n <> lparen <> commify (map pretty ps) <> rparen
-- myFsep (pretty n : map pretty ps)
prettyPrec _ (HsPTuple ps) = parenList . map pretty $ ps
-- ezyang: Desugar list notation into explicit cons's; didn't do
-- anything, probably need to do nonprec
prettyPrec _ (HsPList []) = text "Nil"
prettyPrec p (HsPList (a:as)) =
prettyPrec p (HsPApp myCons [a, (HsPList as)])
--bracketList . punctuate comma . map pretty $ ps
-- ezyang: Might be buggy
prettyPrec _ (HsPParen p) = pretty 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) =
myFsep [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 ppHsAType 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
i <- fmap f getPPEnv
case e of
PPOffsideRule -> nest i . vcat $ dl
PPSemiColon -> nest i . prettyBlock $ dl
_ -> flatBlock dl
ppBindings :: [Doc] -> Doc
ppBindings dl = do
e <- fmap layout getPPEnv
case e of
PPOffsideRule -> vcat dl
PPSemiColon -> vcat . punctuate semi $ dl
_ -> hsep . punctuate semi $ 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