on master help sign in
Improve error messages based on testing
7139c03Evan Czaplicki
src/Parse/Expression.hs+4−2
@@ -276,9 +276,10 @@ exprHelp start (State ops lastExpr end pos) =
276 opName <- infixOp
276 opName <- infixOp
277 opEnd <- getPosition
277 opEnd <- getPosition
278 let op = A.at opStart opEnd opName
278 let op = A.at opStart opEnd opName
279− spaces
279+ spos <- whitespace
280+ hint (E.AfterOpExpr opName) (checkSpace spos)
280 newStart <- getPosition
281 newStart <- getPosition
281− oneOf
282+ hint (E.AfterOpExpr opName) $ oneOf $
282 [ -- negative terms
283 [ -- negative terms
283 do guard ("-" == opName && end /= opStart && opEnd == newStart)
284 do guard ("-" == opName && end /= opStart && opEnd == newStart)
284 rawTerm <- term
285 rawTerm <- term
@@ -312,6 +313,7 @@ exprHelp start (State ops lastExpr end pos) =
312 ]
313 ]
313
314
314 , -- argument
315 , -- argument
316+ hint E.Arg $
315 do checkSpace pos
317 do checkSpace pos
316 arg <- term
318 arg <- term
317 newEnd <- getPosition
319 newEnd <- getPosition
src/Parse/Helpers.hs+2−9
@@ -41,8 +41,7 @@ qualifiedCapVar =
41
41
42qualifiedCapVarHelp :: Parser a
42qualifiedCapVarHelp :: Parser a
43qualifiedCapVarHelp =
43qualifiedCapVarHelp =
44− do ctx <- getContext
44+ deadend [E.CapVar]
45− failure (E.Theories ctx [E.CapVar])
46
45
47
46
48qualifiedVar :: Parser Text
47qualifiedVar :: Parser Text
@@ -198,13 +197,7 @@ inContext ctx parser =
198
197
199spaces :: Parser ()
198spaces :: Parser ()
200spaces =
199spaces =
201− do (SPos (R.Position _ col)) <- whitespace
200+ checkSpace =<< whitespace
202− indent <- getIndent
203− if col > indent && col > 1
204− then return ()
205− else
206− do ctx <- getContext
207− failure (E.Theories ctx [E.BadSpace])
208
201
209
202
210checkSpace :: SPos -> Parser ()
203checkSpace :: SPos -> Parser ()
src/Parse/Module.hs+5−2
@@ -33,7 +33,8 @@ header =
33
33
34fullHeader :: Parser (Module.Header [Module.UserImport])
34fullHeader :: Parser (Module.Header [Module.UserImport])
35fullHeader =
35fullHeader =
36+ do pushContext E.Module
36− do tag <- sourceTag
37+ tag <- sourceTag
37 spaces
38 spaces
38 name <- qualifiedCapVar
39 name <- qualifiedCapVar
39 spaces
40 spaces
@@ -41,11 +42,12 @@ fullHeader =
41 hint E.Exposing $ keyword "exposing"
42 hint E.Exposing $ keyword "exposing"
42 spaces
43 spaces
43 exports <- listing (addLocation listingValue)
44 exports <- listing (addLocation listingValue)
45+ popContext ()
44 start <- getPosition
46 start <- getPosition
45 freshLine E.DocCommentDecl
47 freshLine E.DocCommentDecl
46 end <- getPosition
48 end <- getPosition
47 docs <- maybeDocComment start end
49 docs <- maybeDocComment start end
48− imports <- chompImports []
50+ imports <- inContext E.Import (chompImports [])
49 return (Module.Header tag name exports settings docs imports)
51 return (Module.Header tag name exports settings docs imports)
50
52
51
53
@@ -126,6 +128,7 @@ setting =
126
128
127maybeDocComment :: R.Position -> R.Position -> Parser (A.Located (Maybe Text))
129maybeDocComment :: R.Position -> R.Position -> Parser (A.Located (Maybe Text))
128maybeDocComment start end =
130maybeDocComment start end =
131+ inContext E.DocComment $
129 oneOf
132 oneOf
130 [ do doc <- addLocation docComment
133 [ do doc <- addLocation docComment
131 freshLine E.ImportDecl
134 freshLine E.ImportDecl
src/Parse/Primitives.hs+1−7
@@ -3,7 +3,7 @@
3module Parse.Primitives
3module Parse.Primitives
4 ( Parser
4 ( Parser
5 , run, runAt
5 , run, runAt
6− , try, failure, deadend, hint, endOfFile
6+ , try, deadend, hint, endOfFile
7 , oneOf
7 , oneOf
8 , symbol, keyword, keywords
8 , symbol, keyword, keywords
9 , lowVar, capVar, infixOp
9 , lowVar, capVar, infixOp
@@ -125,12 +125,6 @@ try parser =
125 _run parser state cok eerr eok eerr
125 _run parser state cok eerr eok eerr
126
126
127
127
128−failure :: Problem -> Parser a
129−failure problem =
130− Parser $ \(State _ _ _ _ row col _) _ cerr _ _ ->
131− cerr (ParseError row col problem)
132−
133−
134shaderFailure :: Int -> Int -> Text -> Parser a
128shaderFailure :: Int -> Int -> Text -> Parser a
135shaderFailure row col msg =
129shaderFailure row col msg =
136 Parser $ \_ _ cerr _ _ ->
130 Parser $ \_ _ cerr _ _ ->
src/Reporting/Error/Syntax.hs+151−65
@@ -10,6 +10,7 @@ module Reporting.Error.Syntax
10 where
10 where
11
11
12import qualified Data.Set as Set
12import qualified Data.Set as Set
13+import qualified Data.Text as Text
13import Data.Text (Text)
14import Data.Text (Text)
14
15
15import qualified Reporting.Render.Type as RenderType
16import qualified Reporting.Render.Type as RenderType
@@ -91,15 +92,23 @@ data Theory
91 | EndOfFile
92 | EndOfFile
92 | FreshLine NextDecl
93 | FreshLine NextDecl
93 | BadSpace
94 | BadSpace
94− deriving (Eq, Ord, Show)
95+ deriving (Eq, Ord)
95
96
96
97
97−data Next = Expr | ElseBranch | Arg | Pattern | Type | Listing | Exposing
98+data Next
99+ = Expr
100+ | AfterOpExpr Text
101+ | ElseBranch
102+ | Arg
103+ | Pattern
104+ | Type
105+ | Listing
106+ | Exposing
98− deriving (Eq, Ord, Show)
107+ deriving (Eq, Ord)
99
108
100
109
101data NextDecl = ModuleDecl | DocCommentDecl | ImportDecl | OtherDecl
110data NextDecl = ModuleDecl | DocCommentDecl | ImportDecl | OtherDecl
102− deriving (Eq, Ord, Show)
111+ deriving (Eq, Ord)
103
112
104
113
105data Context
114data Context
@@ -523,31 +532,32 @@ problemToReport problem =
523 BadOp op context ->
532 BadOp op context ->
524 case op of
533 case op of
525 HasType ->
534 HasType ->
526− badOp context "the \"has type\" operator (:)"
535+ badOp context "the \"has type\" operator" "(:)"
527 "type annotations and record types"
536 "type annotations and record types"
528 "Maybe you want :: instead? Or maybe your indentation is a bit off?"
537 "Maybe you want :: instead? Or maybe your indentation is a bit off?"
529
538
530 Equals ->
539 Equals ->
531− badOp context "an equals sign (=)"
540+ badOp context "an equals sign" "(=)"
532 "definitions"
541 "definitions"
533 "Maybe you want == instead? Or maybe your indentation is a bit off?"
542 "Maybe you want == instead? Or maybe your indentation is a bit off?"
534
543
535 Arrow ->
544 Arrow ->
536 if isCaseRelated context then
545 if isCaseRelated context then
537 parseReport
546 parseReport
538− "I am parsing a case expression, but this arrow (->) is out of place."
547+ "I ran into a stray arrow (->) while parsing this `case` expression."
539 ( reflowParagraph $
548 ( reflowParagraph $
540− "Each branch in a case expression needs to start on the same\
549+ "All branches in a `case` must be indented the exact\
550+ \ same amount, so the patterns are vertically\
541− \ column, so maybe this branch is indented too much?"
551+ \ aligned. Maybe this branch is indented too much?"
542 )
552 )
543
553
544 else
554 else
545− badOp context "an arrow (->)"
555+ badOp context "an arrow" "(->)"
546 "cases expressions and anonymous functions"
556 "cases expressions and anonymous functions"
547 "Maybe you want > or >= instead?"
557 "Maybe you want > or >= instead?"
548
558
549 Pipe ->
559 Pipe ->
550− badOp context "a vertical bar (|)"
560+ badOp context "a vertical bar" "(|)"
551 "type declarations"
561 "type declarations"
552 "Maybe you want || instead?"
562 "Maybe you want || instead?"
553
563
@@ -561,75 +571,85 @@ problemToReport problem =
561 )
571 )
562
572
563 Theories context allTheories ->
573 Theories context allTheories ->
574+ let
575+ starter =
576+ "I got confused while trying to parse "
577+ <> contextToText "your code" "" context
578+ <> "."
579+ in
580+ parseReport starter $
564− case Set.toList (Set.fromList allTheories) of
581+ case Set.toList (Set.fromList allTheories) of
565− [] ->
582+ [] ->
566− parseReport
583+ Help.stack
567− "Something went wrong when parsing this code."
568− ( reflowParagraph $
584+ [ reflowParagraph $
569− "I do not have any suggestions though, and I suspect there is some\
585+ "I do not have any suggestions though!"
586+ , reflowParagraph $
570− \ sort of bug. Can you get it down to an <http://sscce.org> and\
587+ "Can you get it down to a <http://sscce.org> and share it at\
571− \ share it at <https://github.com/elm-lang/error-message-catalog/issues>?\
588+ \ <https://github.com/elm-lang/error-message-catalog/issues>?\
572− \ That way we can figure out how to give better advice!"
589+ \ That way we can figure out how to give better advice!"
573− )
590+ ]
574
591
575− [theory] ->
592+ [theory] ->
576− parseReport
577− "I got confused while trying to parse your code."
578− ( reflowParagraph $
593+ reflowParagraph $
579− contextToText context
580− <> " right now, so I was expecting "
594+ "I was expecting to see "
581− <> theoryToText theory
595+ <> addPeriod (theoryToText context theory)
582− )
583
596
584− theories ->
597+ theories ->
585− parseReport
586− "I got confused while trying to parse your code."
587− ( Help.vcat $
598+ Help.vcat $
588− [ reflowParagraph $
589− contextToText context <> ", so I was expecting:"
599+ [ text "I was expecting:"
590 , text ""
600 , text ""
591 ]
601 ]
592− ++ map (bullet . theoryToText) theories
602+ ++ map (bullet . theoryToText context) theories
593− )
594
603
595
604
596bullet :: Text -> Help.Doc
605bullet :: Text -> Help.Doc
597bullet point =
606bullet point =
598− Help.indent 2 (reflowParagraph point)
607+ Help.hang 4 (" - " <> reflowParagraph point)
608+
599
609
610+addPeriod :: Text -> Text
611+addPeriod msg =
612+ if Text.last msg `elem` ['`', ')', '.', '!', '?'] then
613+ msg
614+ else
615+ msg <> "."
600
616
617+
601−badOp :: [Context] -> Text -> Text -> Text -> Report.Report
618+badOp :: [Context] -> Text -> Text -> Text -> Text -> Report.Report
602−badOp context opName setting hint =
619+badOp context opName op setting hint =
603 parseReport ("I was not expecting " <> opName <> " here.") $
620 parseReport ("I was not expecting " <> opName <> " here.") $
621+ Help.stack
604− reflowParagraph $
622+ [ reflowParagraph $
605− "It should only appear in " <> setting <> ", but "
623+ "A " <> op <> " should only appear in " <> setting
606− <> contextToText context <> ". " <> hint
624+ <> contextToText "" ", but I think I am parsing " context <> "."
625+ , reflowParagraph hint
626+ ]
607
627
608
628
609−contextToText :: [Context] -> Text
629+contextToText :: Text -> Text -> [Context] -> Text
610−contextToText contextStack =
630+contextToText defaultText prefixText contextStack =
611 case contextStack of
631 case contextStack of
612 [] ->
632 [] ->
613− "I am in between top-level declarations right now."
633+ defaultText
614
634
615 context : rest ->
635 context : rest ->
616 let anchor = getAnchor rest in
636 let anchor = getAnchor rest in
617− "I think I am parsing " <>
637+ prefixText <>
618 case context of
638 case context of
619 ExprIf -> "an `if`" <> anchor
639 ExprIf -> "an `if`" <> anchor
620 ExprLet -> "a `let`" <> anchor
640 ExprLet -> "a `let`" <> anchor
621 ExprFunc -> "an anonymous function" <> anchor
641 ExprFunc -> "an anonymous function" <> anchor
622 ExprCase -> "a `case`" <> anchor
642 ExprCase -> "a `case`" <> anchor
623 ExprList -> "a list" <> anchor
643 ExprList -> "a list" <> anchor
624− ExprTuple -> "a tuple" <> anchor
644+ ExprTuple -> "a expression (in parentheses)" <> anchor
625 ExprRecord -> "a record" <> anchor
645 ExprRecord -> "a record" <> anchor
626− Definition name -> "the definition of `" <> name <> "`"
646+ Definition name -> name <> "'s definition"
627− Annotation name -> "the type annotation for `" <> name <> "`"
647+ Annotation name -> name <> "'s type annotation"
628− TypeTuple -> "a tuple type" <> anchor
648+ TypeTuple -> "a type (in parentheses)" <> anchor
629 TypeRecord -> "a record type" <> anchor
649 TypeRecord -> "a record type" <> anchor
630− PatternList -> "a pattern" <> anchor
650+ PatternList -> "a list pattern" <> anchor
631− PatternTuple -> "a pattern" <> anchor
651+ PatternTuple -> "a pattern (in parentheses)" <> anchor
632− PatternRecord -> "a pattern" <> anchor
652+ PatternRecord -> "a record pattern" <> anchor
633 Module -> "a module declaration"
653 Module -> "a module declaration"
634 Import -> "an import"
654 Import -> "an import"
635 DocComment -> "a documentation comment"
655 DocComment -> "a documentation comment"
@@ -643,8 +663,8 @@ getAnchor :: [Context] -> Text
643getAnchor context =
663getAnchor context =
644 case context of
664 case context of
645 [] -> ""
665 [] -> ""
646− Definition name : _ -> " in the definition of `" <> name <> "`"
666+ Definition name : _ -> " in " <> name <> "'s definition"
647− Annotation name : _ -> " in the type annotation for `" <> name <> "`"
667+ Annotation name : _ -> " in " <> name <> "'s type annotation"
648 _ : rest -> getAnchor rest
668 _ : rest -> getAnchor rest
649
669
650
670
@@ -656,20 +676,20 @@ isCaseRelated context =
656 _ : rest -> isCaseRelated rest
676 _ : rest -> isCaseRelated rest
657
677
658
678
659−theoryToText :: Theory -> Text
679+theoryToText :: [Context] -> Theory -> Text
660−theoryToText theory =
680+theoryToText context theory =
661 case theory of
681 case theory of
662 Keyword keyword ->
682 Keyword keyword ->
663 "the `" <> keyword <> "` keyword"
683 "the `" <> keyword <> "` keyword"
664
684
665 Symbol symbol ->
685 Symbol symbol ->
666 case symbol of
686 case symbol of
667− "=" -> "an equals sign (=)"
687+ "=" -> equalsTheory context
668 "->" -> "an arrow (->) followed by an expression"
688 "->" -> "an arrow (->) followed by an expression"
669 ":" -> "the \"has type\" symbol (:) followed by a type"
689 ":" -> "the \"has type\" symbol (:) followed by a type"
670 "," -> "a comma"
690 "," -> "a comma"
671− "|" -> "a vertical bar (|)"
691+ "|" -> barTheory context
672− "::" -> "the cons operator (::)"
692+ "::" -> "the cons operator (::) followed by more list elements"
673 "." -> "a dot (.)"
693 "." -> "a dot (.)"
674 "-" -> "a minus sign (-)"
694 "-" -> "a minus sign (-)"
675 "_" -> "an underscore"
695 "_" -> "an underscore"
@@ -688,7 +708,7 @@ theoryToText theory =
688 "an upper-case variable, like `Maybe` or `Just`"
708 "an upper-case variable, like `Maybe` or `Just`"
689
709
690 InfixOp ->
710 InfixOp ->
691− "an infix operator, like + or =="
711+ "an infix operator, like (+) or (==)"
692
712
693 Digit ->
713 Digit ->
694 "a digit from 0 to 9"
714 "a digit from 0 to 9"
@@ -697,10 +717,10 @@ theoryToText theory =
697 "the end of the file"
717 "the end of the file"
698
718
699 BadSpace ->
719 BadSpace ->
700− "more indentation"
720+ badSpace context
701
721
702 FreshLine nextDecl ->
722 FreshLine nextDecl ->
703− "a fresh line with no indentation for " <>
723+ "a fresh line (without any leading spaces) for " <>
704 case nextDecl of
724 case nextDecl of
705 ModuleDecl -> "an `import`"
725 ModuleDecl -> "an `import`"
706 DocCommentDecl -> "an `import`"
726 DocCommentDecl -> "an `import`"
@@ -710,9 +730,75 @@ theoryToText theory =
710 Expecting next ->
730 Expecting next ->
711 case next of
731 case next of
712 Expr -> "an expression, like x or 42"
732 Expr -> "an expression, like x or 42"
733+ AfterOpExpr op -> "an expression after that (" <> op <> ") operator, like x or 42"
713− ElseBranch -> "an `else` branch. An `if` must handle both possibilities!"
734+ ElseBranch -> "an `else` branch. An `if` must handle both possibilities."
714 Arg -> "an argument, like `name` or `total`"
735 Arg -> "an argument, like `name` or `total`"
715 Pattern -> "a pattern, like `name` or (Just x)"
736 Pattern -> "a pattern, like `name` or (Just x)"
716 Type -> "a type, like Int or (List String)"
737 Type -> "a type, like Int or (List String)"
717 Listing -> "a list of exposed values and types, like (..) or (x,y,z)"
738 Listing -> "a list of exposed values and types, like (..) or (x,y,z)"
718 Exposing -> "something like `exposing (..)`"
739 Exposing -> "something like `exposing (..)`"
740+
741+
742+equalsTheory :: [Context] -> Text
743+equalsTheory context =
744+ case context of
745+ [] ->
746+ "an equals sign (=)"
747+
748+ first : rest ->
749+ case first of
750+ ExprRecord -> "an equals sign (=) followed by an expression"
751+ Definition name -> "an equals sign (=) followed by " <> name <> "'s definition"
752+ TypeUnion -> "an equals sign (=) followed by the first union type constructor"
753+ TypeAlias -> "an equals sign (=) followed by the aliased type"
754+ _ -> equalsTheory rest
755+
756+
757+barTheory :: [Context] -> Text
758+barTheory context =
759+ case context of
760+ [] ->
761+ "a vertical bar (|)"
762+
763+ first : rest ->
764+ case first of
765+ ExprRecord -> "a vertical bar (|) followed by the record fields you want to update"
766+ TypeRecord -> "a vertical bar (|) followed by some record field types"
767+ TypeUnion -> "a vertical bar (|) followed by more union type constructors"
768+ _ -> barTheory rest
769+
770+
771+badSpace :: [Context] -> Text
772+badSpace context =
773+ case context of
774+ [] ->
775+ "more indentation? I was not done with that last thing yet."
776+
777+ first : rest ->
778+ case first of
779+ ExprIf -> "the end of that `if`" <> badSpaceEnd
780+ ExprLet -> "the end of that `let`" <> badSpaceEnd
781+ ExprFunc -> badSpace rest
782+ ExprCase -> "more of that `case`" <> badSpaceEnd
783+ ExprList -> "the end of that list" <> badSpaceEnd
784+ ExprTuple -> "a closing paren" <> badSpaceEnd
785+ ExprRecord -> "the end of that record" <> badSpaceEnd
786+ Definition name -> "the rest of " <> name <> "'s definition" <> badSpaceEnd
787+ Annotation name -> "the rest of " <> name <> "'s type annotation" <> badSpaceEnd
788+ TypeTuple -> "a closing paren" <> badSpaceEnd
789+ TypeRecord -> "the end of that record" <> badSpaceEnd
790+ PatternList -> "the end of that list" <> badSpaceEnd
791+ PatternTuple -> "a closing paren" <> badSpaceEnd
792+ PatternRecord -> "the end of that record" <> badSpaceEnd
793+ Module -> "something like `module Main exposing (..)`"
794+ Import -> "something like `import Html exposing (..)`"
795+ DocComment -> badSpace rest
796+ TypeUnion -> "more of that union type" <> badSpaceEnd
797+ TypeAlias -> "more of that type alias" <> badSpaceEnd
798+ Infix -> "more of that infix declaration" <> badSpaceEnd
799+ Port -> "more of that port declaration" <> badSpaceEnd
800+
801+
802+badSpaceEnd :: Text
803+badSpaceEnd =
804+ ". Maybe you forgot some code? Or you need more indentation?"