@@ -16,12 +16,17 @@ module Language.PureScript.Docs.Convert
16import Prelude ()
16import Prelude ()
17import Prelude.Compat
17import Prelude.Compat
19−import Control.Monad.Error.Class (MonadError)
19+import Control.Arrow ((&&&), second)
20−import Control.Arrow ((&&&))
21import Control.Category ((>>>))
20import Control.Category ((>>>))
22+import Control.Monad.State (runStateT)
23+import Control.Monad.Writer.Strict (runWriterT)
24+import Control.Monad.Error.Class (MonadError)
22import qualified Data.Map as Map
25import qualified Data.Map as Map
27+import Text.Parsec (eof)
24import qualified Language.PureScript as P
28import qualified Language.PureScript as P
29+import qualified Language.PureScript.Constants as C
26import Language.PureScript.Docs.Types
31import Language.PureScript.Docs.Types
27import Language.PureScript.Docs.Convert.Single (convertSingleModule, collectBookmarks)
32import Language.PureScript.Docs.Convert.Single (convertSingleModule, collectBookmarks)
@@ -33,18 +38,17 @@ import Language.PureScript.Docs.Convert.ReExports (updateReExports)
33-- documentation.
38-- documentation.
35convertModulesInPackage ::
40convertModulesInPackage ::
36− (Functor m, MonadError P.MultipleErrors m) =>
41+ (Functor m, Applicative m, MonadError P.MultipleErrors m) =>
38 [InPackage P.Module] ->
42 [InPackage P.Module] ->
39 m [Module]
43 m [Module]
40−convertModulesInPackage env modules =
44+convertModulesInPackage modules =
41 go modules
45 go modules
43 localNames =
47 localNames =
44− map (P.runModuleName . P.getModuleName) (takeLocals modules)
48+ map P.getModuleName (takeLocals modules)
46 map ignorePackage
50 map ignorePackage
47− >>> convertModules env
51+ >>> convertModules
48 >>> fmap (filter ((`elem` localNames) . modName))
52 >>> fmap (filter ((`elem` localNames) . modName))
@@ -53,35 +57,140 @@ convertModulesInPackage env modules =
53-- imports/exports information about the list of modules, which is needed for
57-- imports/exports information about the list of modules, which is needed for
54-- documenting re-exports.
58-- documenting re-exports.
56−-- Preconditions:
60+-- Note that the whole module dependency graph must be included in the list; if
61+-- some modules import things from other modules, then those modules must also
58−-- * If any module in the list re-exports documentation from other
64+-- For value declarations, if explicit type signatures are omitted, or a
59−-- modules, those modules must also be included in the list.
65+-- wildcard type is used, then we typecheck the modules and use the inferred
60−-- * The modules passed must have had names desugared and re-exports
66+-- types.
63−-- If either of these are not satisfied, an internal error will be thrown. To
64−-- avoid this, it is recommended to use
65−-- Language.PureScript.Docs.ParseAndDesugar to construct the inputs to this
68convertModules ::
68convertModules ::
69− (Functor m, MonadError P.MultipleErrors m) =>
69+ (Functor m, Applicative m, MonadError P.MultipleErrors m) =>
71 [P.Module] ->
70 [P.Module] ->
72 m [Module]
71 m [Module]
73−convertModules env =
72+convertModules =
74+ >>> fmap (fst >>> map importPrim)
74− P.sortModules >>> fmap (convertSorted env . fst)
75+ >=> convertSorted
77+importPrim :: P.Module -> P.Module
78+importPrim = P.addDefaultImport (P.ModuleName [P.ProperName C.prim])
77-- Convert a sorted list of modules.
81-- Convert a sorted list of modules.
79−convertSorted :: P.Env -> [P.Module] -> [Module]
83+convertSorted ::
84+ (Functor m, Applicative m, MonadError P.MultipleErrors m) =>
80−convertSorted env modules =
87+convertSorted modules = do
81− let
88+ (env, convertedModules) <- second (map convertSingleModule) <$> partiallyDesugar modules
83− map P.getModuleName modules
90+ modulesWithTypes <- typeCheckIfNecessary modules convertedModules
84− moduleMap =
91+ let moduleMap = Map.fromList (map (modName &&& id) modulesWithTypes)
85− Map.fromList $ map (P.getModuleName &&& convertSingleModule) modules
92+
86− in
93+ let traversalOrder = map P.getModuleName modules
87− Map.elems (updateReExports env traversalOrder moduleMap)
94+ pure (Map.elems (updateReExports env traversalOrder moduleMap))
97+-- If any exported value declarations have either wildcard type signatures, or
98+-- none at all, then typecheck in order to fill them in with the inferred
101+typeCheckIfNecessary ::
102+ (Functor m, Applicative m, MonadError P.MultipleErrors m) =>
106+typeCheckIfNecessary modules convertedModules =
107+ if any hasWildcards convertedModules
109+ else pure convertedModules
113+ any ((==) (ValueDeclaration P.TypeWildcard) . declInfo) . modDeclarations
116+ checkEnv <- snd <$> typeCheck modules
117+ pure (map (insertValueTypes checkEnv) convertedModules)
120+-- Typechecks all the modules together. Also returns the final 'P.Environment',
121+-- which is useful for adding in inferred types where explicit declarations
122+-- were not provided.
125+ (Functor m, MonadError P.MultipleErrors m) =>
127+ m ([P.Module], P.Environment)
129+ (P.desugar [] >=> check)
130+ >>> fmap (second P.checkEnv)
137+ (traverse P.typeCheckModule ms)
138+ (P.emptyCheckState P.initEnvironment)
141+ fmap fst . runWriterT
144+-- Updates all the types of the ValueDeclarations inside the module based on
145+-- their types inside the given Environment.
148+ P.Environment -> Module -> Module
149+insertValueTypes env m =
150+ m { modDeclarations = map go (modDeclarations m) }
152+ go (d@Declaration { declInfo = ValueDeclaration P.TypeWildcard }) =
154+ ident = parseIdent (declTitle d)
155+ ty = lookupName ident
157+ d { declInfo = ValueDeclaration ty }
162+ either (err . ("failed to parse Ident: " ++)) id . runParser P.parseIdent
165+ let key = (modName m, name)
166+ in case Map.lookup key (P.names env) of
170+ err ("name not found: " ++ show key)
173+ P.internalError ("Docs.Convert.insertValueTypes: " ++ msg)
175+runParser :: P.TokenParser a -> String -> Either String a
176+runParser p s = either (Left . show) Right $ do
178+ P.runTokenParser "" (p <* eof) ts
181+-- Partially desugar modules so that they are suitable for extracting
182+-- documentation information from.
185+ (Functor m, Applicative m, MonadError P.MultipleErrors m) =>
187+ -> m (P.Env, [P.Module])
188+partiallyDesugar = P.evalSupplyT 0 . desugar'
191+ traverse P.desugarDoModule
192+ >=> P.desugarCasesModule
193+ >=> P.desugarTypeDeclarationsModule
194+ >=> ignoreWarnings . P.desugarImportsWithEnv []
196+ ignoreWarnings = fmap fst . runWriterT