on master help sign in
Get docComment parsing working again
commitf284fab1553148f968ebf32375598d98a78853a9 authorEvan Czaplicki <evancz@users.noreply.github.com> dateMon 12 Dec 2016, 15:54 (10 years ago) parent12c5078
6 files changed+179−93
src/AST/Module.hs+7−7 src/Canonicalize.hs+1−1 src/Docs/Check.hs+106−71 src/Elm/Compiler.hs+2−2 src/Parse/Module.hs+11−7 src/Parse/Primitives.hs+52−5
src/AST/Module.hs+7−7
@@ -46,7 +46,7 @@ data Header imports =
4646 , _name :: Name.Raw
4747 , _exports :: Var.Listing (A.Located Var.Value)
4848 , _settings :: SourceSettings
49− , _docs :: Maybe (A.Located Text)
49+ , _docs :: A.Located (Maybe Text)
5050 , _imports :: imports
5151 }
5252
@@ -56,9 +56,9 @@ instance Show (Header a) where
5656 show (_name header)
5757
5858
59−defaultHeader :: imports -> Header imports
60−defaultHeader imports_ =
61− Header Normal "Main" Var.openListing emptySettings Nothing imports_
59+defaultHeader :: R.Position -> R.Position -> imports -> Header imports
60+defaultHeader start end imports_ =
61+ Header Normal "Main" Var.openListing emptySettings (A.at start end Nothing) imports_
6262
6363
6464
@@ -81,7 +81,7 @@ data SourceInfo =
8181 Source
8282 { srcTag :: SourceTag
8383 , srcSettings :: SourceSettings
84− , srcDocs :: Maybe (A.Located Text)
84+ , srcDocs :: A.Located (Maybe Text)
8585 , srcExports :: Var.Listing (A.Located Var.Value)
8686 , srcImports :: [UserImport]
8787 , srcDecls :: [Decl.Source]
@@ -109,7 +109,7 @@ type Valid =
109109
110110data ValidInfo =
111111 Valid
112− { validDocs :: Maybe (A.Located Text)
112+ { validDocs :: A.Located (Maybe Text)
113113 , validExports :: Var.Listing (A.Located Var.Value)
114114 , validImports :: ([DefaultImport], [UserImport])
115115 , validDecls :: Decl.Valid
@@ -148,7 +148,7 @@ data ImportMethod =
148148
149149data Info program =
150150 Info
151− { docs :: Maybe (A.Located Docs.Centralized)
151+ { docs :: A.Located (Maybe Docs.Centralized)
152152 , exports :: [Var.Value]
153153 , imports :: [Name.Raw]
154154 , program :: program
src/Canonicalize.hs+1−1
@@ -79,7 +79,7 @@ module' allCanonicalImports interfaces modul =
7979 canonicalDecls
8080
8181 centralizedDocs =
82− fmap (A.map (Docs.centralize canonicalDecls)) docs
82+ A.map (fmap (Docs.centralize canonicalDecls)) docs
8383
8484 typeToPair (A.A _ (D.Type name args body)) =
8585 ( name, (args, body) )
src/Docs/Check.hs+106−71
@@ -1,84 +1,91 @@
1−module Docs.Check (Result, check) where
1+module Docs.Check (check) where
22
3−--import qualified Data.List as List
4−--import qualified Data.Map as Map
5−--import qualified Data.Set as Set
6−--import qualified Data.Traversable as T
3+import qualified Data.List as List
4+import qualified Data.Map as Map
5+import qualified Data.Set as Set
6+import Data.Text (Text)
77
88import qualified AST.Variable as Var
99import qualified Docs.AST as Docs
10−--import qualified Elm.Compiler.Type as Type
11−--import Elm.Utils ((|>))
12−--import Parse.Helpers
10+import qualified Elm.Compiler.Type as Type
11+import Elm.Utils ((|>))
1312import qualified Reporting.Annotation as A
14−import qualified Reporting.Error.Docs as Error
15−--import qualified Reporting.Error.Helpers as Error (nearbyNames)
16−--import qualified Reporting.Region as R
13+import qualified Reporting.Error as Error
14+import qualified Reporting.Error.Docs as E
15+import qualified Reporting.Helpers as Help (nearbyNames)
16+import qualified Reporting.Region as R
1717import qualified Reporting.Result as R
18+import Parse.Helpers
19+ ( Parser, addLocation, getPosition
20+ , spaces, checkSpace, whitespace, SPos(..)
21+ , capVar, lowVar, leftParen, rightParen, infixOp, runAt
22+ , chompUntilDocs, comma, oneOf
23+ )
1824
1925
2026
21−type Result w a =
22− R.Result () w Error.Error a
23−
24−
2527-- CHECK DOCUMENTATION
2628
27−check :: [Var.Value] -> Maybe (A.Located Docs.Centralized) -> Result w Docs.Checked
28−check exports maybeDocs =
29− R.ok (error "TODO check docs" exports maybeDocs)
30−{-
29+
30+check :: [Var.Value] -> A.Located (Maybe Docs.Centralized) -> R.Result () w Error.Error Docs.Checked
31+check exports (A.A region maybeDocs) =
3132 case maybeDocs of
3233 Nothing ->
33− R.throw region Error.NoDocs
34+ R.throw region (Error.Docs E.NoDocs)
3435
3536 Just docs ->
36− checkHelp region exports docs
37+ checkHelp region exports docs
3738
3839
39−checkHelp :: R.Region -> [Var.Value] -> Docs.Centralized -> Result w Docs.Checked
40+checkHelp :: R.Region -> [Var.Value] -> Docs.Centralized -> R.Result () w Error.Error Docs.Checked
4041checkHelp region exports (Docs.Docs comment aliases types values) =
4142 let
42− docNames =
43− commentedNames region comment
44−
45− docSet =
46− Set.fromList (map A.drop docNames)
47−
48− checkCategory checkValue dict =
49− dict
50− |> Map.filterWithKey (\key _ -> Set.member key docSet)
51− |> Map.mapWithKey checkValue
52− |> T.traverse id
53−
5443 exportedUnions =
5544 map (\(tipe, Var.Listing tags _) -> (tipe, tags)) (Var.getUnions exports)
5645 in
57− (\() -> Docs.Docs comment)
58− <$> checkModuleComment region exports docNames
59− <*> checkCategory (checkComment Docs.aliasComment) aliases
60− <*> checkCategory (checkUnion exportedUnions) types
61− <*> checkCategory checkValue values
46+ do docNames <- parseNames region comment
47+ let docSet = Set.fromList (map A.drop docNames)
48+ R.mapError Error.Docs $
49+ (\() -> Docs.Docs comment)
50+ <$> checkModuleComment region exports docNames
51+ <*> checkCategory docSet (checkComment Docs.aliasComment) aliases
52+ <*> checkCategory docSet (checkUnion exportedUnions) types
53+ <*> checkCategory docSet checkValue values
54+
6255
56+type Result w a = R.Result () w E.Error a
6357
64−checkComment :: (a -> Maybe String) -> String -> A.Located a -> Result w (A.Located a)
58+
59+checkCategory
60+ :: Set.Set Text
61+ -> (Text -> a -> Result w b)
62+ -> Map.Map Text a
63+ -> Result w (Map.Map Text b)
64+checkCategory docSet check dict =
65+ dict
66+ |> Map.filterWithKey (\key _ -> Set.member key docSet)
67+ |> Map.mapWithKey check
68+ |> traverse id
69+
70+
71+checkComment :: (a -> Maybe Text) -> Text -> A.Located a -> Result w (A.Located a)
6572checkComment getComment name (A.A region value) =
6673 case getComment value of
6774 Nothing ->
68− R.throw region (Error.NoComment name)
75+ R.throw region (E.NoComment name)
6976
7077 Just _ ->
7178 R.ok (A.A region value)
7279
7380
74−checkUnion :: [(String, [String])] -> String -> A.Located Docs.Union -> Result w (A.Located Docs.Union)
81+checkUnion :: [(Text, [Text])] -> Text -> A.Located Docs.Union -> Result w (A.Located Docs.Union)
7582checkUnion exportedUnions name value =
7683 const
7784 <$> filterUnionTags exportedUnions name value
7885 <*> checkComment Docs.unionComment name value
7986
8087
81−filterUnionTags :: [(String, [String])] -> String -> A.Located Docs.Union -> Result w (A.Located Docs.Union)
88+filterUnionTags :: [(Text, [Text])] -> Text -> A.Located Docs.Union -> Result w (A.Located Docs.Union)
8289filterUnionTags exportedUnions name (A.A region union@(Docs.Union _ _ ctors)) =
8390 let
8491 exportedTags =
@@ -91,26 +98,28 @@ filterUnionTags exportedUnions name (A.A region union@(Docs.Union _ _ ctors)) =
9198
9299
93100
94−checkValue :: String -> A.Located (Docs.Value (Maybe Type.Type)) -> Result w (A.Located (Docs.Value Type.Type))
101+checkValue :: Text -> A.Located (Docs.Value (Maybe Type.Type)) -> Result w (A.Located (Docs.Value Type.Type))
95102checkValue name value =
96103 const
97104 <$> hasType name value
98105 <*> checkComment Docs.valueComment name value
99106
100107
101−hasType :: String -> A.Located (Docs.Value (Maybe Type.Type)) -> Result w (A.Located (Docs.Value Type.Type))
108+hasType :: Text -> A.Located (Docs.Value (Maybe Type.Type)) -> Result w (A.Located (Docs.Value Type.Type))
102109hasType name (A.A region value) =
103110 case Docs.valueType value of
104111 Just tipe ->
105112 R.ok (A.A region (value { Docs.valueType = tipe }))
106113
107114 Nothing ->
108− R.throw region (Error.NoType name)
115+ R.throw region (E.NoType name)
116+
109117
110118
111119-- CHECK MODULE COMMENT
112120
113−checkModuleComment :: R.Region -> [Var.Value] -> [A.Located String] -> Result w ()
121+
122+checkModuleComment :: R.Region -> [Var.Value] -> [A.Located Text] -> Result w ()
114123checkModuleComment docRegion exports locatedDocNames =
115124 let
116125 exportNames =
@@ -123,12 +132,12 @@ checkModuleComment docRegion exports locatedDocNames =
123132 Map.fromList (map (\(A.A region name) -> (name, region)) locatedDocNames)
124133
125134 extraNameError (name, region) =
126− R.throw region (Error.OnlyInDocs name (Error.nearbyNames id name exportNames))
135+ R.throw region (E.OnlyInDocs name (Help.nearbyNames id name exportNames))
127136
128137 docErrors =
129138 Map.difference docDict exportDict
130139 |> Map.toList
131− |> T.traverse extraNameError
140+ |> traverse extraNameError
132141
133142 namesOnlyInExports =
134143 Map.difference exportDict docDict
@@ -139,41 +148,67 @@ checkModuleComment docRegion exports locatedDocNames =
139148 if null namesOnlyInExports then
140149 R.ok ()
141150 else
142− R.throw docRegion (Error.OnlyInExports namesOnlyInExports)
151+ R.throw docRegion (E.OnlyInExports namesOnlyInExports)
143152 in
144153 (\_ _ -> ())
145154 <$> exportErrors
146155 <*> docErrors
147156
148157
149−commentedNames :: R.Region -> String -> [A.Located String]
150−commentedNames (R.Region (R.Position line column) _) comment =
151− let
152− nameParser =
153− choice
154− [ do string "@docs"
155− whitespace
156− commaSep1 (addLocation (var <|> parens infixOp))
157− , do anyUntil simpleNewline
158− return []
158+
159+-- PARSE DOC COMMENT
160+
161+
162+parseNames :: R.Region -> Text -> R.Result () w Error.Error [A.Located Text]
163+parseNames (R.Region (R.Position row col) _) comment =
164+ case runAt row (col + 3) (namesParser []) comment of
165+ Left (A.A region parseError) ->
166+ R.throw region (Error.Syntax parseError)
167+
168+ Right names ->
169+ R.ok names
170+
171+
172+
173+namesParser :: [A.Located Text] -> Parser [A.Located Text]
174+namesParser names =
175+ do isDocs <- chompUntilDocs
176+ if isDocs then namesParserHelp names else return names
177+
178+
179+namesParserHelp :: [A.Located Text] -> Parser [A.Located Text]
180+namesParserHelp names =
181+ do pos <- getPosition
182+ (SPos spos) <- whitespace
183+ if pos == spos
184+ then namesParser names
185+ else namesParser =<< chompNames names
186+
187+
188+chompNames :: [A.Located Text] -> Parser [A.Located Text]
189+chompNames names =
190+ do name <- addLocation (oneOf [ lowVar, capVar, operator ])
191+ spos <- whitespace
192+ oneOf
193+ [ do checkSpace spos
194+ comma
195+ spaces
196+ chompNames (name:names)
197+ , return names
159198 ]
160199
161− docCommentParser =
162− do setPosition (newPos "docs" line (column + 3))
163− concat <$> many nameParser
164− in
165− case parse docCommentParser comment of
166− Left _ ->
167− []
168200
169− Right names ->
170− names
201+operator :: Parser Text
202+operator =
203+ do leftParen
204+ op <- infixOp
205+ rightParen
206+ return op
171207
172208
173−valueName :: Var.Value -> String
209+valueName :: Var.Value -> Text
174210valueName value =
175211 case value of
176212 Var.Value name -> name
177213 Var.Alias name -> name
178214 Var.Union name _ -> name
179−-}
src/Elm/Compiler.hs+2−2
@@ -96,7 +96,7 @@ compile context source interfaces =
9696
9797 (Result.Result oneLocalizer warnings answer) =
9898 do modul <- Compile.compile packageName dependencies interfaces source
99− docs <- Result.format Error.Docs (docsGen isExposed modul)
99+ docs <- Result.format id (docsGen isExposed modul)
100100
101101 let interface = Module.toInterface packageName modul
102102 let javascript = {-# SCC elm_compiler_generate #-} JS.generate modul
@@ -124,7 +124,7 @@ data Result = Result
124124 }
125125
126126
127−docsGen :: Bool -> Module.Optimized -> Docs.Result w (Maybe Docs.Documentation)
127+docsGen :: Bool -> Module.Optimized -> Result.Result () w Error.Error (Maybe Docs.Documentation)
128128docsGen isExposed (Module.Module name _ info) =
129129 if not isExposed then
130130 Result.ok Nothing
src/Parse/Module.hs+11−7
@@ -17,10 +17,12 @@ import qualified Reporting.Region as R
1717
1818header :: Parser (Module.Header [Module.UserImport])
1919header =
20− do freshLine
20+ do start <- getPosition
21+ freshLine
22+ end <- getPosition
2123 oneOf
2224 [ fullHeader
23− , Module.defaultHeader <$> chompImports []
25+ , Module.defaultHeader start end <$> chompImports []
2426 ]
2527
2628
@@ -38,8 +40,10 @@ fullHeader =
3840 keyword "exposing" -- TODO <?> "something like `exposing (..)` which replaced `where` in 0.17"
3941 spaces
4042 exports <- listing (addLocation listingValue)
43+ start <- getPosition
4144 freshLine
42− docs <- maybeDocComment
45+ end <- getPosition
46+ docs <- maybeDocComment start end
4347 imports <- chompImports []
4448 return (Module.Header tag name exports settings docs imports)
4549
@@ -119,13 +123,13 @@ setting =
119123-- DOC COMMENTS
120124
121125
122−maybeDocComment :: Parser (Maybe (A.Located Text))
123−maybeDocComment =
126+maybeDocComment :: R.Position -> R.Position -> Parser (A.Located (Maybe Text))
127+maybeDocComment start end =
124128 oneOf
125129 [ do doc <- addLocation docComment
126130 freshLine
127− return (Just doc)
128− , return Nothing
131+ return (A.map Just doc)
132+ , return (A.at start end Nothing)
129133 ]
130134
131135
src/Parse/Primitives.hs+52−5
@@ -2,7 +2,7 @@
22{-# LANGUAGE BangPatterns, Rank2Types, UnboxedTuples, OverloadedStrings #-}
33module Parse.Primitives
44 ( Parser
5− , run
5+ , run, runAt
66 , try, failure, deadend, expecting, endOfFile
77 , oneOf
88 , symbol, keyword, keywords
@@ -10,7 +10,7 @@ module Parse.Primitives
1010 , getPosition, getCol
1111 , getIndent, setIndent
1212 , SPos(..), whitespace
13− , docComment
13+ , docComment, chompUntilDocs
1414 , string, character
1515 , digit, number
1616 , shaderSource, shaderFailure
@@ -92,8 +92,13 @@ loneTheory row col theory =
9292
9393
9494run :: Parser a -> Text -> Either (A.Located E.Error) a
95−run parser (Text.Text array offset length) =
96− case _run parser (State array offset length 0 1 1) Ok Err Ok Err of
95+run parser text =
96+ runAt 1 1 parser text
97+
98+
99+runAt :: Int -> Int -> Parser a -> Text -> Either (A.Located E.Error) a
100+runAt sRow sCol parser (Text.Text array offset length) =
101+ case _run parser (State array offset length 0 sRow sCol) Ok Err Ok Err of
97102 Ok value _ ->
98103 Right value
99104
@@ -270,7 +275,7 @@ moveCursor array offset length row col =
270275 let
271276 !word = Text.unsafeIndex array offset
272277 in
273− if word == 0x000A then
278+ if word == 0x000A {- \n -} then
274279 moveCursor array (offset + 1) (length - 1) (row + 1) 1
275280
276281 else if word < 0xD800 || word > 0xDBFF then
@@ -652,6 +657,48 @@ docComment =
652657 (State array newOffset newLength indent newRow newCol)
653658
654659
660+chompUntilDocs :: Parser Bool
661+chompUntilDocs =
662+ Parser $ \(State array offset length indent row col) cok _ _ _ ->
663+ let
664+ (# isStart, newOffset, newLength, newRow, newCol #) =
665+ eatDocs array offset length row col
666+ in
667+ cok isStart (State array newOffset newLength indent newRow newCol)
668+
669+
670+eatDocs :: Text.Array -> Int -> Int -> Int -> Int -> (# Bool, Int, Int, Int, Int #)
671+eatDocs array offset length row col =
672+ if length == 0 then
673+ (# False, offset, length, row, col #)
674+
675+ else if isDocsStart array offset length then
676+ (# True, offset + 5, length - 5, row, col + 5 #)
677+
678+ else
679+ let
680+ !word = Text.unsafeIndex array offset
681+ in
682+ if word == 0x000A {- \n -} then
683+ eatDocs array (offset + 1) (length - 1) (row + 1) 1
684+
685+ else if word < 0xD800 || word > 0xDBFF then
686+ eatDocs array (offset + 1) (length - 1) row (col + 1)
687+
688+ else
689+ eatDocs array (offset + 2) (length - 2) row (col + 1)
690+
691+
692+isDocsStart :: Text.Array -> Int -> Int -> Bool
693+isDocsStart array offset length =
694+ length >= 5
695+ && Text.unsafeIndex array offset == 0x0040 {- @ -}
696+ && Text.unsafeIndex array (offset + 1) == 0x0064 {- d -}
697+ && Text.unsafeIndex array (offset + 2) == 0x006F {- o -}
698+ && Text.unsafeIndex array (offset + 3) == 0x0063 {- c -}
699+ && Text.unsafeIndex array (offset + 4) == 0x0073 {- s -}
700+
701+
655702
656703-- STRINGS
657704