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
|
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ExistentialQuantification #-}
module LambdaCube.Compiler.Pretty
( module LambdaCube.Compiler.Pretty
) where
import Data.Monoid
import Data.String
import Data.Char
--import qualified Data.Set as Set
--import qualified Data.Map as Map
import Control.Monad.Identity
import Control.Monad.Reader
import Control.Monad.State
import Control.Arrow hiding ((<+>))
import Control.DeepSeq
--import Debug.Trace
import qualified Text.PrettyPrint.ANSI.Leijen as P
import LambdaCube.Compiler.Utils
-------------------------------------------------------------------------------- fixity
data Fixity
= Infix !Int
| InfixL !Int
| InfixR !Int
deriving (Eq, Show)
instance PShow Fixity where
pShow = \case
Infix i -> "infix" `DApp` pShow i
InfixL i -> "infixl" `DApp` pShow i
InfixR i -> "infixr" `DApp` pShow i
precedence, leftPrecedence, rightPrecedence :: Fixity -> Int
precedence = \case
Infix i -> i
InfixR i -> i
InfixL i -> i
leftPrecedence (InfixL i) = i
leftPrecedence f = precedence f + 1
rightPrecedence (InfixR i) = i
rightPrecedence f = precedence f + 1
-------------------------------------------------------------------------------- doc data type
data Doc
= forall f . Traversable f => DDocOp (f P.Doc -> P.Doc) (f Doc)
| DFormat (P.Doc -> P.Doc) Doc
| DAtom DocAtom
| DInfix Fixity Doc DocAtom Doc
| DFreshName Bool{-used-} Doc
| DVar Int
| DUp Int Doc
| DExpand Doc Doc
data DocAtom
= SimpleAtom String
| ComplexAtom String Int Doc DocAtom
mapDocAtom f (SimpleAtom s) = SimpleAtom s
mapDocAtom f (ComplexAtom s i d a) = ComplexAtom s i (f s i d) $ mapDocAtom f a
instance IsString Doc where
fromString = text
text = DText
pattern DText s = DAtom (SimpleAtom s)
instance Monoid Doc where
mempty = text ""
mappend = dTwo mappend
instance NFData Doc where
rnf x = rnf $ show x -- TODO
strip :: Doc -> Doc
strip = \case
DFormat _ x -> strip x
DUp _ x -> strip x
DFreshName _ x -> strip x
x -> x
simple :: Doc -> Bool
simple x = case strip x of
DAtom{} -> True
DVar{} -> True
_ -> False
instance Show Doc where
show = show . renderDoc
plainShow :: PShow a => a -> String
plainShow = show . P.plain . renderDoc . pShow
renderDoc :: Doc -> P.Doc
renderDoc
= render
. addPar (-10)
. flip runReader ((\s n -> '_': n: s) <$> iterate ('\'':) "" <*> ['a'..'z'])
. flip evalStateT (flip (:) <$> iterate ('\'':) "" <*> ['a'..'z'])
. showVars
. expand True
where
noexpand = expand False
expand full = \case
DExpand short long -> expand full $ if full then long else short
DFormat c x -> DFormat c $ expand full x
DDocOp x d -> DDocOp x $ expand full <$> d
DAtom s -> DAtom $ mapDocAtom (\_ _ -> noexpand) s
DInfix pr x op y -> DInfix pr (noexpand x) (mapDocAtom (\_ _ -> noexpand) op) (noexpand y)
DVar i -> DVar i
DFreshName b x -> DFreshName b $ noexpand x
DUp i x -> DUp i $ noexpand x
showVars = \case
DAtom s -> DAtom <$> showVarA s
DFormat c x -> DFormat c <$> showVars x
DDocOp x d -> DDocOp x <$> traverse showVars d
DInfix pr x op y -> DInfix pr <$> showVars x <*> showVarA op <*> showVars y
DVar i -> asks $ text . (!! i)
DFreshName True x -> gets head >>= \n -> modify tail >> local (n:) (showVars x)
DFreshName False x -> local ("_":) $ showVars x
DUp i x -> local (dropIndex i) $ showVars x
where
showVarA (SimpleAtom s) = pure $ SimpleAtom s
showVarA (ComplexAtom s i d a) = ComplexAtom s i <$> showVars d <*> showVarA a
addPar :: Int -> Doc -> Doc
addPar pr x = case x of
DAtom x -> DAtom $ addParA x
DInfix pr' x op y -> (if protect then DParen else id)
$ DInfix pr' (addPar (leftPrecedence pr') x) (addParA op) (addPar (rightPrecedence pr') y)
DFormat c x -> DFormat c $ addPar pr x
DDocOp x d -> DDocOp x $ addPar (-10) <$> d
where
addParA = mapDocAtom (\_ -> addPar)
protect = case x of
DInfix f _ _ _ -> precedence f < pr
_ -> False
render :: Doc -> P.Doc
render = snd . render'
where
render' = \case
DFormat c x -> second c $ render' x
DDocOp f d -> (('\0', '\0'), f $ render <$> d)
DAtom x -> renderA x
DInfix _ x op y -> render' x <++> renderA op <++> render' y
renderA (SimpleAtom s) = rtext s
renderA (ComplexAtom s _ d a) = rtext s <++> render' d <++> renderA a
rtext "" = (('\0', '\0'), mempty)
rtext s@(h:_) = ((h, last s), P.text s)
((lx, rx), x) <++> ((ly, ry), y) = ((lx, ry), z)
where
z | sep rx ly = x P.<+> y
| otherwise = x P.<> y
sep x y
| x == '\0' || y == '\0' = False
| isSpace x || isSpace y = False
| y == ',' = False
| x == ',' = True
| x == '\\' && (isOpen y || isAlph y) = False
| isOpen x = False
| isClose y = False
| otherwise = True
where
isAlph c = isAlphaNum c || c `elem` ("'_" :: String)
isOpen c = c `elem` ("({[" :: String)
isClose c = c `elem` (")}]" :: String)
-------------------------------------------------------------------------- combinators
-- add wl-pprint combinators as necessary here
red = DFormat P.dullred
green = DFormat P.dullgreen
blue = DFormat P.dullblue
onred = DFormat P.ondullred
ongreen = DFormat P.ondullgreen
onblue = DFormat P.ondullblue
underline = DFormat P.underline
-- add wl-pprint combinators as necessary here
(<+>) = dTwo (P.<+>)
(</>) = dTwo (P.</>)
(<$$>) = dTwo (P.<$$>)
nest n = dOne (P.nest n)
tupled = dList P.tupled
hsep = dList P.hsep
vcat = dList P.vcat
dOne f = DDocOp (f . runIdentity) . Identity
dTwo f x y = DDocOp (\(Two x y) -> f x y) (Two x y)
dList f = DDocOp f
data Two a = Two a a
deriving (Functor, Foldable, Traversable)
bracketed [] = text "[]"
bracketed xs = DPar "[" (foldr1 DComma xs) "]"
shVar = DVar
shortForm d = DPar "" d ""
expand = DExpand
pattern DPar l d r = DAtom (ComplexAtom l (-20) d (SimpleAtom r))
pattern DParen x = DPar "(" x ")"
pattern DBrace x = DPar "{" x "}"
pattern DOp s f l r = DInfix f l (SimpleAtom s) r
pattern DSep p a b = DOp " " p a b
pattern DGlue p a b = DOp "" p a b
pattern DArr_ s x y = DOp s (InfixR (-1)) x y
pattern DArr x y = DArr_ "->" x y
pattern DAnn x y = DOp "::" (InfixR (-3)) x y
pattern DApp x y = DSep (InfixL 10) x y
pattern DComma a b = DOp "," (InfixR (-20)) a b
braces = DBrace
parens = DParen
shTuple [] = "()"
shTuple [x] = DParen $ DParen x
shTuple xs = DParen $ foldr1 DComma xs
shLet i a b = shLam' (shLet' (blue $ shVar i) $ DUp i a) (DUp i b)
shLet_ a b = DFreshName True $ shLam' (shLet' (shVar 0) $ DUp 0 a) b
shLet' = DOp ":=" (Infix (-4))
shAnn True x (strip -> DText "Type") = x
shAnn _ x y = DOp "::" (InfixR (-3)) x y
shArr = DArr
shCstr = DOp "~" (Infix (-2))
pattern DForall vs e = DArr_ "." (DSep (Infix 10) (DText "forall") vs) e
pattern DContext vs e = DArr_ "=>" vs e
pattern DParContext vs e = DContext (DParen vs) e
pattern DLam vs e = DSep (InfixR (-10)) (DAtom (ComplexAtom "\\" 11 vs (SimpleAtom "->"))) e
shLam' x (DFreshName True d) = DFreshName True $ shLam' (DUp 0 x) d
shLam' x (DLam xs y) = DLam (DSep (InfixR 11) x xs) y
shLam' x y = DLam x y
showForall x (DFreshName u d) = DFreshName u $ showForall (DUp 0 x) d
showForall x (DForall xs y) = DForall (DSep (InfixR 11) x xs) y
showForall x y = DForall x y
showContext x (DFreshName u d) = DFreshName u $ showContext (DUp 0 x) d
showContext x (DParContext xs y) = DParContext (DComma x xs) y
showContext x (DContext xs y) = DParContext (DComma x xs) y
showContext x y = DContext x y
--------------------------------------------------------------------------------
class PShow a where
pShow :: a -> Doc
ppShow :: PShow a => a -> String
ppShow = show . pShow
instance PShow Doc where pShow = id
instance PShow Int where pShow = fromString . show
instance PShow Integer where pShow = fromString . show
instance PShow Double where pShow = fromString . show
instance PShow Char where pShow = fromString . show
instance PShow () where pShow _ = "()"
instance PShow Bool where
pShow b = if b then "True" else "False"
instance (PShow a, PShow b) => PShow (Either a b) where
pShow = either (("Left" `DApp`) . pShow) (("Right" `DApp`) . pShow)
instance (PShow a, PShow b) => PShow (a, b) where
pShow (a, b) = tupled [pShow a, pShow b]
instance (PShow a, PShow b, PShow c) => PShow (a, b, c) where
pShow (a, b, c) = tupled [pShow a, pShow b, pShow c]
instance PShow a => PShow [a] where
pShow = bracketed . map pShow
instance PShow a => PShow (Maybe a) where
pShow = maybe "Nothing" (("Just" `DApp`) . pShow)
--instance PShow a => PShow (Set a) where
-- pShow = pShow . Set.toList
--instance (PShow s, PShow a) => PShow (Map s a) where
-- pShow = braces . vcat . map (\(k, t) -> pShow k <> P.colon <+> pShow t) . Map.toList
|