on 294ee07 help sign in
elk/src/Reporting/Error/Syntax.hs
864 lines 28 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 | BadOp BadOp ContextStack
79 | Theories ContextStack [Theory]
82data BadOp = HasType | Equals | Arrow | Pipe | Dot
85data Theory
86 = Keyword Text
87 | Symbol Text
88 | Expecting Next
89 | LowVar
90 | CapVar
91 | InfixOp
92 | Digit
93 | EndOfFile
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 "Ran into a bad escape code."
467 ( reflowParagraph
468 "Elm allows typical escape characters like \\n and \\t, but you can\
469 \ also use \\x0040 to refer to unicode characters by their hex code.\
470 \ It seems like something has gone wrong with one of these codes."
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'. It is not all strings!\
486 \ If you really do want a character though, something went wrong\
487 \ and I did not find the 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 BadOp op stack ->
533 case op of
534 HasType ->
535 badOp subRegion stack "A" "\"has type\" operator"
536 "type annotations and record types"
537 "Maybe you want :: instead? Or maybe something is indented too much?"
539 Equals ->
540 badEquals subRegion stack
542 Arrow ->
543 if isCaseRelated stack then
544 parseReport
545 "I ran into a stray arrow while parsing this `case` expression."
546 ( reflowParagraph $
547 "All branches in a `case` must be indented the exact\
548 \ same amount, so the patterns are vertically\
549 \ aligned. Maybe this branch is indented too much?"
550 )
552 else
553 badOp subRegion stack "An" "arrow"
554 "cases expressions and anonymous functions"
555 "Maybe you want > or >= instead?"
557 Pipe ->
558 badOp subRegion stack "A" "vertical bar"
559 "type declarations"
560 "Maybe you want || instead?"
562 Dot ->
563 parseReport
564 "I was not expecting this dot."
565 ( reflowParagraph $
566 "Dots are for record access and decimal points, so\
567 \ they cannot float around on their own. Maybe\
568 \ there is some extra whitespace?"
569 )
571 Theories stack allTheories ->
572 let
573 starter =
574 "Something went wrong while parsing "
575 <> contextToText "your code" "" stack
576 <> "."
577 in
578 parseReport starter $
579 case Set.toList (Set.fromList allTheories) of
580 [] ->
581 Help.stack
582 [ reflowParagraph $
583 "I do not have any suggestions though!"
584 , reflowParagraph $
585 "Can you get it down to a <http://sscce.org> and share it at\
586 \ <https://github.com/elm-lang/error-message-catalog/issues>?\
587 \ That way we can figure out how to give better advice!"
588 ]
590 [theory] ->
591 reflowParagraph $
592 "I was expecting to see "
593 <> addPeriod (theoryToText stack theory)
595 theories ->
596 Help.vcat $
597 [ text "I was expecting:"
598 , text ""
599 ]
600 ++ map (bullet . theoryToText stack) theories
603bullet :: Text -> Help.Doc
604bullet point =
605 Help.hang 4 (" - " <> reflowParagraph point)
608addPeriod :: Text -> Text
609addPeriod msg =
610 if Text.last msg `elem` ['`', ')', '.', '!', '?'] then
611 msg
612 else
613 msg <> "."
616badOp :: Maybe R.Region -> ContextStack -> Text -> Text -> Text -> Text -> Report.Report
617badOp subRegion stack article opName setting hint =
618 let
619 pre =
620 "I was not expecting this " <> opName
621 <> contextToText "" " while parsing " stack <> "."
622 in
623 makeParseReport subRegion pre $
624 reflowParagraph $
625 article <> " " <> opName <> " should only appear in "
626 <> setting <> ". " <> hint
629badEquals :: Maybe R.Region -> ContextStack -> Report.Report
630badEquals subRegion stack =
631 let
632 pre =
633 "I was not expecting this equals sign"
634 <> contextToText "" " while parsing " stack <> "."
635 in
636 makeParseReport subRegion pre (badEqualsHelp stack)
639badEqualsHelp :: ContextStack -> Help.Doc
640badEqualsHelp stack =
641 case stack of
642 [] ->
643 reflowParagraph $
644 "Maybe you want == instead? Or maybe something is indented too much?"
646 (ExprRecord, _) : _ ->
647 reflowParagraph $
648 "Records look like { x = 3, y = 4 } with the equals sign right\
649 \ after the field name. Maybe you forgot a comma?"
651 (Definition _, _) : rest ->
652 reflowParagraph $
653 "Maybe this is supposed to be a separate definition? If so, it\
654 \ is indented too far. "
655 <>
656 if any ((==) ExprLet . fst) rest then
657 "All definitions in a `let` expression must be vertically aligned."
658 else
659 "Spaces are not allowed before top-level definitions."
661 _ : rest ->
662 badEqualsHelp rest
665contextToText :: Text -> Text -> ContextStack -> Text
666contextToText defaultText prefixText stack =
667 case stack of
668 [] ->
669 defaultText
671 (context, _) : rest ->
672 let anchor = getAnchor rest in
673 prefixText <>
674 case context of
675 ExprIf -> "an `if`" <> anchor
676 ExprLet -> "a `let`" <> anchor
677 ExprFunc -> "an anonymous function" <> anchor
678 ExprCase -> "a `case`" <> anchor
679 ExprList -> "a list" <> anchor
680 ExprTuple -> "an expression (in parentheses)" <> anchor
681 ExprRecord -> "a record" <> anchor
682 Definition name -> name <> "'s definition"
683 Annotation name -> name <> "'s type annotation"
684 TypeTuple -> "a type (in parentheses)" <> anchor
685 TypeRecord -> "a record type" <> anchor
686 PatternList -> "a list pattern" <> anchor
687 PatternTuple -> "a pattern (in parentheses)" <> anchor
688 PatternRecord -> "a record pattern" <> anchor
689 Module -> "a module declaration"
690 Import -> "an import"
691 TypeUnion -> "a union type"
692 TypeAlias -> "a type alias"
693 Infix -> "an infix declaration"
694 Port -> "a port declaration"
697getAnchor :: ContextStack -> Text
698getAnchor stack =
699 case stack of
700 [] ->
701 ""
703 (context, _) : rest ->
704 case context of
705 Definition name ->
706 " in " <> name <> "'s definition"
708 Annotation name ->
709 " in " <> name <> "'s type annotation"
711 _ ->
712 getAnchor rest
715isCaseRelated :: ContextStack -> Bool
716isCaseRelated stack =
717 case stack of
718 [] ->
719 False
721 (context, _) : rest ->
722 context == ExprCase || isCaseRelated rest
725theoryToText :: ContextStack -> Theory -> Text
726theoryToText context theory =
727 case theory of
728 Keyword keyword ->
729 "the `" <> keyword <> "` keyword"
731 Symbol symbol ->
732 case symbol of
733 "=" -> equalsTheory context
734 "->" -> "an arrow (->) followed by an expression"
735 ":" -> "the \"has type\" symbol (:) followed by a type"
736 "," -> "a comma"
737 "|" -> barTheory context
738 "::" -> "the cons operator (::) followed by more list elements"
739 "." -> "a dot (.)"
740 "-" -> "a minus sign (-)"
741 "_" -> "an underscore"
742 "(" -> "a left paren, for grouping or starting tuples"
743 ")" -> "a closing paren"
744 "[" -> "a left square bracket, for starting lists"
745 "]" -> "a right square bracket, to end a list"
746 "{" -> "a left curly brace, for starting records"
747 "}" -> "a right curly brace, to end a record"
748 "{-|" -> "a doc comment, like {-| example -}"
749 _ -> "the (" <> symbol <> ") symbol"
751 LowVar ->
752 "a lower-case variable, like `x` or `user`"
754 CapVar ->
755 "an upper-case variable, like `Maybe` or `Just`"
757 InfixOp ->
758 "an infix operator, like (+) or (==)"
760 Digit ->
761 "a digit from 0 to 9"
763 EndOfFile ->
764 "the end of the file"
766 BadSpace ->
767 badSpace context
769 Expecting next ->
770 case next of
771 Decl -> "a declaration, like `x = 5` or `type alias Model = { ... }`"
772 Expr -> "an expression, like x or 42"
773 AfterOpExpr op -> "an expression after that (" <> op <> ") operator, like x or 42"
774 ElseBranch -> "an `else` branch. An `if` must handle both possibilities."
775 Arg -> "an argument, like `name` or `total`"
776 Pattern -> "a pattern, like `name` or (Just x)"
777 Type -> "a type, like Int or (List String)"
778 Listing -> "a list of exposed values and types, like (..) or (x,y,z)"
779 Exposing -> "something like `exposing (..)`"
782equalsTheory :: ContextStack -> Text
783equalsTheory stack =
784 case stack of
785 [] ->
786 "an equals sign (=)"
788 (context, _) : rest ->
789 case context of
790 ExprRecord -> "an equals sign (=) followed by an expression"
791 Definition name -> "an equals sign (=) followed by " <> name <> "'s definition"
792 TypeUnion -> "an equals sign (=) followed by the first union type constructor"
793 TypeAlias -> "an equals sign (=) followed by the aliased type"
794 _ -> equalsTheory rest
797barTheory :: ContextStack -> Text
798barTheory stack =
799 case stack of
800 [] ->
801 "a vertical bar (|)"
803 (context, _) : rest ->
804 case context of
805 ExprRecord -> "a vertical bar (|) followed by the record fields you want to update"
806 TypeRecord -> "a vertical bar (|) followed by some record field types"
807 TypeUnion -> "a vertical bar (|) followed by more union type constructors"
808 _ -> barTheory rest
811badSpace :: ContextStack -> Text
812badSpace stack =
813 case stack of
814 [] ->
815 "more indentation? I was not done with that last thing yet."
817 (context, _) : rest ->
818 case context of
819 ExprIf -> "the end of that `if`" <> badSpaceExprEnd rest
820 ExprLet -> "the end of that `let`" <> badSpaceExprEnd rest
821 ExprFunc -> badSpace rest
822 ExprCase -> "more of that `case`" <> badSpaceExprEnd rest
823 ExprList -> "the end of that list" <> badSpaceExprEnd rest
824 ExprTuple -> "a closing paren" <> badSpaceExprEnd rest
825 ExprRecord -> "the end of that record" <> badSpaceExprEnd rest
826 Definition name -> "the rest of " <> name <> "'s definition" <> badSpaceExprEnd stack
827 Annotation name -> "the rest of " <> name <> "'s type annotation" <> badSpaceEnd
828 TypeTuple -> "a closing paren" <> badSpaceEnd
829 TypeRecord -> "the end of that record" <> badSpaceEnd
830 PatternList -> "the end of that list" <> badSpaceEnd
831 PatternTuple -> "a closing paren" <> badSpaceEnd
832 PatternRecord -> "the end of that record" <> badSpaceEnd
833 Module -> "something like `module Main exposing (..)`"
834 Import -> "something like `import Html exposing (..)`"
835 TypeUnion -> "more of that union type" <> badSpaceEnd
836 TypeAlias -> "more of that type alias" <> badSpaceEnd
837 Infix -> "more of that infix declaration" <> badSpaceEnd
838 Port -> "more of that port declaration" <> badSpaceEnd
841badSpaceEnd :: Text
842badSpaceEnd =
843 ". Maybe you forgot some code? Or you need more indentation?"
846badSpaceExprEnd :: ContextStack -> Text
847badSpaceExprEnd stack =
848 case stack of
849 [] ->
850 badSpaceEnd
852 (Definition name, R.Position _ column) : _ ->
853 let
854 ending =
855 if column <= 1 then
856 "to be indented?"
857 else
858 "more indentation? (Try " <> i2t (column + 1) <> "+ spaces.)"
859 in
860 ". Maybe you forgot some code? Or maybe the body of `" <> name
861 <> "` needs " <> ending
863 _ : rest ->
864 badSpaceExprEnd rest