on 5fcbf86 help sign in
elk/src/Parse/Module.hs
295 lines 7.0 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Parse.Module
4 ( module_
5 , chompImports
6 , freshLine
7 )
8 where
11import qualified Data.ByteString as B
12import Data.Text (Text)
14import qualified AST.Source as Src
15import qualified Elm.Name as N
16import Parse.Primitives (Parser, oneOf)
17import qualified Parse.Primitives as P
18import qualified Parse.Primitives.Keyword as Keyword
19import qualified Parse.Primitives.Symbol as Symbol
20import qualified Parse.Primitives.Variable as Var
21import qualified Parse.Primitives.Whitespace as W
22import qualified Reporting.Annotation as A
23import qualified Reporting.Error.Syntax as E
24import qualified Reporting.Region as R
28-- HEADER
31module_ :: Parser decls -> Parser (Src.Module decls)
32module_ chompDecls =
33 do freshLine
34 oneOf
35 [ do start <- P.getPosition
36 P.pushContext start E.Module
37 (name, effects) <- chompNameAndEffects
38 P.hint E.Exposing $ Keyword.exposing_
39 P.spaces
40 exports <- exposing
41 P.popContext ()
42 docs <- maybeDocComment
43 imports <- chompImports []
44 decls <- chompDecls
45 return (Src.Module name effects docs exports imports decls)
46 , Src.defaultModule
47 <$> chompImports []
48 <*> chompDecls
49 ]
53-- MODULE NAME
54--
55-- module MyThing
56-- port module MyThing
57-- effect module MyThing where { command = MyCmd }
58--
59chompNameAndEffects :: Parser (N.Name, Src.Effects)
60chompNameAndEffects =
61 oneOf
62 [
63 do Keyword.module_
64 P.spaces
65 name <- Var.moduleName
66 P.spaces
67 return ( name, Src.NoEffects )
68 ,
69 do start <- P.getPosition
70 Keyword.port_
71 P.spaces
72 Keyword.module_
73 end <- P.getPosition
74 P.spaces
75 name <- Var.moduleName
76 P.spaces
77 return ( name, Src.Ports (R.Region start end) )
78 ,
79 do start <- P.getPosition
80 Keyword.effect_
81 P.spaces
82 Keyword.module_
83 end <- P.getPosition
84 P.spaces
85 name <- Var.moduleName
86 P.spaces
87 manager <- chompManager
88 return ( name, Src.Manager (R.Region start end) manager )
89 ]
93-- MANAGER
94--
95-- where { command = MyCmd }
96-- where { subscription = MySub }
97-- where { command = MyCmd, subscription = MySub }
98--
99chompManager :: Parser Src.Manager
100chompManager =
101 do Keyword.where_
102 P.spaces
103 Symbol.leftCurly
104 P.spaces
105 oneOf
106 [ do cmd <- chompCommand
107 P.spaces
108 oneOf
109 [ do Symbol.rightCurly
110 P.spaces
111 return (Src.Cmd cmd)
112 , do Symbol.comma
113 P.spaces
114 sub <- chompSubscription
115 P.spaces
116 Symbol.rightCurly
117 P.spaces
118 return (Src.Fx cmd sub)
119 ]
120 , do sub <- chompSubscription
121 P.spaces
122 oneOf
123 [ do Symbol.rightCurly
124 P.spaces
125 return (Src.Sub sub)
126 , do Symbol.comma
127 P.spaces
128 cmd <- chompCommand
129 P.spaces
130 Symbol.rightCurly
131 P.spaces
132 return (Src.Fx cmd sub)
133 ]
134 ]
137chompCommand :: Parser (A.Located Text)
138chompCommand =
139 do Keyword.command_
140 P.spaces
141 Symbol.equals
142 P.spaces
143 P.addLocation Var.upper
146chompSubscription :: Parser (A.Located Text)
147chompSubscription =
148 do Keyword.subscription_
149 P.spaces
150 Symbol.equals
151 P.spaces
152 P.addLocation Var.upper
156-- DOC COMMENTS
159maybeDocComment :: Parser (A.Located (Maybe B.ByteString))
160maybeDocComment =
161 do oldEnd <- P.getPosition
162 freshLine
163 newStart <- P.getPosition
164 oneOf
165 [ do doc <- W.docComment
166 end <- P.getPosition
167 freshLine
168 return (A.at newStart end (Just doc))
169 , return (A.at oldEnd newStart Nothing)
170 ]
174-- IMPORTS
177chompImports :: [Src.Import] -> Parser [Src.Import]
178chompImports imports =
179 oneOf
180 [ do start <- P.getPosition
181 Keyword.import_
182 P.pushContext start E.Import
183 P.spaces
184 name <- P.addLocation Var.moduleName
185 pos <- W.whitespace
186 oneOf
187 [ do P.checkFreshLine pos
188 P.popContext ()
189 chompImports $
190 Src.Import name Nothing (Src.Explicit []) : imports
191 , do P.checkSpace pos
192 oneOf
193 [ chompAs name imports
194 , chompExposing name Nothing imports
195 ]
196 ]
197 , return (reverse imports)
198 ]
201chompAs :: A.Located Text -> [Src.Import] -> Parser [Src.Import]
202chompAs name imports =
203 do Keyword.as_
204 P.spaces
205 alias <- Var.upper
206 pos <- W.whitespace
207 oneOf
208 [ do P.checkFreshLine pos
209 P.popContext ()
210 chompImports $
211 Src.Import name (Just alias) (Src.Explicit []) : imports
212 , do P.checkSpace pos
213 chompExposing name (Just alias) imports
214 ]
217chompExposing :: A.Located Text -> Maybe Text -> [Src.Import] -> Parser [Src.Import]
218chompExposing name maybeAlias imports =
219 do Keyword.exposing_
220 P.spaces
221 exposed <- exposing
222 freshLine
223 P.popContext ()
224 chompImports $
225 Src.Import name maybeAlias exposed : imports
229-- LISTING
232exposing :: Parser Src.Exposing
233exposing =
234 P.hint E.Listing $
235 do Symbol.leftParen
236 P.spaces
237 oneOf
238 [ do Symbol.doubleDot
239 P.spaces
240 Symbol.rightParen
241 return Src.Open
242 , do entry <- P.addLocation chompEntry
243 P.spaces
244 exposingHelp [entry]
245 ]
248exposingHelp :: [A.Located Src.Exposed] -> Parser Src.Exposing
249exposingHelp revEntries =
250 oneOf
251 [ do Symbol.comma
252 P.spaces
253 entry <- P.addLocation chompEntry
254 P.spaces
255 exposingHelp (entry:revEntries)
256 , do Symbol.rightParen
257 return (Src.Explicit (reverse revEntries))
258 ]
261chompEntry :: Parser Src.Exposed
262chompEntry =
263 oneOf
264 [ Src.Lower <$> Var.lower
265 , do Symbol.leftParen
266 op <- Symbol.binop
267 Symbol.rightParen
268 return (Src.Lower op)
269 , do name <- Var.upper
270 P.spaces
271 Src.Upper name <$> privacy
272 ]
275privacy :: Parser Src.Privacy
276privacy =
277 oneOf
278 [ do Symbol.leftParen
279 P.spaces
280 Symbol.doubleDot
281 P.spaces
282 Symbol.rightParen
283 return Src.Public
284 , return Src.Private
285 ]
289-- FRESH LINES
292freshLine :: Parser ()
293freshLine =
294 P.checkFreshLine =<< W.whitespace