forked from purescript/purescript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRender.hs
More file actions
239 lines (206 loc) · 9.02 KB
/
Render.hs
File metadata and controls
239 lines (206 loc) · 9.02 KB
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
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ViewPatterns #-}
-- | Functions for rendering documentation generated from PureScript code.
module Language.PureScript.Docs.Render (
renderModule,
collectBookmarks
) where
import Control.Monad
import Data.Either
import Data.Monoid ((<>))
import Data.Maybe (mapMaybe)
import Data.List (nub)
import qualified Language.PureScript as P
import Language.PureScript.Docs.RenderedCode
import Language.PureScript.Docs.Types
import Language.PureScript.Docs.Utils.MonoidExtras
-- |
-- Render a single Module.
--
renderModule :: P.Module -> RenderedModule
renderModule m@(P.Module coms moduleName _ _) =
RenderedModule (show moduleName) comments declarations
where
comments = renderComments coms
declarations = groupChildren declarationsWithChildren
declarationsWithChildren = mapMaybe go (P.exportedDeclarations m)
go decl = getDeclarationTitle decl
>>= renderDeclaration decl
-- | An intermediate stage which we go through during rendering.
--
-- In the first pass, we take all top level declarations in the module, and
-- render those which should appear at the top level in the output, as well as
-- those which should appear as children of other declarations in the output.
--
-- In the second pass, we move all children under their respective parents,
-- or discard them if none are found.
--
-- This two-pass system is only necessary for type instance declarations, since
-- they appear at the top level in the AST, and since they might need to appear
-- as children in two places (for example, if a data type defined in a module
-- is an instance of a type class also defined in that module).
--
-- This data type is used as an intermediate type between the two stages. The
-- Left case is a child declaration, together with a list of parent declaration
-- titles which this may appear as a child of.
--
-- The Right case is a top level declaration which should pass straight through
-- the second stage; the only way it might change is if child declarations are
-- added to it.
type IntermediateDeclaration
= Either ([String], RenderedChildDeclaration) RenderedDeclaration
-- | Move child declarations into their respective parents; the second pass.
-- See the comments under the type synonym IntermediateDeclaration for more
-- information.
groupChildren :: [IntermediateDeclaration] -> [RenderedDeclaration]
groupChildren (partitionEithers -> (children, toplevels)) =
foldl go toplevels children
where
go ds (parentTitles, child) =
map (\d ->
if rdTitle d `elem` parentTitles
then d { rdChildren = rdChildren d ++ [child] }
else d) ds
getDeclarationTitle :: P.Declaration -> Maybe String
getDeclarationTitle (P.TypeDeclaration name _) = Just (show name)
getDeclarationTitle (P.ExternDeclaration name _) = Just (show name)
getDeclarationTitle (P.DataDeclaration _ name _ _) = Just (show name)
getDeclarationTitle (P.ExternDataDeclaration name _) = Just (show name)
getDeclarationTitle (P.TypeSynonymDeclaration name _ _) = Just (show name)
getDeclarationTitle (P.TypeClassDeclaration name _ _ _) = Just (show name)
getDeclarationTitle (P.TypeInstanceDeclaration name _ _ _ _) = Just (show name)
getDeclarationTitle (P.PositionedDeclaration _ _ d) = getDeclarationTitle d
getDeclarationTitle _ = Nothing
basicDeclaration :: String -> RenderedCode -> Maybe IntermediateDeclaration
basicDeclaration title code = Just (Right (RenderedDeclaration title Nothing code Nothing []))
renderDeclaration :: P.Declaration -> String -> Maybe IntermediateDeclaration
renderDeclaration (P.TypeDeclaration ident' ty) title =
basicDeclaration title code
where
code = ident (show ident')
<> sp <> syntax "::" <> sp
<> renderType ty
renderDeclaration (P.ExternDeclaration ident' ty) title =
basicDeclaration title code
where
code = ident (show ident')
<> sp <> syntax "::" <> sp
<> renderType ty
renderDeclaration (P.DataDeclaration dtype name args ctors) title =
Just (Right (RenderedDeclaration title Nothing code Nothing children))
where
typeApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
code = keyword (show dtype) <> sp <> renderType typeApp
children = map renderCtor ctors
-- TODO: Comments for data constructors?
renderCtor (ctor', tys) =
let typeApp' = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing ctor')) tys
childCode = renderType typeApp'
in RenderedChildDeclaration (show ctor') Nothing childCode Nothing ChildDataConstructor
renderDeclaration (P.ExternDataDeclaration name kind') title =
basicDeclaration title code
where
code = keywordData <> sp
<> renderType (P.TypeConstructor (P.Qualified Nothing name))
<> sp <> syntax "::" <> sp
<> renderKind kind'
renderDeclaration (P.TypeSynonymDeclaration name args ty) title =
basicDeclaration title code
where
typeApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
code = mintersperse sp
[ keywordType
, renderType typeApp
, syntax "="
, renderType ty
]
renderDeclaration (P.TypeClassDeclaration name args implies ds) title = do
Just (Right (RenderedDeclaration title Nothing code Nothing children))
where
code = mintersperse sp $
[keywordClass]
++ maybe [] (:[]) superclasses
++ [renderType classApp]
++ if (not (null ds)) then [keywordWhere] else []
superclasses
| null implies = Nothing
| otherwise = Just $
syntax "("
<> mintersperse (syntax "," <> sp) (map renderImplies implies)
<> syntax ") <="
renderImplies (pn, tys) =
let supApp = foldl P.TypeApp (P.TypeConstructor pn) tys
in renderType supApp
classApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
children = map renderClassMember ds
-- TODO: Comments for type class members
renderClassMember (P.PositionedDeclaration _ _ d) = renderClassMember d
renderClassMember (P.TypeDeclaration ident' ty) =
let childCode =
mintersperse sp
[ ident (show ident')
, syntax "::"
, renderType ty
]
in RenderedChildDeclaration (show ident') Nothing childCode Nothing ChildTypeClassMember
renderClassMember _ = error "Invalid argument to renderClassMember."
renderDeclaration (P.TypeInstanceDeclaration name constraints className tys _) title = do
Just (Left (classNameString : typeNameStrings, childDecl))
where
classNameString = unQual className
typeNameStrings = nub (concatMap (P.everythingOnTypes (++) extractProperNames) tys)
unQual x = let (P.Qualified _ y) = x in show y
extractProperNames (P.TypeConstructor n) = [unQual n]
extractProperNames (P.SaturatedTypeSynonym n _) = [unQual n]
extractProperNames _ = []
childDecl = RenderedChildDeclaration title Nothing code Nothing ChildInstance
code =
mintersperse sp $
[ keywordInstance
, ident (show name)
, syntax "::"
] ++ maybe [] (:[]) constraints'
++ [ renderType classApp ]
constraints'
| null constraints = Nothing
| otherwise = Just (syntax "(" <> renderedConstraints <> syntax ") =>")
renderedConstraints = mintersperse (syntax "," <> sp) (map renderConstraint constraints)
renderConstraint (pn, tys') =
let supApp = foldl P.TypeApp (P.TypeConstructor pn) tys'
in renderType supApp
classApp = foldl P.TypeApp (P.TypeConstructor className) tys
renderDeclaration (P.PositionedDeclaration srcSpan com d') title =
fmap (addComments . addSourceSpan) (renderDeclaration d' title)
where
addComments (Left (t, d)) = Left (t, d { rcdComments = renderComments com })
addComments (Right d) = Right (d { rdComments = renderComments com })
addSourceSpan (Left (t, d)) = Left (t, d { rcdSourceSpan = Just srcSpan })
addSourceSpan (Right d) = Right (d { rdSourceSpan = Just srcSpan })
renderDeclaration _ _ = Nothing
renderComments :: [P.Comment] -> Maybe String
renderComments cs = do
let raw = concatMap toLines cs
guard (all hasPipe raw && not (null raw))
return (go raw)
where
go = unlines . map stripPipes
toLines (P.LineComment s) = [s]
toLines (P.BlockComment s) = lines s
hasPipe s = case dropWhile (== ' ') s of { ('|':_) -> True; _ -> False }
stripPipes = dropPipe . dropWhile (== ' ')
dropPipe ('|':' ':s) = s
dropPipe ('|':s) = s
dropPipe s = s
toTypeVar :: (String, Maybe P.Kind) -> P.Type
toTypeVar (s, Nothing) = P.TypeVar s
toTypeVar (s, Just k) = P.KindedType (P.TypeVar s) k
collectBookmarks :: InPackage P.Module -> [Bookmark]
collectBookmarks (Local m) = map Local (collectBookmarks' m)
collectBookmarks (FromDep pkg m) = map (FromDep pkg) (collectBookmarks' m)
collectBookmarks' :: P.Module -> [(P.ModuleName, String)]
collectBookmarks' m =
map (P.getModuleName m, )
(mapMaybe getDeclarationTitle
(P.exportedDeclarations m))