git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Store more information in RenderedCode / refactoring
04d7668Harry Garrood
purescript.cabal+3−1
@@ -123,6 +123,7 @@ library
123 containers -any,
123 containers -any,
124 clock -any,
124 clock -any,
125 data-ordlist >= 0.4.7.0,
125 data-ordlist >= 0.4.7.0,
126+ deepseq -any,
126 directory >= 1.2,
127 directory >= 1.2,
127 dlist -any,
128 dlist -any,
128 edit-distance -any,
129 edit-distance -any,
@@ -266,7 +267,8 @@ library
266 Language.PureScript.Docs.Types
267 Language.PureScript.Docs.Types
267 Language.PureScript.Docs.RenderedCode
268 Language.PureScript.Docs.RenderedCode
268 Language.PureScript.Docs.RenderedCode.Types
269 Language.PureScript.Docs.RenderedCode.Types
269− Language.PureScript.Docs.RenderedCode.Render
270+ Language.PureScript.Docs.RenderedCode.RenderType
271+ Language.PureScript.Docs.RenderedCode.RenderKind
270 Language.PureScript.Docs.AsMarkdown
272 Language.PureScript.Docs.AsMarkdown
271 Language.PureScript.Docs.ParseInPackage
273 Language.PureScript.Docs.ParseInPackage
272 Language.PureScript.Docs.Utils.MonoidExtras
274 Language.PureScript.Docs.Utils.MonoidExtras
src/Language/PureScript/Docs.hs+1−2
@@ -10,6 +10,5 @@ import Language.PureScript.Docs.Convert as Docs
10import Language.PureScript.Docs.Prim as Docs
10import Language.PureScript.Docs.Prim as Docs
11import Language.PureScript.Docs.ParseInPackage as Docs
11import Language.PureScript.Docs.ParseInPackage as Docs
12import Language.PureScript.Docs.Render as Docs
12import Language.PureScript.Docs.Render as Docs
13−import Language.PureScript.Docs.RenderedCode.Render as Docs
13+import Language.PureScript.Docs.RenderedCode as Docs
14−import Language.PureScript.Docs.RenderedCode.Types as Docs
15import Language.PureScript.Docs.Types as Docs
14import Language.PureScript.Docs.Types as Docs
src/Language/PureScript/Docs/AsMarkdown.hs+4−6
@@ -77,12 +77,10 @@ declAsMarkdown mn decl@Declaration{..} = do
77codeToString :: RenderedCode -> Text
77codeToString :: RenderedCode -> Text
78codeToString = outputWith elemAsMarkdown
78codeToString = outputWith elemAsMarkdown
79 where
79 where
80− elemAsMarkdown (Syntax x) = x
80+ elemAsMarkdown (Syntax x) = x
81− elemAsMarkdown (Ident x _) = x
82− elemAsMarkdown (Ctor x _) = x
83− elemAsMarkdown (Kind x) = x
84− elemAsMarkdown (Keyword x) = x
81+ elemAsMarkdown (Keyword x) = x
85− elemAsMarkdown Space = " "
82+ elemAsMarkdown Space = " "
83+ elemAsMarkdown (Symbol _ x _) = x
86
84
87-- fixityAsMarkdown :: P.Fixity -> Docs
85-- fixityAsMarkdown :: P.Fixity -> Docs
88-- fixityAsMarkdown (P.Fixity associativity precedence) =
86-- fixityAsMarkdown (P.Fixity associativity precedence) =
src/Language/PureScript/Docs/Render.hs+17−27
@@ -28,7 +28,7 @@ renderDeclarationWithOptions :: RenderTypeOptions -> Declaration -> RenderedCode
28renderDeclarationWithOptions opts Declaration{..} =
28renderDeclarationWithOptions opts Declaration{..} =
29 mintersperse sp $ case declInfo of
29 mintersperse sp $ case declInfo of
30 ValueDeclaration ty ->
30 ValueDeclaration ty ->
31− [ ident declTitle
31+ [ ident' declTitle
32 , syntax "::"
32 , syntax "::"
33 , renderType' ty
33 , renderType' ty
34 ]
34 ]
@@ -70,40 +70,25 @@ renderDeclarationWithOptions opts Declaration{..} =
70 [idents from <> sp <> syntax "->" <> sp <> idents to | (from, to) <- fundeps ]
70 [idents from <> sp <> syntax "->" <> sp <> idents to | (from, to) <- fundeps ]
71 ]
71 ]
72 where
72 where
73− idents = mintersperse sp . map ident
73+ idents = mintersperse sp . map ident'
74
74
75− AliasDeclaration (P.Fixity associativity precedence) for@(P.Qualified _ alias) ->
75+ AliasDeclaration (P.Fixity associativity precedence) for ->
76 [ keywordFixity associativity
76 [ keywordFixity associativity
77 , syntax $ T.pack $ show precedence
77 , syntax $ T.pack $ show precedence
78− , ident $ renderQualAlias for
78+ , alias for
79− , keyword "as"
79+ , keywordAs
80− , ident $ adjustAliasName alias declTitle
80+ , aliasName for declTitle
81 ]
81 ]
82
82
83 ExternKindDeclaration ->
83 ExternKindDeclaration ->
84 [ keywordKind
84 [ keywordKind
85− , renderKind (P.NamedKind (notQualified declTitle))
85+ , kind (notQualified declTitle)
86 ]
86 ]
87
87
88 where
88 where
89 renderType' :: P.Type -> RenderedCode
89 renderType' :: P.Type -> RenderedCode
90 renderType' = renderTypeWithOptions opts
90 renderType' = renderTypeWithOptions opts
91
91
92− renderQualAlias :: FixityAlias -> Text
93− renderQualAlias (P.Qualified mn alias)
94− | mn == currentModule opts = renderAlias id alias
95− | otherwise = renderAlias (\f -> P.showQualified f . P.Qualified mn) alias
96−
97− renderAlias
98− :: (forall a. (a -> Text) -> a -> Text)
99− -> Either (P.ProperName 'P.TypeName) (Either P.Ident (P.ProperName 'P.ConstructorName))
100− -> Text
101− renderAlias f
102− = either (("type " <>) . f P.runProperName)
103− $ either (f P.runIdent) (f P.runProperName)
104−
105− adjustAliasName _ title = T.tail (T.init title)
106−
107renderChildDeclaration :: ChildDeclaration -> RenderedCode
92renderChildDeclaration :: ChildDeclaration -> RenderedCode
108renderChildDeclaration = renderChildDeclarationWithOptions defaultRenderTypeOptions
93renderChildDeclaration = renderChildDeclarationWithOptions defaultRenderTypeOptions
109
94
@@ -113,18 +98,17 @@ renderChildDeclarationWithOptions opts ChildDeclaration{..} =
113 ChildInstance constraints ty ->
98 ChildInstance constraints ty ->
114 maybeToList (renderConstraints constraints) ++ [ renderType' ty ]
99 maybeToList (renderConstraints constraints) ++ [ renderType' ty ]
115 ChildDataConstructor args ->
100 ChildDataConstructor args ->
116− [ renderType' typeApp' ]
101+ [ dataCtor' cdeclTitle ]
117− where
102+ ++ map renderTypeAtom' args
118− typeApp' = foldl P.TypeApp ctor' args
119− ctor' = P.TypeConstructor (notQualified cdeclTitle)
120
103
121 ChildTypeClassMember ty ->
104 ChildTypeClassMember ty ->
122− [ ident cdeclTitle
105+ [ ident' cdeclTitle
123 , syntax "::"
106 , syntax "::"
124 , renderType' ty
107 , renderType' ty
125 ]
108 ]
126 where
109 where
127 renderType' = renderTypeWithOptions opts
110 renderType' = renderTypeWithOptions opts
111+ renderTypeAtom' = renderTypeAtomWithOptions opts
128
112
129renderConstraint :: P.Constraint -> RenderedCode
113renderConstraint :: P.Constraint -> RenderedCode
130renderConstraint = renderConstraintWithOptions defaultRenderTypeOptions
114renderConstraint = renderConstraintWithOptions defaultRenderTypeOptions
@@ -151,6 +135,12 @@ renderConstraintsWithOptions opts constraints
151notQualified :: Text -> P.Qualified (P.ProperName a)
135notQualified :: Text -> P.Qualified (P.ProperName a)
152notQualified = P.Qualified Nothing . P.ProperName
136notQualified = P.Qualified Nothing . P.ProperName
153
137
138+ident' :: Text -> RenderedCode
139+ident' = ident . P.Qualified Nothing . P.Ident
140+
141+dataCtor' :: Text -> RenderedCode
142+dataCtor' = dataCtor . notQualified
143+
154typeApp :: Text -> [(Text, Maybe P.Kind)] -> P.Type
144typeApp :: Text -> [(Text, Maybe P.Kind)] -> P.Type
155typeApp title typeArgs =
145typeApp title typeArgs =
156 foldl P.TypeApp
146 foldl P.TypeApp
src/Language/PureScript/Docs/RenderedCode.hs+9−8
@@ -1,8 +1,9 @@
1−
1+
2−-- | Data types and functions for representing a simplified form of PureScript
2+-- | Data types and functions for representing a simplified form of PureScript
3−-- code, intended for use in e.g. HTML documentation.
3+-- code, intended for use in e.g. HTML documentation.
4−
4+
5−module Language.PureScript.Docs.RenderedCode (module RenderedCode) where
5+module Language.PureScript.Docs.RenderedCode (module RenderedCode) where
6−
6+
7−import Language.PureScript.Docs.RenderedCode.Types as RenderedCode
7+import Language.PureScript.Docs.RenderedCode.Types as RenderedCode
8−import Language.PureScript.Docs.RenderedCode.Render as RenderedCode
8+import Language.PureScript.Docs.RenderedCode.RenderType as RenderedCode
9+import Language.PureScript.Docs.RenderedCode.RenderKind as RenderedCode
src/Language/PureScript/Docs/RenderedCode/RenderKind.hsnew file+57
@@ -0,0 +1,57 @@
1+-- | Functions for producing RenderedCode values from PureScript Kind values.
2+--
3+module Language.PureScript.Docs.RenderedCode.RenderKind
4+ ( renderKind
5+ ) where
6+
7+-- TODO: This is pretty much copied from Language.PureScript.Pretty.Kinds.
8+-- Ideally we would unify the two.
9+
10+import Prelude.Compat
11+
12+import Control.Arrow (ArrowPlus(..))
13+import Control.PatternArrows as PA
14+
15+import Data.Monoid ((<>))
16+import Data.Maybe (fromMaybe)
17+import qualified Data.Text as T
18+
19+import Language.PureScript.Crash
20+import Language.PureScript.Kinds
21+
22+import Language.PureScript.Docs.RenderedCode.Types
23+
24+typeLiterals :: Pattern () Kind RenderedCode
25+typeLiterals = mkPattern match
26+ where
27+ match (KUnknown u) =
28+ Just $ typeVar $ T.cons 'k' (T.pack (show u))
29+ match (NamedKind n) =
30+ Just $ kind n
31+ match _ = Nothing
32+
33+matchRow :: Pattern () Kind ((), Kind)
34+matchRow = mkPattern match
35+ where
36+ match (Row k) = Just ((), k)
37+ match _ = Nothing
38+
39+funKind :: Pattern () Kind (Kind, Kind)
40+funKind = mkPattern match
41+ where
42+ match (FunKind arg ret) = Just (arg, ret)
43+ match _ = Nothing
44+
45+-- | Generate RenderedCode value representing a Kind
46+renderKind :: Kind -> RenderedCode
47+renderKind
48+ = fromMaybe (internalError "Incomplete pattern")
49+ . PA.pattern matchKind ()
50+ where
51+ matchKind :: Pattern () Kind RenderedCode
52+ matchKind = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchKind)
53+
54+ operators :: OperatorTable () Kind RenderedCode
55+ operators =
56+ OperatorTable [ [ Wrap matchRow $ \_ k -> syntax "#" <> sp <> k]
57+ , [ AssocR funKind $ \arg ret -> arg <> sp <> syntax "->" <> sp <> ret ] ]
src/Language/PureScript/Docs/RenderedCode/Render.hs → src/Language/PureScript/Docs/RenderedCode/RenderType.hsrenamed+25−32
@@ -1,13 +1,13 @@
1-- | Functions for producing RenderedCode values from PureScript Type values.
1-- | Functions for producing RenderedCode values from PureScript Type values.
2
2
3−module Language.PureScript.Docs.RenderedCode.Render
3+module Language.PureScript.Docs.RenderedCode.RenderType
4 ( renderType
4 ( renderType
5 , renderTypeAtom
5 , renderTypeAtom
6 , renderRow
6 , renderRow
7− , renderKind
8 , RenderTypeOptions(..)
7 , RenderTypeOptions(..)
9 , defaultRenderTypeOptions
8 , defaultRenderTypeOptions
10 , renderTypeWithOptions
9 , renderTypeWithOptions
10+ , renderTypeAtomWithOptions
11 ) where
11 ) where
12
12
13import Prelude.Compat
13import Prelude.Compat
@@ -20,39 +20,40 @@ import Control.Arrow ((<+>))
20import Control.PatternArrows as PA
20import Control.PatternArrows as PA
21
21
22import Language.PureScript.Crash
22import Language.PureScript.Crash
23−import Language.PureScript.Docs.RenderedCode.Types
24−import Language.PureScript.Docs.Utils.MonoidExtras
25import Language.PureScript.Environment
23import Language.PureScript.Environment
26import Language.PureScript.Kinds
24import Language.PureScript.Kinds
27import Language.PureScript.Names
25import Language.PureScript.Names
28−import Language.PureScript.Pretty.Kinds
29import Language.PureScript.Pretty.Types
26import Language.PureScript.Pretty.Types
30import Language.PureScript.Types
27import Language.PureScript.Types
31import Language.PureScript.Label (Label)
28import Language.PureScript.Label (Label)
32
29
30+import Language.PureScript.Docs.RenderedCode.Types
31+import Language.PureScript.Docs.Utils.MonoidExtras
32+import Language.PureScript.Docs.RenderedCode.RenderKind (renderKind)
33+
33typeLiterals :: Pattern () Type RenderedCode
34typeLiterals :: Pattern () Type RenderedCode
34typeLiterals = mkPattern match
35typeLiterals = mkPattern match
35 where
36 where
36 match TypeWildcard{} =
37 match TypeWildcard{} =
37 Just (syntax "_")
38 Just (syntax "_")
38 match (TypeVar var) =
39 match (TypeVar var) =
39− Just (ident var)
40+ Just (typeVar var)
40 match (PrettyPrintObject row) =
41 match (PrettyPrintObject row) =
41 Just $ mintersperse sp
42 Just $ mintersperse sp
42 [ syntax "{"
43 [ syntax "{"
43 , renderRow row
44 , renderRow row
44 , syntax "}"
45 , syntax "}"
45 ]
46 ]
46− match (TypeConstructor (Qualified mn name)) =
47+ match (TypeConstructor n) =
47− Just (ctor (runProperName name) (maybeToContainingModule mn))
48+ Just (typeCtor n)
48 match REmpty =
49 match REmpty =
49 Just (syntax "()")
50 Just (syntax "()")
50 match row@RCons{} =
51 match row@RCons{} =
51 Just (syntax "(" <> renderRow row <> syntax ")")
52 Just (syntax "(" <> renderRow row <> syntax ")")
52 match (BinaryNoParensType op l r) =
53 match (BinaryNoParensType op l r) =
53 Just $ renderTypeAtom l <> sp <> renderTypeAtom op <> sp <> renderTypeAtom r
54 Just $ renderTypeAtom l <> sp <> renderTypeAtom op <> sp <> renderTypeAtom r
54− match (TypeOp (Qualified mn op)) =
55+ match (TypeOp n) =
55− Just (ident' (runOpName op) (maybeToContainingModule mn))
56+ Just (typeOp n)
56 match _ =
57 match _ =
57 Nothing
58 Nothing
58
59
@@ -87,7 +88,7 @@ renderHead = mintersperse (syntax "," <> sp) . map renderLabel
87renderLabel :: (Label, Type) -> RenderedCode
88renderLabel :: (Label, Type) -> RenderedCode
88renderLabel (label, ty) =
89renderLabel (label, ty) =
89 mintersperse sp
90 mintersperse sp
90− [ syntax $ prettyPrintLabel label
91+ [ typeVar $ prettyPrintLabel label
91 , syntax "::"
92 , syntax "::"
92 , renderType ty
93 , renderType ty
93 ]
94 ]
@@ -139,7 +140,7 @@ matchType = buildPrettyPrinter operators matchTypeAtom
139 OperatorTable [ [ AssocL typeApp $ \f x -> f <> sp <> x ]
140 OperatorTable [ [ AssocL typeApp $ \f x -> f <> sp <> x ]
140 , [ AssocR appliedFunction $ \arg ret -> mintersperse sp [arg, syntax "->", ret] ]
141 , [ AssocR appliedFunction $ \arg ret -> mintersperse sp [arg, syntax "->", ret] ]
141 , [ Wrap constrained $ \deps ty -> renderConstraints deps ty ]
142 , [ Wrap constrained $ \deps ty -> renderConstraints deps ty ]
142− , [ Wrap forall_ $ \idents ty -> mconcat [syntax "forall", sp, mintersperse sp (map ident idents), syntax ".", sp, ty] ]
143+ , [ Wrap forall_ $ \tyVars ty -> mconcat [keywordForall, sp, mintersperse sp (map typeVar tyVars), syntax ".", sp, ty] ]
143 , [ Wrap kinded $ \k ty -> mintersperse sp [ty, syntax "::", renderKind k] ]
144 , [ Wrap kinded $ \k ty -> mintersperse sp [ty, syntax "::", renderKind k] ]
144 , [ Wrap explicitParens $ \_ ty -> ty ]
145 , [ Wrap explicitParens $ \_ ty -> ty ]
145 ]
146 ]
@@ -154,12 +155,6 @@ insertPlaceholders :: RenderTypeOptions -> Type -> Type
154insertPlaceholders opts =
155insertPlaceholders opts =
155 everywhereOnTypesTopDown convertForAlls . everywhereOnTypes (convert opts)
156 everywhereOnTypesTopDown convertForAlls . everywhereOnTypes (convert opts)
156
157
157−dePrim :: Type -> Type
158−dePrim ty@(TypeConstructor (Qualified _ name))
159− | ty == tyBoolean || ty == tyNumber || ty == tyString =
160− TypeConstructor $ Qualified Nothing name
161−dePrim other = other
162−
163convert :: RenderTypeOptions -> Type -> Type
158convert :: RenderTypeOptions -> Type -> Type
164convert _ (TypeApp (TypeApp f arg) ret) | f == tyFunction = PrettyPrintFunction arg ret
159convert _ (TypeApp (TypeApp f arg) ret) | f == tyFunction = PrettyPrintFunction arg ret
165convert opts (TypeApp o r) | o == tyRecord && prettyPrintObjects opts = PrettyPrintObject r
160convert opts (TypeApp o r) | o == tyRecord && prettyPrintObjects opts = PrettyPrintObject r
@@ -173,28 +168,20 @@ convertForAlls (ForAll i ty _) = go [i] ty
173convertForAlls other = other
168convertForAlls other = other
174
169
175preprocessType :: RenderTypeOptions -> Type -> Type
170preprocessType :: RenderTypeOptions -> Type -> Type
176−preprocessType opts = dePrim . insertPlaceholders opts
171+preprocessType opts = insertPlaceholders opts
172+
177
173
178-- |
174-- |
179−-- Render code representing a Kind
175+-- Render code representing a Type
180--
176--
181−renderKind :: Kind -> RenderedCode
177+renderType :: Type -> RenderedCode
182−renderKind = kind . prettyPrintKind
178+renderType = renderTypeWithOptions defaultRenderTypeOptions
183
179
184-- |
180-- |
185-- Render code representing a Type, as it should appear inside parentheses
181-- Render code representing a Type, as it should appear inside parentheses
186--
182--
187renderTypeAtom :: Type -> RenderedCode
183renderTypeAtom :: Type -> RenderedCode
188−renderTypeAtom
189− = fromMaybe (internalError "Incomplete pattern")
190− . PA.pattern matchTypeAtom ()
191− . preprocessType defaultRenderTypeOptions
192−
193−-- |
194−-- Render code representing a Type
195−--
196−renderType :: Type -> RenderedCode
197−renderType = renderTypeWithOptions defaultRenderTypeOptions
184+renderTypeAtom = renderTypeAtomWithOptions defaultRenderTypeOptions
198
185
199data RenderTypeOptions = RenderTypeOptions
186data RenderTypeOptions = RenderTypeOptions
200 { prettyPrintObjects :: Bool
187 { prettyPrintObjects :: Bool
@@ -213,3 +200,9 @@ renderTypeWithOptions opts
213 = fromMaybe (internalError "Incomplete pattern")
200 = fromMaybe (internalError "Incomplete pattern")
214 . PA.pattern matchType ()
201 . PA.pattern matchType ()
215 . preprocessType opts
202 . preprocessType opts
203+
204+renderTypeAtomWithOptions :: RenderTypeOptions -> Type -> RenderedCode
205+renderTypeAtomWithOptions opts
206+ = fromMaybe (internalError "Incomplete pattern")
207+ . PA.pattern matchTypeAtom ()
208+ . preprocessType opts
src/Language/PureScript/Docs/RenderedCode/Types.hs+251−74
@@ -1,4 +1,5 @@
1{-# LANGUAGE GeneralizedNewtypeDeriving #-}
1{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+{-# LANGUAGE DeriveGeneric #-}
2
3
3-- | Data types and functions for representing a simplified form of PureScript
4-- | Data types and functions for representing a simplified form of PureScript
4-- code, intended for use in e.g. HTML documentation.
5-- code, intended for use in e.g. HTML documentation.
@@ -11,15 +12,16 @@ module Language.PureScript.Docs.RenderedCode.Types
11 , containingModuleToMaybe
12 , containingModuleToMaybe
12 , maybeToContainingModule
13 , maybeToContainingModule
13 , fromContainingModule
14 , fromContainingModule
15+ , fromQualified
16+ , Namespace(..)
17+ , Link(..)
18+ , FixityAlias
14 , RenderedCode
19 , RenderedCode
15 , asRenderedCode
20 , asRenderedCode
16 , outputWith
21 , outputWith
17 , sp
22 , sp
23+ , parens
18 , syntax
24 , syntax
19− , ident
20− , ident'
21− , ctor
22− , kind
23 , keyword
25 , keyword
24 , keywordForall
26 , keywordForall
25 , keywordData
27 , keywordData
@@ -30,105 +32,216 @@ module Language.PureScript.Docs.RenderedCode.Types
30 , keywordWhere
32 , keywordWhere
31 , keywordFixity
33 , keywordFixity
32 , keywordKind
34 , keywordKind
35+ , keywordAs
36+ , ident
37+ , dataCtor
38+ , typeCtor
39+ , typeOp
40+ , typeVar
41+ , kind
42+ , alias
43+ , aliasName
33 ) where
44 ) where
34
45
35import Prelude.Compat
46import Prelude.Compat
47+import GHC.Generics (Generic)
36
48
49+import Control.DeepSeq (NFData)
37import Control.Monad.Error.Class (MonadError(..))
50import Control.Monad.Error.Class (MonadError(..))
38
51
52+import Data.Monoid ((<>))
39import Data.Aeson.BetterErrors
53import Data.Aeson.BetterErrors
40import qualified Data.Aeson as A
54import qualified Data.Aeson as A
41import Data.Text (Text)
55import Data.Text (Text)
56+import qualified Data.Text as T
57+import qualified Data.ByteString.Lazy as BS
58+import qualified Data.Text.Encoding as TE
42
59
60+import Language.PureScript.Names
43−import qualified Language.PureScript as P
61+import Language.PureScript.AST (Associativity(..))
62+import Language.PureScript.Crash (internalError)
44
63
45−-- |
64+-- | Given a list of actions, attempt them all, returning the first success.
46−-- A single element in a rendered code fragment. The intention is to support
65+-- If all the actions fail, 'tryAll' returns the first argument.
47−-- multiple output formats. For example, plain text, or highlighted HTML.
66+tryAll :: MonadError e m => m a -> [m a] -> m a
48−--
67+tryAll = foldr $ \x y -> catchError x (const y)
49−data RenderedCodeElement
50− = Syntax Text
51− | Ident Text ContainingModule
52− | Ctor Text ContainingModule
53− | Kind Text
54− | Keyword Text
55− | Space
56− deriving (Show, Eq, Ord)
57
68
58−instance A.ToJSON RenderedCodeElement where
69+firstEq :: Text -> Parse Text a -> Parse Text a
59− toJSON (Syntax str) =
70+firstEq str p = nth 0 (withText (eq str)) *> p
60− A.toJSON ["syntax", str]
61− toJSON (Ident str mn) =
62− A.toJSON ["ident", A.toJSON str, A.toJSON mn]
63− toJSON (Ctor str mn) =
64− A.toJSON ["ctor", A.toJSON str, A.toJSON mn ]
65− toJSON (Kind str) =
66− A.toJSON ["kind", str]
67− toJSON (Keyword str) =
68− A.toJSON ["keyword", str]
69− toJSON Space =
70− A.toJSON ["space" :: Text]
71−
72−asRenderedCodeElement :: Parse Text RenderedCodeElement
73−asRenderedCodeElement =
74− a Syntax "syntax" <|>
75− asIdent <|>
76− asCtor <|>
77− a Kind "kind" <|>
78− a Keyword "keyword" <|>
79− asSpace <|>
80− unableToParse
81 where
71 where
82− p <|> q = catchError p (const q)
72+ eq s s' = if s == s' then Right () else Left ""
83
73
84− a ctor' ctorStr = ctor' <$> (nth 0 (withText (eq ctorStr)) *> nth 1 asText)
74+-- |
85− asIdent = nth 0 (withText (eq "ident")) *> (Ident <$> nth 1 asText <*> nth 2 asContainingModule)
75+-- Try the given parsers in sequence. If all fail, fail with the given message,
86− asCtor = nth 0 (withText (eq "ctor")) *> (Ctor <$> nth 1 asText <*> nth 2 asContainingModule)
76+-- and include the JSON in the error.
87− asSpace = nth 0 (withText (eq "space")) *> pure Space
77+--
78+tryParse :: Text -> [Parse Text a] -> Parse Text a
79+tryParse msg =
80+ tryAll (withValue (Left . (fullMsg <>) . showJSON))
88
81
89− eq s s' = if s == s' then Right () else Left ""
82+ where
83+ fullMsg = "Invalid " <> msg <> ": "
90
84
91− unableToParse = withText Left
85+ showJSON :: A.Value -> Text
86+ showJSON = TE.decodeUtf8 . BS.toStrict . A.encode
92
87
93-- |
88-- |
94−-- This type is isomorphic to 'Maybe' 'P.ModuleName'. It makes code a bit easier
89+-- This type is isomorphic to 'Maybe' 'ModuleName'. It makes code a bit
95−-- to read, as the meaning is more explicit.
90+-- easier to read, as the meaning is more explicit.
96--
91--
97data ContainingModule
92data ContainingModule
98 = ThisModule
93 = ThisModule
99− | OtherModule P.ModuleName
94+ | OtherModule ModuleName
100 deriving (Show, Eq, Ord)
95 deriving (Show, Eq, Ord)
101
96
102instance A.ToJSON ContainingModule where
97instance A.ToJSON ContainingModule where
103− toJSON mn = A.toJSON (P.runModuleName <$> containingModuleToMaybe mn)
98+ toJSON = A.toJSON . go
99+ where
100+ go = \case
101+ ThisModule -> ["ThisModule"]
102+ OtherModule mn -> ["OtherModule", runModuleName mn]
104
103
104+instance A.FromJSON ContainingModule where
105+ parseJSON = toAesonParser id asContainingModule
106+
105−asContainingModule :: Parse e ContainingModule
107+asContainingModule :: Parse Text ContainingModule
106asContainingModule =
108asContainingModule =
109+ tryParse "containing module" $
110+ current ++ backwardsCompat
111+ where
112+ current =
113+ [ firstEq "ThisModule" (pure ThisModule)
114+ , firstEq "OtherModule" (OtherModule <$> nth 1 asModuleName)
115+ ]
116+
117+ -- For JSON produced by compilers up to 0.10.5.
118+ backwardsCompat =
107− maybeToContainingModule <$> perhaps (P.moduleNameFromString <$> asText)
119+ [ maybeToContainingModule <$> perhaps asModuleName
120+ ]
121+
122+ asModuleName = moduleNameFromString <$> asText
108
123
109-- |
124-- |
110−-- Convert a 'Maybe' 'P.ModuleName' to a 'ContainingModule', using the obvious
125+-- Convert a 'Maybe' 'ModuleName' to a 'ContainingModule', using the obvious
111-- isomorphism.
126-- isomorphism.
112--
127--
113−maybeToContainingModule :: Maybe P.ModuleName -> ContainingModule
128+maybeToContainingModule :: Maybe ModuleName -> ContainingModule
114maybeToContainingModule Nothing = ThisModule
129maybeToContainingModule Nothing = ThisModule
115maybeToContainingModule (Just mn) = OtherModule mn
130maybeToContainingModule (Just mn) = OtherModule mn
116
131
117-- |
132-- |
118−-- Convert a 'ContainingModule' to a 'Maybe' 'P.ModuleName', using the obvious
133+-- Convert a 'ContainingModule' to a 'Maybe' 'ModuleName', using the obvious
119-- isomorphism.
134-- isomorphism.
120--
135--
121−containingModuleToMaybe :: ContainingModule -> Maybe P.ModuleName
136+containingModuleToMaybe :: ContainingModule -> Maybe ModuleName
122containingModuleToMaybe ThisModule = Nothing
137containingModuleToMaybe ThisModule = Nothing
123containingModuleToMaybe (OtherModule mn) = Just mn
138containingModuleToMaybe (OtherModule mn) = Just mn
124
139
125-- |
140-- |
126-- A version of 'fromMaybe' for 'ContainingModule' values.
141-- A version of 'fromMaybe' for 'ContainingModule' values.
127--
142--
128−fromContainingModule :: P.ModuleName -> ContainingModule -> P.ModuleName
143+fromContainingModule :: ModuleName -> ContainingModule -> ModuleName
129fromContainingModule def ThisModule = def
144fromContainingModule def ThisModule = def
130fromContainingModule _ (OtherModule mn) = mn
145fromContainingModule _ (OtherModule mn) = mn
131
146
147+fromQualified :: Qualified a -> (ContainingModule, a)
148+fromQualified (Qualified mn x) =
149+ (maybeToContainingModule mn, x)
150+
151+data Link
152+ = NoLink
153+ | Link ContainingModule
154+ deriving (Show, Eq, Ord)
155+
156+instance A.ToJSON Link where
157+ toJSON = \case
158+ NoLink -> A.toJSON ["NoLink" :: Text]
159+ Link mn -> A.toJSON ["Link", A.toJSON mn]
160+
161+asLink :: Parse Text Link
162+asLink =
163+ tryParse "link"
164+ [ firstEq "NoLink" (pure NoLink)
165+ , firstEq "Link" (Link <$> nth 1 asContainingModule)
166+ ]
167+
168+instance A.FromJSON Link where
169+ parseJSON = toAesonParser id asLink
170+
171+data Namespace
172+ = ValueLevel
173+ | TypeLevel
174+ | KindLevel
175+ deriving (Show, Eq, Ord, Generic)
176+
177+instance NFData Namespace
178+
179+instance A.ToJSON Namespace where
180+ toJSON = A.toJSON . show
181+
182+asNamespace :: Parse Text Namespace
183+asNamespace =
184+ tryParse "namespace"
185+ [ withText $ \case
186+ "ValueLevel" -> Right ValueLevel
187+ "TypeLevel" -> Right TypeLevel
188+ "KindLevel" -> Right KindLevel
189+ _ -> Left ""
190+ ]
191+
192+instance A.FromJSON Namespace where
193+ parseJSON = toAesonParser id asNamespace
194+
195+-- |
196+-- A single element in a rendered code fragment. The intention is to support
197+-- multiple output formats. For example, plain text, or highlighted HTML.
198+--
199+data RenderedCodeElement
200+ = Syntax Text
201+ | Keyword Text
202+ | Space
203+ -- | Any symbol which you might or might not want to link to, in any
204+ -- namespace (value, type, or kind). Note that this is not related to the
205+ -- kind called Symbol for type-level strings.
206+ | Symbol Namespace Text Link
207+ deriving (Show, Eq, Ord)
208+
209+instance A.ToJSON RenderedCodeElement where
210+ toJSON (Syntax str) =
211+ A.toJSON ["syntax", str]
212+ toJSON (Keyword str) =
213+ A.toJSON ["keyword", str]
214+ toJSON Space =
215+ A.toJSON ["space" :: Text]
216+ toJSON (Symbol ns str link) =
217+ A.toJSON ["symbol", A.toJSON ns, A.toJSON str, A.toJSON link]
218+
219+asRenderedCodeElement :: Parse Text RenderedCodeElement
220+asRenderedCodeElement =
221+ tryParse "RenderedCodeElement" $
222+ [ a Syntax "syntax"
223+ , a Keyword "keyword"
224+ , asSpace
225+ , asSymbol
226+ ] ++ backwardsCompat
227+ where
228+ a ctor' ctorStr = firstEq ctorStr (ctor' <$> nth 1 asText)
229+ asSymbol = firstEq "symbol" (Symbol <$> nth 1 asNamespace <*> nth 2 asText <*> nth 3 asLink)
230+ asSpace = firstEq "space" (pure Space)
231+
232+ -- These will make some mistakes e.g. treating data constructors as types,
233+ -- because the old code did not save information which is necessary to
234+ -- distinguish these cases. This is the best we can do.
235+ backwardsCompat =
236+ [ oldAsIdent
237+ , oldAsCtor
238+ , oldAsKind
239+ ]
240+
241+ oldAsIdent = firstEq "ident" (Symbol ValueLevel <$> nth 1 asText <*> nth 2 (Link <$> asContainingModule))
242+ oldAsCtor = firstEq "ctor" (Symbol TypeLevel <$> nth 1 asText <*> nth 2 (Link <$> asContainingModule))
243+ oldAsKind = firstEq "kind" (Symbol KindLevel <$> nth 1 asText <*> pure (Link ThisModule))
244+
132-- |
245-- |
133-- A type representing a highly simplified version of PureScript code, intended
246-- A type representing a highly simplified version of PureScript code, intended
134-- for use in output formats like plain text or HTML.
247-- for use in output formats like plain text or HTML.
@@ -158,21 +271,17 @@ outputWith f = foldMap f . unRC
158sp :: RenderedCode
271sp :: RenderedCode
159sp = RC [Space]
272sp = RC [Space]
160
273
274+-- |
275+-- Wrap a RenderedCode value in parens.
276+parens :: RenderedCode -> RenderedCode
277+parens x = syntax "(" <> x <> syntax ")"
278+
279+-- possible TODO: instead of this function, export RenderedCode values for
280+-- each syntax element, eg syntaxArr (== syntax "->"), syntaxLBrace,
281+-- syntaxRBrace, etc.
161syntax :: Text -> RenderedCode
282syntax :: Text -> RenderedCode
162syntax x = RC [Syntax x]
283syntax x = RC [Syntax x]
163
284
164−ident :: Text -> RenderedCode
165−ident x = RC [Ident x ThisModule]
166−
167−ident' :: Text -> ContainingModule -> RenderedCode
168−ident' x m = RC [Ident x m]
169−
170−ctor :: Text -> ContainingModule -> RenderedCode
171−ctor x m = RC [Ctor x m]
172−
173−kind :: Text -> RenderedCode
174−kind x = RC [Kind x]
175−
176keyword :: Text -> RenderedCode
285keyword :: Text -> RenderedCode
177keyword kw = RC [Keyword kw]
286keyword kw = RC [Keyword kw]
178
287
@@ -197,10 +306,78 @@ keywordInstance = keyword "instance"
197keywordWhere :: RenderedCode
306keywordWhere :: RenderedCode
198keywordWhere = keyword "where"
307keywordWhere = keyword "where"
199
308
200−keywordFixity :: P.Associativity -> RenderedCode
309+keywordFixity :: Associativity -> RenderedCode
201−keywordFixity P.Infixl = keyword "infixl"
310+keywordFixity Infixl = keyword "infixl"
202−keywordFixity P.Infixr = keyword "infixr"
311+keywordFixity Infixr = keyword "infixr"
203−keywordFixity P.Infix = keyword "infix"
312+keywordFixity Infix = keyword "infix"
204
313
205keywordKind :: RenderedCode
314keywordKind :: RenderedCode
206keywordKind = keyword "kind"
315keywordKind = keyword "kind"
316+
317+keywordAs :: RenderedCode
318+keywordAs = keyword "as"
319+
320+ident :: Qualified Ident -> RenderedCode
321+ident (fromQualified -> (mn, name)) =
322+ RC [Symbol ValueLevel (runIdent name) (Link mn)]
323+
324+dataCtor :: Qualified (ProperName 'ConstructorName) -> RenderedCode
325+dataCtor (fromQualified -> (mn, name)) =
326+ RC [Symbol ValueLevel (runProperName name) (Link mn)]
327+
328+typeCtor :: Qualified (ProperName 'TypeName) -> RenderedCode
329+typeCtor (fromQualified -> (mn, name)) =
330+ RC [Symbol TypeLevel (runProperName name) (Link mn)]
331+
332+typeOp :: Qualified (OpName 'TypeOpName) -> RenderedCode
333+typeOp (fromQualified -> (mn, name)) =
334+ RC [Symbol TypeLevel (runOpName name) (Link mn)]
335+
336+typeVar :: Text -> RenderedCode
337+typeVar x = RC [Symbol TypeLevel x NoLink]
338+
339+kind :: Qualified (ProperName 'KindName) -> RenderedCode
340+kind (fromQualified -> (mn, name)) =
341+ RC [Symbol KindLevel (runProperName name) (Link mn)]
342+
343+type FixityAlias = Qualified (Either (ProperName 'TypeName) (Either Ident (ProperName 'ConstructorName)))
344+
345+alias :: FixityAlias -> RenderedCode
346+alias for =
347+ prefix <> RC [Symbol ns name (Link mn)]
348+ where
349+ (ns, name, mn) = unpackFixityAlias for
350+ prefix = case ns of
351+ TypeLevel ->
352+ keywordType <> sp
353+ _ ->
354+ mempty
355+
356+aliasName :: FixityAlias -> Text -> RenderedCode
357+aliasName for name' =
358+ let
359+ (ns, _, _) = unpackFixityAlias for
360+ unParen = T.tail . T.init
361+ name = unParen name'
362+ in
363+ case ns of
364+ ValueLevel ->
365+ ident (Qualified Nothing (Ident name))
366+ TypeLevel ->
367+ typeCtor (Qualified Nothing (ProperName name))
368+ KindLevel ->
369+ internalError "Kind aliases are not supported"
370+
371+-- | Converts a FixityAlias into a different representation which is more
372+-- useful to other functions in this module.
373+unpackFixityAlias :: FixityAlias -> (Namespace, Text, ContainingModule)
374+unpackFixityAlias (fromQualified -> (mn, x)) =
375+ case x of
376+ -- We add some seemingly superfluous type signatures here just to be extra
377+ -- sure we are not mixing up our namespaces.
378+ Left (n :: ProperName 'TypeName) ->
379+ (TypeLevel, runProperName n, mn)
380+ Right (Left n) ->
381+ (ValueLevel, runIdent n, mn)
382+ Right (Right (n :: ProperName 'ConstructorName)) ->
383+ (ValueLevel, runProperName n, mn)
src/Language/PureScript/Docs/Types.hs+33−3
@@ -28,7 +28,8 @@ import Web.Bower.PackageMeta hiding (Version, displayError)
28import Language.PureScript.Docs.RenderedCode as ReExports
28import Language.PureScript.Docs.RenderedCode as ReExports
29 (RenderedCode, asRenderedCode,
29 (RenderedCode, asRenderedCode,
30 ContainingModule(..), asContainingModule,
30 ContainingModule(..), asContainingModule,
31− RenderedCodeElement(..), asRenderedCodeElement)
31+ RenderedCodeElement(..), asRenderedCodeElement,
32+ Namespace(..), FixityAlias)
32
33
33--------------------
34--------------------
34-- Types
35-- Types
@@ -183,8 +184,6 @@ convertFundepsToStrings args fundeps =
183 ) $ argsVec V.!? i
184 ) $ argsVec V.!? i
184 toArgs from to = (map getArg from, map getArg to)
185 toArgs from to = (map getArg from, map getArg to)
185
186
186−type FixityAlias = P.Qualified (Either (P.ProperName 'P.TypeName) (Either P.Ident (P.ProperName 'P.ConstructorName)))
187−
188declInfoToString :: DeclarationInfo -> Text
187declInfoToString :: DeclarationInfo -> Text
189declInfoToString (ValueDeclaration _) = "value"
188declInfoToString (ValueDeclaration _) = "value"
190declInfoToString (DataDeclaration _ _) = "data"
189declInfoToString (DataDeclaration _ _) = "data"
@@ -194,6 +193,23 @@ declInfoToString (TypeClassDeclaration _ _ _) = "typeClass"
194declInfoToString (AliasDeclaration _ _) = "alias"
193declInfoToString (AliasDeclaration _ _) = "alias"
195declInfoToString ExternKindDeclaration = "kind"
194declInfoToString ExternKindDeclaration = "kind"
196
195
196+declInfoNamespace :: DeclarationInfo -> Namespace
197+declInfoNamespace = \case
198+ ValueDeclaration{} ->
199+ ValueLevel
200+ DataDeclaration{} ->
201+ TypeLevel
202+ ExternDataDeclaration{} ->
203+ TypeLevel
204+ TypeSynonymDeclaration{} ->
205+ TypeLevel
206+ TypeClassDeclaration{} ->
207+ TypeLevel
208+ AliasDeclaration _ alias ->
209+ either (const TypeLevel) (const ValueLevel) (P.disqualify alias)
210+ ExternKindDeclaration{} ->
211+ KindLevel
212+
197isTypeClass :: Declaration -> Bool
213isTypeClass :: Declaration -> Bool
198isTypeClass Declaration{..} =
214isTypeClass Declaration{..} =
199 case declInfo of
215 case declInfo of
@@ -269,6 +285,20 @@ childDeclInfoToString (ChildInstance _ _) = "instance"
269childDeclInfoToString (ChildDataConstructor _) = "dataConstructor"
285childDeclInfoToString (ChildDataConstructor _) = "dataConstructor"
270childDeclInfoToString (ChildTypeClassMember _) = "typeClassMember"
286childDeclInfoToString (ChildTypeClassMember _) = "typeClassMember"
271
287
288+childDeclInfoNamespace :: ChildDeclarationInfo -> Namespace
289+childDeclInfoNamespace =
290+ -- We could just write this as `const ValueLevel` but by doing it this way,
291+ -- if another constructor is added, we get a warning which acts as a prompt
292+ -- to update this, instead of having this function (possibly incorrectly)
293+ -- just return ValueLevel for the new constructor.
294+ \case
295+ ChildInstance{} ->
296+ ValueLevel
297+ ChildDataConstructor{} ->
298+ ValueLevel
299+ ChildTypeClassMember{} ->
300+ ValueLevel
301+
272isTypeClassMember :: ChildDeclaration -> Bool
302isTypeClassMember :: ChildDeclaration -> Bool
273isTypeClassMember ChildDeclaration{..} =
303isTypeClassMember ChildDeclaration{..} =
274 case cdeclInfo of
304 case cdeclInfo of