on master help sign in
Shuffle things so Error.Syntax focuses more on parsing problems
commitfe2a01c71fb5498245c186050f15bc3de8c0f24b authorEvan Czaplicki <evancz@users.noreply.github.com> dateMon 15 Jan 2018, 15:56 (9 years ago) parentb537946
1 file changed+366−555
src/Reporting/Error/Syntax.hs+366−555
src/Reporting/Error/Syntax.hs+366−555
@@ -11,15 +11,16 @@ module Reporting.Error.Syntax
1111 )
1212 where
1313
14−import qualified Data.Set as Set
14+
15+import Data.Monoid ((<>))
1516import qualified Data.Text as Text
1617import Data.Text (Text)
1718
18−import qualified Reporting.Render.Type as RenderType
19+import qualified Elm.Name as N
1920import qualified Reporting.Region as R
21+import qualified Reporting.Render.Code as Code
2022import qualified Reporting.Report as Report
21−import qualified Reporting.Helpers as Help
22−import Reporting.Helpers ((<>), dullyellow, green, hsep, i2t, reflowParagraph, text)
23+import qualified Reporting.Helpers as H
2324
2425
2526
@@ -27,31 +28,10 @@ import Reporting.Helpers ((<>), dullyellow, green, hsep, i2t, reflowParagraph, t
2728
2829
2930data Error
30− = Parse (Maybe R.Region) Problem
31− | BadFunctionName Int
32− | BadPattern Text
33−
34− | CommentOnNothing
35−
36− | SettingsOnNormalModule
37− | SettingsOnPortModule
38− | DuplicateSettingOnEffectModule Text
39− | BadSettingOnEffectModule Text
40− | NoSettingsOnEffectModule
41− | MissingManagerOnEffectModule Text
42− | UnexpectedPort Text
43−
44− | TypeWithoutDefinition Text
45−
46− | DuplicateArgument Text Text
47− | DuplicateFieldName R.Region Text
48− | DuplicateValueDeclaration Text
49− | DuplicateTypeDeclaration Text
50− | DuplicateDefinition Text
51− | UnboundTypeVarsInUnion Text [Text] [Text]
52− | UnboundTypeVarsInAlias Text [Text] [Text]
53− | UnusedTypeVarsInAlias Text [Text] [Text]
54− | MessyTypeVarsInAlias Text [Text] [Text] [Text]
31+ = CommentOnNothing R.Region
32+ | UnexpectedPort R.Region N.Name
33+ | TypeWithoutDefinition R.Region N.Name
34+ | Parse R.Region (Maybe R.Region) Problem
5535
5636
5737
@@ -72,13 +52,14 @@ data Problem
7252 | NewLineInChar
7353 | BadEscape Int EscapeProblem
7454 | BadChar Int
75− | BadNumberDot
55+ | BadNumberDot Int
7656 | BadNumberEnd
7757 | BadNumberExp
7858 | BadNumberHex
7959 | BadNumberZero
60+ | FloatInPattern
8061 | BadShader Text
81− | BadUnderscore Char
62+ | BadUnderscore Int
8263 | BadOp BadOp ContextStack
8364 | Theories ContextStack [Theory]
8465
@@ -87,15 +68,15 @@ data EscapeProblem
8768 = UnknownEscape
8869 | UnicodeSyntax
8970 | UnicodeRange
90− | UnicodeLength Int Text
71+ | UnicodeLength Int String
9172
9273
9374data BadOp = HasType | Equals | Arrow | Pipe | Dot
9475
9576
9677data Theory
97− = Keyword Text
98− | Symbol Text
78+ = Keyword String
79+ | Symbol String
9980 | Expecting Next
10081 | LowVar
10182 | CapVar
@@ -130,8 +111,8 @@ data Context
130111 | ExprTuple
131112 | ExprRecord
132113 ----------------
133− | Definition Text
134− | Annotation Text
114+ | Definition N.Name
115+ | Annotation N.Name
135116 ----------------
136117 | TypeTuple
137118 | TypeRecord
@@ -153,599 +134,406 @@ data Context
153134-- TO REPORT
154135
155136
156−toReport :: RenderType.Localizer -> Error -> Report.Report
157−toReport _localizer err =
137+toReport :: Code.Source -> Error -> Report.Report
138+toReport source err =
158139 case err of
159− Parse subRegion problem ->
160− problemToReport subRegion problem
161−
162− BadFunctionName arity ->
163− Report.report
164− "BAD FUNCTION DEFINITION"
165− Nothing
166− "Complex patterns cannot be used as function names."
167− ( reflowParagraph $
168− "This function definition has " <> i2t arity <> " arguments, but instead\
169− \ of a normal name like `add` or `reverse` it has a pattern. There is no\
170− \ way to \"deconstruct\" a function with pattern matching, so this needs to\
171− \ be changed to a normal name."
172− )
173−
174− BadPattern name ->
175− Report.report
176− "BAD PATTERN"
177− Nothing
178− ("The free variable `" <> name <> "` appears more than once in this pattern.")
179− ( Help.stack
180− [ text "Rename the variables so there are no duplicates."
181− , reflowParagraph $
182− "In Elm, pattern matching works by binding these free variables to subsections\
183− \ of the matching value. It does not make sense to have the same name for two\
184− \ different subsections though! When you say `" <> name <> "` in some code, there\
185− \ is no way for me to know which subsection you mean!"
186− ]
187− )
188−
189− CommentOnNothing ->
190− Report.report
191− "STRAY COMMENT"
192− Nothing
193− ("This documentation comment is not followed by anything.")
194− ( reflowParagraph $
140+ CommentOnNothing region ->
141+ Report.Report "STRAY COMMENT" region [] $
142+ Report.toCodeSnippet source region Nothing
143+ (
144+ "This documentation comment is not followed by anything."
145+ ,
146+ H.reflow $
195147 "All documentation comments need to be right above the declaration they\
196148 \ describe. Maybe some code got deleted or commented out by accident? Or\
197149 \ maybe this comment is here by accident?"
198150 )
199151
200− SettingsOnNormalModule ->
201− Report.report
202− "BAD MODULE DECLARATION"
203− Nothing
204− "A normal module can expose values, but not settings like this."
205− ( reflowParagraph $
206− "If you want a normal module, just remove this stuff. If you want to create\
207− \ an `effect module` you forgot to use the `effect` keyword. In that\
208− \ case, change `module` to `effect module` and you should be headed in\
209− \ the right direction!"
210− )
211−
212− SettingsOnPortModule ->
213− Report.report
214− "BAD MODULE DECLARATION"
215− Nothing
216− "A port module can expose values, but not have settings like this."
217− ( reflowParagraph $
218− "If you want a port module, just remove this stuff. If you want to create\
219− \ a custom effect module instead (which is rare) change `port module`\
220− \ to `effect module` and you should be headed in the right direction!"
221− )
222−
223− DuplicateSettingOnEffectModule name ->
224− Report.report
225− "EFFECT MODULE PROBLEM"
226− Nothing
227− ("You have defined " <> Help.functionName name <> " multiple times.")
228− ( reflowParagraph $
229− "There can only be one " <> Help.functionName name
230− <> " though! Remove until there is one left."
231− )
232−
233− BadSettingOnEffectModule name ->
234− Report.report
235− "EFFECT MODULE PROBLEM"
236− Nothing
237− ("Setting " <> Help.functionName name <> " is not recognized.")
238− ( reflowParagraph $
239− "Remove this entry and you should be all set!"
240− )
241−
242− NoSettingsOnEffectModule ->
243− Report.report
244− "EFFECT MODULE PROBLEM"
245− Nothing
246− ("You are defining an effect module, but it has no settings.")
247− ( reflowParagraph $
248− "If you just wanted a normal module, change the keywords `effect module`\
249− \ to `module` and you should be all set. If you want a proper effect module,\
250− \ you need to specify your commands and/or subscriptions. Read more about this\
251− \ here: <http://guide.elm-lang.org/effect_managers/>"
252− )
253−
254− MissingManagerOnEffectModule name ->
255− Report.report
256− "EFFECT MODULE PROBLEM"
257− Nothing
258− ("You are defining an effect module, but there is no " <> Help.functionName name <> " defined.")
259− ( reflowParagraph $
260− "There is a small set of top-level functions and values that must be defined\
261− \ in any complete effect module. The best thing is probably to just read more\
262− \ about effect modules here:\
263− \ <http://guide.elm-lang.org/effect_managers/>"
264− )
265−
266− UnexpectedPort name ->
267− Report.report
268− "BAD PORT"
269− Nothing
270− ("You are declaring port " <> Help.functionName name <> " in a normal module.")
271− ( reflowParagraph $
272− "All ports must be defined in a `port module`. You should probably have only\
273− \ one of these for your project. This way all of your foreign interactions\
274− \ stay relatively organized."
275− )
276−
277− TypeWithoutDefinition valueName ->
278− Report.report
279− "MISSING DEFINITION"
280− Nothing
281− ("There is a type annotation for `" <> valueName <> "` but there"
282− <> " is no corresponding definition!"
283− )
284− ( text $
285− "Directly below the type annotation, put a definition like:\n\n"
286− <> " " <> valueName <> " = 42"
287− )
288−
289− DuplicateArgument funcName argName ->
290− Report.report
291− "DUPLICATE ARGUMENT"
292− Nothing
293− ( "The name `" <> argName
294− <> "` is used more than once in the arguments of "
295− <> Help.functionName funcName <> "."
296− )
297− ( reflowParagraph $
298− "Rename things until `" <> argName <> "` is used only once.\
299− \ Otherwise how can we tell which one you want when you\
300− \ say `" <> argName <> "` it in the body of your function?"
301− )
302−
303− DuplicateFieldName region name ->
304− Report.report
305− "DUPLICATE FIELD"
306− (Just region)
307− ("This record has more than one field named `" <> name <> "`.")
308− (text "There can only be one. Do some renaming to make sure the names are distinct!")
309−
310− DuplicateValueDeclaration name ->
311− Report.report
312− "DUPLICATE DEFINITION"
313− Nothing
314− ( "Naming multiple top-level values " <> Help.functionName name <> " makes things\n"
315− <> "ambiguous. When you say " <> Help.functionName name <> " which one do you want?"
316− )
317− ( reflowParagraph $
318− "Find all the top-level values named " <> Help.functionName name
319− <> " and do some renaming. Make sure the names are distinct!"
320− )
321−
322− DuplicateTypeDeclaration name ->
323− Report.report
324− "DUPLICATE DEFINITION"
325− Nothing
326− ( "There are multiple types named `" <> name <> "` in this module."
327− )
328− ( reflowParagraph $
329− "Search through this module, find all the types named `"
330− <> name <> "`, and give each of them a unique name."
331− )
332−
333− DuplicateDefinition name ->
334− Report.report
335− "DUPLICATE DEFINITION"
336− Nothing
337− ("There are multiple values named `" <> name <> "` in this let-expression."
338− )
339− ( reflowParagraph $
340− "Search through this let-expression, find all the values named `"
341− <> name <> "`, and give each of them a unique name."
342− )
343−
344− UnboundTypeVarsInUnion typeName givenVars unbound ->
345− unboundTypeVars "type" typeName givenVars unbound
346−
347− UnboundTypeVarsInAlias typeName givenVars unbound ->
348− unboundTypeVars "type alias" typeName givenVars unbound
349−
350− UnusedTypeVarsInAlias typeName givenVars unused ->
351− Report.report
352− "UNUSED TYPE VARIABLES"
353− Nothing
354− ( "Type alias `" <> typeName <> "` cannot have unused type variables: "
355− <> Help.commaSep unused
356− )
357− ( Help.stack
358− [ text "You probably need to change the declaration like this:"
359− , dullyellow $ hsep $
360− map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ ["=", "..."])
152+ UnexpectedPort region name ->
153+ Report.Report "BAD PORT" region [] $
154+ Report.toCodeSnippet source region Nothing
155+ (
156+ H.reflow $
157+ "You are declaring port `" <> N.toString name <> "` in a normal module."
158+ ,
159+ H.stack
160+ [ "It needs to be in a `port` module."
161+ , H.link "Hint"
162+ "Ports are not a traditional FFI for calling JS functions directly. They need a different mindset! Read"
163+ "ports"
164+ "to learn how to use ports effectively."
361165 ]
362166 )
363167
364− MessyTypeVarsInAlias typeName givenVars unused unbound ->
365− Report.report
366− "TYPE VARIABLE PROBLEMS"
367− Nothing
368− ( "Type alias `" <> typeName <> "` has some problems with type variables."
168+ TypeWithoutDefinition region valueName ->
169+ Report.Report "MISSING DEFINITION" region [] $
170+ Report.toCodeSnippet source region Nothing
171+ (
172+ H.reflow $
173+ "There is a type annotation for `" <> N.toString valueName
174+ <> "` but there is no corresponding definition!"
175+ ,
176+ "Directly below the type annotation, put a definition like:\n\n"
177+ <> " " <> H.nameToDoc valueName <> " = 42"
369178 )
370− ( Help.stack
371− [ reflowParagraph $
372− "The declaration says it uses certain type variables ("
373− <> Help.commaSep unused <> ") but they do not appear in the aliased type. "
374− <> "Furthermore, the aliased type says it uses type variables ("
375− <> Help.commaSep unbound
376− <> ") that do not appear in the declaration."
377− , text "You probably need to change the declaration like this:"
378− , dullyellow $ hsep $
379− map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ unbound ++ ["=", "..."])
380− ]
381− )
382−
383−
384−unboundTypeVars :: Text -> Text -> [Text] -> [Text] -> Report.Report
385−unboundTypeVars declKind typeName givenVars unboundVars =
386− Report.report
387− "UNBOUND TYPE VARIABLES"
388− Nothing
389− ( Help.capitalize declKind <> " `" <> typeName <> "` must declare its use of type variable"
390− <> Help.commaSep unboundVars
391− )
392− ( Help.stack
393− [ text "You probably need to change the declaration like this:"
394− , hsep $
395− map text (declKind : typeName : givenVars)
396− ++ map (dullyellow . text) unboundVars
397− ++ map text ["=", "..."]
398− , reflowParagraph $
399− "Here's why. Imagine one `" <> typeName <> "` where `" <> head unboundVars <>
400− "` is an Int and another where it is a Bool. When we explicitly list the type\
401− \ variables, the type checker can see that they are actually different types."
402− ]
403− )
404179
180+ Parse region subRegion problem ->
181+ Report.Report "PARSE ERROR" (maybe region id subRegion) [] $
182+ Report.toCodeSnippet source region subRegion $
183+ problemToDocs problem
405184
406185
407−-- PARSE ERROR TO REPORT
408186
187+-- PARSE ERROR TO DOCS
409188
410−makeParseReport :: Maybe R.Region -> Text -> Help.Doc -> Report.Report
411−makeParseReport subRegion pre post =
412− Report.report "PARSE ERROR" subRegion pre post
413189
414−
415−problemToReport :: Maybe R.Region -> Problem -> Report.Report
416−problemToReport subRegion problem =
417− let parseReport = makeParseReport subRegion in
190+problemToDocs :: Problem -> (H.Doc, H.Doc)
191+problemToDocs problem =
418192 case problem of
419193 Tab ->
420− parseReport
194+ (
421195 "I ran into a tab, but tabs are not allowed in Elm files."
422− (reflowParagraph "Replace the tab with spages.")
196+ ,
197+ "Replace the tab with spaces."
198+ )
423199
424200 EndOfFile_Comment ->
425− parseReport
201+ (
426202 "I got to the end of the file while parsing a multi-line comment."
427− ( Help.stack
428− [ reflowParagraph $
429− "Multi-line comments look like {- comment -}, and it looks like\
430− \ you are missing the closing marker."
431− , reflowParagraph $
432− "Nested multi-line comments like {- this {- and this -} -} are allowed.\
433− \ That means the opening and closing markers must be balanced, just\
434− \ like parentheses in normal code. Maybe that is the problem?"
435− ]
436− )
203+ ,
204+ H.stack
205+ [ H.reflow $
206+ "Multi-line comments look like {- comment -}, and it looks like\
207+ \ you are missing the closing marker."
208+ , H.toSimpleHint $
209+ "Nested multi-line comments like {- this {- and this -} -} are allowed.\
210+ \ The opening and closing markers must be balanced though, just\
211+ \ like parentheses in normal code. Maybe that is the problem?"
212+ ]
213+ )
437214
438215 EndOfFile_Shader ->
439− parseReport
216+ (
440217 "I got to the end of the file while parsing a GLSL block."
441− (reflowParagraph $
218+ ,
219+ H.reflow $
442220 "A shader should be defined in a block like this: [glsl| ... |]"
443− )
221+ )
444222
445223 EndOfFile_String ->
446− parseReport
224+ (
447225 "I got to the end of the file while parsing a string."
448− (reflowParagraph $
226+ ,
227+ H.reflow $
449228 "Strings look like \"this\" with double quotes on each end.\
450− \ So the closing double quote seems to be missing."
451− )
229+ \ Is the closing double quote missing in your code?"
230+ )
452231
453232 EndOfFile_MultiString ->
454− parseReport
233+ (
455234 "I got to the end of the file while parsing a multi-line string."
456− (reflowParagraph $
457− "Multi-line strings begin and end with three double quotes in a\
458− \ row, like \"\"\"this\"\"\". So the closing marker seems\
459− \ to be missing."
460− )
235+ ,
236+ H.reflow $
237+ "Multi-line strings look like \"\"\"this\"\"\" with three double quotes on each\
238+ \ end. Is the closing triple quote missing in your code?"
239+ )
461240
462241 EndOfFile_Char ->
463− parseReport
242+ (
464243 "I got to the end of the file while parsing a character."
465− (reflowParagraph $
466− "Characters look like 'x' with single quotes on each end.\
467− \ So the closing single quote seems to be missing."
468− )
244+ ,
245+ H.reflow $
246+ "Characters look like 'c' with single quotes on each end.\
247+ \ Is the closing single quote missing in your code?"
248+ )
469249
470250 NewLineInString ->
471− parseReport
251+ (
472252 "This string is missing the closing quote."
473− ( Help.stack
474− [ reflowParagraph $
475− "Elm strings must start and end with a double quote, like \"this\"."
476− , reflowParagraph $
477− "If you want a string that can contain newlines, use three double quotes in a\
478− \ row, like \"\"\"this\"\"\"."
479− ]
480− )
253+ ,
254+ H.stack
255+ [ H.reflow $
256+ "Elm strings like \"this\" cannot contain newlines."
257+ , H.toSimpleHint $
258+ "For strings that CAN contain newlines, say \"\"\"this\"\"\" for Elm’s\
259+ \ multi-line string syntax. It allows unescaped newlines and double quotes."
260+ ]
261+ )
481262
482263 NewLineInChar ->
483− parseReport
264+ (
484265 "This character is missing the closing quote."
485− ( reflowParagraph $
486− "Elm characters must start and end with a single quote, like 'a' and 'b'"
487− )
266+ ,
267+ "Elm characters must start and end with a single quote. Valid examples\n\
268+ \ include 'a', 'b', '\n', 'ø', and '\\u{00F8}' for unicode code points."
269+ )
488270
489271 BadEscape _ escapeProblem ->
490− uncurry parseReport (escapeProblemToReport escapeProblem)
272+ case escapeProblem of
273+ UnknownEscape ->
274+ (
275+ "Backslashes always start escaped characters, but I do not recognize this one:"
276+ , H.stack
277+ [ "Maybe there is some typo?"
278+ , H.toSimpleHint "Valid escape characters include:"
279+ , H.indent 4 $ H.vcat $
280+ [ "\\n"
281+ , "\\r"
282+ , "\\t"
283+ , "\\\""
284+ , "\\\'"
285+ , "\\\\"
286+ , "\\u{03BB}"
287+ ]
288+ , H.reflow $
289+ "The last one lets encode ANY character by its Unicode code\
290+ \ point, so use that for anything outside the ordinary six."
291+ ]
292+ )
293+
294+ UnicodeSyntax ->
295+ (
296+ "I ran into an invalid Unicode escape character:"
297+ ,
298+ H.stack
299+ [ "Here are some examples of valid Unicode escape characters:"
300+ , H.indent 4 $ H.vcat $
301+ [ "\\u{0041}"
302+ , "\\u{03BB}"
303+ , "\\u{6728}"
304+ , "\\u{1F60A}"
305+ ]
306+ , H.reflow $
307+ "Notice that the code point is always surrounded by curly\
308+ \ braces. They are required!"
309+ ]
310+ )
311+
312+ UnicodeRange ->
313+ (
314+ "This is not a real Unicode code point:"
315+ ,
316+ "All valid Unicode code points are between 0 and 10FFFF."
317+ )
318+
319+ UnicodeLength numDigits badCode ->
320+ if numDigits < 4 then
321+ (
322+ "Every Unicode code point needs at least four digits:"
323+ ,
324+ let
325+ goodCode = replicate (4 - numDigits) '0' ++ badCode
326+ escape = "\\u{" <> H.text goodCode <> "}"
327+ in
328+ H.hsep [ "Try", H.dullyellow escape, "instead?" ]
329+ )
330+
331+ else
332+ (
333+ "This Unicode code point has too many digits:"
334+ ,
335+ H.fillSep
336+ ["Valid","code","points","are","between"
337+ , H.dullyellow "\\u{0000}", "and", H.dullyellow "\\u{10FFFF}"
338+ ,"so","it","must","have","between","four","and","six","digits."
339+ ]
340+ )
491341
492342 BadChar _ ->
493− parseReport
343+ (
494344 "Ran into a bad use of single quotes."
495− ( Help.stack
496− [ reflowParagraph $
497− "If you want to create a string, switch to double quotes:"
498− , Help.indent 4 $
499− dullyellow (text "'this'")
500− <> text " => "
501− <> green (text "\"this\"")
502− , reflowParagraph $
503− "Unlike JavaScript, Elm distinguishes between strings like \"hello\"\
504− \ and individual characters like 'A' and '3'. If you really do want\
505− \ a character though, something went wrong and I did not find the\
506− \ closing single quote."
507− ]
508− )
509−
510− BadNumberDot ->
511− parseReport
345+ ,
346+ H.stack
347+ [ H.reflow $
348+ "If you want to create a string, switch to double quotes:"
349+ , H.indent 4 $
350+ H.dullyellow "'this'" <> " => " <> H.green "\"this\""
351+ , H.toSimpleHint $
352+ "Unlike JavaScript, Elm distinguishes between strings like \"hello\"\
353+ \ and individual characters like 'A' and '3'. If you really do want\
354+ \ a character though, something went wrong and I did not find the\
355+ \ closing single quote."
356+ ]
357+ )
358+
359+ BadNumberDot numberBeforeDot ->
360+ (
512361 "Numbers cannot end with a decimal points."
513− ( reflowParagraph $
514− "Leave it off or add some digits after it, like or 3 or 3.0"
515− )
362+ ,
363+ let
364+ number =
365+ H.text (show numberBeforeDot)
366+ in
367+ "Saying " <> H.green number <> " or " <> H.green (number <> ".0") <> " will work though!"
368+ )
516369
517370 BadNumberEnd ->
518− parseReport
371+ (
519372 "Numbers cannot have letters or underscores in them."
520− ( reflowParagraph $
521− "Maybe a space is missing between a number and a variable?"
522− )
373+ ,
374+ H.reflow $
375+ "Maybe a space is missing between a number and a variable?"
376+ )
523377
524378 BadNumberExp ->
525− parseReport
379+ (
526380 "If you put the letter E in a number, it should followed by more digits."
527− ( reflowParagraph $
528− "If you want to say 1000, you can also say 1e3.\
529− \ You cannot just end it with an E though!"
530− )
381+ ,
382+ H.reflow $
383+ "If you want to say 1000, you can also say 1e3.\
384+ \ You cannot just end it with an E though!"
385+ )
531386
532387 BadNumberHex ->
533− parseReport
388+ (
534389 "I see the start of a hex number, but not the end."
535− ( reflowParagraph $
536− "A hex number looks like 0x123ABC, where the 0x is followed by hexidecimal digits (i.e. 0123456789abcdefABCDEF)"
537− )
390+ ,
391+ H.reflow $
392+ "A hex number looks like 0x123ABC, where the 0x is followed by hexidecimal\
393+ \ digits. Valid hexidecimal digits include: 0123456789abcdefABCDEF"
394+ )
538395
539396 BadNumberZero ->
540− parseReport
541− "Normal numbers cannot start with a zero. Take the zeros off the front."
542− ( reflowParagraph $
543− "Only numbers like 0x0040 or 0.25 can start with a zero."
544− )
397+ (
398+ "Normal numbers cannot start with zeros. Take the zeros off the front."
399+ ,
400+ H.reflow $
401+ "Only numbers like 0x0040 or 0.25 can start with a zero."
402+ )
403+
404+ FloatInPattern ->
405+ (
406+ "I cannot pattern match with floating point numbers:"
407+ ,
408+ H.reflow $
409+ "Equality on floats can be unreliable, so you usually want to check that they\
410+ \ are nearby with some sort of (abs (actual - expected) < 0.001) check."
411+ )
545412
546413 BadShader msg ->
547− parseReport
414+ (
548415 "I ran into a problem while parsing this GLSL block."
549− (reflowParagraph msg)
416+ ,
417+ H.reflow (Text.unpack msg)
418+ )
550419
551− BadUnderscore char ->
552− parseReport
553− ("An underscore cannot be immediately followed by `" <> Text.singleton char <> "`.")
554− ( reflowParagraph $
555− "Variable names cannot start with an underscore in Elm. You can\
556− \ use an underscore as a \"wildcard\" that matches anything\
557− \ though. So maybe you forgot a space after the underscore?"
558− )
420+ BadUnderscore _ ->
421+ (
422+ "A variable name cannot start with an underscore:"
423+ ,
424+ H.reflow $
425+ "You can (1) use a wildcard like _ to ignore the value or you can (2) use\
426+ \ a name that starts with a letter to access the value later. Pick one!"
427+ )
559428
560429 BadOp op stack ->
561430 case op of
562431 HasType ->
563− badOp subRegion stack "A" "\"has type\" operator"
432+ badOp stack "A" "\"has type\" operator"
564433 "type annotations and record types"
565434 "Maybe you want :: instead? Or maybe something is indented too much?"
566435
567436 Equals ->
568− badEquals subRegion stack
437+ (
438+ H.reflow $
439+ "I was not expecting this equals sign"
440+ <> contextToString " here" " while parsing " stack <> "."
441+ ,
442+ toBadEqualsHint stack
443+ )
569444
570445 Arrow ->
571446 if isCaseRelated stack then
572− parseReport
447+ (
573448 "I ran into a stray arrow while parsing this `case` expression."
574− ( reflowParagraph $
575− "All branches in a `case` must be indented the exact\
576− \ same amount, so the patterns are vertically\
577− \ aligned. Maybe this branch is indented too much?"
578− )
449+ ,
450+ H.reflow $
451+ "All branches in a `case` must be indented the exact\
452+ \ same amount, so the patterns are vertically\
453+ \ aligned. Maybe this branch is indented too much?"
454+ )
579455
580456 else
581− badOp subRegion stack "An" "arrow"
457+ badOp stack "An" "arrow"
582458 "cases expressions and anonymous functions"
583459 "Maybe you want > or >= instead?"
584460
585461 Pipe ->
586− badOp subRegion stack "A" "vertical bar"
462+ badOp stack "A" "vertical bar"
587463 "type declarations"
588464 "Maybe you want || instead?"
589465
590466 Dot ->
591− parseReport
467+ (
592468 "I was not expecting this dot."
593− ( reflowParagraph $
594− "Dots are for record access and decimal points, so\
595− \ they cannot float around on their own. Maybe\
596− \ there is some extra whitespace?"
597− )
469+ ,
470+ H.reflow $
471+ "Dots are for record access and decimal points, so\
472+ \ they cannot float around on their own. Maybe\
473+ \ there is some extra whitespace?"
474+ )
598475
599476 Theories stack allTheories ->
600− let
601− starter =
602− "Something went wrong while parsing "
603− <> contextToText "your code" "" stack
604− <> "."
605− in
606− parseReport starter $
607− case Set.toList (Set.fromList allTheories) of
608− [] ->
609− Help.stack
610− [ reflowParagraph $
611− "I do not have any suggestions though!"
612− , reflowParagraph $
613− "Can you get it down to a <http://sscce.org> and share it at\
614− \ <https://github.com/elm-lang/error-message-catalog/issues>?\
615− \ That way we can figure out how to give better advice!"
616− ]
617−
618− [theory] ->
619− reflowParagraph $
620− "I was expecting to see "
621− <> addPeriod (theoryToText stack theory)
622−
623− theories ->
624− Help.vcat $
625− [ text "I was expecting:"
626− , text ""
627− ]
628− ++ map (bullet . theoryToText stack) theories
629−
630−
631−escapeProblemToReport :: EscapeProblem -> ( Text, Help.Doc )
632−escapeProblemToReport escapeProblem =
633− case escapeProblem of
634− UnknownEscape ->
635− ( "A backslash starts an escaped character, but I do not recognize this one:"
636− , Help.stack
637− [ "Maybe there is some typo?"
638− , Help.toSimpleHint "Valid escape characters include:"
639− , Help.indent 4 $ Help.vcat $
640− [ "\\n"
641− , "\\r"
642− , "\\t"
643− , "\\\""
644− , "\\\'"
645− , "\\\\"
646− , "\\u{03BB}"
647− ]
648− , reflowParagraph $
649− "The last one lets encode ANY character by its Unicode code\
650− \ point, so there are no other escape characters in Elm."
651− ]
652− )
653−
654− UnicodeSyntax ->
655− ( "I ran into an invalid Unicode escape character:"
656− , Help.stack
657− [ "Here are some examples of valid Unicode escape characters:"
658− , Help.indent 4 $ Help.vcat $
659− [ "\\u{0041}"
660− , "\\u{03BB}"
661− , "\\u{6728}"
662− , "\\u{1F60A}"
477+ (
478+ H.reflow $
479+ "Something went wrong while parsing " <> contextToString "your code" "" stack <> "."
480+ ,
481+ case allTheories of
482+ [] ->
483+ H.stack
484+ [ H.reflow $
485+ "I do not have any suggestions though!"
486+ , H.reflow $
487+ "Can you get it down to a <http://sscce.org> and share it at\
488+ \ <https://github.com/elm-lang/error-message-catalog/issues>?\
489+ \ That way we can figure out how to give better advice!"
663490 ]
664− , reflowParagraph $
665− "Notice that the code point is always surrounded by curly\
666− \ braces. They are required!"
667− ]
668− )
669−
670− UnicodeRange ->
671− ( "This is not a real Unicode code point:"
672− , "All valid Unicode code points are between 0 and 10FFFF."
673− )
674491
675− UnicodeLength numDigits badCode ->
676− let
677− moreOrFewer =
678− if numDigits < 4 then "more" else "fewer"
679−
680− goodCode =
681− Text.justifyRight 4 '0' $ Text.dropWhile (== '0') badCode
492+ [theory] ->
493+ H.reflow $
494+ "I was expecting to see "
495+ <> addPeriod (theoryToString stack theory)
682496
683− suggestion =
684− [ "Try"
685− , "using"
686− , dullyellow $ text $ "\\u{" <> goodCode <> "}"
687− , "instead."
688− ]
689− in
690− ( "This Unicode code point needs " <> moreOrFewer <> " digits:"
691− , hsep suggestion
497+ theories ->
498+ H.vcat $
499+ [ "I was expecting:"
500+ , ""
501+ ]
502+ ++ map (bullet . theoryToString stack) theories
692503 )
693504
694505
695506
696−-- HELPERS
507+-- BAD OP HELPERS
697508
698509
699−bullet :: Text -> Help.Doc
700−bullet point =
701− Help.hang 4 (" - " <> reflowParagraph point)
702−
703−
704−addPeriod :: Text -> Text
705−addPeriod msg =
706− if Text.last msg `elem` ['`', ')', '.', '!', '?'] then
707− msg
708− else
709− msg <> "."
510+badOp :: ContextStack -> String -> String -> String -> String -> ( H.Doc, H.Doc )
511+badOp stack article opName setting hint =
512+ (
513+ H.reflow $
514+ "I was not expecting this " <> opName
515+ <> contextToString " here" " while parsing " stack <> "."
516+ ,
517+ H.reflow $
518+ article <> " " <> opName <> " should only appear in "
519+ <> setting <> ". " <> hint
520+ )
710521
711522
712−badOp :: Maybe R.Region -> ContextStack -> Text -> Text -> Text -> Text -> Report.Report
713−badOp subRegion stack article opName setting hint =
714− let
715− pre =
716− "I was not expecting this " <> opName
717− <> contextToText "" " while parsing " stack <> "."
718− in
719− makeParseReport subRegion pre $
720− reflowParagraph $
721− article <> " " <> opName <> " should only appear in "
722− <> setting <> ". " <> hint
723−
724−
725−badEquals :: Maybe R.Region -> ContextStack -> Report.Report
726−badEquals subRegion stack =
727− let
728− pre =
729− "I was not expecting this equals sign"
730− <> contextToText "" " while parsing " stack <> "."
731− in
732− makeParseReport subRegion pre (badEqualsHelp stack)
733−
734−
735−badEqualsHelp :: ContextStack -> Help.Doc
736−badEqualsHelp stack =
523+toBadEqualsHint :: ContextStack -> H.Doc
524+toBadEqualsHint stack =
737525 case stack of
738526 [] ->
739− reflowParagraph $
527+ H.reflow $
740528 "Maybe you want == instead? Or maybe something is indented too much?"
741529
742530 (ExprRecord, _) : _ ->
743− reflowParagraph $
531+ H.reflow $
744532 "Records look like { x = 3, y = 4 } with the equals sign right\
745533 \ after the field name. Maybe you forgot a comma?"
746534
747535 (Definition _, _) : rest ->
748− reflowParagraph $
536+ H.reflow $
749537 "Maybe this is supposed to be a separate definition? If so, it\
750538 \ is indented too far. "
751539 <>
@@ -755,28 +543,43 @@ badEqualsHelp stack =
755543 "Spaces are not allowed before top-level definitions."
756544
757545 _ : rest ->
758− badEqualsHelp rest
546+ toBadEqualsHint rest
547+
548+
549+
550+isCaseRelated :: ContextStack -> Bool
551+isCaseRelated stack =
552+ case stack of
553+ [] ->
554+ False
555+
556+ (context, _) : rest ->
557+ context == ExprCase || isCaseRelated rest
558+
759559
760560
761−contextToText :: Text -> Text -> ContextStack -> Text
762−contextToText defaultText prefixText stack =
561+-- CONTEXT
562+
563+
564+contextToString :: String -> String -> ContextStack -> String
565+contextToString defaultString prefixString stack =
763566 case stack of
764567 [] ->
765− defaultText
568+ defaultString
766569
767570 (context, _) : rest ->
768571 let anchor = getAnchor rest in
769− prefixText <>
572+ prefixString <>
770573 case context of
771− ExprIf -> "an `if`" <> anchor
772− ExprLet -> "a `let`" <> anchor
574+ ExprIf -> "an `if` expression" <> anchor
575+ ExprLet -> "a `let` expression" <> anchor
773576 ExprFunc -> "an anonymous function" <> anchor
774− ExprCase -> "a `case`" <> anchor
577+ ExprCase -> "a `case` expression" <> anchor
775578 ExprList -> "a list" <> anchor
776579 ExprTuple -> "an expression (in parentheses)" <> anchor
777580 ExprRecord -> "a record" <> anchor
778− Definition name -> name <> "'s definition"
779− Annotation name -> name <> "'s type annotation"
581+ Definition name -> N.toString name <> "'s definition"
582+ Annotation name -> N.toString name <> "'s type annotation"
780583 TypeTuple -> "a type (in parentheses)" <> anchor
781584 TypeRecord -> "a record type" <> anchor
782585 PatternList -> "a list pattern" <> anchor
@@ -790,7 +593,7 @@ contextToText defaultText prefixText stack =
790593 Port -> "a port declaration"
791594
792595
793−getAnchor :: ContextStack -> Text
596+getAnchor :: ContextStack -> String
794597getAnchor stack =
795598 case stack of
796599 [] ->
@@ -799,27 +602,34 @@ getAnchor stack =
799602 (context, _) : rest ->
800603 case context of
801604 Definition name ->
802− " in " <> name <> "'s definition"
605+ " in " <> N.toString name <> "'s definition"
803606
804607 Annotation name ->
805− " in " <> name <> "'s type annotation"
608+ " in " <> N.toString name <> "'s type annotation"
806609
807610 _ ->
808611 getAnchor rest
809612
810613
811−isCaseRelated :: ContextStack -> Bool
812−isCaseRelated stack =
813− case stack of
814− [] ->
815− False
816614
817− (context, _) : rest ->
818− context == ExprCase || isCaseRelated rest
615+-- THEORY HELPERS
616+
617+
618+bullet :: String -> H.Doc
619+bullet point =
620+ H.hang 4 (" - " <> H.fillSep (map H.text (words point)))
621+
622+
623+addPeriod :: String -> String
624+addPeriod msg =
625+ if last msg `elem` ['`', ')', '.', '!', '?'] then
626+ msg
627+ else
628+ msg <> "."
819629
820630
821−theoryToText :: ContextStack -> Theory -> Text
822−theoryToText context theory =
631+theoryToString :: ContextStack -> Theory -> String
632+theoryToString context theory =
823633 case theory of
824634 Keyword keyword ->
825635 "the `" <> keyword <> "` keyword"
@@ -841,7 +651,7 @@ theoryToText context theory =
841651 "]" -> "a right square bracket, to end a list"
842652 "{" -> "a left curly brace, for starting records"
843653 "}" -> "a right curly brace, to end a record"
844− "{-|" -> "a doc comment, like {-| example -}"
654+ "{-|" -> "a doc comment, like {-| this -}"
845655 _ -> "the (" <> symbol <> ") symbol"
846656
847657 LowVar ->
@@ -863,7 +673,7 @@ theoryToText context theory =
863673 case next of
864674 Decl -> "a declaration, like `x = 5` or `type alias Model = { ... }`"
865675 Expr -> "an expression, like x or 42"
866− AfterOpExpr op -> "an expression after that (" <> op <> ") operator, like x or 42"
676+ AfterOpExpr op -> "an expression after that (" <> N.toString op <> ") operator, like x or 42"
867677 ElseBranch -> "an `else` branch. An `if` must handle both possibilities."
868678 Arg -> "an argument, like `name` or `total`"
869679 Pattern -> "a pattern, like `name` or (Just x)"
@@ -872,7 +682,7 @@ theoryToText context theory =
872682 Exposing -> "something like `exposing (..)`"
873683
874684
875−equalsTheory :: ContextStack -> Text
685+equalsTheory :: ContextStack -> String
876686equalsTheory stack =
877687 case stack of
878688 [] ->
@@ -881,13 +691,13 @@ equalsTheory stack =
881691 (context, _) : rest ->
882692 case context of
883693 ExprRecord -> "an equals sign (=) followed by an expression"
884− Definition name -> "an equals sign (=) followed by " <> name <> "'s definition"
694+ Definition name -> "an equals sign (=) followed by " <> N.toString name <> "'s definition"
885695 TypeUnion -> "an equals sign (=) followed by the first union type constructor"
886696 TypeAlias -> "an equals sign (=) followed by the aliased type"
887697 _ -> equalsTheory rest
888698
889699
890−barTheory :: ContextStack -> Text
700+barTheory :: ContextStack -> String
891701barTheory stack =
892702 case stack of
893703 [] ->
@@ -901,7 +711,7 @@ barTheory stack =
901711 _ -> barTheory rest
902712
903713
904−badSpace :: ContextStack -> Text
714+badSpace :: ContextStack -> String
905715badSpace stack =
906716 case stack of
907717 [] ->
@@ -916,8 +726,8 @@ badSpace stack =
916726 ExprList -> "the end of that list" <> badSpaceExprEnd rest
917727 ExprTuple -> "a closing paren" <> badSpaceExprEnd rest
918728 ExprRecord -> "the end of that record" <> badSpaceExprEnd rest
919− Definition name -> "the rest of " <> name <> "'s definition" <> badSpaceExprEnd stack
920− Annotation name -> "the rest of " <> name <> "'s type annotation" <> badSpaceEnd
729+ Definition name -> "the rest of " <> N.toString name <> "'s definition" <> badSpaceExprEnd stack
730+ Annotation name -> "the rest of " <> N.toString name <> "'s type annotation" <> badSpaceEnd
921731 TypeTuple -> "a closing paren" <> badSpaceEnd
922732 TypeRecord -> "the end of that record" <> badSpaceEnd
923733 PatternList -> "the end of that list" <> badSpaceEnd
@@ -931,12 +741,12 @@ badSpace stack =
931741 Port -> "more of that port declaration" <> badSpaceEnd
932742
933743
934−badSpaceEnd :: Text
744+badSpaceEnd :: String
935745badSpaceEnd =
936746 ". Maybe you forgot some code? Or you need more indentation?"
937747
938748
939−badSpaceExprEnd :: ContextStack -> Text
749+badSpaceExprEnd :: ContextStack -> String
940750badSpaceExprEnd stack =
941751 case stack of
942752 [] ->
@@ -948,9 +758,10 @@ badSpaceExprEnd stack =
948758 if column <= 1 then
949759 "to be indented?"
950760 else
951− "more indentation? (Try " <> i2t (column + 1) <> "+ spaces.)"
761+ "more indentation? (Try " <> show (column + 1) <> "+ spaces.)"
952762 in
953− ". Maybe you forgot some code? Or maybe the body of `" <> name
763+ ". Maybe you forgot some code? Or maybe the body of `"
764+ <> N.toString name
954765 <> "` needs " <> ending
955766
956767 _ : rest ->