on master help sign in
Add parse error messages for strings and chars

Track location of error message a little bit better in the parser as well.

commit7324fca5b93ea91d7129ca6c5dee724dad5ca534 authorEvan Czaplicki <evancz@users.noreply.github.com> dateFri 3 May 2019, 18:03 (7 years ago) parent5147a5a
2 files changed+232−272
compiler/src/Parse/Utf8.hs+31−34 compiler/src/Reporting/Error/Syntax.hs+201−238
compiler/src/Parse/Utf8.hs+31−34
@@ -28,7 +28,7 @@ character toExpectation toError =
2828 eerr row col toExpectation
2929
3030 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
3232 Good newPos newCol numChars mostRecent ->
3333 if numChars /= 1 then
3434 cerr row col (toError (E.CharNotString (fromIntegral (newCol - col))))
@@ -42,18 +42,18 @@ character toExpectation toError =
4242 CharEndless newCol ->
4343 cerr row newCol (toError E.CharEndless)
4444
45− CharEscape newCol escape ->
46− cerr row newCol (toError (E.CharEscape escape))
45+ CharEscape r c escape ->
46+ cerr r c (toError (E.CharEscape escape))
4747
4848
4949data CharResult
5050 = Good (Ptr Word8) Col Word16 Utf8.Chunk
5151 | CharEndless Col
52− | CharEscape Col E.Escape
52+ | CharEscape Row Col E.Escape
5353
5454
55−chompChar :: Ptr Word8 -> Ptr Word8 -> Col -> Word16 -> Utf8.Chunk -> CharResult
56−chompChar pos end col numChars mostRecent =
55+chompChar :: Ptr Word8 -> Ptr Word8 -> Row -> Col -> Word16 -> Utf8.Chunk -> CharResult
56+chompChar pos end row col numChars mostRecent =
5757 if pos >= end then
5858 CharEndless col
5959
@@ -68,18 +68,18 @@ chompChar pos end col numChars mostRecent =
6868 CharEndless col
6969
7070 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
7272
7373 else if word == 0x5C {- \ -} then
74− case eatEscape (plusPtr pos 1) end col of
74+ case eatEscape (plusPtr pos 1) end row col of
7575 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)
7777
7878 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)
8080
81− EscapeProblem badEscape ->
82− CharEscape col badEscape
81+ EscapeProblem r c badEscape ->
82+ CharEscape r c badEscape
8383
8484 EscapeEndOfFile ->
8585 CharEndless col
@@ -89,7 +89,7 @@ chompChar pos end col numChars mostRecent =
8989 !width = P.getCharWidth pos end word
9090 !newPos = plusPtr pos width
9191 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)
9393
9494
9595
@@ -186,7 +186,7 @@ singleString pos end row col initialPos revChunks =
186186 addEscape singleQuote initialPos pos revChunks
187187
188188 else if word == 0x5C {- \ -} then
189− case eatEscape (plusPtr pos 1) end col of
189+ case eatEscape (plusPtr pos 1) end row col of
190190 EscapeNormal ->
191191 singleString (plusPtr pos 2) end row (col + 2) initialPos revChunks
192192
@@ -195,8 +195,8 @@ singleString pos end row col initialPos revChunks =
195195 singleString newPos end row (col + fromIntegral delta) newPos $
196196 addEscape (Utf8.CodePoint code) initialPos pos revChunks
197197
198− EscapeProblem x ->
199− Err row col (E.StringEscape x)
198+ EscapeProblem r c x ->
199+ Err r c (E.StringEscape x)
200200
201201 EscapeEndOfFile ->
202202 Err row (col + 1) E.StringEndless_Single
@@ -237,7 +237,7 @@ multiString pos end row col initialPos sr sc revChunks =
237237 addEscape carriageReturn initialPos pos revChunks
238238
239239 else if word == 0x5C {- \ -} then
240− case eatEscape (plusPtr pos 1) end col of
240+ case eatEscape (plusPtr pos 1) end row col of
241241 EscapeNormal ->
242242 multiString (plusPtr pos 2) end row (col + 2) initialPos sr sc revChunks
243243
@@ -246,8 +246,8 @@ multiString pos end row col initialPos sr sc revChunks =
246246 multiString newPos end row (col + fromIntegral delta) newPos sr sc $
247247 addEscape (Utf8.CodePoint code) initialPos pos revChunks
248248
249− EscapeProblem x ->
250− Err row col (E.StringEscape x)
249+ EscapeProblem r c x ->
250+ Err r c (E.StringEscape x)
251251
252252 EscapeEndOfFile ->
253253 Err sr sc E.StringEndless_Multi
@@ -265,11 +265,11 @@ data Escape
265265 = EscapeNormal
266266 | EscapeUnicode !Int !Int
267267 | EscapeEndOfFile
268− | EscapeProblem E.Escape
268+ | EscapeProblem Row Col E.Escape
269269
270270
271−eatEscape :: Ptr Word8 -> Ptr Word8 -> Word16 -> Escape
272−eatEscape pos end startCol =
271+eatEscape :: Ptr Word8 -> Ptr Word8 -> Row -> Col -> Escape
272+eatEscape pos end row col =
273273 if pos >= end then
274274 EscapeEndOfFile
275275
@@ -281,14 +281,14 @@ eatEscape pos end startCol =
281281 0x22 {- " -} -> EscapeNormal
282282 0x27 {- ' -} -> EscapeNormal
283283 0x5C {- \ -} -> EscapeNormal
284− 0x75 {- u -} -> eatUnicode (plusPtr pos 1) end startCol
285− _ -> EscapeProblem (E.EscapeUnknown startCol (startCol + 1))
284+ 0x75 {- u -} -> eatUnicode (plusPtr pos 1) end row col
285+ _ -> EscapeProblem row col E.EscapeUnknown
286286
287287
288−eatUnicode :: Ptr Word8 -> Ptr Word8 -> Word16 -> Escape
289−eatUnicode pos end startCol =
288+eatUnicode :: Ptr Word8 -> Ptr Word8 -> Row -> Col -> Escape
289+eatUnicode pos end row col =
290290 if pos >= end || P.unsafeIndex pos /= 0x7B {- { -} then
291− EscapeProblem $ E.BadUnicodeFormat startCol (startCol + 1)
291+ EscapeProblem row col (E.BadUnicodeFormat 2)
292292 else
293293 let
294294 !digitPos = plusPtr pos 1
@@ -296,18 +296,15 @@ eatUnicode pos end startCol =
296296 !numDigits = minusPtr newPos digitPos
297297 in
298298 if newPos >= end || P.unsafeIndex newPos /= 0x7D {- } -} then
299− EscapeProblem $ E.BadUnicodeFormat startCol $
300− startCol + fromIntegral (minusPtr newPos pos)
299+ EscapeProblem row col $ E.BadUnicodeFormat (2 + fromIntegral (minusPtr newPos pos))
301300
302301 else if code < 0 || 0x10FFFF < code then
303− EscapeProblem $ E.BadUnicodeCode startCol $
304− startCol + fromIntegral (minusPtr newPos pos) + 1
302+ EscapeProblem row col $ E.BadUnicodeCode (3 + fromIntegral (minusPtr newPos pos))
305303
306304 else if numDigits < 4 || 6 < numDigits then
307− EscapeProblem $
305+ EscapeProblem row col $
308306 E.BadUnicodeLength
309− startCol
310− (startCol + fromIntegral (minusPtr newPos pos) + 1)
307+ (3 + fromIntegral (minusPtr newPos pos))
311308 numDigits
312309 code
313310
compiler/src/Reporting/Error/Syntax.hs+201−238
@@ -49,7 +49,7 @@ import Prelude hiding (Char, String)
4949import qualified Data.Char as Char
5050import qualified Data.Name as Name
5151import Data.Word (Word16)
52−--import Numeric (showHex)
52+import Numeric (showHex)
5353
5454import qualified Elm.ModuleName as ModuleName
5555import Parse.Primitives (Row, Col)
@@ -470,7 +470,7 @@ data TTuple
470470data Char
471471 = CharEndless
472472 | CharEscape Escape
473− | CharNotString Int
473+ | CharNotString Word16
474474
475475
476476data String
@@ -480,10 +480,10 @@ data String
480480
481481
482482data Escape
483− = EscapeUnknown Word16 Word16
484− | BadUnicodeFormat Word16 Word16
485− | BadUnicodeCode Word16 Word16
486− | BadUnicodeLength Word16 Word16 Int Int
483+ = EscapeUnknown
484+ | BadUnicodeFormat Word16
485+ | BadUnicodeCode Word16
486+ | BadUnicodeLength Word16 Int Int
487487
488488
489489data Number
@@ -550,7 +550,7 @@ toReport source err =
550550 ++ ModuleName.toChars expectedName
551551 ++ "` here. Make the following change, and you should be all set!"
552552 , 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)
554554 , D.toSimpleNote $
555555 "I require that module names correspond to file paths. This makes it much\
556556 \ easier to explore unfamiliar codebases! So if you want to keep the current\
@@ -835,11 +835,11 @@ toExprReport source _ expr _ _ =
835835 Start _ _ ->
836836 error "TODO Start"
837837
838− Char _ _ _ ->
839− error "TODO Char"
838+ Char char row col ->
839+ toCharReport source char row col
840840
841− String _ _ _ ->
842− error "TODO String"
841+ String string row col ->
842+ toStringReport source string row col
843843
844844 Number number row col ->
845845 toNumberReport source number row col
@@ -884,6 +884,196 @@ toExprReport source _ expr _ _ =
884884 error "TODO IndentMoreExpr"
885885
886886
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+
8871077toNumberReport :: Code.Source -> Number -> Row -> Col -> Report.Report
8881078toNumberReport source number row col =
8891079 let
@@ -1051,233 +1241,6 @@ toNumberReport source number row col =
10511241 "I need a single digit between 0 and 9 inclusive."
10521242 )
10531243
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−
12811244 Operator ->
12821245 Report.Report "EXPECTING AN OPERATOR" region [] $
12831246 Report.toCodeSnippet source region Nothing