@@ -20,6 +20,7 @@ import qualified AST.Helpers as Help
20import qualified AST.Literal as L
20import qualified AST.Literal as L
21import qualified AST.PrettyPrint as P
21import qualified AST.PrettyPrint as P
22import qualified AST.Variable as Variable
22import qualified AST.Variable as Variable
23+import Elm.Utils ((|>))
24reserveds :: [String]
25reserveds :: [String]
25reserveds =
26reserveds =
@@ -33,66 +34,91 @@ reserveds =
33 , "deriving", "port"
34 , "deriving", "port"
36expecting = flip (<?>)
38expecting = flip (<?>)
38type OpTable = Map.Map String (Int, Decl.Assoc)
41type OpTable = Map.Map String (Int, Decl.Assoc)
39type SourceM = State SourcePos
42type SourceM = State SourcePos
40type IParser a = ParsecT String OpTable SourceM a
43type IParser a = ParsecT String OpTable SourceM a
42iParse :: IParser a -> String -> Either ParseError a
46iParse :: IParser a -> String -> Either ParseError a
47+iParse parser source =
43−iParse = iParseWithTable "" Map.empty
48+ iParseWithTable "" Map.empty parser source
45iParseWithTable :: SourceName -> OpTable -> IParser a -> String -> Either ParseError a
51iParseWithTable :: SourceName -> OpTable -> IParser a -> String -> Either ParseError a
46iParseWithTable sourceName table aParser input =
52iParseWithTable sourceName table aParser input =
47 runIndent sourceName $ runParserT aParser table sourceName input
53 runIndent sourceName $ runParserT aParser table sourceName input
49var :: IParser String
58var :: IParser String
50−var = makeVar (letter <|> char '_' <?> "variable")
60+ makeVar (letter <|> char '_' <?> "variable")
52lowVar :: IParser String
63lowVar :: IParser String
53−lowVar = makeVar (lower <?> "lower case variable")
65+ makeVar (lower <?> "lower case variable")
54capVar :: IParser String
68capVar :: IParser String
55−capVar = makeVar (upper <?> "upper case variable")
70+ makeVar (upper <?> "upper case variable")
57qualifiedVar :: IParser String
73qualifiedVar :: IParser String
58−qualifiedVar = do
74+qualifiedVar =
59− vars <- many ((++) <$> capVar <*> string ".")
75+ do vars <- many ((++) <$> capVar <*> string ".")
60− (++) (concat vars) <$> lowVar
76+ (++) (concat vars) <$> lowVar
62rLabel :: IParser String
79rLabel :: IParser String
63rLabel = lowVar
80rLabel = lowVar
65innerVarChar :: IParser Char
83innerVarChar :: IParser Char
66−innerVarChar = alphaNum <|> char '_' <|> char '\'' <?> ""
85+ alphaNum <|> char '_' <|> char '\'' <?> ""
68makeVar :: IParser Char -> IParser String
88makeVar :: IParser Char -> IParser String
69−makeVar p = do
89+makeVar p =
70− v <- (:) <$> p <*> many innerVarChar
90+ do v <- (:) <$> p <*> many innerVarChar
71− if v `elem` reserveds
91+ if v `elem` reserveds
72− then fail $ "unexpected keyword '" ++ v ++ "', variables cannot be keywords"
92+ then fail $ "unexpected keyword '" ++ v ++ "', variables cannot be keywords"
73− else return v
93+ else return v
75reserved :: String -> IParser String
96reserved :: String -> IParser String
76reserved word =
97reserved word =
77− try (string word >> notFollowedBy innerVarChar) >> return word
98+ (try (string word >> notFollowedBy innerVarChar) >> return word)
78 <?> "reserved word '" ++ word ++ "'"
99 <?> "reserved word '" ++ word ++ "'"
80anyOp :: IParser String
104anyOp :: IParser String
81−anyOp = betwixt '`' '`' qualifiedVar <|> symOp <?> "infix operator (e.g. +, *, ||)"
106+ betwixt '`' '`' qualifiedVar
108+ <?> "infix operator"
83symOp :: IParser String
111symOp :: IParser String
84−symOp = do op <- many1 (satisfy Help.isSymbol)
113+ do op <- many1 (satisfy Help.isSymbol)
85− guard (op `notElem` [ "=", "..", "->", "--", "|", "\8594", ":" ])
114+ guard (op `notElem` [ "=", "..", "->", "--", "|", "\8594", ":" ])
86− case op of
115+ case op of
87− "." -> notFollowedBy lower >> return op
116+ "." -> notFollowedBy lower >> return op
88− "\8728" -> return "."
117+ "\8728" -> return "."
89− _ -> return op
118+ _ -> return op
91−padded :: IParser a -> IParser a
120+
92−padded p = do whitespace
121+-- COMMON SYMBOLS
97equals :: IParser String
123equals :: IParser String
98equals = string "="
124equals = string "="
@@ -104,58 +130,86 @@ hasType :: IParser String
104hasType = string ":" <?> "':' (a type annotation)'"
130hasType = string ":" <?> "':' (a type annotation)'"
107−commitIf check p = commit <|> try p
133+commitIf check p =
108− where commit = do (try $ lookAhead check) >> p
137+ try (lookAhead check) >> p
110spaceySepBy1 :: IParser b -> IParser a -> IParser [a]
142spaceySepBy1 :: IParser b -> IParser a -> IParser [a]
111−spaceySepBy1 sep p = do
143+spaceySepBy1 sep p =
112− a <- p
144+ do a <- p
113− (a:) <$> many (commitIf (whitespace >> sep) (padded sep >> p))
145+ (a:) <$> many (commitIf (whitespace >> sep) (padded sep >> p))
116commaSep1 :: IParser a -> IParser [a]
148commaSep1 :: IParser a -> IParser [a]
117−commaSep1 = spaceySepBy1 (char ',' <?> "comma ','")
150+ spaceySepBy1 (char ',' <?> "comma ','")
119commaSep :: IParser a -> IParser [a]
153commaSep :: IParser a -> IParser [a]
120−commaSep = option [] . commaSep1
155+ option [] . commaSep1
122semiSep1 :: IParser a -> IParser [a]
158semiSep1 :: IParser a -> IParser [a]
123−semiSep1 = spaceySepBy1 (char ';' <?> "semicolon ';'")
160+ spaceySepBy1 (char ';' <?> "semicolon ';'")
125pipeSep1 :: IParser a -> IParser [a]
163pipeSep1 :: IParser a -> IParser [a]
126−pipeSep1 = spaceySepBy1 (char '|' <?> "type divider '|'")
165+ spaceySepBy1 (char '|' <?> "type divider '|'")
128consSep1 :: IParser a -> IParser [a]
168consSep1 :: IParser a -> IParser [a]
129−consSep1 = spaceySepBy1 (string "::" <?> "cons operator '::'")
170+ spaceySepBy1 (string "::" <?> "cons operator '::'")
131dotSep1 :: IParser a -> IParser [a]
173dotSep1 :: IParser a -> IParser [a]
132−dotSep1 p = (:) <$> p <*> many (try (char '.') >> p)
175+ (:) <$> p <*> many (try (char '.') >> p)
134spaceSep1 :: IParser a -> IParser [a]
178spaceSep1 :: IParser a -> IParser [a]
135−spaceSep1 p = (:) <$> p <*> spacePrefix p
180+ (:) <$> p <*> spacePrefix p
184+ constrainedSpacePrefix p (\_ -> return ())
137−spacePrefix p = constrainedSpacePrefix p (\_ -> return ())
139constrainedSpacePrefix p constraint =
187constrainedSpacePrefix p constraint =
140− many $ choice [ try (spacing >> lookAhead (oneOf "[({")) >> p
189+ [ try (spacing >> lookAhead (oneOf "[({")) >> p
141− , try (spacing >> p)
190+ , try (spacing >> p)
144 spacing = do
193 spacing = do
145 n <- whitespace
194 n <- whitespace
146 constraint n
195 constraint n
155−followedBy a b = do x <- a ; b ; return x
201+followedBy a b =
210+ char b <?> "closing '" ++ [b] ++ "'"
157−betwixt a b c = do char a ; out <- c
158− char b <?> "closing '" ++ [b] ++ "'" ; return out
160surround a z name p = do
214surround a z name p = do
@@ -163,170 +217,252 @@ surround a z name p = do
163 char z <?> unwords ["closing", name, show z]
217 char z <?> unwords ["closing", name, show z]
166−braces :: IParser a -> IParser a
167−braces = surround '[' ']' "brace"
221+braces :: IParser a -> IParser a
223+ surround '[' ']' "brace"
169−parens :: IParser a -> IParser a
226+parens :: IParser a -> IParser a
170−parens = surround '(' ')' "paren"
228+ surround '(' ')' "paren"
172brackets :: IParser a -> IParser a
231brackets :: IParser a -> IParser a
173−brackets = surround '{' '}' "bracket"
233+ surround '{' '}' "bracket"
236+-- HELPERS FOR EXPRESSIONS
175addLocation :: (P.Pretty a) => IParser a -> IParser (Annotation.Located a)
238addLocation :: (P.Pretty a) => IParser a -> IParser (Annotation.Located a)
176−addLocation expr = do
239+addLocation expr =
177− (start, e, end) <- located expr
240+ do (start, e, end) <- located expr
178− return (Annotation.at start end e)
241+ return (Annotation.at start end e)
180located :: IParser a -> IParser (SourcePos, a, SourcePos)
244located :: IParser a -> IParser (SourcePos, a, SourcePos)
181−located p = do
245+located p =
182− start <- getPosition
246+ do start <- getPosition
184− end <- getPosition
248+ end <- getPosition
185− return (start, e, end)
249+ return (start, e, end)
187accessible :: IParser Source.Expr -> IParser Source.Expr
252accessible :: IParser Source.Expr -> IParser Source.Expr
188−accessible expr = do
253+accessible expr =
189− start <- getPosition
254+ do start <- getPosition
190− ce@(Annotation.A _ e) <- expr
255+ ce@(Annotation.A _ e) <- expr
191− let rest f = do
256+ let rest f = do
192− let dot = char '.' >> notFollowedBy (char '.')
257+ let dot = char '.' >> notFollowedBy (char '.')
193− access <- optionMaybe (try dot <?> "field access (e.g. List.map)")
258+ access <- optionMaybe (try dot <?> "field access (e.g. List.map)")
194− case access of
259+ case access of
195− Nothing -> return ce
260+ Nothing -> return ce
196− Just _ -> accessible $ do
261+ Just _ -> accessible $ do
197− v <- var <?> "field access (e.g. List.map)"
262+ v <- var <?> "field access (e.g. List.map)"
198− end <- getPosition
263+ end <- getPosition
199− return (Annotation.at start end (f v))
264+ return (Annotation.at start end (f v))
200− case e of
265+ case e of
201− E.Var (Variable.Raw (c:cs))
266+ E.Var (Variable.Raw (c:cs))
202− | isUpper c -> rest (\v -> E.rawVar (c:cs ++ '.':v))
267+ | isUpper c -> rest (\v -> E.rawVar (c:cs ++ '.':v))
203− | otherwise -> rest (E.Access ce)
268+ | otherwise -> rest (E.Access ce)
204− _ -> rest (E.Access ce)
269+ _ -> rest (E.Access ce)
274+padded :: IParser a -> IParser a
207spaces :: IParser String
282spaces :: IParser String
208−spaces = concat <$> many1 (multiComment <|> string " ") <?> "spaces"
284+ concat <$> many1 (string " " <|> multiComment) <?> "spaces"
210forcedWS :: IParser String
287forcedWS :: IParser String
211−forcedWS = choice [ try $ (++) <$> spaces <*> (concat <$> many nl_space)
290+ [ try $ (++) <$> spaces <*> (concat <$> many nl_space)
212− , try $ concat <$> many1 nl_space ]
291+ , try $ concat <$> many1 nl_space
213− where nl_space = try ((++) <$> (concat <$> many1 newline) <*> spaces)
295+ try ((++) <$> (concat <$> many1 newline) <*> spaces)
215-- Just eats whitespace until the next meaningful character.
298-- Just eats whitespace until the next meaningful character.
216dumbWhitespace :: IParser String
299dumbWhitespace :: IParser String
217−dumbWhitespace = concat <$> many (spaces <|> newline)
301+ concat <$> many (spaces <|> newline)
219whitespace :: IParser String
304whitespace :: IParser String
220−whitespace = option "" forcedWS <?> "whitespace"
306+ option "" forcedWS
222freshLine :: IParser [[String]]
309freshLine :: IParser [[String]]
223−freshLine = try (many1 newline >> many space_nl) <|> try (many1 space_nl) <?> ""
311+ try (many1 newline >> many space_nl) <|> try (many1 space_nl) <?> ""
224− where space_nl = try $ spaces >> many1 newline
313+ space_nl = try $ spaces >> many1 newline
226newline :: IParser String
316newline :: IParser String
227−newline = simpleNewline <|> lineComment <?> "newline"
318+ simpleNewline <|> lineComment <?> "newline"
229simpleNewline :: IParser String
321simpleNewline :: IParser String
230−simpleNewline = try (string "\r\n") <|> string "\n"
323+ try (string "\r\n") <|> string "\n"
232lineComment :: IParser String
326lineComment :: IParser String
233−lineComment = do
327+lineComment =
234− try (string "--")
328+ do try (string "--")
235− comment <- anyUntil $ simpleNewline <|> (eof >> return "\n")
329+ comment <- anyUntil $ simpleNewline <|> (eof >> return "\n")
236− return ("--" ++ comment)
330+ return ("--" ++ comment)
238multiComment :: IParser String
333multiComment :: IParser String
239−multiComment = (++) <$> try (string "{-") <*> closeComment
335+ (++) <$> try (string "{-") <*> closeComment
241closeComment :: IParser String
338closeComment :: IParser String
242closeComment =
339closeComment =
243− anyUntil . choice $
340+ anyUntil $
244− [ try (string "-}") <?> "close comment"
342+ [ try (string "-}") <?> "close comment"
245− , concat <$> sequence [ try (string "{-"), closeComment, closeComment ]
343+ , concat <$> sequence [ try (string "{-"), closeComment, closeComment ]
248until :: IParser a -> IParser b -> IParser b
356until :: IParser a -> IParser b -> IParser b
249−until p end = go
357+until p end =
251− go = end <|> (p >> go)
360+ go = end <|> (p >> go)
253anyUntil :: IParser String -> IParser String
363anyUntil :: IParser String -> IParser String
254−anyUntil end = go
364+anyUntil end =
256− go = end <|> (:) <$> anyChar <*> go
368+ end <|> (:) <$> anyChar <*> go
258ignoreUntil :: IParser a -> IParser (Maybe a)
371ignoreUntil :: IParser a -> IParser (Maybe a)
259−ignoreUntil end = go
372+ignoreUntil end =
261− ignore p = const () <$> p
375+ ignore p =
262− filler = choice [ try (ignore chr) <|> ignore str
380+ [ try (ignore chr) <|> ignore str
263− , ignore multiComment
381+ , ignore multiComment
264− , ignore markdown
382+ , ignore markdown
265− , ignore anyChar
383+ , ignore anyChar
267− go = choice [ Just <$> end
388+ [ Just <$> end
268− , filler `until` choice [ const Nothing <$> eof, newline >> go ]
389+ , filler `until` choice [ const Nothing <$> eof, newline >> go ]
271onFreshLines :: (a -> b -> b) -> b -> IParser a -> IParser b
393onFreshLines :: (a -> b -> b) -> b -> IParser a -> IParser b
272−onFreshLines insert init thing = go init
394+onFreshLines insert init thing =
274− go values = do
397+ go values =
275− optionValue <- ignoreUntil thing
398+ do optionValue <- ignoreUntil thing
276− case optionValue of
399+ case optionValue of
277− Nothing -> return values
400+ Nothing -> return values
278− Just v -> go (insert v values)
401+ Just v -> go (insert v values)
280withSource :: IParser a -> IParser (String, a)
404withSource :: IParser a -> IParser (String, a)
281−withSource p = do
405+withSource p =
282− start <- getParserState
406+ do start <- getParserState
283− result <- p
407+ result <- p
284− endPos <- getPosition
408+ endPos <- getPosition
285− setParserState start
409+ setParserState start
286− raw <- anyUntilPos endPos
410+ raw <- anyUntilPos endPos
287− return (raw, result)
411+ return (raw, result)
289anyUntilPos :: SourcePos -> IParser String
414anyUntilPos :: SourcePos -> IParser String
290−anyUntilPos pos = go
415+anyUntilPos pos =
292− go = do currentPos <- getPosition
418+ go = do currentPos <- getPosition
293− case currentPos == pos of
419+ case currentPos == pos of
294− True -> return []
420+ True -> return []
295− False -> (:) <$> anyChar <*> go
421+ False -> (:) <$> anyChar <*> go
424+-- BASIC LANGUAGE LITERALS
297markdown :: IParser String
426markdown :: IParser String
298markdown =
427markdown =
299− do try (string "[markdown|")
428+ do try (string "[markdown|")
300− closeMarkdown id
429+ closeMarkdown id
302− closeMarkdown markdownBuilder =
431+ closeMarkdown markdownBuilder =
303− choice [ do try (string "|]")
433+ [ do try (string "|]")
304− return (markdownBuilder "")
434+ return (markdownBuilder "")
305− , do c <- anyChar
435+ , do c <- anyChar
306− closeMarkdown (markdownBuilder . (c:))
436+ closeMarkdown (markdownBuilder . (c:))
309shader :: IParser (String, L.GLShaderTipe)
440shader :: IParser (String, L.GLShaderTipe)
311− do try (string "[glsl|")
442+ do try (string "[glsl|")
312− rawSrc <- closeShader id
443+ rawSrc <- closeShader id
313− case glSource rawSrc of
444+ case glSource rawSrc of
314− Left err -> parserFail . show $ err
445+ Left err -> parserFail . show $ err
315− Right tipe -> return (rawSrc, tipe)
446+ Right tipe -> return (rawSrc, tipe)
317− closeShader builder = choice
448+ closeShader builder =
318− [ do try (string "|]")
450+ [ do try (string "|]")
319− return (builder "")
451+ return (builder "")
320− , do c <- anyChar
452+ , do c <- anyChar
321− closeShader (builder . (c:))
453+ closeShader (builder . (c:))
324glSource :: String -> Either ParseError L.GLShaderTipe
457glSource :: String -> Either ParseError L.GLShaderTipe
325glSource src =
458glSource src =
326 case GLP.parse src of
459 case GLP.parse src of
327− Right (GLS.TranslationUnit decls) ->
328− Right . foldr addGLinput emptyDecls . join . map extractGLinputs $ decls
329 Left e -> Left e
460 Left e -> Left e
461+ Right (GLS.TranslationUnit decls) ->
462+ map extractGLinputs decls
464+ |> foldr addGLinput emptyDecls
331 emptyDecls = L.GLShaderTipe Map.empty Map.empty Map.empty
467 emptyDecls = L.GLShaderTipe Map.empty Map.empty Map.empty
@@ -367,6 +503,7 @@ glSource src =
370str :: IParser String
507str :: IParser String
371str = expecting "String" $ do
508str = expecting "String" $ do
372 s <- choice [ multiStr, singleStr ]
509 s <- choice [ multiStr, singleStr ]
@@ -394,46 +531,60 @@ str = expecting "String" $ do
394 choice [ char '\n' >> return "\\n"
531 choice [ char '\n' >> return "\\n"
395 , char '\r' >> return "\\r" ]
532 , char '\r' >> return "\\r" ]
397sandwich :: Char -> String -> String
535sandwich :: Char -> String -> String
398−sandwich delim s = delim : s ++ [delim]
536+sandwich delim s =
537+ delim : s ++ [delim]
400escaped :: Char -> IParser String
540escaped :: Char -> IParser String
401−escaped delim = try $ do
541+escaped delim =
402− char '\\'
543+ char '\\'
403− c <- char '\\' <|> char delim
544+ c <- char '\\' <|> char delim
404− return ['\\', c]
545+ return ['\\', c]
406chr :: IParser Char
548chr :: IParser Char
407−chr = betwixt '\'' '\'' character <?> "character"
550+ betwixt '\'' '\'' character <?> "character"
409− nonQuote = satisfy (/='\'')
552+ nonQuote = satisfy (/='\'')
410− character = do
554+ character =
411− c <- choice [ escaped '\''
556+ [ escaped '\''
412− , (:) <$> char '\\' <*> many1 nonQuote
557+ , (:) <$> char '\\' <*> many1 nonQuote
413− , (:[]) <$> nonQuote ]
558+ , (:[]) <$> nonQuote
414− processAs T.charLiteral $ sandwich '\'' c
561+ processAs T.charLiteral $ sandwich '\'' c
416processAs :: (T.GenTokenParser String u SourceM -> IParser a) -> String -> IParser a
564processAs :: (T.GenTokenParser String u SourceM -> IParser a) -> String -> IParser a
565+processAs processor s =
417−processAs processor s = calloutParser s (processor lexer)
566+ calloutParser s (processor lexer)
419− calloutParser :: String -> IParser a -> IParser a
568+ calloutParser :: String -> IParser a -> IParser a
569+ calloutParser inp p =
420− calloutParser inp p = either (fail . show) return (iParse p inp)
570+ either (fail . show) return (iParse p inp)
422− lexer :: T.GenTokenParser String u SourceM
572+ lexer :: T.GenTokenParser String u SourceM
423− lexer = T.makeTokenParser elmDef
573+ lexer = T.makeTokenParser elmDef
425− -- I don't know how many of these are necessary for charLiteral/stringLiteral
575+ -- I don't know how many of these are necessary for charLiteral/stringLiteral
426− elmDef :: T.GenLanguageDef String u SourceM
576+ elmDef :: T.GenLanguageDef String u SourceM
427− elmDef = T.LanguageDef
578+ T.LanguageDef
428− { T.commentStart = "{-"
579+ { T.commentStart = "{-"
429− , T.commentEnd = "-}"
580+ , T.commentEnd = "-}"
430− , T.commentLine = "--"
581+ , T.commentLine = "--"
431− , T.nestedComments = True
582+ , T.nestedComments = True
432− , T.identStart = undefined
583+ , T.identStart = undefined
433− , T.identLetter = undefined
584+ , T.identLetter = undefined
434− , T.opStart = undefined
585+ , T.opStart = undefined
435− , T.opLetter = undefined
586+ , T.opLetter = undefined
436− , T.reservedNames = reserveds
587+ , T.reservedNames = reserveds
437− , T.reservedOpNames = [":", "->", "<-", "|"]
588+ , T.reservedOpNames = [":", "->", "<-", "|"]
438− , T.caseSensitive = True
589+ , T.caseSensitive = True