on bb35d68 help sign in
elk/src/Reporting/Error/Syntax.hs
870 lines 29 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Error.Syntax
4 ( Error(..)
5 , ParseError(..)
6 , Problem(..), Theory(..)
7 , ContextStack, Context(..)
8 , BadOp(..), Next(..)
9 , toReport
10 )
11 where
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)
25-- ALL SYNTAX ERRORS
28data Error
29 = Parse (Maybe R.Region) Problem
30 | BadFunctionName Int
31 | BadPattern Text
33 | CommentOnNothing
35 | SettingsOnNormalModule
36 | SettingsOnPortModule
37 | DuplicateSettingOnEffectModule Text
38 | BadSettingOnEffectModule Text
39 | NoSettingsOnEffectModule
40 | MissingManagerOnEffectModule Text
41 | UnexpectedPort 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]
57-- PARSE ERRORS
60data ParseError = ParseError !Int !Int !Problem
63data Problem
64 = Tab
65 | EndOfFile_Comment
66 | EndOfFile_Shader
67 | EndOfFile_String
68 | EndOfFile_MultiString
69 | NewLineInString
70 | BadEscape
71 | BadChar
72 | BadNumberDot
73 | BadNumberEnd
74 | BadNumberExp
75 | BadNumberHex
76 | BadNumberZero
77 | BadShader Text
78 | BadUnderscore Char
79 | BadOp BadOp ContextStack
80 | Theories ContextStack [Theory]
83data BadOp = HasType | Equals | Arrow | Pipe | Dot
86data Theory
87 = Keyword Text
88 | Symbol Text
89 | Expecting Next
90 | LowVar
91 | CapVar
92 | InfixOp
93 | Digit
94 | BadSpace
95 deriving (Eq, Ord)
98data Next
99 = Decl
100 | Expr
101 | AfterOpExpr Text
102 | ElseBranch
103 | Arg
104 | Pattern
105 | Type
106 | Listing
107 | Exposing
108 deriving (Eq, Ord)
111type ContextStack = [(Context, R.Position)]
114data Context
115 = ExprIf
116 | ExprLet
117 | ExprFunc
118 | ExprCase
119 | ExprList
120 | ExprTuple
121 | ExprRecord
122 ----------------
123 | Definition Text
124 | Annotation Text
125 ----------------
126 | TypeTuple
127 | TypeRecord
128 ----------------
129 | PatternList
130 | PatternTuple
131 | PatternRecord
132 ----------------
133 | Module
134 | Import
135 | TypeUnion
136 | TypeAlias
137 | Infix
138 | Port
139 deriving (Eq, Ord, Show)
143-- TO REPORT
146toReport :: RenderType.Localizer -> Error -> Report.Report
147toReport _localizer err =
148 case err of
149 Parse subRegion problem ->
150 problemToReport subRegion problem
152 BadFunctionName arity ->
153 Report.report
154 "BAD FUNCTION DEFINITION"
155 Nothing
156 "Complex patterns cannot be used as function names."
157 ( reflowParagraph $
158 "This function definition has " <> i2t arity <> " arguments, but instead\
159 \ of a normal name like `add` or `reverse` it has a pattern. There is no\
160 \ way to \"deconstruct\" a function with pattern matching, so this needs to\
161 \ be changed to a normal name."
162 )
164 BadPattern name ->
165 Report.report
166 "BAD PATTERN"
167 Nothing
168 ("The free variable `" <> name <> "` appears more than once in this pattern.")
169 ( Help.stack
170 [ text "Rename the variables so there are no duplicates."
171 , reflowParagraph $
172 "In Elm, pattern matching works by binding these free variables to subsections\
173 \ of the matching value. It does not make sense to have the same name for two\
174 \ different subsections though! When you say `" <> name <> "` in some code, there\
175 \ is no way for me to know which subsection you mean!"
176 ]
177 )
179 CommentOnNothing ->
180 Report.report
181 "STRAY COMMENT"
182 Nothing
183 ("This documentation comment is not followed by anything.")
184 ( reflowParagraph $
185 "All documentation comments need to be right above the declaration they\
186 \ describe. Maybe some code got deleted or commented out by accident? Or\
187 \ maybe this comment is here by accident?"
188 )
190 SettingsOnNormalModule ->
191 Report.report
192 "BAD MODULE DECLARATION"
193 Nothing
194 "A normal module can expose values, but not settings like this."
195 ( reflowParagraph $
196 "If you want a normal module, just remove this stuff. If you want to create\
197 \ an `effect module` you forgot to use the `effect` keyword. In that\
198 \ case, change `module` to `effect module` and you should be headed in\
199 \ the right direction!"
200 )
202 SettingsOnPortModule ->
203 Report.report
204 "BAD MODULE DECLARATION"
205 Nothing
206 "A port module can expose values, but not have settings like this."
207 ( reflowParagraph $
208 "If you want a port module, just remove this stuff. If you want to create\
209 \ a custom effect module instead (which is rare) change `port module`\
210 \ to `effect module` and you should be headed in the right direction!"
211 )
213 DuplicateSettingOnEffectModule name ->
214 Report.report
215 "EFFECT MODULE PROBLEM"
216 Nothing
217 ("You have defined " <> Help.functionName name <> " multiple times.")
218 ( reflowParagraph $
219 "There can only be one " <> Help.functionName name
220 <> " though! Remove until there is one left."
221 )
223 BadSettingOnEffectModule name ->
224 Report.report
225 "EFFECT MODULE PROBLEM"
226 Nothing
227 ("Setting " <> Help.functionName name <> " is not recognized.")
228 ( reflowParagraph $
229 "Remove this entry and you should be all set!"
230 )
232 NoSettingsOnEffectModule ->
233 Report.report
234 "EFFECT MODULE PROBLEM"
235 Nothing
236 ("You are defining an effect module, but it has no settings.")
237 ( reflowParagraph $
238 "If you just wanted a normal module, change the keywords `effect module`\
239 \ to `module` and you should be all set. If you want a proper effect module,\
240 \ you need to specify your commands and/or subscriptions. Read more about this\
241 \ here: <http://guide.elm-lang.org/effect_managers/>"
242 )
244 MissingManagerOnEffectModule name ->
245 Report.report
246 "EFFECT MODULE PROBLEM"
247 Nothing
248 ("You are defining an effect module, but there is no " <> Help.functionName name <> " defined.")
249 ( reflowParagraph $
250 "There is a small set of top-level functions and values that must be defined\
251 \ in any complete effect module. The best thing is probably to just read more\
252 \ about effect modules here:\
253 \ <http://guide.elm-lang.org/effect_managers/>"
254 )
256 UnexpectedPort name ->
257 Report.report
258 "BAD PORT"
259 Nothing
260 ("You are declaring port " <> Help.functionName name <> " in a normal module.")
261 ( reflowParagraph $
262 "All ports must be defined in a `port module`. You should probably have only\
263 \ one of these for your project. This way all of your foreign interactions\
264 \ stay relatively organized."
265 )
267 TypeWithoutDefinition valueName ->
268 Report.report
269 "MISSING DEFINITION"
270 Nothing
271 ("There is a type annotation for `" <> valueName <> "` but there"
272 <> " is no corresponding definition!"
273 )
274 ( text $
275 "Directly below the type annotation, put a definition like:\n\n"
276 <> " " <> valueName <> " = 42"
277 )
279 DuplicateArgument funcName argName ->
280 Report.report
281 "DUPLICATE ARGUMENT"
282 Nothing
283 ( "The name `" <> argName
284 <> "` is used more than once in the arguments of "
285 <> Help.functionName funcName <> "."
286 )
287 ( reflowParagraph $
288 "Rename things until `" <> argName <> "` is used only once.\
289 \ Otherwise how can we tell which one you want when you\
290 \ say `" <> argName <> "` it in the body of your function?"
291 )
293 DuplicateFieldName region name ->
294 Report.report
295 "DUPLICATE FIELD"
296 (Just region)
297 ("This record has more than one field named `" <> name <> "`.")
298 (text "There can only be one. Do some renaming to make sure the names are distinct!")
300 DuplicateValueDeclaration name ->
301 Report.report
302 "DUPLICATE DEFINITION"
303 Nothing
304 ( "Naming multiple top-level values " <> Help.functionName name <> " makes things\n"
305 <> "ambiguous. When you say " <> Help.functionName name <> " which one do you want?"
306 )
307 ( reflowParagraph $
308 "Find all the top-level values named " <> Help.functionName name
309 <> " and do some renaming. Make sure the names are distinct!"
310 )
312 DuplicateTypeDeclaration name ->
313 Report.report
314 "DUPLICATE DEFINITION"
315 Nothing
316 ( "There are multiple types named `" <> name <> "` in this module."
317 )
318 ( reflowParagraph $
319 "Search through this module, find all the types named `"
320 <> name <> "`, and give each of them a unique name."
321 )
323 DuplicateDefinition name ->
324 Report.report
325 "DUPLICATE DEFINITION"
326 Nothing
327 ("There are multiple values named `" <> name <> "` in this let-expression."
328 )
329 ( reflowParagraph $
330 "Search through this let-expression, find all the values named `"
331 <> name <> "`, and give each of them a unique name."
332 )
334 UnboundTypeVarsInUnion typeName givenVars unbound ->
335 unboundTypeVars "type" typeName givenVars unbound
337 UnboundTypeVarsInAlias typeName givenVars unbound ->
338 unboundTypeVars "type alias" typeName givenVars unbound
340 UnusedTypeVarsInAlias typeName givenVars unused ->
341 Report.report
342 "UNUSED TYPE VARIABLES"
343 Nothing
344 ( "Type alias `" <> typeName <> "` cannot have unused type variables: "
345 <> Help.commaSep unused
346 )
347 ( Help.stack
348 [ text "You probably need to change the declaration like this:"
349 , dullyellow $ hsep $
350 map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ ["=", "..."])
351 ]
352 )
354 MessyTypeVarsInAlias typeName givenVars unused unbound ->
355 Report.report
356 "TYPE VARIABLE PROBLEMS"
357 Nothing
358 ( "Type alias `" <> typeName <> "` has some problems with type variables."
359 )
360 ( Help.stack
361 [ reflowParagraph $
362 "The declaration says it uses certain type variables ("
363 <> Help.commaSep unused <> ") but they do not appear in the aliased type. "
364 <> "Furthermore, the aliased type says it uses type variables ("
365 <> Help.commaSep unbound
366 <> ") that do not appear in the declaration."
367 , text "You probably need to change the declaration like this:"
368 , dullyellow $ hsep $
369 map text ("type" : "alias" : typeName : filter (`notElem` unused) givenVars ++ unbound ++ ["=", "..."])
370 ]
371 )
374unboundTypeVars :: Text -> Text -> [Text] -> [Text] -> Report.Report
375unboundTypeVars declKind typeName givenVars unboundVars =
376 Report.report
377 "UNBOUND TYPE VARIABLES"
378 Nothing
379 ( Help.capitalize declKind <> " `" <> typeName <> "` must declare its use of type variable"
380 <> Help.commaSep unboundVars
381 )
382 ( Help.stack
383 [ text "You probably need to change the declaration like this:"
384 , hsep $
385 map text (declKind : typeName : givenVars)
386 ++ map (dullyellow . text) unboundVars
387 ++ map text ["=", "..."]
388 , reflowParagraph $
389 "Here's why. Imagine one `" <> typeName <> "` where `" <> head unboundVars <>
390 "` is an Int and another where it is a Bool. When we explicitly list the type\
391 \ variables, the type checker can see that they are actually different types."
392 ]
393 )
397-- PARSE ERROR TO REPORT
400makeParseReport :: Maybe R.Region -> Text -> Help.Doc -> Report.Report
401makeParseReport subRegion pre post =
402 Report.report "PARSE ERROR" subRegion pre post
405problemToReport :: Maybe R.Region -> Problem -> Report.Report
406problemToReport subRegion problem =
407 let parseReport = makeParseReport subRegion in
408 case problem of
409 Tab ->
410 parseReport
411 "I ran into a tab, but tabs are not allowed in Elm files."
412 (reflowParagraph "Replace the tab with spages.")
414 EndOfFile_Comment ->
415 parseReport
416 "I got to the end of the file while parsing a multi-line comment."
417 ( Help.stack
418 [ reflowParagraph $
419 "Multi-line comments look like {- comment -}, and it looks like\
420 \ you are missing the closing marker."
421 , reflowParagraph $
422 "Nested multi-line comments like {- this {- and this -} -} are allowed.\
423 \ That means the opening and closing markers must be balanced, just\
424 \ like parentheses in normal code. Maybe that is the problem?"
425 ]
426 )
428 EndOfFile_Shader ->
429 parseReport
430 "I got to the end of the file while parsing a GLSL block."
431 (reflowParagraph $
432 "A shader should be defined in a block like this: [glsl| ... |]"
433 )
435 EndOfFile_String ->
436 parseReport
437 "I got to the end of the file while parsing a string."
438 (reflowParagraph $
439 "Strings look like \"this\" with double quotes on each end.\
440 \ So the closing double quote seems to be missing."
441 )
443 EndOfFile_MultiString ->
444 parseReport
445 "I got to the end of the file while parsing a multi-line string."
446 (reflowParagraph $
447 "Multi-line strings begin and end with three double quotes in a\
448 \ row, like \"\"\"this\"\"\". So the closing marker seems\
449 \ to be missing."
450 )
452 NewLineInString ->
453 parseReport
454 "This string is missing the closing quote."
455 ( Help.stack
456 [ reflowParagraph $
457 "Elm strings must start and end with a double quote, like \"this\"."
458 , reflowParagraph $
459 "If you want a string that can contain newlines, use three double quotes in a\
460 \ row, like \"\"\"this\"\"\"."
461 ]
462 )
464 BadEscape ->
465 parseReport
466 "A backslash starts an escaped character, but I do not recognize this one:"
467 ( reflowParagraph
468 "Elm allows typical escape characters like \\\\ and \\n and \\t. You can\
469 \ also say \\u0040 to refer to unicode characters by their hex code.\
470 \ Maybe there is some typo?"
471 )
473 BadChar ->
474 parseReport
475 "Ran into a bad use of single quotes."
476 ( Help.stack
477 [ reflowParagraph $
478 "If you want to create a string, switch to double quotes:"
479 , Help.indent 4 $
480 dullyellow (text "'this'")
481 <> text " => "
482 <> dullyellow (text "\"this\"")
483 , reflowParagraph $
484 "Unlike JavaScript, Elm distinguishes between strings like \"hello\"\
485 \ and individual characters like 'A' and '3'. If you really do want\
486 \ a character though, something went wrong and I did not find the\
487 \ closing single quote."
488 ]
489 )
491 BadNumberDot ->
492 parseReport
493 "Numbers cannot end with a decimal points."
494 ( reflowParagraph $
495 "Leave it off or add some digits after it, like or 3 or 3.0"
496 )
498 BadNumberEnd ->
499 parseReport
500 "Numbers cannot have letters or underscores in them."
501 ( reflowParagraph $
502 "Maybe a space is missing between a number and a variable?"
503 )
505 BadNumberExp ->
506 parseReport
507 "If you put the letter E in a number, it should followed by more digits."
508 ( reflowParagraph $
509 "If you want to say 1000, you can also say 1e3.\
510 \ You cannot just end it with an E though!"
511 )
513 BadNumberHex ->
514 parseReport
515 "I see the start of a hex number, but not the end."
516 ( reflowParagraph $
517 "A hex number looks like 0x123ABC, where the 0x is followed by hexidecimal digits (i.e. 0123456789abcdefABCDEF)"
518 )
520 BadNumberZero ->
521 parseReport
522 "Normal numbers cannot start with a zero. Take the zeros off the front."
523 ( reflowParagraph $
524 "Only numbers like 0x0040 or 0.25 can start with a zero."
525 )
527 BadShader msg ->
528 parseReport
529 "I ran into a problem while parsing this GLSL block."
530 (reflowParagraph msg)
532 BadUnderscore char ->
533 parseReport
534 ("An underscore cannot be immediately followed by `" <> Text.singleton char <> "`.")
535 ( reflowParagraph $
536 "Variable names cannot start with an underscore in Elm. You can\
537 \ use an underscore as a \"wildcard\" that matches anything\
538 \ though. So maybe you forgot a space after the underscore?"
539 )
541 BadOp op stack ->
542 case op of
543 HasType ->
544 badOp subRegion stack "A" "\"has type\" operator"
545 "type annotations and record types"
546 "Maybe you want :: instead? Or maybe something is indented too much?"
548 Equals ->
549 badEquals subRegion stack
551 Arrow ->
552 if isCaseRelated stack then
553 parseReport
554 "I ran into a stray arrow while parsing this `case` expression."
555 ( reflowParagraph $
556 "All branches in a `case` must be indented the exact\
557 \ same amount, so the patterns are vertically\
558 \ aligned. Maybe this branch is indented too much?"
559 )
561 else
562 badOp subRegion stack "An" "arrow"
563 "cases expressions and anonymous functions"
564 "Maybe you want > or >= instead?"
566 Pipe ->
567 badOp subRegion stack "A" "vertical bar"
568 "type declarations"
569 "Maybe you want || instead?"
571 Dot ->
572 parseReport
573 "I was not expecting this dot."
574 ( reflowParagraph $
575 "Dots are for record access and decimal points, so\
576 \ they cannot float around on their own. Maybe\
577 \ there is some extra whitespace?"
578 )
580 Theories stack allTheories ->
581 let
582 starter =
583 "Something went wrong while parsing "
584 <> contextToText "your code" "" stack
585 <> "."
586 in
587 parseReport starter $
588 case Set.toList (Set.fromList allTheories) of
589 [] ->
590 Help.stack
591 [ reflowParagraph $
592 "I do not have any suggestions though!"
593 , reflowParagraph $
594 "Can you get it down to a <http://sscce.org> and share it at\
595 \ <https://github.com/elm-lang/error-message-catalog/issues>?\
596 \ That way we can figure out how to give better advice!"
597 ]
599 [theory] ->
600 reflowParagraph $
601 "I was expecting to see "
602 <> addPeriod (theoryToText stack theory)
604 theories ->
605 Help.vcat $
606 [ text "I was expecting:"
607 , text ""
608 ]
609 ++ map (bullet . theoryToText stack) theories
612bullet :: Text -> Help.Doc
613bullet point =
614 Help.hang 4 (" - " <> reflowParagraph point)
617addPeriod :: Text -> Text
618addPeriod msg =
619 if Text.last msg `elem` ['`', ')', '.', '!', '?'] then
620 msg
621 else
622 msg <> "."
625badOp :: Maybe R.Region -> ContextStack -> Text -> Text -> Text -> Text -> Report.Report
626badOp subRegion stack article opName setting hint =
627 let
628 pre =
629 "I was not expecting this " <> opName
630 <> contextToText "" " while parsing " stack <> "."
631 in
632 makeParseReport subRegion pre $
633 reflowParagraph $
634 article <> " " <> opName <> " should only appear in "
635 <> setting <> ". " <> hint
638badEquals :: Maybe R.Region -> ContextStack -> Report.Report
639badEquals subRegion stack =
640 let
641 pre =
642 "I was not expecting this equals sign"
643 <> contextToText "" " while parsing " stack <> "."
644 in
645 makeParseReport subRegion pre (badEqualsHelp stack)
648badEqualsHelp :: ContextStack -> Help.Doc
649badEqualsHelp stack =
650 case stack of
651 [] ->
652 reflowParagraph $
653 "Maybe you want == instead? Or maybe something is indented too much?"
655 (ExprRecord, _) : _ ->
656 reflowParagraph $
657 "Records look like { x = 3, y = 4 } with the equals sign right\
658 \ after the field name. Maybe you forgot a comma?"
660 (Definition _, _) : rest ->
661 reflowParagraph $
662 "Maybe this is supposed to be a separate definition? If so, it\
663 \ is indented too far. "
664 <>
665 if any ((==) ExprLet . fst) rest then
666 "All definitions in a `let` expression must be vertically aligned."
667 else
668 "Spaces are not allowed before top-level definitions."
670 _ : rest ->
671 badEqualsHelp rest
674contextToText :: Text -> Text -> ContextStack -> Text
675contextToText defaultText prefixText stack =
676 case stack of
677 [] ->
678 defaultText
680 (context, _) : rest ->
681 let anchor = getAnchor rest in
682 prefixText <>
683 case context of
684 ExprIf -> "an `if`" <> anchor
685 ExprLet -> "a `let`" <> anchor
686 ExprFunc -> "an anonymous function" <> anchor
687 ExprCase -> "a `case`" <> anchor
688 ExprList -> "a list" <> anchor
689 ExprTuple -> "an expression (in parentheses)" <> anchor
690 ExprRecord -> "a record" <> anchor
691 Definition name -> name <> "'s definition"
692 Annotation name -> name <> "'s type annotation"
693 TypeTuple -> "a type (in parentheses)" <> anchor
694 TypeRecord -> "a record type" <> anchor
695 PatternList -> "a list pattern" <> anchor
696 PatternTuple -> "a pattern (in parentheses)" <> anchor
697 PatternRecord -> "a record pattern" <> anchor
698 Module -> "a module declaration"
699 Import -> "an import"
700 TypeUnion -> "a union type"
701 TypeAlias -> "a type alias"
702 Infix -> "an infix declaration"
703 Port -> "a port declaration"
706getAnchor :: ContextStack -> Text
707getAnchor stack =
708 case stack of
709 [] ->
710 ""
712 (context, _) : rest ->
713 case context of
714 Definition name ->
715 " in " <> name <> "'s definition"
717 Annotation name ->
718 " in " <> name <> "'s type annotation"
720 _ ->
721 getAnchor rest
724isCaseRelated :: ContextStack -> Bool
725isCaseRelated stack =
726 case stack of
727 [] ->
728 False
730 (context, _) : rest ->
731 context == ExprCase || isCaseRelated rest
734theoryToText :: ContextStack -> Theory -> Text
735theoryToText context theory =
736 case theory of
737 Keyword keyword ->
738 "the `" <> keyword <> "` keyword"
740 Symbol symbol ->
741 case symbol of
742 "=" -> equalsTheory context
743 "->" -> "an arrow (->) followed by an expression"
744 ":" -> "the \"has type\" symbol (:) followed by a type"
745 "," -> "a comma"
746 "|" -> barTheory context
747 "::" -> "the cons operator (::) followed by more list elements"
748 "." -> "a dot (.)"
749 "-" -> "a minus sign (-)"
750 "_" -> "an underscore"
751 "(" -> "a left paren, for grouping or starting tuples"
752 ")" -> "a closing paren"
753 "[" -> "a left square bracket, for starting lists"
754 "]" -> "a right square bracket, to end a list"
755 "{" -> "a left curly brace, for starting records"
756 "}" -> "a right curly brace, to end a record"
757 "{-|" -> "a doc comment, like {-| example -}"
758 _ -> "the (" <> symbol <> ") symbol"
760 LowVar ->
761 "a lower-case variable, like `x` or `user`"
763 CapVar ->
764 "an upper-case variable, like `Maybe` or `Just`"
766 InfixOp ->
767 "an infix operator, like (+) or (==)"
769 Digit ->
770 "a digit from 0 to 9"
772 BadSpace ->
773 badSpace context
775 Expecting next ->
776 case next of
777 Decl -> "a declaration, like `x = 5` or `type alias Model = { ... }`"
778 Expr -> "an expression, like x or 42"
779 AfterOpExpr op -> "an expression after that (" <> op <> ") operator, like x or 42"
780 ElseBranch -> "an `else` branch. An `if` must handle both possibilities."
781 Arg -> "an argument, like `name` or `total`"
782 Pattern -> "a pattern, like `name` or (Just x)"
783 Type -> "a type, like Int or (List String)"
784 Listing -> "a list of exposed values and types, like (..) or (x,y,z)"
785 Exposing -> "something like `exposing (..)`"
788equalsTheory :: ContextStack -> Text
789equalsTheory stack =
790 case stack of
791 [] ->
792 "an equals sign (=)"
794 (context, _) : rest ->
795 case context of
796 ExprRecord -> "an equals sign (=) followed by an expression"
797 Definition name -> "an equals sign (=) followed by " <> name <> "'s definition"
798 TypeUnion -> "an equals sign (=) followed by the first union type constructor"
799 TypeAlias -> "an equals sign (=) followed by the aliased type"
800 _ -> equalsTheory rest
803barTheory :: ContextStack -> Text
804barTheory stack =
805 case stack of
806 [] ->
807 "a vertical bar (|)"
809 (context, _) : rest ->
810 case context of
811 ExprRecord -> "a vertical bar (|) followed by the record fields you want to update"
812 TypeRecord -> "a vertical bar (|) followed by some record field types"
813 TypeUnion -> "a vertical bar (|) followed by more union type constructors"
814 _ -> barTheory rest
817badSpace :: ContextStack -> Text
818badSpace stack =
819 case stack of
820 [] ->
821 "more indentation? I was not done with that last thing yet."
823 (context, _) : rest ->
824 case context of
825 ExprIf -> "the end of that `if`" <> badSpaceExprEnd rest
826 ExprLet -> "the end of that `let`" <> badSpaceExprEnd rest
827 ExprFunc -> badSpace rest
828 ExprCase -> "more of that `case`" <> badSpaceExprEnd rest
829 ExprList -> "the end of that list" <> badSpaceExprEnd rest
830 ExprTuple -> "a closing paren" <> badSpaceExprEnd rest
831 ExprRecord -> "the end of that record" <> badSpaceExprEnd rest
832 Definition name -> "the rest of " <> name <> "'s definition" <> badSpaceExprEnd stack
833 Annotation name -> "the rest of " <> name <> "'s type annotation" <> badSpaceEnd
834 TypeTuple -> "a closing paren" <> badSpaceEnd
835 TypeRecord -> "the end of that record" <> badSpaceEnd
836 PatternList -> "the end of that list" <> badSpaceEnd
837 PatternTuple -> "a closing paren" <> badSpaceEnd
838 PatternRecord -> "the end of that record" <> badSpaceEnd
839 Module -> "something like `module Main exposing (..)`"
840 Import -> "something like `import Html exposing (..)`"
841 TypeUnion -> "more of that union type" <> badSpaceEnd
842 TypeAlias -> "more of that type alias" <> badSpaceEnd
843 Infix -> "more of that infix declaration" <> badSpaceEnd
844 Port -> "more of that port declaration" <> badSpaceEnd
847badSpaceEnd :: Text
848badSpaceEnd =
849 ". Maybe you forgot some code? Or you need more indentation?"
852badSpaceExprEnd :: ContextStack -> Text
853badSpaceExprEnd stack =
854 case stack of
855 [] ->
856 badSpaceEnd
858 (Definition name, R.Position _ column) : _ ->
859 let
860 ending =
861 if column <= 1 then
862 "to be indented?"
863 else
864 "more indentation? (Try " <> i2t (column + 1) <> "+ spaces.)"
865 in
866 ". Maybe you forgot some code? Or maybe the body of `" <> name
867 <> "` needs " <> ending
869 _ : rest ->
870 badSpaceExprEnd rest