on master help sign in
Add parse error messages for strings and chars
7324fcaEvan Czaplicki
compiler/src/Parse/Utf8.hs+31−34
@@ -28,7 +28,7 @@ character toExpectation toError =
28 eerr row col toExpectation
28 eerr row col toExpectation
29
29
30 else
30 else
31− case chompChar (plusPtr pos 1) end (col + 1) 0 placeholder of
31+ case chompChar (plusPtr pos 1) end row (col + 1) 0 placeholder of
32 Good newPos newCol numChars mostRecent ->
32 Good newPos newCol numChars mostRecent ->
33 if numChars /= 1 then
33 if numChars /= 1 then
34 cerr row col (toError (E.CharNotString (fromIntegral (newCol - col))))
34 cerr row col (toError (E.CharNotString (fromIntegral (newCol - col))))
@@ -42,18 +42,18 @@ character toExpectation toError =
42 CharEndless newCol ->
42 CharEndless newCol ->
43 cerr row newCol (toError E.CharEndless)
43 cerr row newCol (toError E.CharEndless)
44
44
45− CharEscape newCol escape ->
45+ CharEscape r c escape ->
46− cerr row newCol (toError (E.CharEscape escape))
46+ cerr r c (toError (E.CharEscape escape))
47
47
48
48
49data CharResult
49data CharResult
50 = Good (Ptr Word8) Col Word16 Utf8.Chunk
50 = Good (Ptr Word8) Col Word16 Utf8.Chunk
51 | CharEndless Col
51 | CharEndless Col
52− | CharEscape Col E.Escape
52+ | CharEscape Row Col E.Escape
53
53
54
54
55−chompChar :: Ptr Word8 -> Ptr Word8 -> Col -> Word16 -> Utf8.Chunk -> CharResult
55+chompChar :: Ptr Word8 -> Ptr Word8 -> Row -> Col -> Word16 -> Utf8.Chunk -> CharResult
56−chompChar pos end col numChars mostRecent =
56+chompChar pos end row col numChars mostRecent =
57 if pos >= end then
57 if pos >= end then
58 CharEndless col
58 CharEndless col
59
59
@@ -68,18 +68,18 @@ chompChar pos end col numChars mostRecent =
68 CharEndless col
68 CharEndless col
69
69
70 else if word == 0x22 {- " -} then
70 else if word == 0x22 {- " -} then
71− chompChar (plusPtr pos 1) end (col + 1) (numChars + 1) doubleQuote
71+ chompChar (plusPtr pos 1) end row (col + 1) (numChars + 1) doubleQuote
72
72
73 else if word == 0x5C {- \ -} then
73 else if word == 0x5C {- \ -} then
74− case eatEscape (plusPtr pos 1) end col of
74+ case eatEscape (plusPtr pos 1) end row col of
75 EscapeNormal ->
75 EscapeNormal ->
76− chompChar (plusPtr pos 2) end (col + 2) (numChars + 1) (Utf8.Slice pos 2)
76+ chompChar (plusPtr pos 2) end row (col + 2) (numChars + 1) (Utf8.Slice pos 2)
77
77
78 EscapeUnicode delta code ->
78 EscapeUnicode delta code ->
79− chompChar (plusPtr pos delta) end (col + fromIntegral delta) (numChars + 1) (Utf8.CodePoint code)
79+ chompChar (plusPtr pos delta) end row (col + fromIntegral delta) (numChars + 1) (Utf8.CodePoint code)
80
80
81− EscapeProblem badEscape ->
81+ EscapeProblem r c badEscape ->
82− CharEscape col badEscape
82+ CharEscape r c badEscape
83
83
84 EscapeEndOfFile ->
84 EscapeEndOfFile ->
85 CharEndless col
85 CharEndless col
@@ -89,7 +89,7 @@ chompChar pos end col numChars mostRecent =
89 !width = P.getCharWidth pos end word
89 !width = P.getCharWidth pos end word
90 !newPos = plusPtr pos width
90 !newPos = plusPtr pos width
91 in
91 in
92− chompChar newPos end (col + 1) (numChars + 1) (Utf8.Slice pos width)
92+ chompChar newPos end row (col + 1) (numChars + 1) (Utf8.Slice pos width)
93
93
94
94
95
95
@@ -186,7 +186,7 @@ singleString pos end row col initialPos revChunks =
186 addEscape singleQuote initialPos pos revChunks
186 addEscape singleQuote initialPos pos revChunks
187
187
188 else if word == 0x5C {- \ -} then
188 else if word == 0x5C {- \ -} then
189− case eatEscape (plusPtr pos 1) end col of
189+ case eatEscape (plusPtr pos 1) end row col of
190 EscapeNormal ->
190 EscapeNormal ->
191 singleString (plusPtr pos 2) end row (col + 2) initialPos revChunks
191 singleString (plusPtr pos 2) end row (col + 2) initialPos revChunks
192
192
@@ -195,8 +195,8 @@ singleString pos end row col initialPos revChunks =
195 singleString newPos end row (col + fromIntegral delta) newPos $
195 singleString newPos end row (col + fromIntegral delta) newPos $
196 addEscape (Utf8.CodePoint code) initialPos pos revChunks
196 addEscape (Utf8.CodePoint code) initialPos pos revChunks
197
197
198− EscapeProblem x ->
198+ EscapeProblem r c x ->
199− Err row col (E.StringEscape x)
199+ Err r c (E.StringEscape x)
200
200
201 EscapeEndOfFile ->
201 EscapeEndOfFile ->
202 Err row (col + 1) E.StringEndless_Single
202 Err row (col + 1) E.StringEndless_Single
@@ -237,7 +237,7 @@ multiString pos end row col initialPos sr sc revChunks =
237 addEscape carriageReturn initialPos pos revChunks
237 addEscape carriageReturn initialPos pos revChunks
238
238
239 else if word == 0x5C {- \ -} then
239 else if word == 0x5C {- \ -} then
240− case eatEscape (plusPtr pos 1) end col of
240+ case eatEscape (plusPtr pos 1) end row col of
241 EscapeNormal ->
241 EscapeNormal ->
242 multiString (plusPtr pos 2) end row (col + 2) initialPos sr sc revChunks
242 multiString (plusPtr pos 2) end row (col + 2) initialPos sr sc revChunks
243
243
@@ -246,8 +246,8 @@ multiString pos end row col initialPos sr sc revChunks =
246 multiString newPos end row (col + fromIntegral delta) newPos sr sc $
246 multiString newPos end row (col + fromIntegral delta) newPos sr sc $
247 addEscape (Utf8.CodePoint code) initialPos pos revChunks
247 addEscape (Utf8.CodePoint code) initialPos pos revChunks
248
248
249− EscapeProblem x ->
249+ EscapeProblem r c x ->
250− Err row col (E.StringEscape x)
250+ Err r c (E.StringEscape x)
251
251
252 EscapeEndOfFile ->
252 EscapeEndOfFile ->
253 Err sr sc E.StringEndless_Multi
253 Err sr sc E.StringEndless_Multi
@@ -265,11 +265,11 @@ data Escape
265 = EscapeNormal
265 = EscapeNormal
266 | EscapeUnicode !Int !Int
266 | EscapeUnicode !Int !Int
267 | EscapeEndOfFile
267 | EscapeEndOfFile
268− | EscapeProblem E.Escape
268+ | EscapeProblem Row Col E.Escape
269
269
270
270
271−eatEscape :: Ptr Word8 -> Ptr Word8 -> Word16 -> Escape
271+eatEscape :: Ptr Word8 -> Ptr Word8 -> Row -> Col -> Escape
272−eatEscape pos end startCol =
272+eatEscape pos end row col =
273 if pos >= end then
273 if pos >= end then
274 EscapeEndOfFile
274 EscapeEndOfFile
275
275
@@ -281,14 +281,14 @@ eatEscape pos end startCol =
281 0x22 {- " -} -> EscapeNormal
281 0x22 {- " -} -> EscapeNormal
282 0x27 {- ' -} -> EscapeNormal
282 0x27 {- ' -} -> EscapeNormal
283 0x5C {- \ -} -> EscapeNormal
283 0x5C {- \ -} -> EscapeNormal
284− 0x75 {- u -} -> eatUnicode (plusPtr pos 1) end startCol
284+ 0x75 {- u -} -> eatUnicode (plusPtr pos 1) end row col
285− _ -> EscapeProblem (E.EscapeUnknown startCol (startCol + 1))
285+ _ -> EscapeProblem row col E.EscapeUnknown
286
286
287
287
288−eatUnicode :: Ptr Word8 -> Ptr Word8 -> Word16 -> Escape
288+eatUnicode :: Ptr Word8 -> Ptr Word8 -> Row -> Col -> Escape
289−eatUnicode pos end startCol =
289+eatUnicode pos end row col =
290 if pos >= end || P.unsafeIndex pos /= 0x7B {- { -} then
290 if pos >= end || P.unsafeIndex pos /= 0x7B {- { -} then
291− EscapeProblem $ E.BadUnicodeFormat startCol (startCol + 1)
291+ EscapeProblem row col (E.BadUnicodeFormat 2)
292 else
292 else
293 let
293 let
294 !digitPos = plusPtr pos 1
294 !digitPos = plusPtr pos 1
@@ -296,18 +296,15 @@ eatUnicode pos end startCol =
296 !numDigits = minusPtr newPos digitPos
296 !numDigits = minusPtr newPos digitPos
297 in
297 in
298 if newPos >= end || P.unsafeIndex newPos /= 0x7D {- } -} then
298 if newPos >= end || P.unsafeIndex newPos /= 0x7D {- } -} then
299− EscapeProblem $ E.BadUnicodeFormat startCol $
299+ EscapeProblem row col $ E.BadUnicodeFormat (2 + fromIntegral (minusPtr newPos pos))
300− startCol + fromIntegral (minusPtr newPos pos)
301
300
302 else if code < 0 || 0x10FFFF < code then
301 else if code < 0 || 0x10FFFF < code then
303− EscapeProblem $ E.BadUnicodeCode startCol $
302+ EscapeProblem row col $ E.BadUnicodeCode (3 + fromIntegral (minusPtr newPos pos))
304− startCol + fromIntegral (minusPtr newPos pos) + 1
305
303
306 else if numDigits < 4 || 6 < numDigits then
304 else if numDigits < 4 || 6 < numDigits then
307− EscapeProblem $
305+ EscapeProblem row col $
308 E.BadUnicodeLength
306 E.BadUnicodeLength
309− startCol
310− (startCol + fromIntegral (minusPtr newPos pos) + 1)
307+ (3 + fromIntegral (minusPtr newPos pos))
311 numDigits
308 numDigits
312 code
309 code
313
310
compiler/src/Reporting/Error/Syntax.hs+201−238
@@ -49,7 +49,7 @@ import Prelude hiding (Char, String)
49import qualified Data.Char as Char
49import qualified Data.Char as Char
50import qualified Data.Name as Name
50import qualified Data.Name as Name
51import Data.Word (Word16)
51import Data.Word (Word16)
52−--import Numeric (showHex)
52+import Numeric (showHex)
53
53
54import qualified Elm.ModuleName as ModuleName
54import qualified Elm.ModuleName as ModuleName
55import Parse.Primitives (Row, Col)
55import Parse.Primitives (Row, Col)
@@ -470,7 +470,7 @@ data TTuple
470data Char
470data Char
471 = CharEndless
471 = CharEndless
472 | CharEscape Escape
472 | CharEscape Escape
473− | CharNotString Int
473+ | CharNotString Word16
474
474
475
475
476data String
476data String
@@ -480,10 +480,10 @@ data String
480
480
481
481
482data Escape
482data Escape
483− = EscapeUnknown Word16 Word16
483+ = EscapeUnknown
484− | BadUnicodeFormat Word16 Word16
484+ | BadUnicodeFormat Word16
485− | BadUnicodeCode Word16 Word16
485+ | BadUnicodeCode Word16
486− | BadUnicodeLength Word16 Word16 Int Int
486+ | BadUnicodeLength Word16 Int Int
487
487
488
488
489data Number
489data Number
@@ -550,7 +550,7 @@ toReport source err =
550 ++ ModuleName.toChars expectedName
550 ++ ModuleName.toChars expectedName
551 ++ "` here. Make the following change, and you should be all set!"
551 ++ "` here. Make the following change, and you should be all set!"
552 , D.indent 4 $
552 , D.indent 4 $
553− D.red (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
553+ D.dullyellow (D.fromName actualName) <> " -> " <> D.green (D.fromName expectedName)
554 , D.toSimpleNote $
554 , D.toSimpleNote $
555 "I require that module names correspond to file paths. This makes it much\
555 "I require that module names correspond to file paths. This makes it much\
556 \ easier to explore unfamiliar codebases! So if you want to keep the current\
556 \ easier to explore unfamiliar codebases! So if you want to keep the current\
@@ -835,11 +835,11 @@ toExprReport source _ expr _ _ =
835 Start _ _ ->
835 Start _ _ ->
836 error "TODO Start"
836 error "TODO Start"
837
837
838− Char _ _ _ ->
838+ Char char row col ->
839− error "TODO Char"
839+ toCharReport source char row col
840
840
841− String _ _ _ ->
841+ String string row col ->
842− error "TODO String"
842+ toStringReport source string row col
843
843
844 Number number row col ->
844 Number number row col ->
845 toNumberReport source number row col
845 toNumberReport source number row col
@@ -884,6 +884,196 @@ toExprReport source _ expr _ _ =
884 error "TODO IndentMoreExpr"
884 error "TODO IndentMoreExpr"
885
885
886
886
887+toCharReport :: Code.Source -> Char -> Row -> Col -> Report.Report
888+toCharReport source char row col =
889+ case char of
890+ CharEndless ->
891+ let
892+ region = toRegion row col
893+ in
894+ Report.Report "MISSING SINGLE QUOTE" region [] $
895+ Report.toCodeSnippet source region Nothing
896+ (
897+ D.reflow $
898+ "I thought I was parsing a character, but I got to the end of\
899+ \ the line without seeing the closing single quote:"
900+ ,
901+ D.reflow $
902+ "Add a closing single quote here!"
903+ )
904+
905+ CharEscape escape ->
906+ toEscapeReport source escape row col
907+
908+ CharNotString width ->
909+ let
910+ region = toWiderRegion row col width
911+ in
912+ Report.Report "NEEDS DOUBLE QUOTES" region [] $
913+ Report.toCodeSnippet source region Nothing
914+ (
915+ "The following string uses single quotes:"
916+ ,
917+ D.stack
918+ [ "Please switch to double quotes instead:"
919+ , D.indent 4 $
920+ D.dullyellow "'this'" <> " => " <> D.green "\"this\""
921+ , D.toSimpleNote $
922+ "Elm uses double quotes for strings like \"hello\", whereas it uses single\
923+ \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
924+ \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
925+ \ individual characters."
926+ ]
927+ )
928+
929+
930+toStringReport :: Code.Source -> String -> Row -> Col -> Report.Report
931+toStringReport source string row col =
932+ case string of
933+ StringEndless_Single ->
934+ let
935+ region = toRegion row col
936+ in
937+ Report.Report "ENDLESS STRING" region [] $
938+ Report.toCodeSnippet source region Nothing
939+ (
940+ D.reflow $
941+ "I got to the end of the line without seeing the closing double quote:"
942+ ,
943+ D.stack
944+ [ D.fillSep $
945+ ["Strings","look","like",D.green "\"this\"","with","double"
946+ ,"quotes","on","each","end.","Is","the","closing","double"
947+ ,"quote","missing","in","your","code?"
948+ ]
949+ , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
950+ ]
951+ )
952+
953+ StringEndless_Multi ->
954+ let
955+ region = toWiderRegion row col 3
956+ in
957+ Report.Report "ENDLESS STRING" region [] $
958+ Report.toCodeSnippet source region Nothing
959+ (
960+ D.reflow $
961+ "I cannot find the end of this multi-line string:"
962+ ,
963+ D.stack
964+ [ D.reflow "Add a \"\"\" somewhere after this to end the string."
965+ , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
966+ ]
967+ )
968+
969+ StringEscape escape ->
970+ toEscapeReport source escape row col
971+
972+
973+toEscapeReport :: Code.Source -> Escape -> Row -> Col -> Report.Report
974+toEscapeReport source escape row col =
975+ case escape of
976+ EscapeUnknown ->
977+ let
978+ region = toWiderRegion row col 2
979+ in
980+ Report.Report "UNKNOWN ESCAPE" region [] $
981+ Report.toCodeSnippet source region Nothing
982+ (
983+ D.reflow $
984+ "Backslashes always start escaped characters, but I do not recognize this one:"
985+ ,
986+ D.stack
987+ [ D.reflow $
988+ "Valid escape characters include:"
989+ , D.dullyellow $ D.indent 4 $ D.vcat $
990+ [ "\\n"
991+ , "\\r"
992+ , "\\t"
993+ , "\\\""
994+ , "\\\'"
995+ , "\\\\"
996+ , "\\u{003D}"
997+ ]
998+ , D.reflow $
999+ "Do you want one of those instead? Maybe you need \\\\ to escape a backslash?"
1000+ , D.toSimpleNote $
1001+ "The last style lets encode ANY character by its Unicode code\
1002+ \ point. That means \\u{0009} and \\t are the same. You can use\
1003+ \ that style for anything not covered by the other six escapes!"
1004+ ]
1005+ )
1006+
1007+ BadUnicodeFormat width ->
1008+ let
1009+ region = toWiderRegion row col width
1010+ in
1011+ Report.Report "BAD UNICODE ESCAPE" region [] $
1012+ Report.toCodeSnippet source region Nothing
1013+ (
1014+ D.reflow $
1015+ "I ran into an invalid Unicode escape:"
1016+ ,
1017+ D.stack
1018+ [ D.reflow $
1019+ "Here are some examples of valid Unicode escapes:"
1020+ , D.dullyellow $ D.indent 4 $ D.vcat $
1021+ [ "\\u{0041}"
1022+ , "\\u{03BB}"
1023+ , "\\u{6728}"
1024+ , "\\u{1F60A}"
1025+ ]
1026+ , D.reflow $
1027+ "Notice that the code point is always surrounded by curly braces.\
1028+ \ Maybe you are missing the opening or closing curly brace?"
1029+ ]
1030+ )
1031+ BadUnicodeCode width ->
1032+ let
1033+ region = toWiderRegion row col width
1034+ in
1035+ Report.Report "BAD UNICODE ESCAPE" region [] $
1036+ Report.toCodeSnippet source region Nothing
1037+ (
1038+ D.reflow $
1039+ "This is not a valid code point:"
1040+ ,
1041+ D.reflow $
1042+ "The valid code points are between 0 and 10FFFF inclusive."
1043+ )
1044+
1045+ BadUnicodeLength width numDigits badCode ->
1046+ let
1047+ region = toWiderRegion row col width
1048+ in
1049+ Report.Report "BAD UNICODE ESCAPE" region [] $
1050+ Report.toCodeSnippet source region Nothing $
1051+ if numDigits < 4 then
1052+ (
1053+ D.reflow $
1054+ "Every code point needs at least four digits:"
1055+ ,
1056+ let
1057+ goodCode = replicate (4 - numDigits) '0' ++ map Char.toUpper (showHex badCode "")
1058+ suggestion = "\\u{" <> D.fromChars goodCode <> "}"
1059+ in
1060+ D.fillSep ["Try",D.green suggestion,"instead?"]
1061+ )
1062+
1063+ else
1064+ (
1065+ D.reflow $
1066+ "This code point has too many digits:"
1067+ ,
1068+ D.fillSep $
1069+ ["Valid","code","points","are","between"
1070+ ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
1071+ ,"so","try","trimming","any","leading","zeros","until"
1072+ ,"you","have","between","four","and","six","digits."
1073+ ]
1074+ )
1075+
1076+
887toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
1077toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
888toNumberReport source number row col =
1078toNumberReport source number row col =
889 let
1079 let
@@ -1051,233 +1241,6 @@ toNumberReport source number row col =
1051 "I need a single digit between 0 and 9 inclusive."
1241 "I need a single digit between 0 and 9 inclusive."
1052 )
1242 )
1053
1243
1054− -- Parse.Utf8
1055−
1056− CharStart ->
1057− Report.Report "EXPECTING A CHARACTER" region [] $
1058− Report.toCodeSnippet source region Nothing
1059− (
1060− D.reflow $
1061− "I was expecting a character here:"
1062− ,
1063− D.stack
1064− [ D.reflow $
1065− "Characters start and end with single quotes, like this:"
1066− , D.indent 4 $ D.vcat $
1067− [ "'a'"
1068− , "'b'"
1069− , "'ø'"
1070− , "'\\n'"
1071− , "'\\u{00F8}'"
1072− ]
1073− , D.reflow $
1074− "That last style lets you encode characters by their unicode\
1075− \ code point, so 'a' is equivalent to '\\u{0061}', 'ø' is\
1076− \ equivalent to '\\u{00F8}', and so on for all code points."
1077− ]
1078− )
1079−
1080− CharEnd ->
1081− Report.Report "MISSING SINGLE QUOTE" region [] $
1082− Report.toCodeSnippet source region Nothing
1083− (
1084− D.reflow $
1085− "I thought I was parsing a character, but I got to the end of\
1086− \ the line without seeing the closing single quote:"
1087− ,
1088− D.stack
1089− [ D.reflow $
1090− "Characters start and end with single quotes, like this:"
1091− , D.indent 4 $ D.vcat $
1092− [ "'a'"
1093− , "'b'"
1094− , "'ø'"
1095− , "'\\n'"
1096− , "'\\u{00F8}'"
1097− ]
1098− , D.reflow $
1099− "That last style lets you encode characters by their unicode\
1100− \ code point, so 'a' is equivalent to '\\u{0061}', 'ø' is\
1101− \ equivalent to '\\u{00F8}', and so on for all code points."
1102− ]
1103− )
1104−
1105− CharNotString startRow startCol ->
1106− let
1107− stringRegion =
1108− A.Region (A.Position startRow startCol) pos
1109− in
1110− Report.Report "NEEDS DOUBLE QUOTES" stringRegion [] $
1111− Report.toCodeSnippet source stringRegion Nothing
1112− (
1113− "The following string uses single quotes:"
1114− ,
1115− D.stack
1116− [ "Please switch to double quotes instead:"
1117− , D.indent 4 $
1118− D.dullyellow "'this'" <> " => " <> D.green "\"this\""
1119− , D.toSimpleNote $
1120− "Elm uses double quotes for strings like \"hello\", whereas it uses single\
1121− \ quotes for individual characters like 'a' and 'ø'. This distinction helps with\
1122− \ code like (String.any (\\c -> c == 'X') \"90210\") where you are inspecting\
1123− \ individual characters."
1124− ]
1125− )
1126−
1127− StringStart ->
1128− Report.Report "EXPECTING A STRING" region [] $
1129− Report.toCodeSnippet source region Nothing
1130− (
1131− D.reflow $
1132− "I was expecting a string here:"
1133− ,
1134− D.fillSep
1135− ["Something","like"
1136− ,D.green "\"this\""
1137− ,"or"
1138− ,D.green "\"that\""
1139− ,"with","double","quotes."
1140− ]
1141− )
1142−
1143− StringEnd_Single ->
1144− Report.Report "ENDLESS STRING" region [] $
1145− Report.toCodeSnippet source region Nothing
1146− (
1147− D.reflow $
1148− "I got to the end of the line without seeing the closing double quote:"
1149− ,
1150− D.stack
1151− [ D.fillSep $
1152− ["Strings","look","like",D.green "\"this\"","with","double"
1153− ,"quotes","on","each","end.","Is","the","closing","double"
1154− ,"quote","missing","in","your","code?"
1155− ]
1156− , D.link "Note" "Read" "TODO" "if you want a string that spans multiple lines."
1157− ]
1158− )
1159−
1160− StringEnd_Multi startRow startCol ->
1161− let
1162− startRegion =
1163− A.Region
1164− (A.Position startRow startCol)
1165− (A.Position startRow (startCol + 3))
1166− in
1167− Report.Report "ENDLESS STRING" startRegion [] $
1168− Report.toCodeSnippet source startRegion Nothing
1169− (
1170− D.reflow $
1171− "I cannot find the end of this multi-line string:"
1172− ,
1173− D.stack
1174− [ D.reflow "Add a \"\"\" somewhere after this to end the string."
1175− , D.link "Hint" "Read" "TODO" "for more information on strings and multi-line strings."
1176− ]
1177− )
1178−
1179− EscapeUnknown startCol endCol ->
1180− let
1181− escapeRegion =
1182− A.Region (A.Position row startCol) (A.Position row endCol)
1183− in
1184− Report.Report "UNKNOWN ESCAPE" escapeRegion [] $
1185− Report.toCodeSnippet source escapeRegion Nothing
1186− (
1187− D.reflow $
1188− "Backslashes always start escaped characters, but I do not recognize this one:"
1189− ,
1190− D.stack
1191− [ D.reflow $
1192− "Valid escape characters include:"
1193− , D.indent 4 $ D.vcat $
1194− [ "\\n"
1195− , "\\r"
1196− , "\\t"
1197− , "\\\""
1198− , "\\\'"
1199− , "\\\\"
1200− , "\\u{03BB}"
1201− ]
1202− , D.reflow $
1203− "The last one lets encode ANY character by its Unicode code\
1204− \ point, so use that for anything outside the ordinary six."
1205− ]
1206− )
1207−
1208− BadUnicodeFormat startCol endCol ->
1209− let
1210− escapeRegion =
1211− A.Region (A.Position row startCol) (A.Position row endCol)
1212− in
1213− Report.Report "BAD UNICODE ESCAPE" escapeRegion [] $
1214− Report.toCodeSnippet source escapeRegion Nothing
1215− (
1216− D.reflow $
1217− "I ran into an invalid Unicode escape:"
1218− ,
1219− D.stack
1220− [ D.reflow $
1221− "Here are some examples of valid Unicode escapes:"
1222− , D.green $ D.indent 4 $ D.vcat $
1223− [ "\\u{0041}"
1224− , "\\u{03BB}"
1225− , "\\u{6728}"
1226− , "\\u{1F60A}"
1227− ]
1228− , D.reflow $
1229− "Notice that the code point is always surrounded by curly\
1230− \ braces. They are required!"
1231− ]
1232− )
1233−
1234− BadUnicodeCode startCol endCol ->
1235− let
1236− escapeRegion =
1237− A.Region (A.Position row startCol) (A.Position row endCol)
1238− in
1239− Report.Report "BAD UNICODE ESCAPE" escapeRegion [] $
1240− Report.toCodeSnippet source escapeRegion Nothing
1241− (
1242− D.reflow $
1243− "This is not a valid code point:"
1244− ,
1245− D.reflow $
1246− "The valid code points are between 0 and 10FFFF inclusive."
1247− )
1248−
1249− BadUnicodeLength startCol endCol numDigits badCode ->
1250− let
1251− escapeRegion =
1252− A.Region (A.Position row startCol) (A.Position row endCol)
1253− in
1254− Report.Report "BAD UNICODE ESCAPE" escapeRegion [] $
1255− Report.toCodeSnippet source escapeRegion Nothing $
1256− if numDigits < 4 then
1257− (
1258− D.reflow $
1259− "Every code point needs at least four digits:"
1260− ,
1261− let
1262− goodCode = replicate (4 - numDigits) '0' ++ showHex badCode ""
1263− escape = "\\u{" <> D.fromChars goodCode <> "}"
1264− in
1265− D.fillSep ["Try",D.green escape,"instead?"]
1266− )
1267−
1268− else
1269− (
1270− D.reflow $
1271− "This code point has too many digits:"
1272− ,
1273− D.fillSep $
1274− ["Valid","code","points","are","between"
1275− ,D.green "\\u{0000}","and",D.green "\\u{10FFFF}" <> ","
1276− ,"so","try","trimming","any","leading","zeros","until"
1277− ,"you","have","between","four","and","six","digits."
1278− ]
1279− )
1280−
1281 Operator ->
1244 Operator ->
1282 Report.Report "EXPECTING AN OPERATOR" region [] $
1245 Report.Report "EXPECTING AN OPERATOR" region [] $
1283 Report.toCodeSnippet source region Nothing
1246 Report.toCodeSnippet source region Nothing