@@ -5,16 +5,17 @@
6-- | Functions for rendering documentation generated from PureScript code.
6-- | Functions for rendering documentation generated from PureScript code.
8−module Language.PureScript.Docs.Render (
8+module Language.PureScript.Docs.Render
9− renderModule,
9+ ( renderModule
10− collectBookmarks
10+ , collectBookmarks
13import Control.Monad
13import Control.Monad
14+import Control.Category ((>>>))
14import Data.Either
15import Data.Either
15import Data.Monoid ((<>))
16import Data.Monoid ((<>))
16−import Data.Maybe (mapMaybe)
17+import Data.Maybe (mapMaybe, isNothing)
17−import Data.List (nub)
18+import Data.List (nub, isPrefixOf, isSuffixOf)
19import qualified Language.PureScript as P
20import qualified Language.PureScript as P
@@ -27,51 +28,82 @@ import Language.PureScript.Docs.Utils.MonoidExtras
28renderModule :: P.Module -> RenderedModule
29renderModule :: P.Module -> RenderedModule
29renderModule m@(P.Module coms moduleName _ _) =
30renderModule m@(P.Module coms moduleName _ _) =
30− RenderedModule (show moduleName) comments declarations
31+ RenderedModule (show moduleName) comments (declarations m)
32 comments = renderComments coms
33 comments = renderComments coms
33− declarations = groupChildren declarationsWithChildren
34+ declarations =
34− declarationsWithChildren = mapMaybe go (P.exportedDeclarations m)
35+ P.exportedDeclarations
35− go decl = getDeclarationTitle decl
36+ >>> mapMaybe (\d -> getDeclarationTitle d >>= renderDeclaration d)
36− >>= renderDeclaration decl
37+ >>> augmentDeclarations
37−
38+ >>> map addDefaultFixity
38−-- | An intermediate stage which we go through during rendering.
40+-- | The data type for an intermediate stage which we go through during
40-- In the first pass, we take all top level declarations in the module, and
43-- In the first pass, we take all top level declarations in the module, and
41−-- render those which should appear at the top level in the output, as well as
44+-- collect other information which will later be used to augment the top level
42−-- those which should appear as children of other declarations in the output.
45+-- declarations. These two situation correspond to the Right and Left
46+-- constructors, respectively.
44−-- In the second pass, we move all children under their respective parents,
48+-- In the second pass, we go over all of the Left values and augment the
45−-- or discard them if none are found.
49+-- relevant declarations, leaving only the augmented Right values.
47−-- This two-pass system is only necessary for type instance declarations, since
51+-- Note that in the Left case, we provide a [String] as well as augment
48−-- they appear at the top level in the AST, and since they might need to appear
52+-- information. The [String] value should be a list of titles of declarations
49−-- as children in two places (for example, if a data type defined in a module
53+-- that the augmentation should apply to. For example, for a type instance
50−-- is an instance of a type class also defined in that module).
54+-- declaration, that would be any types or type classes mentioned in the
55+-- instance. For a fixity declaration, it would be just the relevant operator's
57+type IntermediateDeclaration
58+ = Either ([String], DeclarationAugment) RenderedDeclaration
60+-- | Some data which will be used to augment a RenderedDeclaration in the
52−-- This data type is used as an intermediate type between the two stages. The
63+-- The AugmentChild constructor allows us to move all children under their
53−-- Left case is a child declaration, together with a list of parent declaration
64+-- respective parents. It is only necessary for type instance declarations,
54−-- titles which this may appear as a child of.
65+-- since they appear at the top level in the AST, and since they might need to
66+-- appear as children in two places (for example, if a data type defined in a
67+-- module is an instance of a type class also defined in that module).
56−-- The Right case is a top level declaration which should pass straight through
69+-- The AugmentFixity constructor allows us to augment operator definitions
57−-- the second stage; the only way it might change is if child declarations are
70+-- with their associativity and precedence.
58−-- added to it.
71+data DeclarationAugment
59−type IntermediateDeclaration
72+ = AugmentChild RenderedChildDeclaration
60− = Either ([String], RenderedChildDeclaration) RenderedDeclaration
73+ | AugmentFixity P.Fixity
62−-- | Move child declarations into their respective parents; the second pass.
75+-- | Augment top-level declarations; the second pass. See the comments under
63−-- See the comments under the type synonym IntermediateDeclaration for more
76+-- the type synonym IntermediateDeclaration for more information.
65−groupChildren :: [IntermediateDeclaration] -> [RenderedDeclaration]
77+augmentDeclarations :: [IntermediateDeclaration] -> [RenderedDeclaration]
66−groupChildren (partitionEithers -> (children, toplevels)) =
78+augmentDeclarations (partitionEithers -> (augments, toplevels)) =
67− foldl go toplevels children
79+ foldl go toplevels augments
69− go ds (parentTitles, child) =
81+ go ds (parentTitles, a) =
70 map (\d ->
82 map (\d ->
71 if rdTitle d `elem` parentTitles
83 if rdTitle d `elem` parentTitles
72− then d { rdChildren = rdChildren d ++ [child] }
84+ then augmentWith a d
73 else d) ds
85 else d) ds
89+ AugmentChild child ->
90+ d { rdChildren = rdChildren d ++ [child] }
91+ AugmentFixity fixity ->
92+ d { rdFixity = Just fixity }
94+-- | Add the default operator fixity for operators which do not have associated
95+-- fixity declarations.
97+-- TODO: This may no longer be necessary after issue 806 is resolved, hopefully
99+addDefaultFixity :: RenderedDeclaration -> RenderedDeclaration
100+addDefaultFixity rd@RenderedDeclaration{..}
101+ | isOp rdTitle && isNothing rdFixity = rd { rdFixity = Just defaultFixity }
104+ isOp str = "(" `isPrefixOf` str && ")" `isSuffixOf` str
105+ defaultFixity = P.Fixity P.Infixl (-1)
75getDeclarationTitle :: P.Declaration -> Maybe String
107getDeclarationTitle :: P.Declaration -> Maybe String
76getDeclarationTitle (P.TypeDeclaration name _) = Just (show name)
108getDeclarationTitle (P.TypeDeclaration name _) = Just (show name)
77getDeclarationTitle (P.ExternDeclaration name _) = Just (show name)
109getDeclarationTitle (P.ExternDeclaration name _) = Just (show name)
@@ -80,11 +112,23 @@ getDeclarationTitle (P.ExternDataDeclaration name _) = Just (show name)
80getDeclarationTitle (P.TypeSynonymDeclaration name _ _) = Just (show name)
112getDeclarationTitle (P.TypeSynonymDeclaration name _ _) = Just (show name)
81getDeclarationTitle (P.TypeClassDeclaration name _ _ _) = Just (show name)
113getDeclarationTitle (P.TypeClassDeclaration name _ _ _) = Just (show name)
82getDeclarationTitle (P.TypeInstanceDeclaration name _ _ _ _) = Just (show name)
114getDeclarationTitle (P.TypeInstanceDeclaration name _ _ _ _) = Just (show name)
115+getDeclarationTitle (P.FixityDeclaration _ name) = Just ("(" ++ name ++ ")")
83getDeclarationTitle (P.PositionedDeclaration _ _ d) = getDeclarationTitle d
116getDeclarationTitle (P.PositionedDeclaration _ _ d) = getDeclarationTitle d
84getDeclarationTitle _ = Nothing
117getDeclarationTitle _ = Nothing
119+-- | Create a basic RenderedDeclaration value.
120+mkDeclaration :: String -> RenderedCode -> RenderedDeclaration
121+mkDeclaration title code =
122+ RenderedDeclaration { rdTitle = title
123+ , rdComments = Nothing
125+ , rdSourceSpan = Nothing
127+ , rdFixity = Nothing
86basicDeclaration :: String -> RenderedCode -> Maybe IntermediateDeclaration
130basicDeclaration :: String -> RenderedCode -> Maybe IntermediateDeclaration
87−basicDeclaration title code = Just (Right (RenderedDeclaration title Nothing code Nothing []))
131+basicDeclaration title code = Just $ Right $ mkDeclaration title code
89renderDeclaration :: P.Declaration -> String -> Maybe IntermediateDeclaration
133renderDeclaration :: P.Declaration -> String -> Maybe IntermediateDeclaration
90renderDeclaration (P.TypeDeclaration ident' ty) title =
134renderDeclaration (P.TypeDeclaration ident' ty) title =
@@ -100,7 +144,7 @@ renderDeclaration (P.ExternDeclaration ident' ty) title =
100 <> sp <> syntax "::" <> sp
144 <> sp <> syntax "::" <> sp
101 <> renderType ty
145 <> renderType ty
102renderDeclaration (P.DataDeclaration dtype name args ctors) title =
146renderDeclaration (P.DataDeclaration dtype name args ctors) title =
103− Just (Right (RenderedDeclaration title Nothing code Nothing children))
147+ Just (Right (mkDeclaration title code) { rdChildren = children })
105 typeApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
149 typeApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
106 code = keyword (show dtype) <> sp <> renderType typeApp
150 code = keyword (show dtype) <> sp <> renderType typeApp
@@ -128,7 +172,7 @@ renderDeclaration (P.TypeSynonymDeclaration name args ty) title =
128 , renderType ty
172 , renderType ty
130renderDeclaration (P.TypeClassDeclaration name args implies ds) title = do
174renderDeclaration (P.TypeClassDeclaration name args implies ds) title = do
131− Just (Right (RenderedDeclaration title Nothing code Nothing children))
175+ Just (Right (mkDeclaration title code) { rdChildren = children })
133 code = mintersperse sp $
177 code = mintersperse sp $
134 [keywordClass]
178 [keywordClass]
@@ -163,7 +207,7 @@ renderDeclaration (P.TypeClassDeclaration name args implies ds) title = do
163 in RenderedChildDeclaration (show ident') Nothing childCode Nothing ChildTypeClassMember
207 in RenderedChildDeclaration (show ident') Nothing childCode Nothing ChildTypeClassMember
164 renderClassMember _ = error "Invalid argument to renderClassMember."
208 renderClassMember _ = error "Invalid argument to renderClassMember."
165renderDeclaration (P.TypeInstanceDeclaration name constraints className tys _) title = do
209renderDeclaration (P.TypeInstanceDeclaration name constraints className tys _) title = do
166− Just (Left (classNameString : typeNameStrings, childDecl))
210+ Just (Left (classNameString : typeNameStrings, AugmentChild childDecl))
168 classNameString = unQual className
212 classNameString = unQual className
169 typeNameStrings = nub (concatMap (P.everythingOnTypes (++) extractProperNames) tys)
213 typeNameStrings = nub (concatMap (P.everythingOnTypes (++) extractProperNames) tys)
@@ -194,14 +238,27 @@ renderDeclaration (P.TypeInstanceDeclaration name constraints className tys _) t
194 in renderType supApp
238 in renderType supApp
196 classApp = foldl P.TypeApp (P.TypeConstructor className) tys
240 classApp = foldl P.TypeApp (P.TypeConstructor className) tys
241+renderDeclaration (P.FixityDeclaration fixity _) title =
242+ Just (Left ([title], AugmentFixity fixity))
197renderDeclaration (P.PositionedDeclaration srcSpan com d') title =
243renderDeclaration (P.PositionedDeclaration srcSpan com d') title =
198 fmap (addComments . addSourceSpan) (renderDeclaration d' title)
244 fmap (addComments . addSourceSpan) (renderDeclaration d' title)
246+ addComments (Right d) =
247+ Right (d { rdComments = renderComments com })
248+ addComments (Left augment) =
200− addComments (Left (t, d)) = Left (t, d { rcdComments = renderComments com })
249+ Left (withAugmentChild (\d -> d { rcdComments = renderComments com })
201− addComments (Right d) = Right (d { rdComments = renderComments com })
250+ augment)
252+ addSourceSpan (Right d) =
253+ Right (d { rdSourceSpan = Just srcSpan })
254+ addSourceSpan (Left augment) =
203− addSourceSpan (Left (t, d)) = Left (t, d { rcdSourceSpan = Just srcSpan })
255+ Left (withAugmentChild (\d -> d { rcdSourceSpan = Just srcSpan })
204− addSourceSpan (Right d) = Right (d { rdSourceSpan = Just srcSpan })
256+ augment)
258+ withAugmentChild f (t, a) =
260+ AugmentChild d -> (t, AugmentChild (f d))
205renderDeclaration _ _ = Nothing
262renderDeclaration _ _ = Nothing
207renderComments :: [P.Comment] -> Maybe String
264renderComments :: [P.Comment] -> Maybe String