1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Syntax
6 , Problem(..), Theory(..)
7 , ContextStack, Context(..)
8 , BadOp(..), Next(..), NextDecl(..)
13import qualified Data.Set as Set
14import qualified Data.Text as Text
15import Data.Text (Text)
17import qualified Reporting.Render.Type as RenderType
18import qualified Reporting.Region as R
19import qualified Reporting.Report as Report
20import qualified Reporting.Helpers as Help
21import Reporting.Helpers ((<>), dullyellow, hsep, i2t, reflowParagraph, text)
29 = Parse (Maybe R.Region) Problem
35 | SettingsOnNormalModule
36 | SettingsOnPortModule
37 | DuplicateSettingOnEffectModule Text
38 | BadSettingOnEffectModule Text
39 | NoSettingsOnEffectModule
40 | MissingManagerOnEffectModule Text
43 | TypeWithoutDefinition Text
45 | DuplicateArgument Text Text
46 | DuplicateFieldName R.Region Text
47 | DuplicateValueDeclaration Text
48 | DuplicateTypeDeclaration Text
49 | DuplicateDefinition Text
50 | UnboundTypeVarsInUnion Text [Text] [Text]
51 | UnboundTypeVarsInAlias Text [Text] [Text]
52 | UnusedTypeVarsInAlias Text [Text] [Text]
53 | MessyTypeVarsInAlias Text [Text] [Text] [Text]
60data ParseError = ParseError !Int !Int !Problem
68 | EndOfFile_MultiString
78 | BadOp BadOp ContextStack
79 | Theories ContextStack [Theory]
82data BadOp = HasType | Equals | Arrow | Pipe | Dot
112data NextDecl = ModuleDecl | DocCommentDecl | ImportDecl | OtherDecl
116type ContextStack = [(Context, R.Position)]
144 deriving (Eq, Ord, Show)
151toReport :: RenderType.Localizer -> Error -> Report.Report
152toReport _localizer err =
154 Parse subRegion problem ->
155 problemToReport subRegion problem
157 BadFunctionName arity ->
159 "BAD FUNCTION DEFINITION"
161 "Complex patterns cannot be used as function names."
163 "This function definition has " <> i2t arity <> " arguments, but instead\
164 \ of a normal name like `add` or `reverse` it has a pattern. There is no\
165 \ way to \"deconstruct\" a function with pattern matching, so this needs to\
166 \ be changed to a normal name."
173 ("The free variable `" <> name <> "` appears more than once in this pattern.")
175 [ text "Rename the variables so there are no duplicates."
177 "In Elm, pattern matching works by binding these free variables to subsections\
178 \ of the matching value. It does not make sense to have the same name for two\
179 \ different subsections though! When you say `" <> name <> "` in some code, there\
180 \ is no way for me to know which subsection you mean!"
188 ("This documentation comment is not followed by anything.")
190 "All documentation comments need to be right above the declaration they\
191 \ describe. Maybe some code got deleted or commented out by accident? Or\
192 \ maybe this comment is here by accident?"
195 SettingsOnNormalModule ->
197 "BAD MODULE DECLARATION"
199 "A normal module can expose values, but not settings like this."
201 "If you want a normal module, just remove this stuff. If you want to create\
202 \ an `effect module` you forgot to use the `effect` keyword. In that\
203 \ case, change `module` to `effect module` and you should be headed in\
204 \ the right direction!"
207 SettingsOnPortModule ->
209 "BAD MODULE DECLARATION"
211 "A port module can expose values, but not have settings like this."
213 "If you want a port module, just remove this stuff. If you want to create\
214 \ a custom effect module instead (which is rare) change `port module`\
215 \ to `effect module` and you should be headed in the right direction!"
218 DuplicateSettingOnEffectModule name ->
220 "EFFECT MODULE PROBLEM"
222 ("You have defined " <> Help.functionName name <> " multiple times.")
224 "There can only be one " <> Help.functionName name
225 <> " though! Remove until there is one left."
228 BadSettingOnEffectModule name ->
230 "EFFECT MODULE PROBLEM"
232 ("Setting " <> Help.functionName name <> " is not recognized.")
234 "Remove this entry and you should be all set!"
237 NoSettingsOnEffectModule ->
239 "EFFECT MODULE PROBLEM"
241 ("You are defining an effect module, but it has no settings.")
243 "If you just wanted a normal module, change the keywords `effect module`\
244 \ to `module` and you should be all set. If you want a proper effect module,\
245 \ you need to specify your commands and/or subscriptions. Read more about this\
246 \ here: <http://guide.elm-lang.org/effect_managers/>"
249 MissingManagerOnEffectModule name ->
251 "EFFECT MODULE PROBLEM"
253 ("You are defining an effect module, but there is no " <> Help.functionName name <> " defined.")
255 "There is a small set of top-level functions and values that must be defined\
256 \ in any complete effect module. The best thing is probably to just read more\
257 \ about effect modules here:\
258 \ <http://guide.elm-lang.org/effect_managers/>"
261 UnexpectedPort name ->
265 ("You are declaring port " <> Help.functionName name <> " in a normal module.")
267 "All ports must be defined in a `port module`. You should probably have only\
268 \ one of these for your project. This way all of your foreign interactions\
269 \ stay relatively organized."
272 TypeWithoutDefinition valueName ->
276 ("There is a type annotation for `" <> valueName <> "` but there"
277 <> " is no corresponding definition!"
280 "Directly below the type annotation, put a definition like:\n\n"
281 <> " " <> valueName <> " = 42"
284 DuplicateArgument funcName argName ->
288 ( "The name `" <> argName
289 <> "` is used more than once in the arguments of "
290 <> Help.functionName funcName <> "."
293 "Rename things until `" <> argName <> "` is used only once.\
294 \ Otherwise how can we tell which one you want when you\
295 \ say `" <> argName <> "` it in the body of your function?"
298 DuplicateFieldName region name ->
302 ("This record has more than one field named `" <> name <> "`.")
303 (text "There can only be one. Do some renaming to make sure the names are distinct!")
305 DuplicateValueDeclaration name ->
307 "DUPLICATE DEFINITION"
309 ( "Naming multiple top-level values " <> Help.functionName name <> " makes things\n"
310 <> "ambiguous. When you say " <> Help.functionName name <> " which one do you want?"
313 "Find all the top-level values named " <> Help.functionName name
314 <> " and do some renaming. Make sure the names are distinct!"
317 DuplicateTypeDeclaration name ->
319 "DUPLICATE DEFINITION"
321 ( "There are multiple types named `" <> name <> "` in this module."
324 "Search through this module, find all the types named `"
325 <> name <> "`, and give each of them a unique name."
328 DuplicateDefinition name ->
330 "DUPLICATE DEFINITION"
332 ("There are multiple values named `" <> name <> "` in this let-expression."
335 "Search through this let-expression, find all the values named `"
336 <> name <> "`, and give each of them a unique name."
339 UnboundTypeVarsInUnion typeName givenVars unbound ->
340 unboundTypeVars "type" typeName givenVars unbound
342 UnboundTypeVarsInAlias typeName givenVars unbound ->
343 unboundTypeVars "type alias" typeName givenVars unbound
345 UnusedTypeVarsInAlias typeName givenVars unused ->
347 "UNUSED TYPE VARIABLES"
349 ( "Type alias `" <> typeName <> "` cannot have unused type variables: "
350 <> Help.commaSep unused
353 [ text "You probably need to change the declaration like this:"
354 , dullyellow $ hsep $
355 map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ ["=", "..."])
359 MessyTypeVarsInAlias typeName givenVars unused unbound ->
361 "TYPE VARIABLE PROBLEMS"
363 ( "Type alias `" <> typeName <> "` has some problems with type variables."
367 "The declaration says it uses certain type variables ("
368 <> Help.commaSep unused <> ") but they do not appear in the aliased type. "
369 <> "Furthermore, the aliased type says it uses type variables ("
370 <> Help.commaSep unbound
371 <> ") that do not appear in the declaration."
372 , text "You probably need to change the declaration like this:"
373 , dullyellow $ hsep $
374 map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ unbound ++ ["=", "..."])
379unboundTypeVars :: Text -> Text -> [Text] -> [Text] -> Report.Report
380unboundTypeVars declKind typeName givenVars unboundVars =
382 "UNBOUND TYPE VARIABLES"
384 ( Help.capitalize declKind <> " `" <> typeName <> "` must declare its use of type variable"
385 <> Help.commaSep unboundVars
388 [ text "You probably need to change the declaration like this:"
390 map text (declKind : typeName : givenVars)
391 ++ map (dullyellow . text) unboundVars
392 ++ map text ["=", "..."]
394 "Here's why. Imagine one `" <> typeName <> "` where `" <> head unboundVars <>
395 "` is an Int and another where it is a Bool. When we explicitly list the type\
396 \ variables, the type checker can see that they are actually different types."
402-- PARSE ERROR TO REPORT
405makeParseReport :: Maybe R.Region -> Text -> Help.Doc -> Report.Report
406makeParseReport subRegion pre post =
407 Report.report "PARSE ERROR" subRegion pre post
410problemToReport :: Maybe R.Region -> Problem -> Report.Report
411problemToReport subRegion problem =
412 let parseReport = makeParseReport subRegion in
416 "I ran into a tab, but tabs are not allowed in Elm files."
417 (reflowParagraph "Replace the tab with spages.")
421 "I got to the end of the file while parsing a multi-line comment."
424 "Multi-line comments look like {- comment -}, and it looks like\
425 \ you are missing the closing marker."
427 "Nested multi-line comments like {- this {- and this -} -} are allowed.\
428 \ That means the opening and closing markers must be balanced, just\
429 \ like parentheses in normal code. Maybe that is the problem?"
435 "I got to the end of the file while parsing a GLSL block."
437 "A shader should be defined in a block like this: [glsl| ... |]"
442 "I got to the end of the file while parsing a string."
444 "Strings look like \"this\" with double quotes on each end.\
445 \ So the closing double quote seems to be missing."
448 EndOfFile_MultiString ->
450 "I got to the end of the file while parsing a multi-line string."
452 "Multi-line strings begin and end with three double quotes in a\
453 \ row, like \"\"\"this\"\"\". So the closing marker seems\
459 "This string is missing the closing quote."
462 "Elm strings must start and end with a double quote, like \"this\"."
464 "If you want a string that can contain newlines, use three double quotes in a\
465 \ row, like \"\"\"this\"\"\"."
471 "Ran into a bad escape code."
473 "Elm allows typical escape characters like \\n and \\t, but you can\
474 \ also use \\x0040 to refer to unicode characters by their hex code.\
475 \ It seems like something has gone wrong with one of these codes."
480 "Ran into a bad use of single quotes."
483 "If you want to create a string, switch to double quotes:"
485 dullyellow (text "'this'")
487 <> dullyellow (text "\"this\"")
489 "Unlike JavaScript, Elm distinguishes between strings like \"hello\"\
490 \ and individual characters like 'A' and '3'. It is not all strings!\
491 \ If you really do want a character though, something went wrong\
492 \ and I did not find the closing single quote."
498 "Numbers cannot end with a decimal points."
500 "Leave it off or add some digits after it, like or 3 or 3.0"
505 "Numbers cannot have letters or underscores in them."
507 "Maybe a space is missing between a number and a variable?"
512 "If you put the letter E in a number, it should followed by more digits."
514 "If you want to say 1000, you can also say 1e3.\
515 \ You cannot just end it with an E though!"
520 "I see the start of a hex number, but not the end."
522 "A hex number looks like 0x123ABC, where the 0x is followed by hexidecimal digits (i.e. 0123456789abcdefABCDEF)"
527 "Normal numbers cannot start with a zero. Take the zeros off the front."
529 "Only numbers like 0x0040 or 0.25 can start with a zero."
534 "I ran into a problem while parsing this GLSL block."
535 (reflowParagraph msg)
540 badOp subRegion stack "the \"has type\" operator" "(:)"
541 "type annotations and record types"
542 "Maybe you want :: instead? Or maybe your indentation is a bit off?"
545 badOp subRegion stack "an equals sign" "(=)"
547 "Maybe you want == instead? Or maybe your indentation is a bit off?"
550 if isCaseRelated stack then
552 "I ran into a stray arrow (->) while parsing this `case` expression."
554 "All branches in a `case` must be indented the exact\
555 \ same amount, so the patterns are vertically\
556 \ aligned. Maybe this branch is indented too much?"
560 badOp subRegion stack "an arrow" "(->)"
561 "cases expressions and anonymous functions"
562 "Maybe you want > or >= instead?"
565 badOp subRegion stack "a vertical bar" "(|)"
567 "Maybe you want || instead?"
571 "I was not expecting a dot (.) here."
573 "Dots are for record access and decimal points, so\
574 \ they cannot float around on their own. Maybe\
575 \ there is some extra whitespace?"
578 Theories stack allTheories ->
581 "Something went wrong while parsing "
582 <> contextToText "your code" "" stack
585 parseReport starter $
586 case Set.toList (Set.fromList allTheories) of
590 "I do not have any suggestions though!"
592 "Can you get it down to a <http://sscce.org> and share it at\
593 \ <https://github.com/elm-lang/error-message-catalog/issues>?\
594 \ That way we can figure out how to give better advice!"
599 "I was expecting to see "
600 <> addPeriod (theoryToText stack theory)
604 [ text "I was expecting:"
607 ++ map (bullet . theoryToText stack) theories
610bullet :: Text -> Help.Doc
612 Help.hang 4 (" - " <> reflowParagraph point)
615addPeriod :: Text -> Text
617 if Text.last msg `elem` ['`', ')', '.', '!', '?'] then
623badOp :: Maybe R.Region -> ContextStack -> Text -> Text -> Text -> Text -> Report.Report
624badOp subRegion stack opName op setting hint =
625 makeParseReport subRegion ("I was not expecting " <> opName <> " here.") $
628 "A " <> op <> " should only appear in " <> setting
629 <> contextToText "" ", but I think I am parsing " stack <> "."
630 , reflowParagraph hint
634contextToText :: Text -> Text -> ContextStack -> Text
635contextToText defaultText prefixText stack =
640 (context, _) : rest ->
641 let anchor = getAnchor rest in
644 ExprIf -> "an `if`" <> anchor
645 ExprLet -> "a `let`" <> anchor
646 ExprFunc -> "an anonymous function" <> anchor
647 ExprCase -> "a `case`" <> anchor
648 ExprList -> "a list" <> anchor
649 ExprTuple -> "an expression (in parentheses)" <> anchor
650 ExprRecord -> "a record" <> anchor
651 Definition name -> name <> "'s definition"
652 Annotation name -> name <> "'s type annotation"
653 TypeTuple -> "a type (in parentheses)" <> anchor
654 TypeRecord -> "a record type" <> anchor
655 PatternList -> "a list pattern" <> anchor
656 PatternTuple -> "a pattern (in parentheses)" <> anchor
657 PatternRecord -> "a record pattern" <> anchor
658 Module -> "a module declaration"
659 Import -> "an import"
660 TypeUnion -> "a union type"
661 TypeAlias -> "a type alias"
662 Infix -> "an infix declaration"
663 Port -> "a port declaration"
666getAnchor :: ContextStack -> Text
672 (context, _) : rest ->
675 " in " <> name <> "'s definition"
678 " in " <> name <> "'s type annotation"
684isCaseRelated :: ContextStack -> Bool
690 (context, _) : rest ->
691 context == ExprCase || isCaseRelated rest
694theoryToText :: ContextStack -> Theory -> Text
695theoryToText context theory =
698 "the `" <> keyword <> "` keyword"
702 "=" -> equalsTheory context
703 "->" -> "an arrow (->) followed by an expression"
704 ":" -> "the \"has type\" symbol (:) followed by a type"
706 "|" -> barTheory context
707 "::" -> "the cons operator (::) followed by more list elements"
709 "-" -> "a minus sign (-)"
710 "_" -> "an underscore"
711 "(" -> "a left paren, for grouping or starting tuples"
712 ")" -> "a closing paren"
713 "[" -> "a left square bracket, for starting lists"
714 "]" -> "a right square bracket, to end a list"
715 "{" -> "a left curly brace, for starting records"
716 "}" -> "a right curly brace, to end a record"
717 "{-|" -> "a doc comment, like {-| example -}"
718 _ -> "the (" <> symbol <> ") symbol"
721 "a lower-case variable, like `x` or `user`"
724 "an upper-case variable, like `Maybe` or `Just`"
727 "an infix operator, like (+) or (==)"
730 "a digit from 0 to 9"
733 "the end of the file"
738 FreshLine nextDecl ->
739 "a fresh line (without any leading spaces) for " <>
741 ModuleDecl -> "something like `module Main exposing (..)`"
742 DocCommentDecl -> "something like `import Html exposing (text)`"
743 ImportDecl -> "an `import` or a declarations"
744 OtherDecl -> "a top-level declaration, like `view model = div [] [...]`"
748 Decl -> "a declaration, like `x = 5` or `type alias Model = { ... }`"
749 Expr -> "an expression, like x or 42"
750 AfterOpExpr op -> "an expression after that (" <> op <> ") operator, like x or 42"
751 ElseBranch -> "an `else` branch. An `if` must handle both possibilities."
752 Arg -> "an argument, like `name` or `total`"
753 Pattern -> "a pattern, like `name` or (Just x)"
754 Type -> "a type, like Int or (List String)"
755 Listing -> "a list of exposed values and types, like (..) or (x,y,z)"
756 Exposing -> "something like `exposing (..)`"
759equalsTheory :: ContextStack -> Text
765 (context, _) : rest ->
767 ExprRecord -> "an equals sign (=) followed by an expression"
768 Definition name -> "an equals sign (=) followed by " <> name <> "'s definition"
769 TypeUnion -> "an equals sign (=) followed by the first union type constructor"
770 TypeAlias -> "an equals sign (=) followed by the aliased type"
771 _ -> equalsTheory rest
774barTheory :: ContextStack -> Text
780 (context, _) : rest ->
782 ExprRecord -> "a vertical bar (|) followed by the record fields you want to update"
783 TypeRecord -> "a vertical bar (|) followed by some record field types"
784 TypeUnion -> "a vertical bar (|) followed by more union type constructors"
788badSpace :: ContextStack -> Text
792 "more indentation? I was not done with that last thing yet."
794 (context, _) : rest ->
796 ExprIf -> "the end of that `if`" <> badSpaceEnd
797 ExprLet -> "the end of that `let`" <> badSpaceEnd
798 ExprFunc -> badSpace rest
799 ExprCase -> "more of that `case`" <> badSpaceEnd
800 ExprList -> "the end of that list" <> badSpaceEnd
801 ExprTuple -> "a closing paren" <> badSpaceEnd
802 ExprRecord -> "the end of that record" <> badSpaceEnd
803 Definition name -> "the rest of " <> name <> "'s definition" <> badSpaceEnd
804 Annotation name -> "the rest of " <> name <> "'s type annotation" <> badSpaceEnd
805 TypeTuple -> "a closing paren" <> badSpaceEnd
806 TypeRecord -> "the end of that record" <> badSpaceEnd
807 PatternList -> "the end of that list" <> badSpaceEnd
808 PatternTuple -> "a closing paren" <> badSpaceEnd
809 PatternRecord -> "the end of that record" <> badSpaceEnd
810 Module -> "something like `module Main exposing (..)`"
811 Import -> "something like `import Html exposing (..)`"
812 TypeUnion -> "more of that union type" <> badSpaceEnd
813 TypeAlias -> "more of that type alias" <> badSpaceEnd
814 Infix -> "more of that infix declaration" <> badSpaceEnd
815 Port -> "more of that port declaration" <> badSpaceEnd
820 ". Maybe you forgot some code? Or you need more indentation?"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list