on master help sign in
Make error messages nicer for single-quoted strings
707bea1Evan Czaplicki
src/Parse/Helpers.hs+79−49
@@ -491,7 +491,7 @@ anyUntilPos pos =
491
491
492
492
493
493
494−-- BASIC LANGUAGE LITERALS
494+-- SHADERS
495
495
496
496
497shader :: IParser (String, L.GLShaderTipe)
497shader :: IParser (String, L.GLShaderTipe)
@@ -565,38 +565,84 @@ glSource src =
565 _ -> []
565 _ -> []
566
566
567
567
568+
569+-- STRINGS AND CHARACTERS
570+
571+
568str :: IParser String
572str :: IParser String
569str =
573str =
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 ++ "\"")
573− where
578+
579+
580+delimitedSequence :: IParser a -> IParser String -> IParser String
574− rawString quote insides =
581+delimitedSequence quote insides =
582+ do quote
575− quote >> manyTill insides quote
583+ concat <$> manyTill insides quote
584+
585+
586+multiStr :: IParser String
587+multiStr =
588+ delimitedSequence (try (string "\"\"\"")) multilineStringChar
589+
590+
591+singleStr :: IParser String
592+singleStr =
593+ delimitedSequence (char '"') (charWithin '"')
594+
595+
596+chr :: IParser Char
597+chr =
598+ expecting "a character like 'x'" $
599+ do char '\''
600+ charSeq <- concat <$> many1 (charWithin '\'') <?> "a character"
601+ case processAs T.charLiteral ("'" ++ charSeq ++ "'") of
602+ Right character ->
603+ do char '\''
604+ return character
605+
606+ Left _ ->
607+ failure $
608+ "Elm uses double quotes for strings. Switch\
609+ \ the ' to \" on both ends of the string and\
610+ \ you should be all set!"
611+
612+
576
613
577− multiStr = rawString (try (string "\"\"\"")) multilineStringChar
614+-- CHARACTER HELPERS
578− singleStr = rawString (char '"') stringChar
579
615
580− stringChar :: IParser String
581− stringChar = choice [ newlineChar, escaped '\"', (:[]) <$> satisfy (/= '\"') ]
582
616
583− multilineStringChar :: IParser String
617+charWithin :: Char -> IParser String
584− multilineStringChar =
618+charWithin delim =
585− do noEnd
619+ choice
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+
590
624
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
630+ , escaped '\"'
631+ , escapeQuotes <$> anyChar
632+ ]
595
633
596
634
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]
638+
639+
640+newlineChar :: IParser String
641+newlineChar =
642+ choice
643+ [ char '\n' >> return "\\n"
644+ , char '\r' >> return "\\r"
645+ ]
600
646
601
647
602escaped :: Char -> IParser String
648escaped :: Char -> IParser String
@@ -607,32 +653,16 @@ escaped delim =
607 return ['\\', c]
653 return ['\\', c]
608
654
609
655
610−chr :: IParser Char
656+processAs
611−chr =
612− betwixt '\'' '\'' character <?> "a character"
613− where
614− nonQuote = satisfy (/='\'')
615−
616− character =
617− do c <- choice
618− [ escaped '\''
619− , (:) <$> char '\\' <*> many1 nonQuote
620− , (:[]) <$> nonQuote
621− ]
622−
623− processAs T.charLiteral $ sandwich '\'' c
624−
625−
626−processAs :: (T.GenTokenParser String u SourceM -> IParser a) -> String -> IParser a
657+ :: (T.GenTokenParser String u SourceM -> IParser a)
658+ -> String
659+ -> Either ParseError a
627−processAs processor s =
660+processAs processor string =
628− calloutParser s (processor lexer)
661+ iParse (processor lexer) string
629 where
662 where
630− calloutParser :: String -> IParser a -> IParser a
631− calloutParser inp p =
632− either (fail . show) return (iParse p inp)
633−
634 lexer :: T.GenTokenParser String u SourceM
663 lexer :: T.GenTokenParser String u SourceM
664+ lexer =
635− lexer = T.makeTokenParser elmDef
665+ T.makeTokenParser elmDef
636
666
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