@@ -9,6 +9,7 @@
9-- Portability :
9-- Portability :
12+-- Constants, and utility functions to be used when parsing
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
@@ -25,6 +26,9 @@ import qualified Text.Parsec.Token as PT
26import Language.PureScript.Names
27import Language.PureScript.Names
30+-- A list of reserved identifiers
28reservedNames :: [String]
32reservedNames :: [String]
29reservedNames = [ "case"
33reservedNames = [ "case"
@@ -76,28 +80,52 @@ reservedNames = [ "case"
76 , "instance"
80 , "instance"
77 , "where" ]
81 , "where" ]
84+-- A list of built-in operator names
79builtInOperators :: [String]
86builtInOperators :: [String]
80builtInOperators = [ "~", "-", "<=", ">=", "<", ">", "*", "/", "%", "++", "+", "<<", ">>>", ">>"
87builtInOperators = [ "~", "-", "<=", ">=", "<", ">", "*", "/", "%", "++", "+", "<<", ">>>", ">>"
81 , "==", "!=", "&&", "||", "&", "^", "|", "!!", "!" ]
88 , "==", "!=", "&&", "||", "&", "^", "|", "!!", "!" ]
91+-- A list of reserved operators
83reservedOpNames :: [String]
93reservedOpNames :: [String]
84reservedOpNames = builtInOperators ++ [ "=>", "->", "=", ".", "\\" ]
94reservedOpNames = builtInOperators ++ [ "=>", "->", "=", ".", "\\" ]
97+-- Valid first characters for an identifier
86identStart :: P.Parsec String u Char
99identStart :: P.Parsec String u Char
87identStart = P.lower <|> P.oneOf "_"
100identStart = P.lower <|> P.oneOf "_"
103+-- Valid first characters for a proper name
89properNameStart :: P.Parsec String u Char
105properNameStart :: P.Parsec String u Char
90properNameStart = P.upper
106properNameStart = P.upper
109+-- Valid identifier characters
92identLetter :: P.Parsec String u Char
111identLetter :: P.Parsec String u Char
93identLetter = P.alphaNum <|> P.oneOf "_'"
112identLetter = P.alphaNum <|> P.oneOf "_'"
115+-- Valid first characters for an operator
95opStart :: P.Parsec String u Char
117opStart :: P.Parsec String u Char
96opStart = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
118opStart = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
121+-- Valid operators characters
98opLetter :: P.Parsec String u Char
123opLetter :: P.Parsec String u Char
99opLetter = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
124opLetter = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
127+-- The PureScript language definition
101langDef :: PT.GenLanguageDef String u Identity
129langDef :: PT.GenLanguageDef String u Identity
102langDef = PT.LanguageDef
130langDef = PT.LanguageDef
103 { PT.reservedNames = reservedNames
131 { PT.reservedNames = reservedNames
@@ -113,104 +141,209 @@ langDef = PT.LanguageDef
113 , PT.caseSensitive = True
141 , PT.caseSensitive = True
145+-- A token parser based on the language definition
116tokenParser :: PT.GenTokenParser String u Identity
147tokenParser :: PT.GenTokenParser String u Identity
117tokenParser = PT.makeTokenParser langDef
148tokenParser = PT.makeTokenParser langDef
119lexeme :: P.Parsec String u a -> P.Parsec String u a
153lexeme :: P.Parsec String u a -> P.Parsec String u a
120lexeme = PT.lexeme tokenParser
154lexeme = PT.lexeme tokenParser
157+-- Parse an identifier
122identifier :: P.Parsec String u String
159identifier :: P.Parsec String u String
123identifier = PT.identifier tokenParser
160identifier = PT.identifier tokenParser
163+-- Parse a reserved word
125reserved :: String -> P.Parsec String u ()
165reserved :: String -> P.Parsec String u ()
126reserved = PT.reserved tokenParser
166reserved = PT.reserved tokenParser
169+-- Parse a reserved operator
128reservedOp :: String -> P.Parsec String u ()
171reservedOp :: String -> P.Parsec String u ()
129reservedOp = PT.reservedOp tokenParser
172reservedOp = PT.reservedOp tokenParser
131operator :: P.Parsec String u String
177operator :: P.Parsec String u String
132operator = PT.operator tokenParser
178operator = PT.operator tokenParser
181+-- Parse a string literal
134stringLiteral :: P.Parsec String u String
183stringLiteral :: P.Parsec String u String
135stringLiteral = PT.stringLiteral tokenParser
184stringLiteral = PT.stringLiteral tokenParser
137whiteSpace :: P.Parsec String u ()
189whiteSpace :: P.Parsec String u ()
138whiteSpace = PT.whiteSpace tokenParser
190whiteSpace = PT.whiteSpace tokenParser
140semi :: P.Parsec String u String
195semi :: P.Parsec String u String
141semi = PT.semi tokenParser
196semi = PT.semi tokenParser
143colon :: P.Parsec String u String
201colon :: P.Parsec String u String
144colon = PT.colon tokenParser
202colon = PT.colon tokenParser
146dot :: P.Parsec String u String
207dot :: P.Parsec String u String
147dot = PT.dot tokenParser
208dot = PT.dot tokenParser
149comma :: P.Parsec String u String
213comma :: P.Parsec String u String
150comma = PT.comma tokenParser
214comma = PT.comma tokenParser
152tick :: P.Parsec String u Char
219tick :: P.Parsec String u Char
153tick = lexeme $ P.char '`'
220tick = lexeme $ P.char '`'
155pipe :: P.Parsec String u Char
225pipe :: P.Parsec String u Char
156pipe = lexeme $ P.char '|'
226pipe = lexeme $ P.char '|'
158natural :: P.Parsec String u Integer
231natural :: P.Parsec String u Integer
159natural = PT.natural tokenParser
232natural = PT.natural tokenParser
235+-- Parse a proper name
237+properName :: P.Parsec String u ProperName
238+properName = lexeme $ ProperName <$> P.try ((:) <$> P.upper <*> many (PT.identLetter langDef) P.<?> "name")
241+-- Parse a qualified name, i.e. M.name or just name
243+parseQualified :: P.Parsec String ParseState a -> P.Parsec String ParseState (Qualified a)
244+parseQualified parser = qual
246+ qual = (Qualified <$> (Just . ModuleName <$> P.try (properName <* delimiter)) <*> parser)
247+ <|> (Qualified Nothing <$> P.try parser)
248+ delimiter = indented *> dot
251+-- Parse an integer or floating point value
253+integerOrFloat :: P.Parsec String u (Either Integer Double)
254+integerOrFloat = (Left <$> P.try (PT.natural tokenParser) <|>
255+ Right <$> P.try (PT.float tokenParser)) P.<?> "number"
258+-- Parse an operator or a built-in operator
260+operatorOrBuiltIn :: P.Parsec String u String
261+operatorOrBuiltIn = P.try operator <|> P.choice (map (\s -> P.try (reservedOp s) >> return s) builtInOperators)
264+-- Parse an identifier or parenthesized operator
266+parseIdent :: P.Parsec String ParseState Ident
267+parseIdent = (Ident <$> identifier) <|> (Op <$> parens operatorOrBuiltIn)
270+-- Parse a token inside square brackets
161squares :: P.Parsec String ParseState a -> P.Parsec String ParseState a
272squares :: P.Parsec String ParseState a -> P.Parsec String ParseState a
162squares = P.between (lexeme $ P.char '[') (lexeme $ indented *> P.char ']') . (indented *>)
273squares = P.between (lexeme $ P.char '[') (lexeme $ indented *> P.char ']') . (indented *>)
276+-- Parse a token inside parentheses
164parens :: P.Parsec String ParseState a -> P.Parsec String ParseState a
278parens :: P.Parsec String ParseState a -> P.Parsec String ParseState a
165parens = P.between (lexeme $ P.char '(') (lexeme $ indented *> P.char ')') . (indented *>)
279parens = P.between (lexeme $ P.char '(') (lexeme $ indented *> P.char ')') . (indented *>)
282+-- Parse a token inside braces
167braces :: P.Parsec String ParseState a -> P.Parsec String ParseState a
284braces :: P.Parsec String ParseState a -> P.Parsec String ParseState a
168braces = P.between (lexeme $ P.char '{') (lexeme $ indented *> P.char '}') . (indented *>)
285braces = P.between (lexeme $ P.char '{') (lexeme $ indented *> P.char '}') . (indented *>)
288+-- Parse a token inside angle brackets
170angles :: P.Parsec String ParseState a -> P.Parsec String ParseState a
290angles :: P.Parsec String ParseState a -> P.Parsec String ParseState a
171angles = P.between (lexeme $ P.char '<') (lexeme $ indented *> P.char '>') . (indented *>)
291angles = P.between (lexeme $ P.char '<') (lexeme $ indented *> P.char '>') . (indented *>)
294+-- Parse zero or more values separated by a separator token
173sepBy :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
296sepBy :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
174sepBy p s = P.sepBy (indented *> p) (indented *> s)
297sepBy p s = P.sepBy (indented *> p) (indented *> s)
300+-- Parse one or more values separated by a separator token
176sepBy1 :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
302sepBy1 :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
177sepBy1 p s = P.sepBy1 (indented *> p) (indented *> s)
303sepBy1 p s = P.sepBy1 (indented *> p) (indented *> s)
306+-- Parse zero or more values separated by semicolons
179semiSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
308semiSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
180semiSep = flip sepBy semi
309semiSep = flip sepBy semi
312+-- Parse one or more values separated by semicolons
182semiSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
314semiSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
183semiSep1 = flip sepBy1 semi
315semiSep1 = flip sepBy1 semi
318+-- Parse zero or more values separated by commas
185commaSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
320commaSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
186commaSep = flip sepBy comma
321commaSep = flip sepBy comma
324+-- Parse one or more values separated by commas
188commaSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
326commaSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
189commaSep1 = flip sepBy1 comma
327commaSep1 = flip sepBy1 comma
191−properName :: P.Parsec String u ProperName
329+-- |
192−properName = lexeme $ ProperName <$> P.try ((:) <$> P.upper <*> many (PT.identLetter langDef) P.<?> "name")
330+-- Run the first parser, then match the second if possible, applying the specified function on a successful match
194−parseQualified :: P.Parsec String ParseState a -> P.Parsec String ParseState (Qualified a)
195−parseQualified parser = qual
197− qual = (Qualified <$> (Just . ModuleName <$> P.try (properName <* delimiter)) <*> parser)
198− <|> (Qualified Nothing <$> P.try parser)
199− delimiter = indented *> dot
201−integerOrFloat :: P.Parsec String u (Either Integer Double)
202−integerOrFloat = (Left <$> P.try (PT.natural tokenParser) <|>
203− Right <$> P.try (PT.float tokenParser)) P.<?> "number"
205augment :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a
332augment :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a
206augment p q f = flip (maybe id $ flip f) <$> p <*> P.optionMaybe q
333augment p q f = flip (maybe id $ flip f) <$> p <*> P.optionMaybe q
336+-- Run the first parser, then match the second zero or more times, applying the specified function for each match
208fold :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a
338fold :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a
209fold first more combine = do
339fold first more combine = do
210 a <- first
340 a <- first
211 bs <- P.many more
341 bs <- P.many more
212 return $ foldl combine a bs
342 return $ foldl combine a bs
345+-- Build a parser from a smaller parser and a list of parsers for postfix operators
214buildPostfixParser :: P.Stream s m t => [a -> P.ParsecT s u m a] -> P.ParsecT s u m a -> P.ParsecT s u m a
347buildPostfixParser :: P.Stream s m t => [a -> P.ParsecT s u m a] -> P.ParsecT s u m a -> P.ParsecT s u m a
215buildPostfixParser fs first = do
348buildPostfixParser fs first = do
216 a <- first
349 a <- first
@@ -222,15 +355,15 @@ buildPostfixParser fs first = do
222 Nothing -> return a
355 Nothing -> return a
223 Just a' -> go a'
356 Just a' -> go a'
225−operatorOrBuiltIn :: P.Parsec String u String
358+-- |
226−operatorOrBuiltIn = P.try operator <|> P.choice (map (\s -> P.try (reservedOp s) >> return s) builtInOperators)
359+-- Parse an identifier in backticks or an operator
228−parseIdent :: P.Parsec String ParseState Ident
229−parseIdent = (Ident <$> identifier) <|> (Op <$> parens operatorOrBuiltIn)
231parseIdentInfix :: P.Parsec String ParseState (Qualified Ident)
361parseIdentInfix :: P.Parsec String ParseState (Qualified Ident)
232parseIdentInfix = (P.between tick tick (parseQualified (Ident <$> identifier))) <|> parseQualified (Op <$> operatorOrBuiltIn)
362parseIdentInfix = (P.between tick tick (parseQualified (Ident <$> identifier))) <|> parseQualified (Op <$> operatorOrBuiltIn)
365+-- Mark the current indentation level
234mark :: P.Parsec String ParseState a -> P.Parsec String ParseState a
367mark :: P.Parsec String ParseState a -> P.Parsec String ParseState a
235mark p = do
368mark p = do
236 current <- indentationLevel <$> P.getState
369 current <- indentationLevel <$> P.getState
@@ -240,17 +373,29 @@ mark p = do
240 P.modifyState $ \st -> st { indentationLevel = current }
373 P.modifyState $ \st -> st { indentationLevel = current }
377+-- Check that the current identation level matches a predicate
243checkIndentation :: (P.Column -> P.Column -> Bool) -> P.Parsec String ParseState ()
379checkIndentation :: (P.Column -> P.Column -> Bool) -> P.Parsec String ParseState ()
244checkIndentation rel = do
380checkIndentation rel = do
245 col <- P.sourceColumn <$> P.getPosition
381 col <- P.sourceColumn <$> P.getPosition
246 current <- indentationLevel <$> P.getState
382 current <- indentationLevel <$> P.getState
247 guard (col `rel` current)
383 guard (col `rel` current)
386+-- Check that the current indentation level is past the current mark
249indented :: P.Parsec String ParseState ()
388indented :: P.Parsec String ParseState ()
250indented = checkIndentation (>) P.<?> "indentation"
389indented = checkIndentation (>) P.<?> "indentation"
392+-- Check that the current indentation level is at the same indentation as the current mark
252same :: P.Parsec String ParseState ()
394same :: P.Parsec String ParseState ()
253same = checkIndentation (==) P.<?> "no indentation"
395same = checkIndentation (==) P.<?> "no indentation"
398+-- Run a parser which supports indentation
255runIndentParser :: P.Parsec String ParseState a -> String -> Either P.ParseError a
400runIndentParser :: P.Parsec String ParseState a -> String -> Either P.ParseError a
256runIndentParser p = P.runParser p (ParseState 0) ""
401runIndentParser p = P.runParser p (ParseState 0) ""