@@ -491,7 +491,7 @@ anyUntilPos pos =
494−-- BASIC LANGUAGE LITERALS
494+-- SHADERS
497shader :: IParser (String, L.GLShaderTipe)
497shader :: IParser (String, L.GLShaderTipe)
@@ -565,38 +565,84 @@ glSource src =
569+-- STRINGS AND CHARACTERS
568str :: IParser String
572str :: IParser String
570− expecting "a string" $
574+ expecting "a string like \"hello\"" $
571− do s <- choice [ multiStr, singleStr ]
575+ do charSeq <- choice [ multiStr, singleStr ]
576+ either (fail . show) return $
572− processAs T.stringLiteral . sandwich '\"' $ concat s
577+ processAs T.stringLiteral ('"' : charSeq ++ "\"")
580+delimitedSequence :: IParser a -> IParser String -> IParser String
574− rawString quote insides =
581+delimitedSequence quote insides =
575− quote >> manyTill insides quote
583+ concat <$> manyTill insides quote
586+multiStr :: IParser String
588+ delimitedSequence (try (string "\"\"\"")) multilineStringChar
591+singleStr :: IParser String
593+ delimitedSequence (char '"') (charWithin '"')
598+ expecting "a character like 'x'" $
600+ charSeq <- concat <$> many1 (charWithin '\'') <?> "a character"
601+ case processAs T.charLiteral ("'" ++ charSeq ++ "'") of
608+ "Elm uses double quotes for strings. Switch\
609+ \ the ' to \" on both ends of the string and\
610+ \ you should be all set!"
577− multiStr = rawString (try (string "\"\"\"")) multilineStringChar
614+-- CHARACTER HELPERS
578− singleStr = rawString (char '"') stringChar
580− stringChar :: IParser String
581− stringChar = choice [ newlineChar, escaped '\"', (:[]) <$> satisfy (/= '\"') ]
583− multilineStringChar :: IParser String
617+charWithin :: Char -> IParser String
584− multilineStringChar =
618+charWithin delim =
586− choice [ newlineChar, escaped '\"', expandQuote <$> anyChar ]
620+ [ escaped delim
587− where
621+ , (:[]) <$> satisfy (/= delim)
588− noEnd = notFollowedBy (string "\"\"\"")
622+ ]
589− expandQuote c = if c == '\"' then "\\\"" else [c]
623+
591− newlineChar :: IParser String
625+multilineStringChar :: IParser String
592− newlineChar =
626+multilineStringChar =
627+ do notFollowedBy (string "\"\"\"")
593− choice [ char '\n' >> return "\\n"
628+ choice
594− , char '\r' >> return "\\r" ]
629+ [ newlineChar
631+ , escapeQuotes <$> anyChar
597−sandwich :: Char -> String -> String
635+escapeQuotes :: Char -> String
598−sandwich delim s =
636+escapeQuotes c =
599− delim : s ++ [delim]
637+ if c == '\"' then "\\\"" else [c]
640+newlineChar :: IParser String
643+ [ char '\n' >> return "\\n"
644+ , char '\r' >> return "\\r"
602escaped :: Char -> IParser String
648escaped :: Char -> IParser String
@@ -607,32 +653,16 @@ escaped delim =
607 return ['\\', c]
653 return ['\\', c]
610−chr :: IParser Char
656+processAs
612− betwixt '\'' '\'' character <?> "a character"
614− nonQuote = satisfy (/='\'')
619− , (:) <$> char '\\' <*> many1 nonQuote
620− , (:[]) <$> nonQuote
623− processAs T.charLiteral $ sandwich '\'' c
626−processAs :: (T.GenTokenParser String u SourceM -> IParser a) -> String -> IParser a
657+ :: (T.GenTokenParser String u SourceM -> IParser a)
659+ -> Either ParseError a
627−processAs processor s =
660+processAs processor string =
628− calloutParser s (processor lexer)
661+ iParse (processor lexer) string
630− calloutParser :: String -> IParser a -> IParser a
631− calloutParser inp p =
632− either (fail . show) return (iParse p inp)
634 lexer :: T.GenTokenParser String u SourceM
663 lexer :: T.GenTokenParser String u SourceM
635− lexer = T.makeTokenParser elmDef
665+ T.makeTokenParser elmDef
637 -- I don't know how many of these are necessary for charLiteral/stringLiteral
667 -- I don't know how many of these are necessary for charLiteral/stringLiteral
638 elmDef :: T.GenLanguageDef String u SourceM
668 elmDef :: T.GenLanguageDef String u SourceM