on f284fab help sign in
elk/src/Reporting/Error/Syntax.hs
568 lines 19 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Syntax
4 ( Error(..)
5 , ParseError(..)
6 , Problem(..), Theory(..)
7 , toReport
8 )
9 where
11import qualified Data.Set as Set
12import Data.Text (Text)
14import qualified Reporting.Render.Type as RenderType
15import qualified Reporting.Region as Region
16import qualified Reporting.Report as Report
17import qualified Reporting.Helpers as Help
18import Reporting.Helpers ((<>), dullyellow, hsep, i2t, reflowParagraph, text)
22-- ALL SYNTAX ERRORS
25data Error
26 = Parse Problem
27 | BadFunctionName Int
28 | BadPattern Text
30 | CommentOnNothing
32 | SettingsOnNormalModule
33 | SettingsOnPortModule
34 | DuplicateSettingOnEffectModule Text
35 | BadSettingOnEffectModule Text
36 | NoSettingsOnEffectModule
37 | MissingManagerOnEffectModule Text
38 | UnexpectedPort Text
40 | TypeWithoutDefinition Text
42 | DuplicateArgument Text Text
43 | DuplicateFieldName Region.Region Text
44 | DuplicateValueDeclaration Text
45 | DuplicateTypeDeclaration Text
46 | DuplicateDefinition Text
47 | UnboundTypeVarsInUnion Text [Text] [Text]
48 | UnboundTypeVarsInAlias Text [Text] [Text]
49 | UnusedTypeVarsInAlias Text [Text] [Text]
50 | MessyTypeVarsInAlias Text [Text] [Text] [Text]
54-- PARSE ERRORS
57data ParseError
58 = ParseError !Int !Int !Problem
61data Problem
62 = Tab
63 | EndOfFile_Comment
64 | EndOfFile_Shader
65 | EndOfFile_String
66 | EndOfFile_MultiString
67 | NewLineInString
68 | BadEscape
69 | BadChar
70 | BadNumberDot
71 | BadNumberEnd
72 | BadNumberExp
73 | BadNumberHex
74 | BadNumberZero
75 | BadShader Text
76 | BadChunkInQualifiedCapVar
77 | HasType
78 | Equals
79 | Arrow
80 | Pipe
81 | Dot
82 | Theories [Theory]
85data Theory
86 = Keyword Text
87 | Symbol Text
88 | Variable
89 | InfixOp
90 | Digit
91 | BadIndent
92 | FreshLine
93 | Expecting Text
94 deriving (Eq, Ord)
98-- TO REPORT
101toReport :: RenderType.Localizer -> Error -> Report.Report
102toReport _localizer err =
103 case err of
104 Parse problem ->
105 problemToReport problem
107 BadFunctionName arity ->
108 Report.report
109 "BAD FUNCTION DEFINITION"
110 Nothing
111 "Complex patterns cannot be used as function names."
112 ( reflowParagraph $
113 "This function definition has " <> i2t arity <> " arguments, but instead\
114 \ of a normal name like `add` or `reverse` it has a pattern. There is no\
115 \ way to \"deconstruct\" a function with pattern matching, so this needs to\
116 \ be changed to a normal name."
117 )
119 BadPattern name ->
120 Report.report
121 "BAD PATTERN"
122 Nothing
123 ("The free variable `" <> name <> "` appears more than once in this pattern.")
124 ( Help.stack
125 [ text "Rename the variables so there are no duplicates."
126 , reflowParagraph $
127 "In Elm, pattern matching works by binding these free variables to subsections\
128 \ of the matching value. It does not make sense to have the same name for two\
129 \ different subsections though! When you say `" <> name <> "` in some code, there\
130 \ is no way for me to know which subsection you mean!"
131 ]
132 )
134 CommentOnNothing ->
135 Report.report
136 "STRAY COMMENT"
137 Nothing
138 ("This documentation comment is not followed by anything.")
139 ( reflowParagraph $
140 "All documentation comments need to be right above the declaration they\
141 \ describe. Maybe some code got deleted or commented out by accident? Or\
142 \ maybe this comment is here by accident?"
143 )
145 SettingsOnNormalModule ->
146 Report.report
147 "BAD MODULE DECLARATION"
148 Nothing
149 "A normal module can expose values, but not settings like this."
150 ( reflowParagraph $
151 "If you want a normal module, just remove this stuff. If you want to create\
152 \ an `effect module` you just forgot to use the `effect` keyword. In that\
153 \ case, just change `module` to `effect module` and you should be headed in\
154 \ the right direction!"
155 )
157 SettingsOnPortModule ->
158 Report.report
159 "BAD MODULE DECLARATION"
160 Nothing
161 "A port module can expose values, but not have settings like this."
162 ( reflowParagraph $
163 "If you want a port module, just remove this stuff. If you want to create\
164 \ a custom effect module instead (which is rare) just change `port module`\
165 \ to `effect module` and you should be headed in the right direction!"
166 )
168 DuplicateSettingOnEffectModule name ->
169 Report.report
170 "EFFECT MODULE PROBLEM"
171 Nothing
172 ("You have defined " <> Help.functionName name <> " multiple times.")
173 ( reflowParagraph $
174 "There can only be one " <> Help.functionName name
175 <> " though! Remove until there is one left."
176 )
178 BadSettingOnEffectModule name ->
179 Report.report
180 "EFFECT MODULE PROBLEM"
181 Nothing
182 ("Setting " <> Help.functionName name <> " is not recognized.")
183 ( reflowParagraph $
184 "Remove this entry and you should be all set!"
185 )
187 NoSettingsOnEffectModule ->
188 Report.report
189 "EFFECT MODULE PROBLEM"
190 Nothing
191 ("You are defining an effect module, but it has no settings.")
192 ( reflowParagraph $
193 "If you just wanted a normal module, change the keywords `effect module`\
194 \ to `module` and you should be all set. If you want a proper effect module,\
195 \ you need to specify your commands and/or subscriptions. Read more about this\
196 \ here: <http://guide.elm-lang.org/effect_managers/>"
197 )
199 MissingManagerOnEffectModule name ->
200 Report.report
201 "EFFECT MODULE PROBLEM"
202 Nothing
203 ("You are defining an effect module, but there is no " <> Help.functionName name <> " defined.")
204 ( reflowParagraph $
205 "There is a small set of top-level functions and values that must be defined\
206 \ in any complete effect module. The best thing is probably to just read more\
207 \ about effect modules here:\
208 \ <http://guide.elm-lang.org/effect_managers/>"
209 )
211 UnexpectedPort name ->
212 Report.report
213 "BAD PORT"
214 Nothing
215 ("You are declaring port " <> Help.functionName name <> " in a normal module.")
216 ( reflowParagraph $
217 "All ports must be defined in a `port module`. You should probably have just\
218 \ one of these for your project. This way all of your foreign interactions\
219 \ stay relatively organized."
220 )
222 TypeWithoutDefinition valueName ->
223 Report.report
224 "MISSING DEFINITION"
225 Nothing
226 ("There is a type annotation for `" <> valueName <> "` but there"
227 <> " is no corresponding definition!"
228 )
229 ( text $
230 "Directly below the type annotation, put a definition like:\n\n"
231 <> " " <> valueName <> " = 42"
232 )
234 DuplicateArgument funcName argName ->
235 Report.report
236 "DUPLICATE ARGUMENT"
237 Nothing
238 ( "The name `" <> argName
239 <> "` is used more than once in the arguments of "
240 <> Help.functionName funcName <> "."
241 )
242 ( reflowParagraph $
243 "Rename things until `" <> argName <> "` is used only once.\
244 \ Otherwise how can we tell which one you want when you\
245 \ say `" <> argName <> "` it in the body of your function?"
246 )
248 DuplicateFieldName region name ->
249 Report.report
250 "DUPLICATE FIELD"
251 (Just region)
252 ("This record has more than one field named `" <> name <> "`.")
253 (text "There can only be one. Do some renaming to make sure the names are distinct!")
255 DuplicateValueDeclaration name ->
256 Report.report
257 "DUPLICATE DEFINITION"
258 Nothing
259 ( "Naming multiple top-level values " <> Help.functionName name <> " makes things\n"
260 <> "ambiguous. When you say " <> Help.functionName name <> " which one do you want?"
261 )
262 ( reflowParagraph $
263 "Find all the top-level values named " <> Help.functionName name
264 <> " and do some renaming. Make sure the names are distinct!"
265 )
267 DuplicateTypeDeclaration name ->
268 Report.report
269 "DUPLICATE DEFINITION"
270 Nothing
271 ( "There are multiple types named `" <> name <> "` in this module."
272 )
273 ( reflowParagraph $
274 "Search through this module, find all the types named `"
275 <> name <> "`, and give each of them a unique name."
276 )
278 DuplicateDefinition name ->
279 Report.report
280 "DUPLICATE DEFINITION"
281 Nothing
282 ("There are multiple values named `" <> name <> "` in this let-expression."
283 )
284 ( reflowParagraph $
285 "Search through this let-expression, find all the values named `"
286 <> name <> "`, and give each of them a unique name."
287 )
289 UnboundTypeVarsInUnion typeName givenVars unbound ->
290 unboundTypeVars "type" typeName givenVars unbound
292 UnboundTypeVarsInAlias typeName givenVars unbound ->
293 unboundTypeVars "type alias" typeName givenVars unbound
295 UnusedTypeVarsInAlias typeName givenVars unused ->
296 Report.report
297 "UNUSED TYPE VARIABLES"
298 Nothing
299 ( "Type alias `" <> typeName <> "` cannot have unused type variables: "
300 <> Help.commaSep unused
301 )
302 ( Help.stack
303 [ text "You probably need to change the declaration like this:"
304 , dullyellow $ hsep $
305 map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ ["=", "..."])
306 ]
307 )
309 MessyTypeVarsInAlias typeName givenVars unused unbound ->
310 Report.report
311 "TYPE VARIABLE PROBLEMS"
312 Nothing
313 ( "Type alias `" <> typeName <> "` has some problems with type variables."
314 )
315 ( Help.stack
316 [ reflowParagraph $
317 "The declaration says it uses certain type variables ("
318 <> Help.commaSep unused <> ") but they do not appear in the aliased type. "
319 <> "Furthermore, the aliased type says it uses type variables ("
320 <> Help.commaSep unbound
321 <> ") that do not appear in the declaration."
322 , text "You probably need to change the declaration like this:"
323 , dullyellow $ hsep $
324 map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ unbound ++ ["=", "..."])
325 ]
326 )
329unboundTypeVars :: Text -> Text -> [Text] -> [Text] -> Report.Report
330unboundTypeVars declKind typeName givenVars unboundVars =
331 Report.report
332 "UNBOUND TYPE VARIABLES"
333 Nothing
334 ( Help.capitalize declKind <> " `" <> typeName <> "` must declare its use of type variable"
335 <> Help.commaSep unboundVars
336 )
337 ( Help.stack
338 [ text "You probably need to change the declaration like this:"
339 , hsep $
340 map text (declKind : typeName : givenVars)
341 ++ map (dullyellow . text) unboundVars
342 ++ map text ["=", "..."]
343 , reflowParagraph $
344 "Here's why. Imagine one `" <> typeName <> "` where `" <> head unboundVars <>
345 "` is an Int and another where it is a Bool. When we explicitly list the type\
346 \ variables, the type checker can see that they are actually different types."
347 ]
348 )
352-- PARSE ERROR TO REPORT
355parseReport :: Text -> Help.Doc -> Report.Report
356parseReport pre post =
357 Report.report "PARSE ERROR" Nothing pre post
360problemToReport :: Problem -> Report.Report
361problemToReport problem =
362 case problem of
363 Tab ->
364 parseReport
365 "I ran into a tab, but tabs are not allowed in Elm files."
366 (reflowParagraph "Replace the tab with spages.")
368 EndOfFile_Comment ->
369 parseReport
370 "I got to the end of the file while parsing a multi-line comment."
371 ( Help.stack
372 [ reflowParagraph $
373 "Multi-line comments look like {- comment -}, and it looks like\
374 \ you are missing the closing marker."
375 , reflowParagraph $
376 "Nested multi-line comments like {- this {- and this -} -} are allowed.\
377 \ That means the opening and closing markers must be balanced, just\
378 \ like parentheses in normal code. Maybe that is the problem?"
379 ]
380 )
382 EndOfFile_Shader ->
383 parseReport
384 "I got to the end of the file while parsing a GLSL block."
385 (reflowParagraph $
386 "A shader should be defined in a block like this: [glsl| ... |]"
387 )
389 EndOfFile_String ->
390 parseReport
391 "I got to the end of the file while parsing a string."
392 (reflowParagraph $
393 "Strings look like \"this\" with double quotes on each end.\
394 \ So the closing double quote seems to be missing."
395 )
397 EndOfFile_MultiString ->
398 parseReport
399 "I got to the end of the file while parsing a multi-line string."
400 (reflowParagraph $
401 "Multi-line strings begin and end with three double quotes in a\
402 \ row, like \"\"\"this\"\"\". So the closing marker seems\
403 \ to be missing."
404 )
406 NewLineInString ->
407 parseReport
408 "This string is missing the closing quote."
409 ( Help.stack
410 [ reflowParagraph $
411 "Elm strings must start and end with a double quote, like \"this\"."
412 , reflowParagraph $
413 "If you want a string that can contain newlines, use three double quotes in a\
414 \ row, like \"\"\"this\"\"\"."
415 ]
416 )
418 BadEscape ->
419 parseReport
420 "Ran into a bad escape code."
421 ( reflowParagraph
422 "Elm allows typical escape characters like \\n and \\t, but you can\
423 \ also use \\x0040 to refer to unicode characters by their hex code.\
424 \ It seems like something has gone wrong with one of these codes."
425 )
427 BadChar ->
428 parseReport
429 "Ran into a bad use of single quotes."
430 ( Help.stack
431 [ reflowParagraph $
432 "If you want to create a string, just switch to double quotes:"
433 , Help.indent 4 $
434 dullyellow (text "'this'")
435 <> text " => "
436 <> dullyellow (text "\"this\"")
437 , reflowParagraph $
438 "Unlike JavaScript, Elm distinguishes between strings like \"hello\"\
439 \ and individual characters like 'A' and '3'. It is not all strings!\
440 \ If you really do want a character though, something went wrong\
441 \ and I did not find the closing single quote."
442 ]
443 )
445 BadNumberDot ->
446 parseReport
447 "Numbers cannot end with a decimal points."
448 ( reflowParagraph $
449 "Leave it off or add some digits after it, like or 3 or 3.0"
450 )
452 BadNumberEnd ->
453 parseReport
454 "Numbers cannot have letters or underscores in them."
455 ( reflowParagraph $
456 "Maybe a space is missing between a number and a variable?"
457 )
459 BadNumberExp ->
460 parseReport
461 "If you put the letter E in a number, it should followed by more digits."
462 ( reflowParagraph $
463 "If you want to say 1000, you can also say 1e3.\
464 \ You cannot just end it with an E though!"
465 )
467 BadNumberHex ->
468 parseReport
469 "I see the start of a hex number, but not the end."
470 ( reflowParagraph $
471 "A hex number looks like 0x123ABC, where the 0x is followed by hexidecimal digits (i.e. 0123456789abcdefABCDEF)"
472 )
474 BadNumberZero ->
475 parseReport
476 "Normal numbers cannot start with a zero. Take the zeros off the front."
477 ( reflowParagraph $
478 "Only numbers like 0x0040 or 0.25 can start with a zero."
479 )
481 BadShader msg ->
482 parseReport
483 "I ran into a problem while parsing this GLSL block."
484 (reflowParagraph msg)
486 BadChunkInQualifiedCapVar ->
487 error "TODO"
489 HasType ->
490 parseReport
491 "Single colons should only show up in types."
492 ( reflowParagraph $
493 "Maybe you want :: instead? Or maybe you are defining\
494 \ a type annotation but there are extra spaces before it?"
495 )
497 Equals ->
498 parseReport
499 "The = operator is reserved for defining variables."
500 ( reflowParagraph $
501 "Maybe you want == instead? Or maybe you are defining a\
502 \ variable but there are extra spaces before it?"
503 )
505 Arrow ->
506 parseReport
507 "Arrows are reserved for cases and anonymous functions."
508 ( reflowParagraph $
509 "Maybe you want > or >= instead?"
510 )
512 Pipe ->
513 parseReport
514 "Vertical bars are reserved for use in type declarations."
515 ( reflowParagraph $
516 "Maybe you want || instead?"
517 )
519 Dot ->
520 parseReport
521 "Dots are for record access and decimal points."
522 ( reflowParagraph $
523 "They cannot float around on their own though, so\
524 \ maybe there is some extra whitespace?"
525 )
527 Theories allTheories ->
528 case Set.toList (Set.fromList allTheories) of
529 [] ->
530 parseReport
531 "Something went wrong when parsing this code."
532 ( reflowParagraph $
533 "I do not have any suggestions though, and I suspect there is some\
534 \ sort of bug. Can you get it down to an <http://sscce.org> and\
535 \ share it at <https://github.com/elm-lang/error-message-catalog/issues>?\
536 \ That way we can figure out how to give better advice!"
537 )
539 theories ->
540 error "TODO" (map theoryToText theories)
543theoryToText :: Theory -> Text
544theoryToText theory =
545 case theory of
546 Keyword _ ->
547 ""
549 Symbol _ ->
550 ""
552 Variable ->
553 ""
555 InfixOp ->
556 ""
558 Digit ->
559 "a digit, like 0 or 6"
561 BadIndent ->
562 ""
564 FreshLine ->
565 ""
567 Expecting _ ->
568 ""